cbor-x 0.9.1 → 1.0.0
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 +67 -21
- package/decode.d.ts +4 -0
- package/decode.js +323 -117
- package/dist/index.js +563 -270
- package/dist/index.min.js +101 -69
- package/dist/node.cjs +560 -265
- package/dist/test.js +62 -8
- package/encode.d.ts +1 -1
- package/encode.js +236 -89
- package/index.d.ts +1 -1
- package/index.js +2 -4
- package/node-index.js +2 -4
- package/package.json +13 -4
- package/.vscode/launch.json +0 -22
- package/dist/index.js.map +0 -1
- package/tests/benchmark-stream.cjs +0 -282
- package/tests/benchmark.cjs +0 -245
- package/tests/example.json +0 -52
- package/tests/example2.json +0 -26
- package/tests/example3.json +0 -22
- package/tests/example4.json +0 -1
- package/tests/example5.json +0 -12
- package/tests/floats.json +0 -1
- package/tests/index.html +0 -28
- package/tests/sample-large.json +0 -231
- package/tests/strings2.json +0 -1
- package/tests/test-compatibility.cjs +0 -36
- package/tests/test-incomplete.js +0 -41
- package/tests/test-node-iterators.js +0 -72
- package/tests/test-node-stream.js +0 -60
- package/tests/test.js +0 -586
package/decode.js
CHANGED
|
@@ -7,7 +7,10 @@ let srcEnd
|
|
|
7
7
|
let position = 0
|
|
8
8
|
let alreadySet
|
|
9
9
|
const EMPTY_ARRAY = []
|
|
10
|
-
const
|
|
10
|
+
const LEGACY_RECORD_INLINE_ID = 105
|
|
11
|
+
const RECORD_DEFINITIONS_ID = 0xdffe
|
|
12
|
+
const RECORD_INLINE_ID = 0xdfff // temporary first-come first-serve tag // proposed tag: 0x7265 // 're'
|
|
13
|
+
const BUNDLED_STRINGS_ID = 0xdff9
|
|
11
14
|
const PACKED_TABLE_TAG_ID = 51
|
|
12
15
|
const PACKED_REFERENCE_TAG_ID = 6
|
|
13
16
|
const STOP_CODE = {}
|
|
@@ -18,13 +21,13 @@ let currentStructures
|
|
|
18
21
|
let srcString
|
|
19
22
|
let srcStringStart = 0
|
|
20
23
|
let srcStringEnd = 0
|
|
24
|
+
let bundledStrings
|
|
21
25
|
let referenceMap
|
|
22
26
|
let currentExtensions = []
|
|
23
27
|
let currentExtensionRanges = []
|
|
24
28
|
let packedValues
|
|
25
29
|
let dataView
|
|
26
30
|
let restoreMapsAsObject
|
|
27
|
-
let sharedValues
|
|
28
31
|
let defaultOptions = {
|
|
29
32
|
useRecords: false,
|
|
30
33
|
mapsAsObjects: true
|
|
@@ -34,13 +37,70 @@ let sequentialMode = false
|
|
|
34
37
|
export class Decoder {
|
|
35
38
|
constructor(options) {
|
|
36
39
|
if (options) {
|
|
40
|
+
if ((options.keyMap || options._keyMap) && !options.useRecords) {
|
|
41
|
+
options.useRecords = false
|
|
42
|
+
options.mapsAsObjects = true
|
|
43
|
+
}
|
|
37
44
|
if (options.useRecords === false && options.mapsAsObjects === undefined)
|
|
38
45
|
options.mapsAsObjects = true
|
|
39
|
-
if (options.getStructures
|
|
46
|
+
if (options.getStructures)
|
|
47
|
+
options.getShared = options.getStructures
|
|
48
|
+
if (options.getShared && !options.structures)
|
|
40
49
|
(options.structures = []).uninitialized = true // this is what we use to denote an uninitialized structures
|
|
50
|
+
if (options.keyMap) {
|
|
51
|
+
this.mapKey = new Map()
|
|
52
|
+
for (let [k,v] of Object.entries(options.keyMap)) this.mapKey.set(v,k)
|
|
53
|
+
}
|
|
41
54
|
}
|
|
42
55
|
Object.assign(this, options)
|
|
43
56
|
}
|
|
57
|
+
/*
|
|
58
|
+
decodeKey(key) {
|
|
59
|
+
return this.keyMap
|
|
60
|
+
? Object.keys(this.keyMap)[Object.values(this.keyMap).indexOf(key)] || key
|
|
61
|
+
: key
|
|
62
|
+
}
|
|
63
|
+
*/
|
|
64
|
+
decodeKey(key) {
|
|
65
|
+
return this.keyMap ? this.mapKey.get(key) || key : key
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
encodeKey(key) {
|
|
69
|
+
return this.keyMap && this.keyMap.hasOwnProperty(key) ? this.keyMap[key] : key
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
encodeKeys(rec) {
|
|
73
|
+
if (!this._keyMap) return rec
|
|
74
|
+
let map = new Map()
|
|
75
|
+
for (let [k,v] of Object.entries(rec)) map.set((this._keyMap.hasOwnProperty(k) ? this._keyMap[k] : k), v)
|
|
76
|
+
return map
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
decodeKeys(map) {
|
|
80
|
+
if (!this._keyMap || map.constructor.name != 'Map') return map
|
|
81
|
+
if (!this._mapKey) {
|
|
82
|
+
this._mapKey = new Map()
|
|
83
|
+
for (let [k,v] of Object.entries(this._keyMap)) this._mapKey.set(v,k)
|
|
84
|
+
}
|
|
85
|
+
let res = {}
|
|
86
|
+
//map.forEach((v,k) => res[Object.keys(this._keyMap)[Object.values(this._keyMap).indexOf(k)] || k] = v)
|
|
87
|
+
map.forEach((v,k) => res[this._mapKey.has(k) ? this._mapKey.get(k) : k] = v)
|
|
88
|
+
return res
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
mapDecode(source, end) {
|
|
92
|
+
|
|
93
|
+
let res = this.decode(source)
|
|
94
|
+
if (this._keyMap) {
|
|
95
|
+
//Experiemntal support for Optimised KeyMap decoding
|
|
96
|
+
switch (res.constructor.name) {
|
|
97
|
+
case 'Array': return res.map(r => this.decodeKeys(r))
|
|
98
|
+
//case 'Map': return this.decodeKeys(res)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return res
|
|
102
|
+
}
|
|
103
|
+
|
|
44
104
|
decode(source, end) {
|
|
45
105
|
if (src) {
|
|
46
106
|
// re-entrant execution, save the state and restore it after we do this decode
|
|
@@ -55,12 +115,21 @@ export class Decoder {
|
|
|
55
115
|
srcStringEnd = 0
|
|
56
116
|
srcString = null
|
|
57
117
|
strings = EMPTY_ARRAY
|
|
118
|
+
bundledStrings = null
|
|
58
119
|
src = source
|
|
59
120
|
// this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
|
|
60
121
|
// technique for getting data from a database where it can be copied into an existing buffer instead of creating
|
|
61
122
|
// new ones
|
|
62
|
-
|
|
63
|
-
|
|
123
|
+
try {
|
|
124
|
+
dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength))
|
|
125
|
+
} catch(error) {
|
|
126
|
+
// if it doesn't have a buffer, maybe it is the wrong type of object
|
|
127
|
+
src = null
|
|
128
|
+
if (source instanceof Uint8Array)
|
|
129
|
+
throw error
|
|
130
|
+
throw new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))
|
|
131
|
+
}
|
|
132
|
+
if (this instanceof Decoder) {
|
|
64
133
|
currentDecoder = this
|
|
65
134
|
packedValues = this.sharedValues &&
|
|
66
135
|
(this.pack ? new Array(this.maxPrivatePackedValues || 16).concat(this.sharedValues) :
|
|
@@ -120,6 +189,9 @@ export function getPosition() {
|
|
|
120
189
|
export function checkedRead() {
|
|
121
190
|
try {
|
|
122
191
|
let result = read()
|
|
192
|
+
if (bundledStrings) // bundled strings to skip past
|
|
193
|
+
position = bundledStrings.postBundlePosition
|
|
194
|
+
|
|
123
195
|
if (position == srcEnd) {
|
|
124
196
|
// finished reading this source, cleanup references
|
|
125
197
|
currentStructures = null
|
|
@@ -182,10 +254,11 @@ export function read() {
|
|
|
182
254
|
position += 8
|
|
183
255
|
return value
|
|
184
256
|
}
|
|
185
|
-
if (currentDecoder.
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
257
|
+
if (currentDecoder.int64AsNumber) {
|
|
258
|
+
token = dataView.getUint32(position) * 0x100000000
|
|
259
|
+
token += dataView.getUint32(position + 4)
|
|
260
|
+
} else
|
|
261
|
+
token = dataView.getBigUint64(position)
|
|
189
262
|
position += 8
|
|
190
263
|
break
|
|
191
264
|
case 0x1f:
|
|
@@ -193,6 +266,7 @@ export function read() {
|
|
|
193
266
|
switch(majorType) {
|
|
194
267
|
case 2: // byte string
|
|
195
268
|
case 3: // text string
|
|
269
|
+
throw new Error('Indefinite length not supported for byte or text strings')
|
|
196
270
|
case 4: // array
|
|
197
271
|
let array = []
|
|
198
272
|
let value, i = 0
|
|
@@ -204,8 +278,8 @@ export function read() {
|
|
|
204
278
|
let key
|
|
205
279
|
if (currentDecoder.mapsAsObjects) {
|
|
206
280
|
let object = {}
|
|
207
|
-
|
|
208
|
-
|
|
281
|
+
if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) object[currentDecoder.decodeKey(key)] = read()
|
|
282
|
+
else while ((key = read()) != STOP_CODE) object[key] = read()
|
|
209
283
|
return object
|
|
210
284
|
} else {
|
|
211
285
|
if (restoreMapsAsObject) {
|
|
@@ -213,8 +287,8 @@ export function read() {
|
|
|
213
287
|
restoreMapsAsObject = false
|
|
214
288
|
}
|
|
215
289
|
let map = new Map()
|
|
216
|
-
|
|
217
|
-
|
|
290
|
+
if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) map.set(currentDecoder.decodeKey(key), read())
|
|
291
|
+
else while ((key = read()) != STOP_CODE) map.set(key, read())
|
|
218
292
|
return map
|
|
219
293
|
}
|
|
220
294
|
case 7:
|
|
@@ -246,16 +320,15 @@ export function read() {
|
|
|
246
320
|
return readFixedString(token)
|
|
247
321
|
case 4: // array
|
|
248
322
|
let array = new Array(token)
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
323
|
+
//if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
|
|
324
|
+
//else
|
|
325
|
+
for (let i = 0; i < token; i++) array[i] = read()
|
|
252
326
|
return array
|
|
253
327
|
case 5: // map
|
|
254
328
|
if (currentDecoder.mapsAsObjects) {
|
|
255
329
|
let object = {}
|
|
256
|
-
for (let i = 0; i < token; i++)
|
|
257
|
-
|
|
258
|
-
}
|
|
330
|
+
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[currentDecoder.decodeKey(read())] = read()
|
|
331
|
+
else for (let i = 0; i < token; i++) object[read()] = read()
|
|
259
332
|
return object
|
|
260
333
|
} else {
|
|
261
334
|
if (restoreMapsAsObject) {
|
|
@@ -263,63 +336,66 @@ export function read() {
|
|
|
263
336
|
restoreMapsAsObject = false
|
|
264
337
|
}
|
|
265
338
|
let map = new Map()
|
|
266
|
-
for (let i = 0; i < token; i++)
|
|
267
|
-
|
|
268
|
-
}
|
|
339
|
+
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read())
|
|
340
|
+
else for (let i = 0; i < token; i++) map.set(read(), read())
|
|
269
341
|
return map
|
|
270
342
|
}
|
|
271
343
|
case 6: // extension
|
|
272
|
-
if (
|
|
273
|
-
let structure = currentStructures[token &
|
|
344
|
+
if (token >= BUNDLED_STRINGS_ID) {
|
|
345
|
+
let structure = currentStructures[token & 0x1fff] // check record structures first
|
|
346
|
+
// At some point we may provide an option for dynamic tag assignment with a range like token >= 8 && (token < 16 || (token > 0x80 && token < 0xc0) || (token > 0x130 && token < 0x4000))
|
|
274
347
|
if (structure) {
|
|
275
|
-
if (!structure.read)
|
|
276
|
-
structure.read = createStructureReader(structure)
|
|
348
|
+
if (!structure.read) structure.read = createStructureReader(structure)
|
|
277
349
|
return structure.read()
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
if (
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (extension.handlesRead)
|
|
301
|
-
return extension(read)
|
|
302
|
-
else
|
|
303
|
-
return extension(read())
|
|
304
|
-
} else {
|
|
305
|
-
let input = read()
|
|
306
|
-
for (let i = 0; i < currentExtensionRanges.length; i++) {
|
|
307
|
-
let value = currentExtensionRanges[i](token, input)
|
|
308
|
-
if (value !== undefined)
|
|
309
|
-
return value
|
|
350
|
+
}
|
|
351
|
+
if (token < 0x10000) {
|
|
352
|
+
if (token == RECORD_INLINE_ID) // we do a special check for this so that we can keep the currentExtensions as densely stored array (v8 stores arrays densely under about 3000 elements)
|
|
353
|
+
return recordDefinition(read())
|
|
354
|
+
else if (token == RECORD_DEFINITIONS_ID) {
|
|
355
|
+
let length = readJustLength()
|
|
356
|
+
let id = read()
|
|
357
|
+
for (let i = 2; i < length; i++) {
|
|
358
|
+
recordDefinition([id++, read()])
|
|
359
|
+
}
|
|
360
|
+
return read()
|
|
361
|
+
} else if (token == BUNDLED_STRINGS_ID) {
|
|
362
|
+
return readBundleExt()
|
|
363
|
+
}
|
|
364
|
+
if (currentDecoder.getShared) {
|
|
365
|
+
loadShared()
|
|
366
|
+
structure = currentStructures[token & 0x1fff]
|
|
367
|
+
if (structure) {
|
|
368
|
+
if (!structure.read)
|
|
369
|
+
structure.read = createStructureReader(structure)
|
|
370
|
+
return structure.read()
|
|
371
|
+
}
|
|
310
372
|
}
|
|
311
|
-
return new Tag(input)
|
|
312
373
|
}
|
|
313
374
|
}
|
|
375
|
+
let extension = currentExtensions[token]
|
|
376
|
+
if (extension) {
|
|
377
|
+
if (extension.handlesRead)
|
|
378
|
+
return extension(read)
|
|
379
|
+
else
|
|
380
|
+
return extension(read())
|
|
381
|
+
} else {
|
|
382
|
+
let input = read()
|
|
383
|
+
for (let i = 0; i < currentExtensionRanges.length; i++) {
|
|
384
|
+
let value = currentExtensionRanges[i](token, input)
|
|
385
|
+
if (value !== undefined)
|
|
386
|
+
return value
|
|
387
|
+
}
|
|
388
|
+
return new Tag(input, token)
|
|
389
|
+
}
|
|
314
390
|
case 7: // fixed value
|
|
315
391
|
switch (token) {
|
|
316
392
|
case 0x14: return false
|
|
317
393
|
case 0x15: return true
|
|
318
394
|
case 0x16: return null
|
|
319
395
|
case 0x17: return; // undefined
|
|
320
|
-
case 0x1f:
|
|
396
|
+
case 0x1f:
|
|
321
397
|
default:
|
|
322
|
-
let packedValue = packedValues[token]
|
|
398
|
+
let packedValue = (packedValues || getPackedValues())[token]
|
|
323
399
|
if (packedValue !== undefined)
|
|
324
400
|
return packedValue
|
|
325
401
|
throw new Error('Unknown token ' + token)
|
|
@@ -335,47 +411,55 @@ export function read() {
|
|
|
335
411
|
}
|
|
336
412
|
const validName = /^[a-zA-Z_$][a-zA-Z\d_$]*$/
|
|
337
413
|
function createStructureReader(structure) {
|
|
338
|
-
let l = structure.length
|
|
339
414
|
function readObject() {
|
|
415
|
+
// get the array size from the header
|
|
416
|
+
let length = src[position++]
|
|
417
|
+
//let majorType = token >> 5
|
|
418
|
+
length = length & 0x1f
|
|
419
|
+
if (length > 0x17) {
|
|
420
|
+
switch (length) {
|
|
421
|
+
case 0x18:
|
|
422
|
+
length = src[position++]
|
|
423
|
+
break
|
|
424
|
+
case 0x19:
|
|
425
|
+
length = dataView.getUint16(position)
|
|
426
|
+
position += 2
|
|
427
|
+
break
|
|
428
|
+
case 0x1a:
|
|
429
|
+
length = dataView.getUint32(position)
|
|
430
|
+
position += 4
|
|
431
|
+
break
|
|
432
|
+
default:
|
|
433
|
+
throw new Error('Expected array header, but got ' + src[position - 1])
|
|
434
|
+
}
|
|
435
|
+
}
|
|
340
436
|
// This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
|
|
341
|
-
if (
|
|
342
|
-
|
|
343
|
-
|
|
437
|
+
if (this.objectLiteralSize === length) // we have a fast object literal reader, use it (assuming it is the right length)
|
|
438
|
+
return this.objectLiteral(read)
|
|
439
|
+
if (this.count++ == 3) { // create a fast reader
|
|
440
|
+
this.objectLiteralSize = length
|
|
441
|
+
this.objectLiteral = currentDecoder.keyMap
|
|
442
|
+
? new Function('r', 'return {' + this.map(k => currentDecoder.decodeKey(k)).map(k => validName.test(k) ? k + ':r()' : ('[' + JSON.stringify(k) + ']:r()')).join(',') + '}')
|
|
443
|
+
: new Function('r', 'return {' + this.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}')
|
|
444
|
+
return this.objectLiteral(read)
|
|
344
445
|
}
|
|
345
|
-
readArrayHeader(l)
|
|
346
446
|
let object = {}
|
|
347
|
-
for (let i = 0; i <
|
|
348
|
-
|
|
349
|
-
object[key] = read()
|
|
350
|
-
}
|
|
447
|
+
if (currentDecoder.keyMap) for (let i = 0; i < length; i++) object[currentDecoder.decodeKey(this[i])] = read()
|
|
448
|
+
else for (let i = 0; i < length; i++) object[this[i]] = read()
|
|
351
449
|
return object
|
|
352
450
|
}
|
|
353
|
-
|
|
451
|
+
structure.count = 0
|
|
354
452
|
return readObject
|
|
355
453
|
}
|
|
356
454
|
|
|
357
|
-
function readArrayHeader(expectedLength) {
|
|
358
|
-
// consume the array header, TODO: check expected length
|
|
359
|
-
let token = src[position++]
|
|
360
|
-
//let majorType = token >> 5
|
|
361
|
-
token = token & 0x1f
|
|
362
|
-
if (token > 0x17) {
|
|
363
|
-
switch (token) {
|
|
364
|
-
case 0x18: position++
|
|
365
|
-
break
|
|
366
|
-
case 0x19: position += 2
|
|
367
|
-
break
|
|
368
|
-
case 0x1a: position += 4
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
455
|
let readFixedString = readStringJS
|
|
374
456
|
let readString8 = readStringJS
|
|
375
457
|
let readString16 = readStringJS
|
|
376
458
|
let readString32 = readStringJS
|
|
377
459
|
|
|
460
|
+
export let isNativeAccelerationEnabled = false
|
|
378
461
|
export function setExtractor(extractStrings) {
|
|
462
|
+
isNativeAccelerationEnabled = true
|
|
379
463
|
readFixedString = readString(1)
|
|
380
464
|
readString8 = readString(2)
|
|
381
465
|
readString16 = readString(3)
|
|
@@ -384,6 +468,8 @@ export function setExtractor(extractStrings) {
|
|
|
384
468
|
return function readString(length) {
|
|
385
469
|
let string = strings[stringPosition++]
|
|
386
470
|
if (string == null) {
|
|
471
|
+
if (bundledStrings)
|
|
472
|
+
return readStringJS(length)
|
|
387
473
|
let extraction = extractStrings(position, srcEnd, length, src)
|
|
388
474
|
if (typeof extraction == 'string') {
|
|
389
475
|
string = extraction
|
|
@@ -710,12 +796,13 @@ function readKey() {
|
|
|
710
796
|
}
|
|
711
797
|
|
|
712
798
|
export class Tag {
|
|
713
|
-
constructor(value) {
|
|
799
|
+
constructor(value, tag) {
|
|
714
800
|
this.value = value
|
|
801
|
+
this.tag = tag
|
|
715
802
|
}
|
|
716
803
|
}
|
|
717
804
|
|
|
718
|
-
let glbl = typeof
|
|
805
|
+
let glbl = typeof self == 'object' ? self : global
|
|
719
806
|
|
|
720
807
|
currentExtensions[0] = (dateString) => {
|
|
721
808
|
// string date extension
|
|
@@ -729,38 +816,62 @@ currentExtensions[1] = (epochSec) => {
|
|
|
729
816
|
|
|
730
817
|
currentExtensions[2] = (buffer) => {
|
|
731
818
|
// bigint extension
|
|
732
|
-
|
|
819
|
+
let value = BigInt(0)
|
|
820
|
+
for (let i = 0, l = buffer.byteLength; i < l; i++) {
|
|
821
|
+
value = BigInt(buffer[i]) + value << BigInt(8)
|
|
822
|
+
}
|
|
823
|
+
return value
|
|
733
824
|
}
|
|
734
825
|
|
|
735
826
|
currentExtensions[3] = (buffer) => {
|
|
736
827
|
// negative bigint extension
|
|
737
|
-
return BigInt(-1) - (
|
|
828
|
+
return BigInt(-1) - currentExtensions[2](buffer)
|
|
829
|
+
}
|
|
830
|
+
currentExtensions[4] = (fraction) => {
|
|
831
|
+
// best to reparse to maintain accuracy
|
|
832
|
+
return +(fraction[1] + 'e' + fraction[0])
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
currentExtensions[5] = (fraction) => {
|
|
836
|
+
// probably not sufficiently accurate
|
|
837
|
+
return fraction[1] * Math.exp(fraction[0] * Math.log(2))
|
|
738
838
|
}
|
|
739
839
|
|
|
740
840
|
// the registration of the record definition extension (tag 105)
|
|
741
|
-
const recordDefinition = () => {
|
|
742
|
-
let
|
|
743
|
-
let structure = definition[
|
|
744
|
-
|
|
745
|
-
currentStructures[id & 0xff] = structure
|
|
841
|
+
const recordDefinition = (definition) => {
|
|
842
|
+
let id = definition[0] - 0xe000
|
|
843
|
+
let structure = definition[1]
|
|
844
|
+
currentStructures[id] = structure
|
|
746
845
|
structure.read = createStructureReader(structure)
|
|
747
846
|
let object = {}
|
|
748
|
-
for (let i = 2,l = definition.length; i < l; i++) {
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
847
|
+
if (currentDecoder.keyMap) for (let i = 2,l = definition.length; i < l; i++) {
|
|
848
|
+
let key = currentDecoder.decodeKey(structure[i - 2])
|
|
849
|
+
object[key] = definition[i]
|
|
850
|
+
}
|
|
851
|
+
else for (let i = 2,l = definition.length; i < l; i++) {
|
|
852
|
+
let key = structure[i - 2]
|
|
853
|
+
object[key] = definition[i]
|
|
854
|
+
}
|
|
752
855
|
return object
|
|
753
856
|
}
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
857
|
+
currentExtensions[LEGACY_RECORD_INLINE_ID] = recordDefinition
|
|
858
|
+
currentExtensions[14] = (value) => {
|
|
859
|
+
if (bundledStrings)
|
|
860
|
+
return bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 += value)
|
|
861
|
+
return new Tag(value, 14)
|
|
862
|
+
}
|
|
863
|
+
currentExtensions[15] = (value) => {
|
|
864
|
+
if (bundledStrings)
|
|
865
|
+
return bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)
|
|
866
|
+
return new Tag(value, 15)
|
|
867
|
+
}
|
|
757
868
|
|
|
758
869
|
currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
|
|
759
870
|
return (glbl[data[0]] || Error)(data[1], data[2])
|
|
760
871
|
}
|
|
761
872
|
const packedTable = (read) => {
|
|
762
873
|
if (src[position++] != 0x84)
|
|
763
|
-
throw new Error('Packed values structure must be followed by 4 element array')
|
|
874
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
764
875
|
let newPackedValues = read() // packed values
|
|
765
876
|
packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues
|
|
766
877
|
packedValues.prefixes = read()
|
|
@@ -771,15 +882,36 @@ packedTable.handlesRead = true
|
|
|
771
882
|
currentExtensions[51] = packedTable
|
|
772
883
|
|
|
773
884
|
currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
|
|
885
|
+
if (!packedValues) {
|
|
886
|
+
if (currentDecoder.getShared)
|
|
887
|
+
loadShared()
|
|
888
|
+
else
|
|
889
|
+
return new Tag(data, PACKED_REFERENCE_TAG_ID)
|
|
890
|
+
}
|
|
774
891
|
if (typeof data == 'number')
|
|
775
892
|
return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
|
|
776
893
|
throw new Error('No support for non-integer packed references yet')
|
|
777
894
|
}
|
|
895
|
+
currentExtensions[25] = (id) => {
|
|
896
|
+
return stringRefs[id]
|
|
897
|
+
}
|
|
898
|
+
currentExtensions[256] = (read) => {
|
|
899
|
+
stringRefs = []
|
|
900
|
+
try {
|
|
901
|
+
return read()
|
|
902
|
+
} finally {
|
|
903
|
+
stringRefs = null
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
currentExtensions[256].handlesRead = true
|
|
778
907
|
|
|
779
|
-
currentExtensions[
|
|
780
|
-
//
|
|
781
|
-
if (!referenceMap)
|
|
908
|
+
currentExtensions[28] = (read) => {
|
|
909
|
+
// shareable http://cbor.schmorp.de/value-sharing (for structured clones)
|
|
910
|
+
if (!referenceMap) {
|
|
782
911
|
referenceMap = new Map()
|
|
912
|
+
referenceMap.id = 0
|
|
913
|
+
}
|
|
914
|
+
let id = referenceMap.id++
|
|
783
915
|
let token = src[position]
|
|
784
916
|
let target
|
|
785
917
|
// TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
|
|
@@ -797,9 +929,10 @@ currentExtensions[40009] = (id) => {
|
|
|
797
929
|
refEntry.target = targetProperties // the placeholder wasn't used, replace with the deserialized one
|
|
798
930
|
return targetProperties // no cycle, can just use the returned read object
|
|
799
931
|
}
|
|
932
|
+
currentExtensions[28].handlesRead = true
|
|
800
933
|
|
|
801
|
-
currentExtensions[
|
|
802
|
-
//
|
|
934
|
+
currentExtensions[29] = (id) => {
|
|
935
|
+
// sharedref http://cbor.schmorp.de/value-sharing (for structured clones)
|
|
803
936
|
let refEntry = referenceMap.get(id)
|
|
804
937
|
refEntry.used = true
|
|
805
938
|
return refEntry.target
|
|
@@ -822,19 +955,36 @@ function combine(a, b) {
|
|
|
822
955
|
return a.concat(b)
|
|
823
956
|
return Object.assign({}, a, b)
|
|
824
957
|
}
|
|
958
|
+
function getPackedValues() {
|
|
959
|
+
if (!packedValues) {
|
|
960
|
+
if (currentDecoder.getShared)
|
|
961
|
+
loadShared()
|
|
962
|
+
else
|
|
963
|
+
throw new Error('No packed values available')
|
|
964
|
+
}
|
|
965
|
+
return packedValues
|
|
966
|
+
}
|
|
967
|
+
const SHARED_DATA_TAG_ID = 0x53687264 // ascii 'Shrd'
|
|
825
968
|
currentExtensionRanges.push((tag, input) => {
|
|
826
969
|
if (tag >= 225 && tag <= 255)
|
|
827
|
-
return combine(
|
|
970
|
+
return combine(getPackedValues().prefixes[tag - 224], input)
|
|
828
971
|
if (tag >= 28704 && tag <= 32767)
|
|
829
|
-
return combine(
|
|
972
|
+
return combine(getPackedValues().prefixes[tag - 28672], input)
|
|
830
973
|
if (tag >= 1879052288 && tag <= 2147483647)
|
|
831
|
-
return combine(
|
|
974
|
+
return combine(getPackedValues().prefixes[tag - 1879048192], input)
|
|
832
975
|
if (tag >= 216 && tag <= 223)
|
|
833
|
-
return combine(input,
|
|
976
|
+
return combine(input, getPackedValues().suffixes[tag - 216])
|
|
834
977
|
if (tag >= 27647 && tag <= 28671)
|
|
835
|
-
return combine(input,
|
|
978
|
+
return combine(input, getPackedValues().suffixes[tag - 27639])
|
|
836
979
|
if (tag >= 1811940352 && tag <= 1879048191)
|
|
837
|
-
return combine(input,
|
|
980
|
+
return combine(input, getPackedValues().suffixes[tag - 1811939328])
|
|
981
|
+
if (tag == SHARED_DATA_TAG_ID) {// we do a special check for this so that we can keep the currentExtensions as densely stored array (v8 stores arrays densely under about 3000 elements)
|
|
982
|
+
return {
|
|
983
|
+
packedValues: packedValues,
|
|
984
|
+
structures: currentStructures.slice(0),
|
|
985
|
+
version: input,
|
|
986
|
+
}
|
|
987
|
+
}
|
|
838
988
|
})
|
|
839
989
|
|
|
840
990
|
export const typedArrays = ['Uint8', 'Uint8Clamped', 'Uint16', 'Uint32', 'BigUint64','Int8', 'Int16', 'Int32', 'BigInt64', 'Float32', 'Float64'].map(type => type + 'Array')
|
|
@@ -851,6 +1001,61 @@ function registerTypedArray(typedArrayName, tag) {
|
|
|
851
1001
|
}
|
|
852
1002
|
}
|
|
853
1003
|
|
|
1004
|
+
function readBundleExt() {
|
|
1005
|
+
let length = readJustLength()
|
|
1006
|
+
let bundlePosition = position + read()
|
|
1007
|
+
for (let i = 2; i < length; i++) {
|
|
1008
|
+
// skip past bundles that were already read
|
|
1009
|
+
let bundleLength = readJustLength() // this will increment position, so must add to position afterwards
|
|
1010
|
+
position += bundleLength
|
|
1011
|
+
}
|
|
1012
|
+
let dataPosition = position
|
|
1013
|
+
position = bundlePosition
|
|
1014
|
+
bundledStrings = [readStringJS(readJustLength()), readStringJS(readJustLength())]
|
|
1015
|
+
bundledStrings.position0 = 0
|
|
1016
|
+
bundledStrings.position1 = 0
|
|
1017
|
+
bundledStrings.postBundlePosition = position
|
|
1018
|
+
position = dataPosition
|
|
1019
|
+
return read()
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
function readJustLength() {
|
|
1023
|
+
let token = src[position++] & 0x1f
|
|
1024
|
+
if (token > 0x17) {
|
|
1025
|
+
switch (token) {
|
|
1026
|
+
case 0x18:
|
|
1027
|
+
token = src[position++]
|
|
1028
|
+
break
|
|
1029
|
+
case 0x19:
|
|
1030
|
+
token = dataView.getUint16(position)
|
|
1031
|
+
position += 2
|
|
1032
|
+
break
|
|
1033
|
+
case 0x1a:
|
|
1034
|
+
token = dataView.getUint32(position)
|
|
1035
|
+
position += 4
|
|
1036
|
+
break
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
return token
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
function loadShared() {
|
|
1043
|
+
if (currentDecoder.getShared) {
|
|
1044
|
+
let sharedData = saveState(() => {
|
|
1045
|
+
// save the state in case getShared modifies our buffer
|
|
1046
|
+
src = null
|
|
1047
|
+
return currentDecoder.getShared()
|
|
1048
|
+
}) || {}
|
|
1049
|
+
let updatedStructures = sharedData.structures || []
|
|
1050
|
+
currentDecoder.sharedVersion = sharedData.version
|
|
1051
|
+
packedValues = currentDecoder.sharedValues = sharedData.packedValues
|
|
1052
|
+
if (currentStructures === true)
|
|
1053
|
+
currentDecoder.structures = currentStructures = updatedStructures
|
|
1054
|
+
else
|
|
1055
|
+
currentStructures.splice.apply(currentStructures, [0, updatedStructures.length].concat(updatedStructures))
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
854
1059
|
function saveState(callback) {
|
|
855
1060
|
let savedSrcEnd = srcEnd
|
|
856
1061
|
let savedPosition = position
|
|
@@ -860,6 +1065,8 @@ function saveState(callback) {
|
|
|
860
1065
|
let savedSrcString = srcString
|
|
861
1066
|
let savedStrings = strings
|
|
862
1067
|
let savedReferenceMap = referenceMap
|
|
1068
|
+
let savedBundledStrings = bundledStrings
|
|
1069
|
+
|
|
863
1070
|
// TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
|
|
864
1071
|
let savedSrc = new Uint8Array(src.slice(0, srcEnd)) // we copy the data in case it changes while external data is processed
|
|
865
1072
|
let savedStructures = currentStructures
|
|
@@ -874,6 +1081,7 @@ function saveState(callback) {
|
|
|
874
1081
|
srcString = savedSrcString
|
|
875
1082
|
strings = savedStrings
|
|
876
1083
|
referenceMap = savedReferenceMap
|
|
1084
|
+
bundledStrings = savedBundledStrings
|
|
877
1085
|
src = savedSrc
|
|
878
1086
|
sequentialMode = savedSequentialMode
|
|
879
1087
|
currentStructures = savedStructures
|
|
@@ -895,8 +1103,6 @@ export const mult10 = new Array(147) // this is a table matching binary exponent
|
|
|
895
1103
|
for (let i = 0; i < 256; i++) {
|
|
896
1104
|
mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103))
|
|
897
1105
|
}
|
|
898
|
-
export const useRecords = false
|
|
899
|
-
export const mapsAsObjects = true
|
|
900
1106
|
let defaultDecoder = new Decoder({ useRecords: false })
|
|
901
1107
|
export const decode = defaultDecoder.decode
|
|
902
1108
|
export const decodeMultiple = defaultDecoder.decodeMultiple
|