cbor-x 1.6.7 → 1.6.9
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 +4 -0
- package/decode.js +157 -28
- package/dist/decode-no-eval.cjs +158 -28
- package/dist/decode-no-eval.cjs.map +1 -1
- package/dist/index-no-eval.cjs +546 -48
- 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 +546 -48
- 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 +601 -100
- package/dist/node.cjs.map +1 -1
- package/dist/test.js +153 -30
- package/dist/test.js.map +1 -1
- package/encode.js +21 -2
- package/index.d.ts +1 -1
- package/iterators.js +123 -19
- package/package.json +2 -2
- package/scan.js +253 -0
- package/stream.js +9 -10
package/dist/test.js
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
const RECORD_INLINE_ID = 0xdfff; // temporary first-come first-serve tag // proposed tag: 0x7265 // 're'
|
|
16
16
|
const BUNDLED_STRINGS_ID = 0xdff9;
|
|
17
17
|
const PACKED_REFERENCE_TAG_ID = 6;
|
|
18
|
-
const STOP_CODE = {};
|
|
19
18
|
let maxArraySize = 112810000; // This is the maximum array size in V8. We would potentially detect and set it higher
|
|
20
19
|
// for JSC, but this is pretty large and should be sufficient for most use cases
|
|
21
20
|
let maxMapSize = 16810000; // JavaScript has a fixed maximum map size of about 16710000, but JS itself enforces this,
|
|
@@ -126,16 +125,11 @@
|
|
|
126
125
|
// re-entrant execution, save the state and restore it after we do this decode
|
|
127
126
|
return saveState(() => {
|
|
128
127
|
clearSource();
|
|
129
|
-
|
|
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
|
-
}
|
|
128
|
+
return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
|
|
136
129
|
})
|
|
137
130
|
}
|
|
138
|
-
|
|
131
|
+
// past the view, the JS string readers would decode the missing bytes as zeros instead of failing as truncated
|
|
132
|
+
srcEnd = end > -1 && end < source.length ? end : source.length;
|
|
139
133
|
position$1 = 0;
|
|
140
134
|
stringPosition = 0;
|
|
141
135
|
srcStringEnd = 0;
|
|
@@ -175,18 +169,28 @@
|
|
|
175
169
|
return checkedRead()
|
|
176
170
|
}
|
|
177
171
|
decodeMultiple(source, forEach) {
|
|
172
|
+
if (src) {
|
|
173
|
+
// Keep the complete nested sequence inside its own decoder state.
|
|
174
|
+
return saveState(() => {
|
|
175
|
+
clearSource();
|
|
176
|
+
return this ? this.decodeMultiple(source, forEach) : defaultDecoder.decodeMultiple(source, forEach)
|
|
177
|
+
})
|
|
178
|
+
}
|
|
178
179
|
let values, lastPosition = 0;
|
|
179
180
|
try {
|
|
180
181
|
let size = source.length;
|
|
181
182
|
sequentialMode = true;
|
|
182
183
|
let value = this ? this.decode(source, size) : defaultDecoder.decode(source, size);
|
|
183
184
|
if (forEach) {
|
|
185
|
+
let end = position$1;
|
|
184
186
|
if (forEach(value) === false) {
|
|
185
187
|
return
|
|
186
188
|
}
|
|
187
|
-
while(
|
|
188
|
-
lastPosition =
|
|
189
|
-
|
|
189
|
+
while(end < size) {
|
|
190
|
+
lastPosition = end;
|
|
191
|
+
value = checkedRead();
|
|
192
|
+
end = position$1;
|
|
193
|
+
if (forEach(value) === false) {
|
|
190
194
|
return
|
|
191
195
|
}
|
|
192
196
|
}
|
|
@@ -200,8 +204,10 @@
|
|
|
200
204
|
return values
|
|
201
205
|
}
|
|
202
206
|
} catch(error) {
|
|
203
|
-
error
|
|
204
|
-
|
|
207
|
+
if (error && (typeof error == 'object' || typeof error == 'function')) {
|
|
208
|
+
error.lastPosition = lastPosition;
|
|
209
|
+
error.values = values;
|
|
210
|
+
}
|
|
205
211
|
throw error
|
|
206
212
|
} finally {
|
|
207
213
|
sequentialMode = false;
|
|
@@ -210,8 +216,10 @@
|
|
|
210
216
|
}
|
|
211
217
|
}
|
|
212
218
|
const nestedDecodeErrors = new WeakSet();
|
|
219
|
+
let arrayAllocationBudget;
|
|
213
220
|
function checkedRead() {
|
|
214
221
|
try {
|
|
222
|
+
arrayAllocationBudget = srcEnd - position$1;
|
|
215
223
|
let result = read();
|
|
216
224
|
if (bundledStrings$1) {
|
|
217
225
|
if (position$1 >= bundledStrings$1.postBundlePosition)
|
|
@@ -253,9 +261,21 @@
|
|
|
253
261
|
}
|
|
254
262
|
}
|
|
255
263
|
|
|
256
|
-
function
|
|
264
|
+
function readBreak() {
|
|
265
|
+
if (position$1 < srcEnd && src[position$1] === 0xff) {
|
|
266
|
+
position$1++;
|
|
267
|
+
return true
|
|
268
|
+
}
|
|
269
|
+
return false
|
|
270
|
+
}
|
|
271
|
+
// neededEnd, from a length check, is a position that the source must extend to before the item can decode. It is a
|
|
272
|
+
// lower bound for any completion of the source: every byte read before the check was within the source, so a longer
|
|
273
|
+
// source reaches the same check with the same length. Streams wait for it instead of decoding on every chunk.
|
|
274
|
+
function endOfCBORError(neededEnd) {
|
|
257
275
|
let error = new Error('Unexpected end of CBOR data');
|
|
258
276
|
error.incomplete = true;
|
|
277
|
+
if (neededEnd)
|
|
278
|
+
error.neededEnd = neededEnd;
|
|
259
279
|
return error
|
|
260
280
|
}
|
|
261
281
|
|
|
@@ -307,6 +327,9 @@
|
|
|
307
327
|
} else if (currentDecoder.int64AsNumber) {
|
|
308
328
|
token = dataView.getUint32(position$1) * 0x100000000;
|
|
309
329
|
token += dataView.getUint32(position$1 + 4);
|
|
330
|
+
position$1 += 8;
|
|
331
|
+
if (majorType === 1) return -1 - token
|
|
332
|
+
break
|
|
310
333
|
} else token = dataView.getBigUint64(position$1);
|
|
311
334
|
position$1 += 8;
|
|
312
335
|
break
|
|
@@ -318,10 +341,10 @@
|
|
|
318
341
|
throw new Error('Indefinite length not supported for byte or text strings')
|
|
319
342
|
case 4: // array
|
|
320
343
|
let array = [];
|
|
321
|
-
let
|
|
322
|
-
while ((
|
|
344
|
+
let i = 0;
|
|
345
|
+
while (!readBreak()) {
|
|
323
346
|
if (i >= maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
|
|
324
|
-
array[i++] =
|
|
347
|
+
array[i++] = read();
|
|
325
348
|
}
|
|
326
349
|
return majorType == 4 ? array : majorType == 3 ? array.join('') : Buffer.concat(array)
|
|
327
350
|
case 5: // map
|
|
@@ -330,13 +353,15 @@
|
|
|
330
353
|
let object = {};
|
|
331
354
|
let i = 0;
|
|
332
355
|
if (currentDecoder.keyMap) {
|
|
333
|
-
while((
|
|
356
|
+
while (!readBreak()) {
|
|
357
|
+
key = read();
|
|
334
358
|
if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
335
359
|
object[safeKey(currentDecoder.decodeKey(key))] = read();
|
|
336
360
|
}
|
|
337
361
|
}
|
|
338
362
|
else {
|
|
339
|
-
while ((
|
|
363
|
+
while (!readBreak()) {
|
|
364
|
+
key = read();
|
|
340
365
|
if (i++ >= objectSizeLimit) throw new Error(`Property count exceeds ${objectSizeLimit}`)
|
|
341
366
|
object[safeKey(key)] = read();
|
|
342
367
|
}
|
|
@@ -350,7 +375,8 @@
|
|
|
350
375
|
let map = new Map();
|
|
351
376
|
if (currentDecoder.keyMap) {
|
|
352
377
|
let i = 0;
|
|
353
|
-
while((
|
|
378
|
+
while (!readBreak()) {
|
|
379
|
+
key = read();
|
|
354
380
|
if (i++ >= maxMapSize) {
|
|
355
381
|
throw new Error(`Map size exceeds ${maxMapSize}`);
|
|
356
382
|
}
|
|
@@ -359,7 +385,8 @@
|
|
|
359
385
|
}
|
|
360
386
|
else {
|
|
361
387
|
let i = 0;
|
|
362
|
-
while ((
|
|
388
|
+
while (!readBreak()) {
|
|
389
|
+
key = read();
|
|
363
390
|
if (i++ >= maxMapSize) {
|
|
364
391
|
throw new Error(`Map size exceeds ${maxMapSize}`);
|
|
365
392
|
}
|
|
@@ -369,7 +396,8 @@
|
|
|
369
396
|
return map
|
|
370
397
|
}
|
|
371
398
|
case 7:
|
|
372
|
-
|
|
399
|
+
// readBreak consumes every break that ends an indefinite-length item
|
|
400
|
+
throw new Error('Unexpected break stop code outside of an indefinite-length item')
|
|
373
401
|
default:
|
|
374
402
|
throw new Error('Invalid major type for indefinite length ' + majorType)
|
|
375
403
|
}
|
|
@@ -383,13 +411,13 @@
|
|
|
383
411
|
case 1: // negative int
|
|
384
412
|
return ~token
|
|
385
413
|
case 2: // buffer
|
|
386
|
-
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
414
|
+
if (token > srcEnd - position$1) throw endOfCBORError(position$1 + token)
|
|
387
415
|
return readBin(token)
|
|
388
416
|
case 3: // string
|
|
389
417
|
if (srcStringEnd >= position$1) { // already extracted, which only covers complete strings
|
|
390
418
|
return srcString.slice(position$1 - srcStringStart, (position$1 += token) - srcStringStart)
|
|
391
419
|
}
|
|
392
|
-
if (token > srcEnd - position$1) throw endOfCBORError()
|
|
420
|
+
if (token > srcEnd - position$1) throw endOfCBORError(position$1 + token)
|
|
393
421
|
if (srcStringEnd == 0 && srcEnd < 140 && token < 32) {
|
|
394
422
|
// for small blocks, avoiding the overhead of the extract call is helpful
|
|
395
423
|
let string = token < 16 ? shortStringInJS(token) : longStringInJS(token);
|
|
@@ -401,7 +429,9 @@
|
|
|
401
429
|
if (token > maxArraySize) throw new Error(`Array length exceeds ${maxArraySize}`)
|
|
402
430
|
// every element occupies at least one byte, so a length beyond what remains in the source can
|
|
403
431
|
// never be satisfied; check before allocating so a tiny header can not force a huge allocation
|
|
404
|
-
|
|
432
|
+
// nested arrays each pass the check above yet still preallocate, so also spend from a
|
|
433
|
+
// per-decode budget of the remaining bytes; the summed lengths of any valid tree stay under it
|
|
434
|
+
if (token > srcEnd - position$1 || (arrayAllocationBudget -= token) < 0) throw endOfCBORError(position$1 + token)
|
|
405
435
|
let array = new Array(token);
|
|
406
436
|
//if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
|
|
407
437
|
//else
|
|
@@ -410,7 +440,7 @@
|
|
|
410
440
|
case 5: // map
|
|
411
441
|
if (currentDecoder.mapsAsObjects) {
|
|
412
442
|
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
|
|
443
|
+
if (token > (srcEnd - position$1) / 2) throw endOfCBORError(position$1 + 2 * token) // each entry needs at least two bytes
|
|
414
444
|
let object = {};
|
|
415
445
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read();
|
|
416
446
|
else for (let i = 0; i < token; i++) object[safeKey(read())] = read();
|
|
@@ -421,7 +451,7 @@
|
|
|
421
451
|
restoreMapsAsObject = false;
|
|
422
452
|
}
|
|
423
453
|
if (token > maxMapSize) throw new Error(`Map size exceeds ${maxMapSize}`)
|
|
424
|
-
if (token > (srcEnd - position$1) / 2) throw endOfCBORError()
|
|
454
|
+
if (token > (srcEnd - position$1) / 2) throw endOfCBORError(position$1 + 2 * token)
|
|
425
455
|
let map = new Map();
|
|
426
456
|
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read());
|
|
427
457
|
else for (let i = 0; i < token; i++) map.set(read(), read());
|
|
@@ -934,6 +964,7 @@
|
|
|
934
964
|
}
|
|
935
965
|
return object
|
|
936
966
|
};
|
|
967
|
+
const legacyRecordDefinition = currentExtensions[LEGACY_RECORD_INLINE_ID];
|
|
937
968
|
currentExtensions[14] = (value) => {
|
|
938
969
|
if (bundledStrings$1)
|
|
939
970
|
return bundledStrings$1[0].slice(bundledStrings$1.position0, bundledStrings$1.position0 += value)
|
|
@@ -1206,6 +1237,8 @@
|
|
|
1206
1237
|
}
|
|
1207
1238
|
|
|
1208
1239
|
function saveState(callback) {
|
|
1240
|
+
let savedFragmentReader = fragmentReadString;
|
|
1241
|
+
let savedReadFixedString = readFixedString;
|
|
1209
1242
|
let savedSrcEnd = srcEnd;
|
|
1210
1243
|
let savedPosition = position$1;
|
|
1211
1244
|
let savedStringPosition = stringPosition;
|
|
@@ -1215,6 +1248,7 @@
|
|
|
1215
1248
|
let savedStrings = strings;
|
|
1216
1249
|
let savedReferenceMap = referenceMap;
|
|
1217
1250
|
let savedBundledStrings = bundledStrings$1;
|
|
1251
|
+
let savedPackedValues = packedValues;
|
|
1218
1252
|
|
|
1219
1253
|
// TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
|
|
1220
1254
|
let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
|
|
@@ -1222,10 +1256,21 @@
|
|
|
1222
1256
|
let savedDecoder = currentDecoder;
|
|
1223
1257
|
let savedSequentialMode = sequentialMode;
|
|
1224
1258
|
let savedRestoreMapsAsObject = restoreMapsAsObject;
|
|
1259
|
+
let savedArrayAllocationBudget = arrayAllocationBudget;
|
|
1260
|
+
if (fragmentReadString) readFixedString = fragmentReadString;
|
|
1261
|
+
fragmentReadString = null;
|
|
1225
1262
|
restoreMapsAsObject = false;
|
|
1226
1263
|
try {
|
|
1227
1264
|
return callback()
|
|
1265
|
+
} catch (error) {
|
|
1266
|
+
// the callback decodes its own source (a shared structures blob, or an extension's embedded data), so a
|
|
1267
|
+
// truncation there cannot be completed by more of the outer input; checkedRead() clears the flag
|
|
1268
|
+
if (error && (typeof error == 'object' || typeof error == 'function'))
|
|
1269
|
+
nestedDecodeErrors.add(error);
|
|
1270
|
+
throw error
|
|
1228
1271
|
} finally {
|
|
1272
|
+
fragmentReadString = savedFragmentReader;
|
|
1273
|
+
readFixedString = savedReadFixedString;
|
|
1229
1274
|
srcEnd = savedSrcEnd;
|
|
1230
1275
|
position$1 = savedPosition;
|
|
1231
1276
|
stringPosition = savedStringPosition;
|
|
@@ -1235,11 +1280,13 @@
|
|
|
1235
1280
|
strings = savedStrings;
|
|
1236
1281
|
referenceMap = savedReferenceMap;
|
|
1237
1282
|
bundledStrings$1 = savedBundledStrings;
|
|
1283
|
+
packedValues = savedPackedValues;
|
|
1238
1284
|
src = savedSrc;
|
|
1239
1285
|
sequentialMode = savedSequentialMode;
|
|
1240
1286
|
currentStructures = savedStructures;
|
|
1241
1287
|
currentDecoder = savedDecoder;
|
|
1242
1288
|
restoreMapsAsObject = savedRestoreMapsAsObject;
|
|
1289
|
+
arrayAllocationBudget = savedArrayAllocationBudget;
|
|
1243
1290
|
dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
|
|
1244
1291
|
}
|
|
1245
1292
|
}
|
|
@@ -1249,8 +1296,15 @@
|
|
|
1249
1296
|
currentStructures = null;
|
|
1250
1297
|
}
|
|
1251
1298
|
|
|
1299
|
+
const registeredExtensions = new Map();
|
|
1300
|
+
let fragmentReadString;
|
|
1301
|
+
|
|
1302
|
+
new Map([[LEGACY_RECORD_INLINE_ID, legacyRecordDefinition], [259, currentExtensions[259]]]);
|
|
1303
|
+
|
|
1252
1304
|
function addExtension$2(extension) {
|
|
1253
1305
|
currentExtensions[extension.tag] = extension.decode;
|
|
1306
|
+
if (typeof extension.decode === 'function') registeredExtensions.set(extension.tag, extension.decode);
|
|
1307
|
+
else registeredExtensions.delete(extension.tag);
|
|
1254
1308
|
}
|
|
1255
1309
|
|
|
1256
1310
|
const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
|
|
@@ -1838,6 +1892,11 @@
|
|
|
1838
1892
|
return encode(json)
|
|
1839
1893
|
}
|
|
1840
1894
|
|
|
1895
|
+
// not in extensions, so class instances that reach writeObject do not pay another instanceof
|
|
1896
|
+
if (constructor === DataView) {
|
|
1897
|
+
writeBuffer(new Uint8Array(value.buffer, value.byteOffset, value.byteLength), makeRoom);
|
|
1898
|
+
return
|
|
1899
|
+
}
|
|
1841
1900
|
// no extension found, write as a plain object
|
|
1842
1901
|
writeObject(value);
|
|
1843
1902
|
}
|
|
@@ -1931,8 +1990,22 @@
|
|
|
1931
1990
|
size++;
|
|
1932
1991
|
}
|
|
1933
1992
|
}
|
|
1934
|
-
|
|
1935
|
-
|
|
1993
|
+
if (size < 0x10000) {
|
|
1994
|
+
// fits in a map-16 (uint16) count: back-patch the reserved 2 bytes
|
|
1995
|
+
target[objectOffset++ + start] = size >> 8;
|
|
1996
|
+
target[objectOffset + start] = size & 0xff;
|
|
1997
|
+
} else {
|
|
1998
|
+
// too many entries for a map-16 count: widen the already-written header
|
|
1999
|
+
// to map-32, mirroring writeArrayHeader's 0x9a/setUint32 path. Shift the
|
|
2000
|
+
// encoded entries 2 bytes forward to make room for the wider (uint32) count.
|
|
2001
|
+
if (position + 2 > safeEnd)
|
|
2002
|
+
makeRoom(position + 2);
|
|
2003
|
+
let headerPosition = objectOffset + start;
|
|
2004
|
+
target.copyWithin(headerPosition + 4, headerPosition + 2, position);
|
|
2005
|
+
position += 2;
|
|
2006
|
+
target[headerPosition - 1] = 0xba; // map 32
|
|
2007
|
+
targetView.setUint32(headerPosition, size);
|
|
2008
|
+
}
|
|
1936
2009
|
} :
|
|
1937
2010
|
(object, skipValues) => {
|
|
1938
2011
|
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
|
|
@@ -2671,6 +2744,15 @@
|
|
|
2671
2744
|
assert.throws(() => decode$1(Buffer.from('7a10000000', 'hex')));
|
|
2672
2745
|
});
|
|
2673
2746
|
|
|
2747
|
+
test('break stop code outside indefinite-length item', function() {
|
|
2748
|
+
assert.throws(() => decode$1(Buffer.from('ff', 'hex')));
|
|
2749
|
+
assert.throws(() => decode$1(Buffer.from('81ff', 'hex')));
|
|
2750
|
+
assert.throws(() => decode$1(Buffer.from('a16161ff', 'hex')));
|
|
2751
|
+
assert.throws(() => decode$1(Buffer.from('c0ff', 'hex')));
|
|
2752
|
+
assert.deepEqual(decode$1(Buffer.from('9f01ff', 'hex')), [1]);
|
|
2753
|
+
assert.deepEqual(decode$1(Buffer.from('bf616101ff', 'hex')), { a: 1 });
|
|
2754
|
+
});
|
|
2755
|
+
|
|
2674
2756
|
test('overlong encoding', function() {
|
|
2675
2757
|
const payload = Buffer.from([0x62, 0xc0, 0xaf]);
|
|
2676
2758
|
const result = decode$1(payload);
|
|
@@ -3010,6 +3092,24 @@
|
|
|
3010
3092
|
var decoded = decode(encoded);
|
|
3011
3093
|
assert.equal(decoded.length, 0);
|
|
3012
3094
|
});
|
|
3095
|
+
test('fixed map size overflow (map-16 to map-32)', function() {
|
|
3096
|
+
this.timeout(120000);
|
|
3097
|
+
// issue #131: the default encode() serializes objects with a back-patched
|
|
3098
|
+
// map-16 (uint16) header, so an object with >= 65536 keys overflowed the
|
|
3099
|
+
// count and the decoder stopped early with "Data read, but end of buffer not
|
|
3100
|
+
// reached". Verify the round-trip across the map-16 -> map-32 boundary.
|
|
3101
|
+
function roundTripObjectWith(count) {
|
|
3102
|
+
var data = {};
|
|
3103
|
+
for (var i = 0; i < count; i++)
|
|
3104
|
+
data['k' + i] = i;
|
|
3105
|
+
var decoded = decode(encode(data));
|
|
3106
|
+
assert.equal(Object.keys(decoded).length, count);
|
|
3107
|
+
assert.deepEqual(decoded, data);
|
|
3108
|
+
}
|
|
3109
|
+
roundTripObjectWith(65535); // map-16 path, must stay unchanged
|
|
3110
|
+
roundTripObjectWith(65536); // first size that needs map-32
|
|
3111
|
+
roundTripObjectWith(70000); // well past the 16-bit boundary
|
|
3112
|
+
});
|
|
3013
3113
|
|
|
3014
3114
|
test('random strings', function(){
|
|
3015
3115
|
var data = [];
|
|
@@ -3136,6 +3236,14 @@
|
|
|
3136
3236
|
var deserialized = encoder.decode(serialized);
|
|
3137
3237
|
assert.equal(deserialized, data);
|
|
3138
3238
|
});
|
|
3239
|
+
test('negative int64 as number', function() {
|
|
3240
|
+
let encoded = Buffer.from('3b0000000e96848f5f', 'hex');
|
|
3241
|
+
assert.equal(new Decoder().decode(encoded), -62654812000n);
|
|
3242
|
+
|
|
3243
|
+
let decoder = new Decoder({ int64AsNumber: true });
|
|
3244
|
+
assert.equal(decoder.decode(encoded), -62654812000);
|
|
3245
|
+
assert.equal(decoder.decode(Buffer.from('3b001ffffffffffffe', 'hex')), Number.MIN_SAFE_INTEGER);
|
|
3246
|
+
});
|
|
3139
3247
|
test('bigint to float', function() {
|
|
3140
3248
|
var data = {
|
|
3141
3249
|
a: 325283295382932843n
|
|
@@ -3180,6 +3288,21 @@
|
|
|
3180
3288
|
assert.equal(decoded[2], 5);
|
|
3181
3289
|
assert.equal(decoded.byteLength, 3);
|
|
3182
3290
|
});
|
|
3291
|
+
test('encode DataView', function() {
|
|
3292
|
+
let bytes = new Uint8Array(40).map((_, i) => i);
|
|
3293
|
+
assert.equal(Buffer.from(encode(new DataView(bytes.buffer, 3, 4))).toString('hex'), '4403040506');
|
|
3294
|
+
assert.equal(Buffer.from(encode(new DataView(bytes.buffer, 5, 30))).toString('hex'),
|
|
3295
|
+
'581e' + Buffer.from(bytes.subarray(5, 35)).toString('hex'));
|
|
3296
|
+
assert.equal(Buffer.from(encode(new DataView(bytes.buffer, 0, 0))).toString('hex'), '40');
|
|
3297
|
+
assert.deepEqual(decode(encode({ v: new DataView(bytes.buffer, 1, 2) })), { v: Buffer.from([1, 2]) });
|
|
3298
|
+
assert.equal(Buffer.from(encode(bytes.buffer.slice(1, 4))).toString('hex'), '43010203');
|
|
3299
|
+
assert.equal(Buffer.from(encode(bytes.subarray(1, 4))).toString('hex'), 'd84043010203');
|
|
3300
|
+
assert.equal(Buffer.from(encode(Buffer.from(bytes.subarray(1, 4)))).toString('hex'), '43010203');
|
|
3301
|
+
assert.equal(Buffer.from(new Encoder({ tagUint8Array: false }).encode(bytes.subarray(1, 4))).toString('hex'), '43010203');
|
|
3302
|
+
let uint16Tag = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1 ? '45' : '41';
|
|
3303
|
+
assert.equal(Buffer.from(encode(new Uint16Array(bytes.buffer, 2, 2))).toString('hex'), 'd8' + uint16Tag + '4402030405');
|
|
3304
|
+
assert.equal(Buffer.from(encode(new Uint8ClampedArray(bytes.buffer, 2, 2))).toString('hex'), 'd844420203');
|
|
3305
|
+
});
|
|
3183
3306
|
|
|
3184
3307
|
test('iterator/indefinite length array', function(){
|
|
3185
3308
|
class NotArray {
|