Skip to content

Commit 21004dd

Browse files
committedJun 29, 2020
Ensure all decoders support Uint8Array-s directly
1 parent 724829e commit 21004dd

File tree

5 files changed

+215
-166
lines changed

5 files changed

+215
-166
lines changed
 

‎encodings/dbcs-codec.js

+27-21
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ DBCSEncoder.prototype.findIdx = findIdx;
476476
function DBCSDecoder(options, codec) {
477477
// Decoder state
478478
this.nodeIdx = 0;
479-
this.prevBuf = Buffer.alloc(0);
479+
this.prevBytes = [];
480480

481481
// Static data
482482
this.decodeTables = codec.decodeTables;
@@ -488,15 +488,12 @@ function DBCSDecoder(options, codec) {
488488
DBCSDecoder.prototype.write = function(buf) {
489489
var newBuf = Buffer.alloc(buf.length*2),
490490
nodeIdx = this.nodeIdx,
491-
prevBuf = this.prevBuf, prevBufOffset = this.prevBuf.length,
492-
seqStart = -this.prevBuf.length, // idx of the start of current parsed sequence.
491+
prevBytes = this.prevBytes, prevOffset = this.prevBytes.length,
492+
seqStart = -this.prevBytes.length, // idx of the start of current parsed sequence.
493493
uCode;
494494

495-
if (prevBufOffset > 0) // Make prev buf overlap a little to make it easier to slice later.
496-
prevBuf = Buffer.concat([prevBuf, buf.slice(0, 10)]);
497-
498495
for (var i = 0, j = 0; i < buf.length; i++) {
499-
var curByte = (i >= 0) ? buf[i] : prevBuf[i + prevBufOffset];
496+
var curByte = (i >= 0) ? buf[i] : prevBytes[i + prevOffset];
500497

501498
// Lookup in current trie node.
502499
var uCode = this.decodeTables[nodeIdx][curByte];
@@ -506,13 +503,18 @@ DBCSDecoder.prototype.write = function(buf) {
506503
}
507504
else if (uCode === UNASSIGNED) { // Unknown char.
508505
// TODO: Callback with seq.
509-
//var curSeq = (seqStart >= 0) ? buf.slice(seqStart, i+1) : prevBuf.slice(seqStart + prevBufOffset, i+1 + prevBufOffset);
510-
i = seqStart; // Try to parse again, after skipping first byte of the sequence ('i' will be incremented by 'for' cycle).
511506
uCode = this.defaultCharUnicode.charCodeAt(0);
507+
i = seqStart; // Skip one byte ('i' will be incremented by the for loop) and try to parse again.
512508
}
513509
else if (uCode === GB18030_CODE) {
514-
var curSeq = (seqStart >= 0) ? buf.slice(seqStart, i+1) : prevBuf.slice(seqStart + prevBufOffset, i+1 + prevBufOffset);
515-
var ptr = (curSeq[0]-0x81)*12600 + (curSeq[1]-0x30)*1260 + (curSeq[2]-0x81)*10 + (curSeq[3]-0x30);
510+
if (i >= 3) {
511+
var ptr = (buf[i-3]-0x81)*12600 + (buf[i-2]-0x30)*1260 + (buf[i-1]-0x81)*10 + (curByte-0x30);
512+
} else {
513+
var ptr = (prevBytes[i-3+prevOffset]-0x81)*12600 +
514+
(((i-2 >= 0) ? buf[i-2] : prevBytes[i-2+prevOffset])-0x30)*1260 +
515+
(((i-1 >= 0) ? buf[i-1] : prevBytes[i-1+prevOffset])-0x81)*10 +
516+
(curByte-0x30);
517+
}
516518
var idx = findIdx(this.gb18030.gbChars, ptr);
517519
uCode = this.gb18030.uChars[idx] + ptr - this.gb18030.gbChars[idx];
518520
}
@@ -533,13 +535,13 @@ DBCSDecoder.prototype.write = function(buf) {
533535
throw new Error("iconv-lite internal error: invalid decoding table value " + uCode + " at " + nodeIdx + "/" + curByte);
534536

535537
// Write the character to buffer, handling higher planes using surrogate pair.
536-
if (uCode > 0xFFFF) {
538+
if (uCode >= 0x10000) {
537539
uCode -= 0x10000;
538-
var uCodeLead = 0xD800 + Math.floor(uCode / 0x400);
540+
var uCodeLead = 0xD800 | (uCode >> 10);
539541
newBuf[j++] = uCodeLead & 0xFF;
540542
newBuf[j++] = uCodeLead >> 8;
541543

542-
uCode = 0xDC00 + uCode % 0x400;
544+
uCode = 0xDC00 | (uCode & 0x3FF);
543545
}
544546
newBuf[j++] = uCode & 0xFF;
545547
newBuf[j++] = uCode >> 8;
@@ -549,26 +551,30 @@ DBCSDecoder.prototype.write = function(buf) {
549551
}
550552

551553
this.nodeIdx = nodeIdx;
552-
this.prevBuf = (seqStart >= 0) ? buf.slice(seqStart) : prevBuf.slice(seqStart + prevBufOffset);
554+
this.prevBytes = (seqStart >= 0)
555+
? Array.prototype.slice.call(buf, seqStart)
556+
: prevBytes.slice(seqStart + prevOffset).concat(Array.prototype.slice.call(buf));
557+
553558
return newBuf.slice(0, j).toString('ucs2');
554559
}
555560

556561
DBCSDecoder.prototype.end = function() {
557562
var ret = '';
558563

559564
// Try to parse all remaining chars.
560-
while (this.prevBuf.length > 0) {
565+
while (this.prevBytes.length > 0) {
561566
// Skip 1 character in the buffer.
562567
ret += this.defaultCharUnicode;
563-
var buf = this.prevBuf.slice(1);
568+
var bytesArr = this.prevBytes.slice(1);
564569

565570
// Parse remaining as usual.
566-
this.prevBuf = Buffer.alloc(0);
571+
this.prevBytes = [];
567572
this.nodeIdx = 0;
568-
if (buf.length > 0)
569-
ret += this.write(buf);
573+
if (bytesArr.length > 0)
574+
ret += this.write(bytesArr);
570575
}
571576

577+
this.prevBytes = [];
572578
this.nodeIdx = 0;
573579
return ret;
574580
}
@@ -580,7 +586,7 @@ function findIdx(table, val) {
580586

581587
var l = 0, r = table.length;
582588
while (l < r-1) { // always table[l] <= val < table[r]
583-
var mid = l + Math.floor((r-l+1)/2);
589+
var mid = l + ((r-l+1) >> 1);
584590
if (table[mid] <= val)
585591
l = mid;
586592
else

‎encodings/utf16.js

+58-43
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ Utf16BEDecoder.prototype.write = function(buf) {
6161
}
6262

6363
Utf16BEDecoder.prototype.end = function() {
64+
this.overflowByte = -1;
6465
}
6566

6667

@@ -103,80 +104,94 @@ Utf16Encoder.prototype.end = function() {
103104

104105
function Utf16Decoder(options, codec) {
105106
this.decoder = null;
106-
this.initialBytes = [];
107-
this.initialBytesLen = 0;
107+
this.initialBufs = [];
108+
this.initialBufsLen = 0;
108109

109110
this.options = options || {};
110111
this.iconv = codec.iconv;
111112
}
112113

113114
Utf16Decoder.prototype.write = function(buf) {
114115
if (!this.decoder) {
115-
// Support Uint8Array
116-
if (!Buffer.isBuffer(buf)) {
117-
buf = Buffer.from(buf)
118-
}
119-
120116
// Codec is not chosen yet. Accumulate initial bytes.
121-
this.initialBytes.push(buf);
122-
this.initialBytesLen += buf.length;
117+
this.initialBufs.push(buf);
118+
this.initialBufsLen += buf.length;
123119

124-
if (this.initialBytesLen < 16) // We need more bytes to use space heuristic (see below)
120+
if (this.initialBufsLen < 16) // We need more bytes to use space heuristic (see below)
125121
return '';
126122

127123
// We have enough bytes -> detect endianness.
128-
var buf = Buffer.concat(this.initialBytes),
129-
encoding = detectEncoding(buf, this.options.defaultEncoding);
124+
var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding);
130125
this.decoder = this.iconv.getDecoder(encoding, this.options);
131-
this.initialBytes.length = this.initialBytesLen = 0;
126+
127+
var resStr = '';
128+
for (var i = 0; i < this.initialBufs.length; i++)
129+
resStr += this.decoder.write(this.initialBufs[i]);
130+
131+
this.initialBufs.length = this.initialBufsLen = 0;
132+
return resStr;
132133
}
133134

134135
return this.decoder.write(buf);
135136
}
136137

137138
Utf16Decoder.prototype.end = function() {
138139
if (!this.decoder) {
139-
var buf = Buffer.concat(this.initialBytes),
140-
encoding = detectEncoding(buf, this.options.defaultEncoding);
140+
var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding);
141141
this.decoder = this.iconv.getDecoder(encoding, this.options);
142142

143-
var res = this.decoder.write(buf),
144-
trail = this.decoder.end();
143+
var resStr = '';
144+
for (var i = 0; i < this.initialBufs.length; i++)
145+
resStr += this.decoder.write(this.initialBufs[i]);
146+
147+
var trail = this.decoder.end();
148+
if (trail)
149+
resStr += trail;
145150

146-
return trail ? (res + trail) : res;
151+
this.initialBufs.length = this.initialBufsLen = 0;
152+
return resStr;
147153
}
148154
return this.decoder.end();
149155
}
150156

151-
function detectEncoding(buf, defaultEncoding) {
152-
var enc = defaultEncoding || 'utf-16le';
153-
154-
if (buf.length >= 2) {
155-
// Check BOM.
156-
if (buf[0] == 0xFE && buf[1] == 0xFF) // UTF-16BE BOM
157-
enc = 'utf-16be';
158-
else if (buf[0] == 0xFF && buf[1] == 0xFE) // UTF-16LE BOM
159-
enc = 'utf-16le';
160-
else {
161-
// No BOM found. Try to deduce encoding from initial content.
162-
// Most of the time, the content has ASCII chars (U+00**), but the opposite (U+**00) is uncommon.
163-
// So, we count ASCII as if it was LE or BE, and decide from that.
164-
var asciiCharsLE = 0, asciiCharsBE = 0, // Counts of chars in both positions
165-
_len = Math.min(buf.length - (buf.length % 2), 64); // Len is always even.
166-
167-
for (var i = 0; i < _len; i += 2) {
168-
if (buf[i] === 0 && buf[i+1] !== 0) asciiCharsBE++;
169-
if (buf[i] !== 0 && buf[i+1] === 0) asciiCharsLE++;
157+
function detectEncoding(bufs, defaultEncoding) {
158+
var b = [];
159+
var charsProcessed = 0;
160+
var asciiCharsLE = 0, asciiCharsBE = 0; // Number of ASCII chars when decoded as LE or BE.
161+
162+
outer_loop:
163+
for (var i = 0; i < bufs.length; i++) {
164+
var buf = bufs[i];
165+
for (var j = 0; j < buf.length; j++) {
166+
b.push(buf[j]);
167+
if (b.length === 2) {
168+
if (charsProcessed === 0) {
169+
// Check BOM first.
170+
if (b[0] === 0xFF && b[1] === 0xFE) return 'utf-16le';
171+
if (b[0] === 0xFE && b[1] === 0xFF) return 'utf-16be';
172+
}
173+
174+
if (b[0] === 0 && b[1] !== 0) asciiCharsBE++;
175+
if (b[0] !== 0 && b[1] === 0) asciiCharsLE++;
176+
177+
b.length = 0;
178+
charsProcessed++;
179+
180+
if (charsProcessed >= 100) {
181+
break outer_loop;
182+
}
170183
}
171-
172-
if (asciiCharsBE > asciiCharsLE)
173-
enc = 'utf-16be';
174-
else if (asciiCharsBE < asciiCharsLE)
175-
enc = 'utf-16le';
176184
}
177185
}
178186

179-
return enc;
187+
// Make decisions.
188+
// Most of the time, the content has ASCII chars (U+00**), but the opposite (U+**00) is uncommon.
189+
// So, we count ASCII as if it was LE or BE, and decide from that.
190+
if (asciiCharsBE > asciiCharsLE) return 'utf-16be';
191+
if (asciiCharsBE < asciiCharsLE) return 'utf-16le';
192+
193+
// Couldn't decide (likely all zeros or not enough data).
194+
return defaultEncoding || 'utf-16le';
180195
}
181196

182197

‎encodings/utf32.js

+125-97
Original file line numberDiff line numberDiff line change
@@ -100,65 +100,86 @@ Utf32Encoder.prototype.end = function() {
100100
function Utf32Decoder(options, codec) {
101101
this.isLE = codec.isLE;
102102
this.badChar = codec.iconv.defaultCharUnicode.charCodeAt(0);
103-
this.overflow = null;
103+
this.overflow = [];
104104
}
105105

106106
Utf32Decoder.prototype.write = function(src) {
107107
if (src.length === 0)
108108
return '';
109109

110-
// Support Uint8Array
111-
if (!Buffer.isBuffer(src)) {
112-
src = Buffer.from(src);
113-
}
110+
var i = 0;
111+
var codepoint = 0;
112+
var dst = Buffer.alloc(src.length + 4);
113+
var offset = 0;
114+
var isLE = this.isLE;
115+
var overflow = this.overflow;
116+
var badChar = this.badChar;
117+
118+
if (overflow.length > 0) {
119+
for (; i < src.length && overflow.length < 4; i++)
120+
overflow.push(src[i]);
121+
122+
if (overflow.length === 4) {
123+
// NOTE: codepoint is a signed int32 and can be negative.
124+
// NOTE: We copied this block from below to help V8 optimize it (it works with array, not buffer).
125+
if (isLE) {
126+
codepoint = overflow[i] | (overflow[i+1] << 8) | (overflow[i+2] << 16) | (overflow[i+3] << 24);
127+
} else {
128+
codepoint = overflow[i+3] | (overflow[i+2] << 8) | (overflow[i+1] << 16) | (overflow[i] << 24);
129+
}
130+
overflow.length = 0;
114131

115-
if (this.overflow)
116-
src = Buffer.concat([this.overflow, src]);
132+
offset = _writeCodepoint(dst, offset, codepoint, badChar);
133+
}
134+
}
117135

118-
var goodLength = src.length - src.length % 4;
136+
// Main loop. Should be as optimized as possible.
137+
for (; i < src.length - 3; i += 4) {
138+
// NOTE: codepoint is a signed int32 and can be negative.
139+
if (isLE) {
140+
codepoint = src[i] | (src[i+1] << 8) | (src[i+2] << 16) | (src[i+3] << 24);
141+
} else {
142+
codepoint = src[i+3] | (src[i+2] << 8) | (src[i+1] << 16) | (src[i] << 24);
143+
}
144+
offset = _writeCodepoint(dst, offset, codepoint, badChar);
145+
}
119146

120-
if (src.length !== goodLength) {
121-
this.overflow = src.slice(goodLength);
122-
src = src.slice(0, goodLength);
147+
// Keep overflowing bytes.
148+
for (; i < src.length; i++) {
149+
overflow.push(src[i]);
123150
}
124-
else
125-
this.overflow = null;
126151

127-
var dst = Buffer.alloc(goodLength);
128-
var offset = 0;
152+
return dst.slice(0, offset).toString('ucs2');
153+
};
129154

130-
for (var i = 0; i < goodLength; i += 4) {
131-
var codepoint = this.isLE ? src.readUInt32LE(i) : src.readUInt32BE(i);
155+
function _writeCodepoint(dst, offset, codepoint, badChar) {
156+
// NOTE: codepoint is signed int32 and can be negative. We keep it that way to help V8 with optimizations.
157+
if (codepoint < 0 || codepoint > 0x10FFFF) {
158+
// Not a valid Unicode codepoint
159+
codepoint = badChar;
160+
}
132161

133-
if (codepoint < 0x10000) {
134-
// Simple 16-bit character
135-
dst.writeUInt16LE(codepoint, offset);
136-
offset += 2;
137-
}
138-
else {
139-
if (codepoint > 0x10FFFF) {
140-
// Not a valid Unicode codepoint
141-
dst.writeUInt16LE(this.badChar, offset);
142-
offset += 2;
143-
}
144-
else {
145-
// Create high and low surrogates.
146-
codepoint -= 0x10000;
147-
var high = 0xD800 | (codepoint >> 10);
148-
var low = 0xDC00 + (codepoint & 0x3FF);
149-
dst.writeUInt16LE(high, offset);
150-
offset += 2;
151-
dst.writeUInt16LE(low, offset);
152-
offset += 2;
153-
}
154-
}
162+
// Ephemeral Planes: Write high surrogate.
163+
if (codepoint >= 0x10000) {
164+
codepoint -= 0x10000;
165+
166+
var high = 0xD800 | (codepoint >> 10);
167+
dst[offset++] = high & 0xff;
168+
dst[offset++] = high >> 8;
169+
170+
// Low surrogate is written below.
171+
var codepoint = 0xDC00 | (codepoint & 0x3FF);
155172
}
156173

157-
return dst.slice(0, offset).toString('ucs2');
174+
// Write BMP char or low surrogate.
175+
dst[offset++] = codepoint & 0xff;
176+
dst[offset++] = codepoint >> 8;
177+
178+
return offset;
158179
};
159180

160181
Utf32Decoder.prototype.end = function() {
161-
this.overflow = null;
182+
this.overflow.length = 0;
162183
};
163184

164185
// == UTF-32 Auto codec =============================================================
@@ -201,91 +222,98 @@ Utf32AutoEncoder.prototype.end = function() {
201222

202223
function Utf32AutoDecoder(options, codec) {
203224
this.decoder = null;
204-
this.initialBytes = [];
205-
this.initialBytesLen = 0;
225+
this.initialBufs = [];
226+
this.initialBufsLen = 0;
206227
this.options = options || {};
207228
this.iconv = codec.iconv;
208229
}
209230

210231
Utf32AutoDecoder.prototype.write = function(buf) {
211232
if (!this.decoder) {
212-
// Support Uint8Array
213-
if (!Buffer.isBuffer(buf)) {
214-
buf = Buffer.from(buf);
215-
}
216-
217233
// Codec is not chosen yet. Accumulate initial bytes.
218-
this.initialBytes.push(buf);
219-
this.initialBytesLen += buf.length;
234+
this.initialBufs.push(buf);
235+
this.initialBufsLen += buf.length;
220236

221-
if (this.initialBytesLen < 32) // We need more bytes to use space heuristic (see below)
237+
if (this.initialBufsLen < 32) // We need more bytes to use space heuristic (see below)
222238
return '';
223239

224240
// We have enough bytes -> detect endianness.
225-
var buf = Buffer.concat(this.initialBytes),
226-
encoding = detectEncoding(buf, this.options.defaultEncoding);
241+
var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding);
227242
this.decoder = this.iconv.getDecoder(encoding, this.options);
228-
this.initialBytes.length = this.initialBytesLen = 0;
243+
244+
var resStr = '';
245+
for (var i = 0; i < this.initialBufs.length; i++)
246+
resStr += this.decoder.write(this.initialBufs[i]);
247+
248+
this.initialBufs.length = this.initialBufsLen = 0;
249+
return resStr;
229250
}
230251

231252
return this.decoder.write(buf);
232253
};
233254

234255
Utf32AutoDecoder.prototype.end = function() {
235256
if (!this.decoder) {
236-
var buf = Buffer.concat(this.initialBytes),
237-
encoding = detectEncoding(buf, this.options.defaultEncoding);
257+
var encoding = detectEncoding(this.initialBufs, this.options.defaultEncoding);
238258
this.decoder = this.iconv.getDecoder(encoding, this.options);
239259

240-
var res = this.decoder.write(buf),
241-
trail = this.decoder.end();
260+
var resStr = '';
261+
for (var i = 0; i < this.initialBufs.length; i++)
262+
resStr += this.decoder.write(this.initialBufs[i]);
242263

243-
return trail ? (res + trail) : res;
264+
var trail = this.decoder.end();
265+
if (trail)
266+
resStr += trail;
267+
268+
this.initialBufs.length = this.initialBufsLen = 0;
269+
return resStr;
244270
}
245271

246272
return this.decoder.end();
247273
};
248274

249-
function detectEncoding(buf, defaultEncoding) {
250-
var enc = defaultEncoding || 'utf-32le';
251-
252-
if (buf.length >= 4) {
253-
// Check BOM.
254-
if (buf.readUInt32BE(0) === 0xFEFF) // UTF-32LE BOM
255-
enc = 'utf-32be';
256-
else if (buf.readUInt32LE(0) === 0xFEFF) // UTF-32LE BOM
257-
enc = 'utf-32le';
258-
else {
259-
// No BOM found. Try to deduce encoding from initial content.
260-
// Using the wrong endian-ism for UTF-32 will very often result in codepoints that are beyond
261-
// the valid Unicode limit of 0x10FFFF. That will be used as the primary determinant.
262-
//
263-
// Further, we can suppose the content is mostly plain ASCII chars (U+00**).
264-
// So, we count ASCII as if it was LE or BE, and decide from that.
265-
var invalidLE = 0, invalidBE = 0;
266-
var asciiCharsLE = 0, asciiCharsBE = 0, // Counts of chars in both positions
267-
_len = Math.min(buf.length - (buf.length % 4), 128); // Len is always even.
268-
269-
for (var i = 0; i < _len; i += 4) {
270-
var b0 = buf[i], b1 = buf[i + 1], b2 = buf[i + 2], b3 = buf[i + 3];
271-
272-
if (b0 !== 0 || b1 > 0x10) ++invalidBE;
273-
if (b3 !== 0 || b2 > 0x10) ++invalidLE;
274-
275-
if (b0 === 0 && b1 === 0 && b2 === 0 && b3 !== 0) asciiCharsBE++;
276-
if (b0 !== 0 && b1 === 0 && b2 === 0 && b3 === 0) asciiCharsLE++;
275+
function detectEncoding(bufs, defaultEncoding) {
276+
var b = [];
277+
var charsProcessed = 0;
278+
var invalidLE = 0, invalidBE = 0; // Number of invalid chars when decoded as LE or BE.
279+
var bmpCharsLE = 0, bmpCharsBE = 0; // Number of BMP chars when decoded as LE or BE.
280+
281+
outer_loop:
282+
for (var i = 0; i < bufs.length; i++) {
283+
var buf = bufs[i];
284+
for (var j = 0; j < buf.length; j++) {
285+
b.push(buf[j]);
286+
if (b.length === 4) {
287+
if (charsProcessed === 0) {
288+
// Check BOM first.
289+
if (b[0] === 0xFF && b[1] === 0xFE && b[2] === 0 && b[3] === 0) {
290+
return 'utf-32le';
291+
}
292+
if (b[0] === 0 && b[1] === 0 && b[2] === 0xFE && b[3] === 0xFF) {
293+
return 'utf-32be';
294+
}
295+
}
296+
297+
if (b[0] !== 0 || b[1] > 0x10) invalidBE++;
298+
if (b[3] !== 0 || b[2] > 0x10) invalidLE++;
299+
300+
if (b[0] === 0 && b[1] === 0 && (b[2] !== 0 || b[3] !== 0)) bmpCharsBE++;
301+
if ((b[0] !== 0 || b[1] !== 0) && b[2] === 0 && b[3] === 0) bmpCharsLE++;
302+
303+
b.length = 0;
304+
charsProcessed++;
305+
306+
if (charsProcessed >= 100) {
307+
break outer_loop;
308+
}
277309
}
278-
279-
if (invalidBE < invalidLE)
280-
enc = 'utf-32be';
281-
else if (invalidLE < invalidBE)
282-
enc = 'utf-32le';
283-
if (asciiCharsBE > asciiCharsLE)
284-
enc = 'utf-32be';
285-
else if (asciiCharsBE < asciiCharsLE)
286-
enc = 'utf-32le';
287310
}
288311
}
289312

290-
return enc;
313+
// Make decisions.
314+
if (bmpCharsBE - invalidBE > bmpCharsLE - invalidLE) return 'utf-32be';
315+
if (bmpCharsBE - invalidBE < bmpCharsLE - invalidLE) return 'utf-32le';
316+
317+
// Couldn't decide (likely all zeros or not enough data).
318+
return defaultEncoding || 'utf-32le';
291319
}

‎encodings/utf7.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Utf7Decoder.prototype.write = function(buf) {
7474
if (i == lastI && buf[i] == minusChar) {// "+-" -> "+"
7575
res += "+";
7676
} else {
77-
var b64str = base64Accum + buf.slice(lastI, i).toString();
77+
var b64str = base64Accum + this.iconv.decode(buf.slice(lastI, i), "ascii");
7878
res += this.iconv.decode(Buffer.from(b64str, 'base64'), "utf16-be");
7979
}
8080

@@ -91,7 +91,7 @@ Utf7Decoder.prototype.write = function(buf) {
9191
if (!inBase64) {
9292
res += this.iconv.decode(buf.slice(lastI), "ascii"); // Write direct chars.
9393
} else {
94-
var b64str = base64Accum + buf.slice(lastI).toString();
94+
var b64str = base64Accum + this.iconv.decode(buf.slice(lastI), "ascii");
9595

9696
var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars.
9797
base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future.
@@ -245,7 +245,7 @@ Utf7IMAPDecoder.prototype.write = function(buf) {
245245
if (i == lastI && buf[i] == minusChar) { // "&-" -> "&"
246246
res += "&";
247247
} else {
248-
var b64str = base64Accum + buf.slice(lastI, i).toString().replace(/,/g, '/');
248+
var b64str = base64Accum + this.iconv.decode(buf.slice(lastI, i), "ascii").replace(/,/g, '/');
249249
res += this.iconv.decode(Buffer.from(b64str, 'base64'), "utf16-be");
250250
}
251251

@@ -262,7 +262,7 @@ Utf7IMAPDecoder.prototype.write = function(buf) {
262262
if (!inBase64) {
263263
res += this.iconv.decode(buf.slice(lastI), "ascii"); // Write direct chars.
264264
} else {
265-
var b64str = base64Accum + buf.slice(lastI).toString().replace(/,/g, '/');
265+
var b64str = base64Accum + this.iconv.decode(buf.slice(lastI), "ascii").replace(/,/g, '/');
266266

267267
var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars.
268268
base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future.

‎lib/streams.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ module.exports = function(stream_module) {
6969
});
7070

7171
IconvLiteDecoderStream.prototype._transform = function(chunk, encoding, done) {
72-
if (!Buffer.isBuffer(chunk))
72+
if (!Buffer.isBuffer(chunk) && !(chunk instanceof Uint8Array))
7373
return done(new Error("Iconv decoding stream needs buffers as its input."));
7474
try {
7575
var res = this.conv.write(chunk);

0 commit comments

Comments
 (0)
Please sign in to comment.