11cb0ef41Sopenharmony_ci// Copyright Joyent, Inc. and other Node contributors. 21cb0ef41Sopenharmony_ci// 31cb0ef41Sopenharmony_ci// Permission is hereby granted, free of charge, to any person obtaining a 41cb0ef41Sopenharmony_ci// copy of this software and associated documentation files (the 51cb0ef41Sopenharmony_ci// "Software"), to deal in the Software without restriction, including 61cb0ef41Sopenharmony_ci// without limitation the rights to use, copy, modify, merge, publish, 71cb0ef41Sopenharmony_ci// distribute, sublicense, and/or sell copies of the Software, and to permit 81cb0ef41Sopenharmony_ci// persons to whom the Software is furnished to do so, subject to the 91cb0ef41Sopenharmony_ci// following conditions: 101cb0ef41Sopenharmony_ci// 111cb0ef41Sopenharmony_ci// The above copyright notice and this permission notice shall be included 121cb0ef41Sopenharmony_ci// in all copies or substantial portions of the Software. 131cb0ef41Sopenharmony_ci// 141cb0ef41Sopenharmony_ci// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 151cb0ef41Sopenharmony_ci// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 161cb0ef41Sopenharmony_ci// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 171cb0ef41Sopenharmony_ci// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 181cb0ef41Sopenharmony_ci// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 191cb0ef41Sopenharmony_ci// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 201cb0ef41Sopenharmony_ci// USE OR OTHER DEALINGS IN THE SOFTWARE. 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci'use strict'; 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ciconst { 251cb0ef41Sopenharmony_ci ArrayBufferIsView, 261cb0ef41Sopenharmony_ci ObjectDefineProperties, 271cb0ef41Sopenharmony_ci Symbol, 281cb0ef41Sopenharmony_ci TypedArrayPrototypeSubarray, 291cb0ef41Sopenharmony_ci} = primordials; 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ciconst { Buffer } = require('buffer'); 321cb0ef41Sopenharmony_ciconst { 331cb0ef41Sopenharmony_ci kIncompleteCharactersStart, 341cb0ef41Sopenharmony_ci kIncompleteCharactersEnd, 351cb0ef41Sopenharmony_ci kMissingBytes, 361cb0ef41Sopenharmony_ci kBufferedBytes, 371cb0ef41Sopenharmony_ci kEncodingField, 381cb0ef41Sopenharmony_ci kSize, 391cb0ef41Sopenharmony_ci decode, 401cb0ef41Sopenharmony_ci flush, 411cb0ef41Sopenharmony_ci encodings, 421cb0ef41Sopenharmony_ci} = internalBinding('string_decoder'); 431cb0ef41Sopenharmony_ciconst internalUtil = require('internal/util'); 441cb0ef41Sopenharmony_ciconst { 451cb0ef41Sopenharmony_ci ERR_INVALID_ARG_TYPE, 461cb0ef41Sopenharmony_ci ERR_INVALID_THIS, 471cb0ef41Sopenharmony_ci ERR_UNKNOWN_ENCODING, 481cb0ef41Sopenharmony_ci} = require('internal/errors').codes; 491cb0ef41Sopenharmony_ciconst isEncoding = Buffer[internalUtil.kIsEncodingSymbol]; 501cb0ef41Sopenharmony_ci 511cb0ef41Sopenharmony_ciconst kNativeDecoder = Symbol('kNativeDecoder'); 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci// Do not cache `Buffer.isEncoding` when checking encoding names as some 541cb0ef41Sopenharmony_ci// modules monkey-patch it to support additional encodings 551cb0ef41Sopenharmony_ci/** 561cb0ef41Sopenharmony_ci * Normalize encoding notation 571cb0ef41Sopenharmony_ci * @param {string} enc 581cb0ef41Sopenharmony_ci * @returns {"utf8" | "utf16le" | "hex" | "ascii" 591cb0ef41Sopenharmony_ci * | "base64" | "latin1" | "base64url"} 601cb0ef41Sopenharmony_ci * @throws {TypeError} Throws an error when encoding is invalid 611cb0ef41Sopenharmony_ci */ 621cb0ef41Sopenharmony_cifunction normalizeEncoding(enc) { 631cb0ef41Sopenharmony_ci const nenc = internalUtil.normalizeEncoding(enc); 641cb0ef41Sopenharmony_ci if (nenc === undefined) { 651cb0ef41Sopenharmony_ci if (Buffer.isEncoding === isEncoding || !Buffer.isEncoding(enc)) 661cb0ef41Sopenharmony_ci throw new ERR_UNKNOWN_ENCODING(enc); 671cb0ef41Sopenharmony_ci return enc; 681cb0ef41Sopenharmony_ci } 691cb0ef41Sopenharmony_ci return nenc; 701cb0ef41Sopenharmony_ci} 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ciconst encodingsMap = {}; 731cb0ef41Sopenharmony_cifor (let i = 0; i < encodings.length; ++i) 741cb0ef41Sopenharmony_ci encodingsMap[encodings[i]] = i; 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci/** 771cb0ef41Sopenharmony_ci * StringDecoder provides an interface for efficiently splitting a series of 781cb0ef41Sopenharmony_ci * buffers into a series of JS strings without breaking apart multi-byte 791cb0ef41Sopenharmony_ci * characters. 801cb0ef41Sopenharmony_ci * @param {string} [encoding=utf-8] 811cb0ef41Sopenharmony_ci */ 821cb0ef41Sopenharmony_cifunction StringDecoder(encoding) { 831cb0ef41Sopenharmony_ci this.encoding = normalizeEncoding(encoding); 841cb0ef41Sopenharmony_ci this[kNativeDecoder] = Buffer.alloc(kSize); 851cb0ef41Sopenharmony_ci this[kNativeDecoder][kEncodingField] = encodingsMap[this.encoding]; 861cb0ef41Sopenharmony_ci} 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci/** 891cb0ef41Sopenharmony_ci * Returns a decoded string, omitting any incomplete multi-bytes 901cb0ef41Sopenharmony_ci * characters at the end of the Buffer, or TypedArray, or DataView 911cb0ef41Sopenharmony_ci * @param {string | Buffer | TypedArray | DataView} buf 921cb0ef41Sopenharmony_ci * @returns {string} 931cb0ef41Sopenharmony_ci * @throws {TypeError} Throws when buf is not in one of supported types 941cb0ef41Sopenharmony_ci */ 951cb0ef41Sopenharmony_ciStringDecoder.prototype.write = function write(buf) { 961cb0ef41Sopenharmony_ci if (typeof buf === 'string') 971cb0ef41Sopenharmony_ci return buf; 981cb0ef41Sopenharmony_ci if (!ArrayBufferIsView(buf)) 991cb0ef41Sopenharmony_ci throw new ERR_INVALID_ARG_TYPE('buf', 1001cb0ef41Sopenharmony_ci ['Buffer', 'TypedArray', 'DataView'], 1011cb0ef41Sopenharmony_ci buf); 1021cb0ef41Sopenharmony_ci if (!this[kNativeDecoder]) { 1031cb0ef41Sopenharmony_ci throw new ERR_INVALID_THIS('StringDecoder'); 1041cb0ef41Sopenharmony_ci } 1051cb0ef41Sopenharmony_ci return decode(this[kNativeDecoder], buf); 1061cb0ef41Sopenharmony_ci}; 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci/** 1091cb0ef41Sopenharmony_ci * Returns any remaining input stored in the internal buffer as a string. 1101cb0ef41Sopenharmony_ci * After end() is called, the stringDecoder object can be reused for new 1111cb0ef41Sopenharmony_ci * input. 1121cb0ef41Sopenharmony_ci * @param {string | Buffer | TypedArray | DataView} [buf] 1131cb0ef41Sopenharmony_ci * @returns {string} 1141cb0ef41Sopenharmony_ci */ 1151cb0ef41Sopenharmony_ciStringDecoder.prototype.end = function end(buf) { 1161cb0ef41Sopenharmony_ci let ret = ''; 1171cb0ef41Sopenharmony_ci if (buf !== undefined) 1181cb0ef41Sopenharmony_ci ret = this.write(buf); 1191cb0ef41Sopenharmony_ci if (this[kNativeDecoder][kBufferedBytes] > 0) 1201cb0ef41Sopenharmony_ci ret += flush(this[kNativeDecoder]); 1211cb0ef41Sopenharmony_ci return ret; 1221cb0ef41Sopenharmony_ci}; 1231cb0ef41Sopenharmony_ci 1241cb0ef41Sopenharmony_ci/* Everything below this line is undocumented legacy stuff. */ 1251cb0ef41Sopenharmony_ci/** 1261cb0ef41Sopenharmony_ci * 1271cb0ef41Sopenharmony_ci * @param {string | Buffer | TypedArray | DataView} buf 1281cb0ef41Sopenharmony_ci * @param {number} offset 1291cb0ef41Sopenharmony_ci * @returns {string} 1301cb0ef41Sopenharmony_ci */ 1311cb0ef41Sopenharmony_ciStringDecoder.prototype.text = function text(buf, offset) { 1321cb0ef41Sopenharmony_ci this[kNativeDecoder][kMissingBytes] = 0; 1331cb0ef41Sopenharmony_ci this[kNativeDecoder][kBufferedBytes] = 0; 1341cb0ef41Sopenharmony_ci return this.write(buf.slice(offset)); 1351cb0ef41Sopenharmony_ci}; 1361cb0ef41Sopenharmony_ci 1371cb0ef41Sopenharmony_ciObjectDefineProperties(StringDecoder.prototype, { 1381cb0ef41Sopenharmony_ci lastChar: { 1391cb0ef41Sopenharmony_ci __proto__: null, 1401cb0ef41Sopenharmony_ci configurable: true, 1411cb0ef41Sopenharmony_ci enumerable: true, 1421cb0ef41Sopenharmony_ci get() { 1431cb0ef41Sopenharmony_ci return TypedArrayPrototypeSubarray(this[kNativeDecoder], 1441cb0ef41Sopenharmony_ci kIncompleteCharactersStart, 1451cb0ef41Sopenharmony_ci kIncompleteCharactersEnd); 1461cb0ef41Sopenharmony_ci }, 1471cb0ef41Sopenharmony_ci }, 1481cb0ef41Sopenharmony_ci lastNeed: { 1491cb0ef41Sopenharmony_ci __proto__: null, 1501cb0ef41Sopenharmony_ci configurable: true, 1511cb0ef41Sopenharmony_ci enumerable: true, 1521cb0ef41Sopenharmony_ci get() { 1531cb0ef41Sopenharmony_ci return this[kNativeDecoder][kMissingBytes]; 1541cb0ef41Sopenharmony_ci }, 1551cb0ef41Sopenharmony_ci }, 1561cb0ef41Sopenharmony_ci lastTotal: { 1571cb0ef41Sopenharmony_ci __proto__: null, 1581cb0ef41Sopenharmony_ci configurable: true, 1591cb0ef41Sopenharmony_ci enumerable: true, 1601cb0ef41Sopenharmony_ci get() { 1611cb0ef41Sopenharmony_ci return this[kNativeDecoder][kBufferedBytes] + 1621cb0ef41Sopenharmony_ci this[kNativeDecoder][kMissingBytes]; 1631cb0ef41Sopenharmony_ci }, 1641cb0ef41Sopenharmony_ci }, 1651cb0ef41Sopenharmony_ci}); 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ciexports.StringDecoder = StringDecoder; 168