mirror of https://github.com/nodejs/node.git
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>pull/18723/merge
parent
b6000d8285
commit
e782715d0a
|
@ -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;
|
||||
}
|
||||
|
||||
/* Everything below this line is undocumented legacy stuff. */
|
||||
|
||||
text(buf, offset) {
|
||||
this[kNativeDecoder][kMissingBytes] = 0;
|
||||
this[kNativeDecoder][kBufferedBytes] = 0;
|
||||
return this.write(buf.slice(offset));
|
||||
}
|
||||
|
||||
get lastTotal() {
|
||||
return this[kNativeDecoder][kBufferedBytes] + this.lastNeed;
|
||||
}
|
||||
|
||||
get lastChar() {
|
||||
return this[kNativeDecoder].subarray(kIncompleteCharactersStart,
|
||||
kIncompleteCharactersEnd);
|
||||
}
|
||||
function StringDecoder(encoding) {
|
||||
this.encoding = normalizeEncoding(encoding);
|
||||
this[kNativeDecoder] = Buffer.alloc(kSize);
|
||||
this[kNativeDecoder][kEncodingField] = encodingsMap[this.encoding];
|
||||
}
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/* 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));
|
||||
};
|
||||
|
||||
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;
|
||||
|
|
|
@ -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');
|
||||
|
|
Loading…
Reference in New Issue