10000 Add support for decoding indefinite length items · arduino/cbor-js@dca0855 · GitHub
[go: up one dir, main page]

Skip to content

Commit dca0855

Browse files
committed
Add support for decoding indefinite length items
1 parent be79ada commit dca0855

File tree

2 files changed

+201
-56
lines changed

2 files changed

+201
-56
lines changed

cbor.js

Lines changed: 96 additions & 50 deletions
F438
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,68 @@ function decode(data, tagger, simpleValue) {
236236
function readUint64() {
237237
return readUint32() * POW_2_32 + readUint32();
238238
}
239+
function readBreak() {
240+
if (dataView.getUint8(offset) !== 0xff)
241+
return false;
242+
offset += 1;
243+
return true;
244+
}
245+
function readLength(additionalInformation) {
246+
if (additionalInformation < 24)
247+
return additionalInformation;
248+
if (additionalInformation === 24)
249+
return readUint8();
250+
if (additionalInformation === 25)
251+
return readUint16();
252+
if (additionalInformation === 26)
253+
return readUint32();
254+
if (additionalInformation === 27)
255+
return readUint64();
256+
if (additionalInformation === 31)
257+
return -1;
258+
throw "Invalid length encoding";
259+
}
260+
function readIndefiniteStringLength(majorType) {
261+
var initialByte = readUint8();
262+
if (initialByte === 0xff)
263+
return -1;
264+
var length = readLength(initialByte & 0x1f);
265+
if (length < 0 || (initialByte >> 5) !== majorType)
266+
throw "Invalid indefinite length element";
267+
return length;
268+
}
269+
270+
function appendUtf16data(utf16data, length) {
271+
for (var i = 0; i < length; ++i) {
272+
var value = readUint8();
273+
if (value & 0x80) {
274+
if (value < 0xe0) {
275+
value = (value & 0x1f) << 6
276+
| (readUint8() & 0x3f);
277+
length -= 1;
278+
} else if (value < 0xf0) {
279+
value = (value & 0x0f) << 12
280+
| (readUint8() & 0x3f) << 6
281+
| (readUint8() & 0x3f);
282+
length -= 2;
283+
} else {
284+
value = (value & 0x0f) << 18
285+
| (readUint8() & 0x3f) << 12
286+
| (readUint8() & 0x3f) << 6
287+
| (readUint8() & 0x3f);
288+
length -= 3;
289+
}
290+
}
291+
292+
if (value < 0x10000) {
293+
utf16data.push(value);
294+
} else {
295+
value -= 0x10000;
296+
utf16data.push(0xd800 | (value >> 10));
297+
utf16data.push(0xdc00 | (value & 0x3ff));
298+
}
299+
}
300+
}
239301

240302
function decodeItem() {
241303
var initialByte = readUint8();
@@ -255,71 +317,55 @@ function decode(data, tagger, simpleValue) {
255317
}
256318
}
257319

258-
switch (additionalInformation) {
259-
case 24:
260-
length = readUint8();
261-
break;
262-
case 25:
263-
length = readUint16();
264-
break;
265-
case 26:
266-
length = readUint32();
267-
break;
268-
case 27:
269-
length = readUint64();
270-
break;
271-
default:
272-
length = additionalInformation;
273-
break;
274-
}
320+
length = readLength(additionalInformation);
321+
if (length < 0 && (majorType < 2 || 6 < majorType))
322+
throw "Invalid length";
275323

276324
switch (majorType) {
277325
case 0:
278326
return length;
279327
case 1:
280328
return -1 - length;
281329
case 2:
282-
return readArrayBuffer(length);
283-
case 3:
284-
var utf16data = [];
285-
for (i = 0; i < length; ++i) {
286-
var value = readUint8();
287-
if (value & 0x80) {
288-
if (value < 0xe0) {
289-
value = (value & 0x1f) << 6
290-
| (readUint8() & 0x3f);
291-
length -= 1;
292-
} else if (value < 0xf0) {
293-
value = (value & 0x0f) << 12
294-
| (readUint8() & 0x3f) << 6
295-
| (readUint8() & 0x3f);
296-
length -= 2;
297-
} else {
298-
value = (value & 0x0f) << 18
299-
| (readUint8() & 0x3f) << 12
300-
| (readUint8() & 0x3f) << 6
301-
| (readUint8() & 0x3f);
302-
length -= 3;
303-
}
330+
if (length < 0) {
331+
var elements = [];
332+
var fullArrayLength = 0;
333+
while ((length = readIndefiniteStringLength(majorType)) >= 0) {
334+
fullArrayLength += length;
335+
elements.push(readArrayBuffer(length));
304336
}
305-
306-
if (value < 0x10000) {
307-
utf16data.push(value);
308-
} else {
309-
value -= 0x10000;
310-
utf16data.push(0xd800 | (value >> 10));
311-
utf16data.push(0xdc00 | (value & 0x3ff));
337+
var fullArray = new Uint8Array(fullArrayLength);
338+
var fullArrayOffset = 0;
339+
for (i = 0; i < elements.length; ++i) {
340+
fullArray.set(elements[i], fullArrayOffset);
341+
fullArrayOffset += elements[i].length;
312342
}
343+
return fullArray;
313344
}
345+
return readArrayBuffer(length);
346+
case 3:
347+
var utf16data = [];
348+
if (length < 0) {
349+
while ((length = readIndefiniteStringLength(majorType)) >= 0)
350+
appendUtf16data(utf16data, length);
351+
} else
352+
appendUtf16data(utf16data, length);
314353
return String.fromCharCode.apply(null, utf16data);
315354
case 4:
316-
var retArray = new Array(length);
317-
for (i = 0; i < length; ++i)
318-
retArray[i] = decodeItem();
355< A851 /td>+
var retArray;
356+
if (length < 0) {
357+
retArray = [];
358+
while (!readBreak())
359+
retArray.push(decodeItem());
360+
} else {
361+
retArray = new Array(length);
362+
for (i = 0; i < length; ++i)
363+
retArray[i] = decodeItem();
364+
}
319365
return retArray;
320366
case 5:
321367
var retObject = {};
322-
for (i = 0; i < length; ++i) {
368+
for (i = 0; i < length || length < 0 && !readBreak(); ++i) {
323369
var key = decodeItem();
324370
retObject[key] = decodeItem();
325371
}

test/tests.js

Lines changed: 105 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ var testcases = function(undefined) {
115115
"Bytestring [1,2,3,4]",
116116
"4401020304",
117117
generateArrayBuffer([1,2,3,4])
118+
], [
119+
"Bytestring [1,2,3,4,5]",
120+
"5f42010243030405ff",
121+
generateArrayBuffer([1,2,3,4,5]),
122+
true
118123
], [
119124
"String ''",
120125
"60",
@@ -143,10 +148,24 @@ var testcases = function(undefined) {
143148
"String '\ud800\udd51' (U+10151)",
144149
"64f0908591",
145150
"\ud800\udd51"
151+
], [
152+
"String 'streaming'",
153+
"7f657374726561646d696e67ff",
154+
"streaming",
155+
true
146156
], [
147157
"Array []",
148158
"80",
149159
[]
160+
], [
161+
"Array ['a', {'b': 'c'}]",
162+
"826161a161626163",
163+
["a", {"b": "c"}]
164+
], [
165+
"Array ['a, {_ 'b': 'c'}]",
166+
"826161bf61626163ff",
167+
["a", {"b": "c"}],
168+
true
150169
], [
151170
"Array [1,2,3]",
152171
"83010203",
@@ -155,10 +174,40 @@ var testcases = function(undefined) {
155174
"Array [1, [2, 3], [4, 5]]",
156175
"8301820203820405",
157176
[1, [2, 3], [4, 5]]
177+
], [
178+
"Array [1, [2, 3], [_ 4, 5]]",
179+
"83018202039f0405ff",
180+
[1, [2, 3], [4, 5]],
181+
true
182+
], [
183+
"Array [1, [_ 2, 3], [4, 5]]",
184+
"83019f0203ff820405",
185+
[1, [2, 3], [4, 5]],
186+
true
158187
], [
159188
"Array [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]",
160189
"98190102030405060708090a0b0c0d0e0f101112131415161718181819",
161190
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
191+
], [
192+
"Array [_ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]",
193+
"9f0102030405060708090a0b0c0d0e0f101112131415161718181819ff",
194+
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25],
195+
true
196+
], [
197+
"Array [_ 1, [2, 3], [4, 5]]",
198+
"9f01820203820405ff",
199+
[1, [2, 3], [4, 5]],
200+
true
201+
], [
202+
"Array [_ 1, [2, 3], [_ 4, 5]]",
203+
"9f018202039f0405ffff",
204+
[1, [2, 3], [4, 5]],
205+
true
206+
], [
207+
"Array [_ ]",
208+
"9fff",
209+
[],
210+
true
162211
], [
163212
"Object {}",
164213
"a0",
@@ -168,10 +217,6 @@ var testcases = function(undefined) {
168217
"a201020304",
169218
{1: 2, 3: 4},
170219
true
171-
], [
172-
"Array ['a', {'b': 'c'}]",
173-
"826161a161626163",
174-
["a", {"b": "c"}]
175220
], [
176221
"Object {'a': 1, 'b': [2, 3]}",
177222
"a26161016162820203",
@@ -182,6 +227,16 @@ var testcases = function(undefined) {
182227
"a56161614161626142616361436164614461656145",
183228
{"a": "A", "b": "B", "c": "C", "d": "D", "e": "E"},
184229
true
230+
], [
231+
"Object {_ 'a': 1, 'b': [_ 2, 3]}",
232+
"bf61610161629f0203ffff",
233+
{"a": 1, "b": [2, 3]},
234+
true
235+
], [
236+
"Object {_ 'Fun': true, 'Amt': -2}",
237+
"bf6346756ef563416d7421ff",
238+
{"Fun": true, "Amt": -2},
239+
true
185240
], [
186241
"Tag Self-describe CBOR 0",
187242
"d9d9f700",
@@ -351,7 +406,7 @@ testcases.forEach(function(testcase) {
351406
var data = testcase[1];
352407
var expected = testcase[2];
353408
var binaryDifference = testcase[3];
354-
409+
355410
test(name, function() {
356411
myDeepEqual(CBOR.decode(hex2arrayBuffer(data)), expected, "Decoding");
357412
var encoded = CBOR.encode(expected);
@@ -381,7 +436,51 @@ test("Remaining Bytes", function() {
381436
} catch (e) {
382437
threw = e;
383438
}
384-
439+
440+
ok(threw, "Thrown exception");
441+
});
442+
443+
test("Invalid length encoding", function() {
444+
var threw = false;
445+
try {
446+
CBOR.decode(hex2arrayBuffer("1e"))
447+
} catch (e) {
448+
threw = e;
449+
}
450+
451+
ok(threw, "Thrown exception");
452+
});
453+
454+
test("Invalid length", function() {
455+
var threw = false;
456+
try {
457+
CBOR.decode(hex2arrayBuffer("1f"))
458+
} catch (e) {
459+
threw = e;
460+
}
461+
462+
ok(threw, "Thrown exception");
463+
});
464+
465+
test("Invalid indefinite length element type", function() {
466+
var threw = false;
467+
try {
468+
CBOR.decode(hex2arrayBuffer("5f00"))
469+
} catch (e) {
470+
threw = e;
471+
}
472+
473+
ok(threw, "Thrown exception");
474+
});
475+
476+
test("Invalid indefinite length element length", function() {
477+
var threw = false;
478+
try {
479+
CBOR.decode(hex2arrayBuffer("5f5f"))
480+
} catch (e) {
481+
threw = e;
482+
}
483+
385484
ok(threw, "Thrown exception");
386485
});
387486

0 commit comments

Comments
 (0)
0