cbor-x 1.6.5 → 1.6.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/decode.d.ts +1 -1
- package/decode.js +89 -52
- package/dist/decode-no-eval.cjs +91 -52
- package/dist/decode-no-eval.cjs.map +1 -1
- package/dist/index-no-eval.cjs +96 -54
- package/dist/index-no-eval.cjs.map +1 -1
- package/dist/index-no-eval.min.js +1 -1
- package/dist/index-no-eval.min.js.map +1 -1
- package/dist/index.js +96 -54
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/node.cjs +109 -70
- package/dist/node.cjs.map +1 -1
- package/dist/test.js +90 -52
- package/dist/test.js.map +1 -1
- package/encode.js +1 -1
- package/index.d.ts +1 -1
- package/iterators.js +6 -4
- package/package.json +1 -1
- package/stream.js +11 -13
package/dist/test.js
CHANGED
|
@@ -19,7 +19,11 @@
|
|
|
19
19
|
let maxArraySize = 112810000; // This is the maximum array size in V8. We would potentially detect and set it higher
|
|
20
20
|
// for JSC, but this is pretty large and should be sufficient for most use cases
|
|
21
21
|
let maxMapSize = 16810000; // JavaScript has a fixed maximum map size of about 16710000, but JS itself enforces this,
|
|
22
|
-
//
|
|
22
|
+
// so we don't need to
|
|
23
|
+
|
|
24
|
+
let maxObjectSize = 16710000; // It takes over a minute to create this many keys in an object, so this is probably a
|
|
25
|
+
// reasonable choice.
|
|
26
|
+
let objectSizeLimit = maxObjectSize; // objects are limited by both maxObjectSize and maxMapSize
|
|
23
27
|
let strings = EMPTY_ARRAY;
|
|
24
28
|
let stringPosition = 0;
|
|
25
29
|
let currentDecoder = {};
|
|
@@ -122,7 +126,13 @@
|
|
|
122
126
|
// re-entrant execution, save the state and restore it after we do this decode
|
|
123
127
|
return saveState(() => {
|
|
124
128
|
clearSource();
|
|
125
|
-
|
|
129
|
+
try {
|
|
130
|
+
return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
|
|
131
|
+
} catch (error) {
|
|
132
|
+
if (error && typeof error == 'object')
|
|
133
|
+
nestedDecodeErrors.add(error);
|
|
134
|
+
throw error
|
|
135
|
+
}
|
|
126
136
|
})
|
|
127
137
|
}
|
|
128
138
|
srcEnd = end > -1 ? end : source.length;
|
|
@@ -199,15 +209,13 @@
|
|
|
199
209
|
}
|
|
200
210
|
}
|
|
201
211
|
}
|
|
212
|
+
const nestedDecodeErrors = new WeakSet();
|
|
202
213
|
function checkedRead() {
|
|
203
214
|
try {
|
|
204
215
|
let result = read();
|
|
205
216
|
if (bundledStrings$1) {
|
|
206
|
-
if (position$1 >= bundledStrings$1.postBundlePosition)
|
|
207
|
-
|
|
208
|
-
error.incomplete = true;
|
|
209
|
-
throw error
|
|
210
|
-
}
|
|
217
|
+
if (position$1 >= bundledStrings$1.postBundlePosition)
|
|
218
|
+
throw new Error('Unexpected bundle position')
|
|
211
219
|
// bundled strings to skip past
|
|
212
220
|
position$1 = bundledStrings$1.postBundlePosition;
|
|
213
221
|
bundledStrings$1 = null;
|
|
@@ -231,20 +239,36 @@
|
|
|
231
239
|
return result
|
|
232
240
|
} catch(error) {
|
|
233
241
|
clearSource();
|
|
234
|
-
if (
|
|
242
|
+
if (nestedDecodeErrors.has(error)) {
|
|
243
|
+
// from a nested decode of embedded data (by an extension), which was complete in this source
|
|
244
|
+
if (error.incomplete)
|
|
245
|
+
error.incomplete = false;
|
|
246
|
+
} else if (error instanceof RangeError && position$1 + 8 > srcEnd ||
|
|
247
|
+
error && typeof error.message == 'string' && error.message.startsWith('Unexpected end of buffer')) {
|
|
248
|
+
// a DataView read past the end of the source; these read at most 8 bytes and precede advancing position.
|
|
249
|
+
// Any other RangeError (such as a stack overflow from deeply nested input) is fatal.
|
|
235
250
|
error.incomplete = true;
|
|
236
251
|
}
|
|
237
252
|
throw error
|
|
238
253
|
}
|
|
239
254
|
}
|
|
240
255
|
|
|
256
|
+
function endOfCBORError() {
|
|
257
|
+
let error = new Error('Unexpected end of CBOR data');
|
|
258
|
+
error.incomplete = true;
|
|
259
|
+
return error
|
|
260
|
+
}
|
|
261
|
+
|
|
241
262
|
function read() {
|
|
263
|
+
// compared as < so that a NaN position (from a corrupt length) also throws instead of reading undefined
|
|
264
|
+
if (!(position$1 < srcEnd)) throw endOfCBORError()
|
|
242
265
|
let token = src[position$1++];
|
|
243
266
|
let majorType = token >> 5;
|
|
244
267
|
token = token & 0x1f;
|
|
245
268
|
if (token > 0x17) {
|
|
246
269
|
switch (token) {
|
|
247
270
|
case 0x18:
|
|
271
|
+
if (position$1 >= srcEnd) throw endOfCBORError()
|
|
248
272
|
token = src[position$1++];
|
|
249
273
|
break
|
|
250
274
|
case 0x19:
|
|
@@ -307,13 +331,13 @@
|
|
|
307
331
|
let i = 0;
|
|
308
332
|
if (currentDecoder.keyMap) {
|
|
309
333
|
while((key = read()) != STOP_CODE) {
|
|
310
|
-
if (i++ >=
|
|
334
|
+
if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
311
335
|
object[safeKey(currentDecoder.decodeKey(key))] = read();
|
|
312
336
|
}
|
|
313
337
|
}
|
|
314
338
|
else {
|
|
315
339
|
while ((key = read()) != STOP_CODE) {
|
|
316
|
-
if (i++ >=
|
|
340
|
+
if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
317
341
|
object[safeKey(key)] = read();
|
|
318
342
|
}
|
|
319
343
|
}
|
|
@@ -359,11 +383,13 @@
|
|
|
359
383
|
case 1: // negative int
|
|
360
384
|
return ~token
|
|
361
385
|
case 2: // buffer
|
|
386
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
362
387
|
return readBin(token)
|
|
363
388
|
case 3: // string
|
|
364
|
-
if (srcStringEnd >= position$1) {
|
|
389
|
+
if (srcStringEnd >= position$1) { // already extracted, which only covers complete strings
|
|
365
390
|
return srcString.slice(position$1 - srcStringStart, (position$1 += token) - srcStringStart)
|
|
366
391
|
}
|
|
392
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
367
393
|
if (srcStringEnd == 0 && srcEnd < 140 && token < 32) {
|
|
368
394
|
// for small blocks, avoiding the overhead of the extract call is helpful
|
|
369
395
|
let string = token < 16 ? shortStringInJS(token) : longStringInJS(token);
|
|
@@ -372,15 +398,19 @@
|
|
|
372
398
|
}
|
|
373
399
|
return readFixedString(token)
|
|
374
400
|
case 4: // array
|
|
375
|
-
if (token
|
|
401
|
+
if (token > maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
|
|
402
|
+
// every element occupies at least one byte, so a length beyond what remains in the source can
|
|
403
|
+
// never be satisfied; check before allocating so a tiny header can not force a huge allocation
|
|
404
|
+
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
376
405
|
let array = new Array(token);
|
|
377
406
|
//if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
|
|
378
407
|
//else
|
|
379
408
|
for (let i = 0; i < token; i++) array[i] = read();
|
|
380
409
|
return array
|
|
381
410
|
case 5: // map
|
|
382
|
-
if (token >= maxMapSize) throw new Error(`Map size exceeds ${maxArraySize}`)
|
|
383
411
|
if (currentDecoder.mapsAsObjects) {
|
|
412
|
+
if (token > objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
413
|
+
if (token > (srcEnd - position$1) / 2) throw endOfCBORError() // each entry needs at least two bytes
|
|
384
414
|
let object = {};
|
|
385
415
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read();
|
|
386
416
|
else for (let i = 0; i < token; i++) object[safeKey(read())] = read();
|
|
@@ -390,6 +420,8 @@
|
|
|
390
420
|
currentDecoder.mapsAsObjects = true;
|
|
391
421
|
restoreMapsAsObject = false;
|
|
392
422
|
}
|
|
423
|
+
if (token > maxMapSize) throw new Error(`Map size exceeds ${maxMapSize}`)
|
|
424
|
+
if (token > (srcEnd - position$1) / 2) throw endOfCBORError()
|
|
393
425
|
let map = new Map();
|
|
394
426
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read());
|
|
395
427
|
else for (let i = 0; i < token; i++) map.set(read(), read());
|
|
@@ -471,11 +503,7 @@
|
|
|
471
503
|
throw new Error('Unknown token ' + token)
|
|
472
504
|
}
|
|
473
505
|
default: // negative int
|
|
474
|
-
if (isNaN(token))
|
|
475
|
-
let error = new Error('Unexpected end of CBOR data');
|
|
476
|
-
error.incomplete = true;
|
|
477
|
-
throw error
|
|
478
|
-
}
|
|
506
|
+
if (isNaN(token)) throw endOfCBORError()
|
|
479
507
|
throw new Error('Unknown CBOR token ' + token)
|
|
480
508
|
}
|
|
481
509
|
}
|
|
@@ -921,18 +949,12 @@
|
|
|
921
949
|
return (glbl[data[0]] || Error)(data[1], data[2])
|
|
922
950
|
};
|
|
923
951
|
const packedTable = (read) => {
|
|
924
|
-
if (
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
error.incomplete = true;
|
|
928
|
-
throw error
|
|
929
|
-
}
|
|
952
|
+
if (!(position$1 < srcEnd)) throw endOfCBORError()
|
|
953
|
+
if (src[position$1++] != 0x84)
|
|
954
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
930
955
|
let newPackedValues = read(); // packed values
|
|
931
|
-
if (!newPackedValues || !newPackedValues.length)
|
|
932
|
-
|
|
933
|
-
error.incomplete = true;
|
|
934
|
-
throw error
|
|
935
|
-
}
|
|
956
|
+
if (!Array.isArray(newPackedValues) || !newPackedValues.length)
|
|
957
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
936
958
|
packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
|
|
937
959
|
packedValues.prefixes = read();
|
|
938
960
|
packedValues.suffixes = read();
|
|
@@ -950,10 +972,7 @@
|
|
|
950
972
|
}
|
|
951
973
|
if (typeof data == 'number')
|
|
952
974
|
return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
|
|
953
|
-
|
|
954
|
-
if (data === undefined)
|
|
955
|
-
error.incomplete = true;
|
|
956
|
-
throw error
|
|
975
|
+
throw new Error('No support for non-integer packed references yet')
|
|
957
976
|
};
|
|
958
977
|
|
|
959
978
|
// The following code is an incomplete implementation of http://cbor.schmorp.de/stringref
|
|
@@ -1023,9 +1042,19 @@
|
|
|
1023
1042
|
(currentExtensions[259] = (read) => {
|
|
1024
1043
|
// https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
|
|
1025
1044
|
// for decoding as a standard Map
|
|
1026
|
-
|
|
1027
|
-
|
|
1045
|
+
let decoder = currentDecoder;
|
|
1046
|
+
if (decoder.mapsAsObjects) {
|
|
1047
|
+
decoder.mapsAsObjects = false;
|
|
1028
1048
|
restoreMapsAsObject = true;
|
|
1049
|
+
try {
|
|
1050
|
+
return read()
|
|
1051
|
+
} finally {
|
|
1052
|
+
// normally restored by the map header, but not if the tagged value is not a map or the read fails
|
|
1053
|
+
if (restoreMapsAsObject) {
|
|
1054
|
+
decoder.mapsAsObjects = true;
|
|
1055
|
+
restoreMapsAsObject = false;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1029
1058
|
}
|
|
1030
1059
|
return read()
|
|
1031
1060
|
}).handlesRead = true;
|
|
@@ -1136,17 +1165,21 @@
|
|
|
1136
1165
|
}
|
|
1137
1166
|
|
|
1138
1167
|
function readJustLength() {
|
|
1168
|
+
if (!(position$1 < srcEnd)) throw endOfCBORError()
|
|
1139
1169
|
let token = src[position$1++] & 0x1f;
|
|
1140
1170
|
if (token > 0x17) {
|
|
1141
1171
|
switch (token) {
|
|
1142
1172
|
case 0x18:
|
|
1173
|
+
if (position$1 >= srcEnd) throw endOfCBORError()
|
|
1143
1174
|
token = src[position$1++];
|
|
1144
1175
|
break
|
|
1145
1176
|
case 0x19:
|
|
1177
|
+
if (position$1 + 2 > srcEnd) throw endOfCBORError()
|
|
1146
1178
|
token = dataView.getUint16(position$1);
|
|
1147
1179
|
position$1 += 2;
|
|
1148
1180
|
break
|
|
1149
1181
|
case 0x1a:
|
|
1182
|
+
if (position$1 + 4 > srcEnd) throw endOfCBORError()
|
|
1150
1183
|
token = dataView.getUint32(position$1);
|
|
1151
1184
|
position$1 += 4;
|
|
1152
1185
|
break
|
|
@@ -1188,22 +1221,27 @@
|
|
|
1188
1221
|
let savedStructures = currentStructures;
|
|
1189
1222
|
let savedDecoder = currentDecoder;
|
|
1190
1223
|
let savedSequentialMode = sequentialMode;
|
|
1191
|
-
let
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1224
|
+
let savedRestoreMapsAsObject = restoreMapsAsObject;
|
|
1225
|
+
restoreMapsAsObject = false;
|
|
1226
|
+
try {
|
|
1227
|
+
return callback()
|
|
1228
|
+
} finally {
|
|
1229
|
+
srcEnd = savedSrcEnd;
|
|
1230
|
+
position$1 = savedPosition;
|
|
1231
|
+
stringPosition = savedStringPosition;
|
|
1232
|
+
srcStringStart = savedSrcStringStart;
|
|
1233
|
+
srcStringEnd = savedSrcStringEnd;
|
|
1234
|
+
srcString = savedSrcString;
|
|
1235
|
+
strings = savedStrings;
|
|
1236
|
+
referenceMap = savedReferenceMap;
|
|
1237
|
+
bundledStrings$1 = savedBundledStrings;
|
|
1238
|
+
src = savedSrc;
|
|
1239
|
+
sequentialMode = savedSequentialMode;
|
|
1240
|
+
currentStructures = savedStructures;
|
|
1241
|
+
currentDecoder = savedDecoder;
|
|
1242
|
+
restoreMapsAsObject = savedRestoreMapsAsObject;
|
|
1243
|
+
dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
|
|
1244
|
+
}
|
|
1207
1245
|
}
|
|
1208
1246
|
function clearSource() {
|
|
1209
1247
|
src = null;
|
|
@@ -1409,7 +1447,7 @@
|
|
|
1409
1447
|
if (throwOnIterable)
|
|
1410
1448
|
return;
|
|
1411
1449
|
encode(value);
|
|
1412
|
-
if (bundledStrings) {
|
|
1450
|
+
if (bundledStrings && bundledStrings.position) { // position is only set once a bundle has been started
|
|
1413
1451
|
writeBundles(start, encode);
|
|
1414
1452
|
}
|
|
1415
1453
|
encoder.offset = position; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|