Skip to content

Commit a89e566

Browse files
fix(browser): fix decoding for strings with surrogate pairs (#13)
1 parent bd91aa7 commit a89e566

File tree

3 files changed

+85
-27
lines changed

3 files changed

+85
-27
lines changed

browser/decode.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function Decoder(buffer) {
1414
}
1515

1616
function utf8Read(view, offset, length) {
17-
var string = '';
17+
var string = '', chr = 0;
1818
for (var i = offset, end = offset + length; i < end; i++) {
1919
var byte = view.getUint8(i);
2020
if ((byte & 0x80) === 0x00) {
@@ -37,12 +37,16 @@ function utf8Read(view, offset, length) {
3737
continue;
3838
}
3939
if ((byte & 0xf8) === 0xf0) {
40-
string += String.fromCharCode(
41-
((byte & 0x07) << 18) |
40+
chr = ((byte & 0x07) << 18) |
4241
((view.getUint8(++i) & 0x3f) << 12) |
4342
((view.getUint8(++i) & 0x3f) << 6) |
44-
((view.getUint8(++i) & 0x3f) << 0)
45-
);
43+
((view.getUint8(++i) & 0x3f) << 0);
44+
if (chr >= 0x010000) { // surrogate pair
45+
chr -= 0x010000;
46+
string += String.fromCharCode((chr >>> 10) + 0xD800, (chr & 0x3FF) + 0xDC00);
47+
} else {
48+
string += String.fromCharCode(chr);
49+
}
4650
continue;
4751
}
4852
throw new Error('Invalid byte ' + byte.toString(16));

test/browser.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
'use strict';
2+
3+
var notepack = {
4+
encode: require('../browser/encode'),
5+
decode: require('../browser/decode')
6+
};
7+
8+
function array(length) {
9+
var arr = new Array(length);
10+
for (var i = 0; i < arr.length; i++) {
11+
arr[i] = 0;
12+
}
13+
return arr;
14+
}
15+
16+
function map(length) {
17+
var result = {};
18+
for (var i = 0; i < length; i++) {
19+
result[i + ''] = 0;
20+
}
21+
return result;
22+
}
23+
24+
describe('notepack (browser build)', function() {
25+
it('ArrayBuffer view', function() {
26+
expect(notepack.decode(Uint8Array.from([ 0x93, 1, 2, 3 ]))).to.deep.equal([ 1, 2, 3 ]);
27+
});
28+
29+
it('offset ArrayBuffer view', function() {
30+
var buffer = new ArrayBuffer(14);
31+
var view = new Uint8Array(buffer);
32+
33+
// Fill with junk before setting the encoded data
34+
view.fill(0xFF);
35+
36+
// Put the encoded data somewhere in the middle of the buffer
37+
view.set([ 0x93, 1, 2, 3 ], 4);
38+
39+
expect(notepack.decode(new Uint8Array(buffer, 4, 4))).to.deep.equal([ 1, 2, 3 ]);
40+
expect(notepack.decode(new Uint16Array(buffer, 4, 2))).to.deep.equal([ 1, 2, 3 ]);
41+
});
42+
43+
it('toJSON', function () {
44+
var obj = {
45+
a: 'b',
46+
toJSON: function () {
47+
return 'c';
48+
}
49+
};
50+
expect(notepack.encode(obj)).to.deep.equal(notepack.encode('c'));
51+
});
52+
53+
it('all formats', function () {
54+
this.timeout(20000);
55+
var expected = {
56+
unsigned: [1, 2, 3, 4, { b: { c: [128, 256, 65536, 4294967296] } }],
57+
signed: [-1, -2, -3, -4, { b: { c: [-33, -129, -32769, -2147483649] } }],
58+
bin: [Uint8Array.of('1', '2', '3').buffer, Uint8Array.from('1'.repeat(256)).buffer, Uint8Array.from('2'.repeat(65536)).buffer],
59+
str: ['abc', 'g'.repeat(32), 'h'.repeat(256), 'i'.repeat(65536)],
60+
array: [[], array(16), array(65536)],
61+
map: {},
62+
nil: null,
63+
bool: { 'true': true, 'false': false, both: [true, false, false, false, true] },
64+
fixext: [undefined, new Date('2140-01-01T13:14:15.678Z'), undefined, new Date('2005-12-31T23:59:59.999Z')],
65+
utf8: ['α', '亜', '\uD83D\uDC26'],
66+
float: [1.1, 1234567891234567.5, Infinity, -Infinity, NaN]
67+
};
68+
expected.map['a'.repeat(32)] = { a: 'a', b: 'b', c: 'c' };
69+
expected.map['b'.repeat(256)] = { a: { b: 1, c: 1, d: 1, e: { f: { g: 2, h: 2 } } } };
70+
expected.map['c'.repeat(65536)] = [{ a: { b: 1, c: 1, d: 1, e: { f: [{ g: 2, h: 2 }] } } }];
71+
expected.map16 = map(65535);
72+
expected.map32 = map(65536);
73+
74+
expect(notepack.decode(notepack.encode(expected))).to.deep.equal(expected);
75+
});
76+
});

test/test.js

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
'use strict';
22

33
var notepack = require('../');
4-
var notepackBrowser = { encode : require('../browser/encode.js'),
5-
decode : require('../browser/decode.js') };
64

75
function array(length) {
86
var arr = new Array(length);
@@ -310,23 +308,3 @@ describe('notepack', function () {
310308
expect(notepack.decode(notepack.encode(fixture))).to.deep.equal(fixture);
311309
});
312310
});
313-
314-
describe('notepack browser', function() {
315-
it('ArrayBuffer view', function() {
316-
expect(notepackBrowser.decode(Uint8Array.from([ 0x93, 1, 2, 3 ]))).to.deep.equal([ 1, 2, 3 ]);
317-
});
318-
319-
it('offset ArrayBuffer view', function() {
320-
var buffer = new ArrayBuffer(14);
321-
var view = new Uint8Array(buffer);
322-
323-
// Fill with junk before setting the encoded data
324-
view.fill(0xFF);
325-
326-
// Put the encoded data somewhere in the middle of the buffer
327-
view.set([ 0x93, 1, 2, 3 ], 4);
328-
329-
expect(notepackBrowser.decode(new Uint8Array(buffer, 4, 4))).to.deep.equal([ 1, 2, 3 ]);
330-
expect(notepackBrowser.decode(new Uint16Array(buffer, 4, 2))).to.deep.equal([ 1, 2, 3 ]);
331-
});
332-
});

0 commit comments

Comments
 (0)