cbor-x 0.9.2 → 1.1.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 +66 -21
- package/decode.d.ts +5 -0
- package/decode.js +344 -118
- package/dist/index.js +650 -327
- package/dist/index.min.js +100 -107
- package/dist/node-index.js +93 -0
- package/dist/node.cjs +651 -325
- package/dist/test.js +107 -9
- package/encode.d.ts +1 -1
- package/encode.js +302 -144
- 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/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,15 @@ export function read() {
|
|
|
182
254
|
position += 8
|
|
183
255
|
return value
|
|
184
256
|
}
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
257
|
+
if (majorType > 1) {
|
|
258
|
+
if (dataView.getUint32(position) > 0)
|
|
259
|
+
throw new Error('JavaScript does not support arrays, maps, or strings with length over 4294967295')
|
|
260
|
+
token = dataView.getUint32(position + 4)
|
|
261
|
+
} else if (currentDecoder.int64AsNumber) {
|
|
262
|
+
token = dataView.getUint32(position) * 0x100000000
|
|
263
|
+
token += dataView.getUint32(position + 4)
|
|
264
|
+
} else
|
|
265
|
+
token = dataView.getBigUint64(position)
|
|
189
266
|
position += 8
|
|
190
267
|
break
|
|
191
268
|
case 0x1f:
|
|
@@ -193,6 +270,7 @@ export function read() {
|
|
|
193
270
|
switch(majorType) {
|
|
194
271
|
case 2: // byte string
|
|
195
272
|
case 3: // text string
|
|
273
|
+
throw new Error('Indefinite length not supported for byte or text strings')
|
|
196
274
|
case 4: // array
|
|
197
275
|
let array = []
|
|
198
276
|
let value, i = 0
|
|
@@ -204,8 +282,8 @@ export function read() {
|
|
|
204
282
|
let key
|
|
205
283
|
if (currentDecoder.mapsAsObjects) {
|
|
206
284
|
let object = {}
|
|
207
|
-
|
|
208
|
-
|
|
285
|
+
if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) object[currentDecoder.decodeKey(key)] = read()
|
|
286
|
+
else while ((key = read()) != STOP_CODE) object[key] = read()
|
|
209
287
|
return object
|
|
210
288
|
} else {
|
|
211
289
|
if (restoreMapsAsObject) {
|
|
@@ -213,8 +291,8 @@ export function read() {
|
|
|
213
291
|
restoreMapsAsObject = false
|
|
214
292
|
}
|
|
215
293
|
let map = new Map()
|
|
216
|
-
|
|
217
|
-
|
|
294
|
+
if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) map.set(currentDecoder.decodeKey(key), read())
|
|
295
|
+
else while ((key = read()) != STOP_CODE) map.set(key, read())
|
|
218
296
|
return map
|
|
219
297
|
}
|
|
220
298
|
case 7:
|
|
@@ -246,16 +324,15 @@ export function read() {
|
|
|
246
324
|
return readFixedString(token)
|
|
247
325
|
case 4: // array
|
|
248
326
|
let array = new Array(token)
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
327
|
+
//if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
|
|
328
|
+
//else
|
|
329
|
+
for (let i = 0; i < token; i++) array[i] = read()
|
|
252
330
|
return array
|
|
253
331
|
case 5: // map
|
|
254
332
|
if (currentDecoder.mapsAsObjects) {
|
|
255
333
|
let object = {}
|
|
256
|
-
for (let i = 0; i < token; i++)
|
|
257
|
-
|
|
258
|
-
}
|
|
334
|
+
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[currentDecoder.decodeKey(read())] = read()
|
|
335
|
+
else for (let i = 0; i < token; i++) object[read()] = read()
|
|
259
336
|
return object
|
|
260
337
|
} else {
|
|
261
338
|
if (restoreMapsAsObject) {
|
|
@@ -263,63 +340,66 @@ export function read() {
|
|
|
263
340
|
restoreMapsAsObject = false
|
|
264
341
|
}
|
|
265
342
|
let map = new Map()
|
|
266
|
-
for (let i = 0; i < token; i++)
|
|
267
|
-
|
|
268
|
-
}
|
|
343
|
+
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read())
|
|
344
|
+
else for (let i = 0; i < token; i++) map.set(read(), read())
|
|
269
345
|
return map
|
|
270
346
|
}
|
|
271
347
|
case 6: // extension
|
|
272
|
-
if (
|
|
273
|
-
let structure = currentStructures[token &
|
|
348
|
+
if (token >= BUNDLED_STRINGS_ID) {
|
|
349
|
+
let structure = currentStructures[token & 0x1fff] // check record structures first
|
|
350
|
+
// 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
351
|
if (structure) {
|
|
275
|
-
if (!structure.read)
|
|
276
|
-
structure.read = createStructureReader(structure)
|
|
352
|
+
if (!structure.read) structure.read = createStructureReader(structure)
|
|
277
353
|
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
|
|
354
|
+
}
|
|
355
|
+
if (token < 0x10000) {
|
|
356
|
+
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)
|
|
357
|
+
return recordDefinition(read())
|
|
358
|
+
else if (token == RECORD_DEFINITIONS_ID) {
|
|
359
|
+
let length = readJustLength()
|
|
360
|
+
let id = read()
|
|
361
|
+
for (let i = 2; i < length; i++) {
|
|
362
|
+
recordDefinition([id++, read()])
|
|
363
|
+
}
|
|
364
|
+
return read()
|
|
365
|
+
} else if (token == BUNDLED_STRINGS_ID) {
|
|
366
|
+
return readBundleExt()
|
|
367
|
+
}
|
|
368
|
+
if (currentDecoder.getShared) {
|
|
369
|
+
loadShared()
|
|
370
|
+
structure = currentStructures[token & 0x1fff]
|
|
371
|
+
if (structure) {
|
|
372
|
+
if (!structure.read)
|
|
373
|
+
structure.read = createStructureReader(structure)
|
|
374
|
+
return structure.read()
|
|
375
|
+
}
|
|
310
376
|
}
|
|
311
|
-
return new Tag(input)
|
|
312
377
|
}
|
|
313
378
|
}
|
|
379
|
+
let extension = currentExtensions[token]
|
|
380
|
+
if (extension) {
|
|
381
|
+
if (extension.handlesRead)
|
|
382
|
+
return extension(read)
|
|
383
|
+
else
|
|
384
|
+
return extension(read())
|
|
385
|
+
} else {
|
|
386
|
+
let input = read()
|
|
387
|
+
for (let i = 0; i < currentExtensionRanges.length; i++) {
|
|
388
|
+
let value = currentExtensionRanges[i](token, input)
|
|
389
|
+
if (value !== undefined)
|
|
390
|
+
return value
|
|
391
|
+
}
|
|
392
|
+
return new Tag(input, token)
|
|
393
|
+
}
|
|
314
394
|
case 7: // fixed value
|
|
315
395
|
switch (token) {
|
|
316
396
|
case 0x14: return false
|
|
317
397
|
case 0x15: return true
|
|
318
398
|
case 0x16: return null
|
|
319
399
|
case 0x17: return; // undefined
|
|
320
|
-
case 0x1f:
|
|
400
|
+
case 0x1f:
|
|
321
401
|
default:
|
|
322
|
-
let packedValue = packedValues[token]
|
|
402
|
+
let packedValue = (packedValues || getPackedValues())[token]
|
|
323
403
|
if (packedValue !== undefined)
|
|
324
404
|
return packedValue
|
|
325
405
|
throw new Error('Unknown token ' + token)
|
|
@@ -335,47 +415,64 @@ export function read() {
|
|
|
335
415
|
}
|
|
336
416
|
const validName = /^[a-zA-Z_$][a-zA-Z\d_$]*$/
|
|
337
417
|
function createStructureReader(structure) {
|
|
338
|
-
let l = structure.length
|
|
339
418
|
function readObject() {
|
|
419
|
+
// get the array size from the header
|
|
420
|
+
let length = src[position++]
|
|
421
|
+
//let majorType = token >> 5
|
|
422
|
+
length = length & 0x1f
|
|
423
|
+
if (length > 0x17) {
|
|
424
|
+
switch (length) {
|
|
425
|
+
case 0x18:
|
|
426
|
+
length = src[position++]
|
|
427
|
+
break
|
|
428
|
+
case 0x19:
|
|
429
|
+
length = dataView.getUint16(position)
|
|
430
|
+
position += 2
|
|
431
|
+
break
|
|
432
|
+
case 0x1a:
|
|
433
|
+
length = dataView.getUint32(position)
|
|
434
|
+
position += 4
|
|
435
|
+
break
|
|
436
|
+
default:
|
|
437
|
+
throw new Error('Expected array header, but got ' + src[position - 1])
|
|
438
|
+
}
|
|
439
|
+
}
|
|
340
440
|
// This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
441
|
+
let compiledReader = this.compiledReader // first look to see if we have the fast compiled function
|
|
442
|
+
while(compiledReader) {
|
|
443
|
+
// we have a fast compiled object literal reader
|
|
444
|
+
if (compiledReader.propertyCount === length)
|
|
445
|
+
return compiledReader(read) // with the right length, so we use it
|
|
446
|
+
compiledReader = compiledReader.next // see if there is another reader with the right length
|
|
344
447
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
448
|
+
if (this.slowReads++ >= 3) { // create a fast compiled reader
|
|
449
|
+
let array = this.length == length ? this : this.slice(0, length)
|
|
450
|
+
compiledReader = currentDecoder.keyMap
|
|
451
|
+
? new Function('r', 'return {' + array.map(k => currentDecoder.decodeKey(k)).map(k => validName.test(k) ? k + ':r()' : ('[' + JSON.stringify(k) + ']:r()')).join(',') + '}')
|
|
452
|
+
: new Function('r', 'return {' + array.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}')
|
|
453
|
+
if (this.compiledReader)
|
|
454
|
+
compiledReader.next = this.compiledReader // if there is an existing one, we store multiple readers as a linked list because it is usually pretty rare to have multiple readers (of different length) for the same structure
|
|
455
|
+
compiledReader.propertyCount = length
|
|
456
|
+
this.compiledReader = compiledReader
|
|
457
|
+
return compiledReader(read)
|
|
350
458
|
}
|
|
459
|
+
let object = {}
|
|
460
|
+
if (currentDecoder.keyMap) for (let i = 0; i < length; i++) object[currentDecoder.decodeKey(this[i])] = read()
|
|
461
|
+
else for (let i = 0; i < length; i++) object[this[i]] = read()
|
|
351
462
|
return object
|
|
352
463
|
}
|
|
353
|
-
|
|
464
|
+
structure.slowReads = 0
|
|
354
465
|
return readObject
|
|
355
466
|
}
|
|
356
467
|
|
|
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
468
|
let readFixedString = readStringJS
|
|
374
469
|
let readString8 = readStringJS
|
|
375
470
|
let readString16 = readStringJS
|
|
376
471
|
let readString32 = readStringJS
|
|
377
472
|
|
|
473
|
+
export let isNativeAccelerationEnabled = false
|
|
378
474
|
export function setExtractor(extractStrings) {
|
|
475
|
+
isNativeAccelerationEnabled = true
|
|
379
476
|
readFixedString = readString(1)
|
|
380
477
|
readString8 = readString(2)
|
|
381
478
|
readString16 = readString(3)
|
|
@@ -384,6 +481,8 @@ export function setExtractor(extractStrings) {
|
|
|
384
481
|
return function readString(length) {
|
|
385
482
|
let string = strings[stringPosition++]
|
|
386
483
|
if (string == null) {
|
|
484
|
+
if (bundledStrings)
|
|
485
|
+
return readStringJS(length)
|
|
387
486
|
let extraction = extractStrings(position, srcEnd, length, src)
|
|
388
487
|
if (typeof extraction == 'string') {
|
|
389
488
|
string = extraction
|
|
@@ -710,12 +809,13 @@ function readKey() {
|
|
|
710
809
|
}
|
|
711
810
|
|
|
712
811
|
export class Tag {
|
|
713
|
-
constructor(value) {
|
|
812
|
+
constructor(value, tag) {
|
|
714
813
|
this.value = value
|
|
814
|
+
this.tag = tag
|
|
715
815
|
}
|
|
716
816
|
}
|
|
717
817
|
|
|
718
|
-
let glbl = typeof
|
|
818
|
+
let glbl = typeof self == 'object' ? self : global
|
|
719
819
|
|
|
720
820
|
currentExtensions[0] = (dateString) => {
|
|
721
821
|
// string date extension
|
|
@@ -729,38 +829,67 @@ currentExtensions[1] = (epochSec) => {
|
|
|
729
829
|
|
|
730
830
|
currentExtensions[2] = (buffer) => {
|
|
731
831
|
// bigint extension
|
|
732
|
-
|
|
832
|
+
let value = BigInt(0)
|
|
833
|
+
for (let i = 0, l = buffer.byteLength; i < l; i++) {
|
|
834
|
+
value = BigInt(buffer[i]) + value << BigInt(8)
|
|
835
|
+
}
|
|
836
|
+
return value
|
|
733
837
|
}
|
|
734
838
|
|
|
735
839
|
currentExtensions[3] = (buffer) => {
|
|
736
840
|
// negative bigint extension
|
|
737
|
-
return BigInt(-1) - (
|
|
841
|
+
return BigInt(-1) - currentExtensions[2](buffer)
|
|
738
842
|
}
|
|
843
|
+
currentExtensions[4] = (fraction) => {
|
|
844
|
+
// best to reparse to maintain accuracy
|
|
845
|
+
return +(fraction[1] + 'e' + fraction[0])
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
currentExtensions[5] = (fraction) => {
|
|
849
|
+
// probably not sufficiently accurate
|
|
850
|
+
return fraction[1] * Math.exp(fraction[0] * Math.log(2))
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
// the registration of the record definition extension
|
|
854
|
+
const recordDefinition = (definition) => {
|
|
855
|
+
let id = definition[0] - 0xe000
|
|
856
|
+
let structure = definition[1]
|
|
857
|
+
let existingStructure = currentStructures[id]
|
|
858
|
+
if (existingStructure && existingStructure.isShared) {
|
|
859
|
+
(currentStructures.restoreStructures || (currentStructures.restoreStructures = []))[id] = existingStructure
|
|
860
|
+
}
|
|
861
|
+
currentStructures[id] = structure
|
|
739
862
|
|
|
740
|
-
// the registration of the record definition extension (tag 105)
|
|
741
|
-
const recordDefinition = () => {
|
|
742
|
-
let definition = read()
|
|
743
|
-
let structure = definition[0]
|
|
744
|
-
let id = definition[1]
|
|
745
|
-
currentStructures[id & 0xff] = structure
|
|
746
863
|
structure.read = createStructureReader(structure)
|
|
747
864
|
let object = {}
|
|
748
|
-
for (let i = 2,l = definition.length; i < l; i++) {
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
865
|
+
if (currentDecoder.keyMap) for (let i = 2,l = definition.length; i < l; i++) {
|
|
866
|
+
let key = currentDecoder.decodeKey(structure[i - 2])
|
|
867
|
+
object[key] = definition[i]
|
|
868
|
+
}
|
|
869
|
+
else for (let i = 2,l = definition.length; i < l; i++) {
|
|
870
|
+
let key = structure[i - 2]
|
|
871
|
+
object[key] = definition[i]
|
|
872
|
+
}
|
|
752
873
|
return object
|
|
753
874
|
}
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
875
|
+
currentExtensions[LEGACY_RECORD_INLINE_ID] = recordDefinition
|
|
876
|
+
currentExtensions[14] = (value) => {
|
|
877
|
+
if (bundledStrings)
|
|
878
|
+
return bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 += value)
|
|
879
|
+
return new Tag(value, 14)
|
|
880
|
+
}
|
|
881
|
+
currentExtensions[15] = (value) => {
|
|
882
|
+
if (bundledStrings)
|
|
883
|
+
return bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)
|
|
884
|
+
return new Tag(value, 15)
|
|
885
|
+
}
|
|
757
886
|
|
|
758
887
|
currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
|
|
759
888
|
return (glbl[data[0]] || Error)(data[1], data[2])
|
|
760
889
|
}
|
|
761
890
|
const packedTable = (read) => {
|
|
762
891
|
if (src[position++] != 0x84)
|
|
763
|
-
throw new Error('Packed values structure must be followed by 4 element array')
|
|
892
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
764
893
|
let newPackedValues = read() // packed values
|
|
765
894
|
packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues
|
|
766
895
|
packedValues.prefixes = read()
|
|
@@ -771,15 +900,36 @@ packedTable.handlesRead = true
|
|
|
771
900
|
currentExtensions[51] = packedTable
|
|
772
901
|
|
|
773
902
|
currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
|
|
903
|
+
if (!packedValues) {
|
|
904
|
+
if (currentDecoder.getShared)
|
|
905
|
+
loadShared()
|
|
906
|
+
else
|
|
907
|
+
return new Tag(data, PACKED_REFERENCE_TAG_ID)
|
|
908
|
+
}
|
|
774
909
|
if (typeof data == 'number')
|
|
775
910
|
return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
|
|
776
911
|
throw new Error('No support for non-integer packed references yet')
|
|
777
912
|
}
|
|
913
|
+
currentExtensions[25] = (id) => {
|
|
914
|
+
return stringRefs[id]
|
|
915
|
+
}
|
|
916
|
+
currentExtensions[256] = (read) => {
|
|
917
|
+
stringRefs = []
|
|
918
|
+
try {
|
|
919
|
+
return read()
|
|
920
|
+
} finally {
|
|
921
|
+
stringRefs = null
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
currentExtensions[256].handlesRead = true
|
|
778
925
|
|
|
779
|
-
currentExtensions[
|
|
780
|
-
//
|
|
781
|
-
if (!referenceMap)
|
|
926
|
+
currentExtensions[28] = (read) => {
|
|
927
|
+
// shareable http://cbor.schmorp.de/value-sharing (for structured clones)
|
|
928
|
+
if (!referenceMap) {
|
|
782
929
|
referenceMap = new Map()
|
|
930
|
+
referenceMap.id = 0
|
|
931
|
+
}
|
|
932
|
+
let id = referenceMap.id++
|
|
783
933
|
let token = src[position]
|
|
784
934
|
let target
|
|
785
935
|
// TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
|
|
@@ -797,9 +947,10 @@ currentExtensions[40009] = (id) => {
|
|
|
797
947
|
refEntry.target = targetProperties // the placeholder wasn't used, replace with the deserialized one
|
|
798
948
|
return targetProperties // no cycle, can just use the returned read object
|
|
799
949
|
}
|
|
950
|
+
currentExtensions[28].handlesRead = true
|
|
800
951
|
|
|
801
|
-
currentExtensions[
|
|
802
|
-
//
|
|
952
|
+
currentExtensions[29] = (id) => {
|
|
953
|
+
// sharedref http://cbor.schmorp.de/value-sharing (for structured clones)
|
|
803
954
|
let refEntry = referenceMap.get(id)
|
|
804
955
|
refEntry.used = true
|
|
805
956
|
return refEntry.target
|
|
@@ -822,19 +973,38 @@ function combine(a, b) {
|
|
|
822
973
|
return a.concat(b)
|
|
823
974
|
return Object.assign({}, a, b)
|
|
824
975
|
}
|
|
976
|
+
function getPackedValues() {
|
|
977
|
+
if (!packedValues) {
|
|
978
|
+
if (currentDecoder.getShared)
|
|
979
|
+
loadShared()
|
|
980
|
+
else
|
|
981
|
+
throw new Error('No packed values available')
|
|
982
|
+
}
|
|
983
|
+
return packedValues
|
|
984
|
+
}
|
|
985
|
+
const SHARED_DATA_TAG_ID = 0x53687264 // ascii 'Shrd'
|
|
825
986
|
currentExtensionRanges.push((tag, input) => {
|
|
826
987
|
if (tag >= 225 && tag <= 255)
|
|
827
|
-
return combine(
|
|
988
|
+
return combine(getPackedValues().prefixes[tag - 224], input)
|
|
828
989
|
if (tag >= 28704 && tag <= 32767)
|
|
829
|
-
return combine(
|
|
990
|
+
return combine(getPackedValues().prefixes[tag - 28672], input)
|
|
830
991
|
if (tag >= 1879052288 && tag <= 2147483647)
|
|
831
|
-
return combine(
|
|
992
|
+
return combine(getPackedValues().prefixes[tag - 1879048192], input)
|
|
832
993
|
if (tag >= 216 && tag <= 223)
|
|
833
|
-
return combine(input,
|
|
994
|
+
return combine(input, getPackedValues().suffixes[tag - 216])
|
|
834
995
|
if (tag >= 27647 && tag <= 28671)
|
|
835
|
-
return combine(input,
|
|
996
|
+
return combine(input, getPackedValues().suffixes[tag - 27639])
|
|
836
997
|
if (tag >= 1811940352 && tag <= 1879048191)
|
|
837
|
-
return combine(input,
|
|
998
|
+
return combine(input, getPackedValues().suffixes[tag - 1811939328])
|
|
999
|
+
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)
|
|
1000
|
+
return {
|
|
1001
|
+
packedValues: packedValues,
|
|
1002
|
+
structures: currentStructures.slice(0),
|
|
1003
|
+
version: input,
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
if (tag == 55799) // self-descriptive CBOR tag, just return input value
|
|
1007
|
+
return input
|
|
838
1008
|
})
|
|
839
1009
|
|
|
840
1010
|
export const typedArrays = ['Uint8', 'Uint8Clamped', 'Uint16', 'Uint32', 'BigUint64','Int8', 'Int16', 'Int32', 'BigInt64', 'Float32', 'Float64'].map(type => type + 'Array')
|
|
@@ -851,6 +1021,61 @@ function registerTypedArray(typedArrayName, tag) {
|
|
|
851
1021
|
}
|
|
852
1022
|
}
|
|
853
1023
|
|
|
1024
|
+
function readBundleExt() {
|
|
1025
|
+
let length = readJustLength()
|
|
1026
|
+
let bundlePosition = position + read()
|
|
1027
|
+
for (let i = 2; i < length; i++) {
|
|
1028
|
+
// skip past bundles that were already read
|
|
1029
|
+
let bundleLength = readJustLength() // this will increment position, so must add to position afterwards
|
|
1030
|
+
position += bundleLength
|
|
1031
|
+
}
|
|
1032
|
+
let dataPosition = position
|
|
1033
|
+
position = bundlePosition
|
|
1034
|
+
bundledStrings = [readStringJS(readJustLength()), readStringJS(readJustLength())]
|
|
1035
|
+
bundledStrings.position0 = 0
|
|
1036
|
+
bundledStrings.position1 = 0
|
|
1037
|
+
bundledStrings.postBundlePosition = position
|
|
1038
|
+
position = dataPosition
|
|
1039
|
+
return read()
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
function readJustLength() {
|
|
1043
|
+
let token = src[position++] & 0x1f
|
|
1044
|
+
if (token > 0x17) {
|
|
1045
|
+
switch (token) {
|
|
1046
|
+
case 0x18:
|
|
1047
|
+
token = src[position++]
|
|
1048
|
+
break
|
|
1049
|
+
case 0x19:
|
|
1050
|
+
token = dataView.getUint16(position)
|
|
1051
|
+
position += 2
|
|
1052
|
+
break
|
|
1053
|
+
case 0x1a:
|
|
1054
|
+
token = dataView.getUint32(position)
|
|
1055
|
+
position += 4
|
|
1056
|
+
break
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
return token
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
function loadShared() {
|
|
1063
|
+
if (currentDecoder.getShared) {
|
|
1064
|
+
let sharedData = saveState(() => {
|
|
1065
|
+
// save the state in case getShared modifies our buffer
|
|
1066
|
+
src = null
|
|
1067
|
+
return currentDecoder.getShared()
|
|
1068
|
+
}) || {}
|
|
1069
|
+
let updatedStructures = sharedData.structures || []
|
|
1070
|
+
currentDecoder.sharedVersion = sharedData.version
|
|
1071
|
+
packedValues = currentDecoder.sharedValues = sharedData.packedValues
|
|
1072
|
+
if (currentStructures === true)
|
|
1073
|
+
currentDecoder.structures = currentStructures = updatedStructures
|
|
1074
|
+
else
|
|
1075
|
+
currentStructures.splice.apply(currentStructures, [0, updatedStructures.length].concat(updatedStructures))
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
|
|
854
1079
|
function saveState(callback) {
|
|
855
1080
|
let savedSrcEnd = srcEnd
|
|
856
1081
|
let savedPosition = position
|
|
@@ -860,6 +1085,8 @@ function saveState(callback) {
|
|
|
860
1085
|
let savedSrcString = srcString
|
|
861
1086
|
let savedStrings = strings
|
|
862
1087
|
let savedReferenceMap = referenceMap
|
|
1088
|
+
let savedBundledStrings = bundledStrings
|
|
1089
|
+
|
|
863
1090
|
// TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
|
|
864
1091
|
let savedSrc = new Uint8Array(src.slice(0, srcEnd)) // we copy the data in case it changes while external data is processed
|
|
865
1092
|
let savedStructures = currentStructures
|
|
@@ -874,6 +1101,7 @@ function saveState(callback) {
|
|
|
874
1101
|
srcString = savedSrcString
|
|
875
1102
|
strings = savedStrings
|
|
876
1103
|
referenceMap = savedReferenceMap
|
|
1104
|
+
bundledStrings = savedBundledStrings
|
|
877
1105
|
src = savedSrc
|
|
878
1106
|
sequentialMode = savedSequentialMode
|
|
879
1107
|
currentStructures = savedStructures
|
|
@@ -895,8 +1123,6 @@ export const mult10 = new Array(147) // this is a table matching binary exponent
|
|
|
895
1123
|
for (let i = 0; i < 256; i++) {
|
|
896
1124
|
mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103))
|
|
897
1125
|
}
|
|
898
|
-
export const useRecords = false
|
|
899
|
-
export const mapsAsObjects = true
|
|
900
1126
|
let defaultDecoder = new Decoder({ useRecords: false })
|
|
901
1127
|
export const decode = defaultDecoder.decode
|
|
902
1128
|
export const decodeMultiple = defaultDecoder.decodeMultiple
|