diff options
author | Anatoli Papirovski <apapirovski@mac.com> | 2018-02-12 01:21:19 -0500 |
---|---|---|
committer | Anatoli Papirovski <apapirovski@mac.com> | 2018-02-13 08:03:23 -0500 |
commit | e782715d0a1c33f98212bdc064b4b4eea198e605 (patch) | |
tree | a08026548f97ddffcd34265528a0f7e3332701d7 | |
parent | b6000d828525f991341bd69fc4550e1316d4c81c (diff) | |
download | android-node-v8-e782715d0a1c33f98212bdc064b4b4eea198e605.tar.gz android-node-v8-e782715d0a1c33f98212bdc064b4b4eea198e605.tar.bz2 android-node-v8-e782715d0a1c33f98212bdc064b4b4eea198e605.zip |
string_decoder: fix regressions
There are libraries which invoke StringDecoder using .call and
.inherits, which directly conflicts with making StringDecoder
be a class which can only be invoked with the new keyword.
Revert to declaring it as a function.
StringDecoder#lastNeed was not defined, redefine it using
the new interface and fix StringDecoder#lastTotal.
PR-URL: https://github.com/nodejs/node/pull/18723
Refs: https://github.com/nodejs/node/pull/18537
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
-rw-r--r-- | lib/string_decoder.js | 88 | ||||
-rw-r--r-- | test/parallel/test-string-decoder.js | 10 |
2 files changed, 61 insertions, 37 deletions
diff --git a/lib/string_decoder.js b/lib/string_decoder.js index d955a66330..04d31b2607 100644 --- a/lib/string_decoder.js +++ b/lib/string_decoder.js @@ -56,47 +56,61 @@ for (var i = 0; i < encodings.length; ++i) // StringDecoder provides an interface for efficiently splitting a series of // buffers into a series of JS strings without breaking apart multi-byte // characters. -class StringDecoder { - constructor(encoding) { - this.encoding = normalizeEncoding(encoding); - this[kNativeDecoder] = Buffer.alloc(kSize); - this[kNativeDecoder][kEncodingField] = encodingsMap[this.encoding]; - } - - write(buf) { - if (typeof buf === 'string') - return buf; - if (!ArrayBuffer.isView(buf)) - throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'buf', - ['Buffer', 'Uint8Array', 'ArrayBufferView']); - return decode(this[kNativeDecoder], buf); - } - - end(buf) { - let ret = ''; - if (buf !== undefined) - ret = this.write(buf); - if (this[kNativeDecoder][kBufferedBytes] > 0) - ret += flush(this[kNativeDecoder]); - return ret; - } +function StringDecoder(encoding) { + this.encoding = normalizeEncoding(encoding); + this[kNativeDecoder] = Buffer.alloc(kSize); + this[kNativeDecoder][kEncodingField] = encodingsMap[this.encoding]; +} - /* Everything below this line is undocumented legacy stuff. */ +StringDecoder.prototype.write = function write(buf) { + if (typeof buf === 'string') + return buf; + if (!ArrayBuffer.isView(buf)) + throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'buf', + ['Buffer', 'Uint8Array', 'ArrayBufferView']); + return decode(this[kNativeDecoder], buf); +}; - text(buf, offset) { - this[kNativeDecoder][kMissingBytes] = 0; - this[kNativeDecoder][kBufferedBytes] = 0; - return this.write(buf.slice(offset)); - } +StringDecoder.prototype.end = function end(buf) { + let ret = ''; + if (buf !== undefined) + ret = this.write(buf); + if (this[kNativeDecoder][kBufferedBytes] > 0) + ret += flush(this[kNativeDecoder]); + return ret; +}; - get lastTotal() { - return this[kNativeDecoder][kBufferedBytes] + this.lastNeed; - } +/* Everything below this line is undocumented legacy stuff. */ +StringDecoder.prototype.text = function text(buf, offset) { + this[kNativeDecoder][kMissingBytes] = 0; + this[kNativeDecoder][kBufferedBytes] = 0; + return this.write(buf.slice(offset)); +}; - get lastChar() { - return this[kNativeDecoder].subarray(kIncompleteCharactersStart, - kIncompleteCharactersEnd); +Object.defineProperties(StringDecoder.prototype, { + lastChar: { + configurable: true, + enumerable: true, + get() { + return this[kNativeDecoder].subarray(kIncompleteCharactersStart, + kIncompleteCharactersEnd); + } + }, + lastNeed: { + configurable: true, + enumerable: true, + get() { + return this[kNativeDecoder][kMissingBytes]; + } + }, + lastTotal: { + configurable: true, + enumerable: true, + get() { + return this[kNativeDecoder][kBufferedBytes] + + this[kNativeDecoder][kMissingBytes]; + } } -} +}); exports.StringDecoder = StringDecoder; diff --git a/test/parallel/test-string-decoder.js b/test/parallel/test-string-decoder.js index 21a0b6c3e3..0e7ea8ffdd 100644 --- a/test/parallel/test-string-decoder.js +++ b/test/parallel/test-string-decoder.js @@ -29,6 +29,11 @@ const StringDecoder = require('string_decoder').StringDecoder; let decoder = new StringDecoder(); assert.strictEqual(decoder.encoding, 'utf8'); +// Should work without 'new' keyword +const decoder2 = {}; +StringDecoder.call(decoder2); +assert.strictEqual(decoder2.encoding, 'utf8'); + // UTF-8 test('utf-8', Buffer.from('$', 'utf-8'), '$'); test('utf-8', Buffer.from('¢', 'utf-8'), '¢'); @@ -84,6 +89,11 @@ test('utf16le', Buffer.from('3DD84DDC', 'hex'), '\ud83d\udc4d'); // thumbs up // Additional UTF-8 tests decoder = new StringDecoder('utf8'); assert.strictEqual(decoder.write(Buffer.from('E1', 'hex')), ''); + +// A quick test for lastNeed & lastTotal which are undocumented. +assert.strictEqual(decoder.lastNeed, 2); +assert.strictEqual(decoder.lastTotal, 3); + assert.strictEqual(decoder.end(), '\ufffd'); decoder = new StringDecoder('utf8'); |