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/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 RECORD_TAG_ID = 0x69
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 && !options.structures)
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
- dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength))
63
- if (this) {
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 (currentDecoder.uint64AsNumber)
186
- return src[position++] * 0x100000000000000 + src[position++] * 0x1000000000000 + src[position++] * 0x10000000000 + src[position++] * 0x100000000 +
187
- src[position++] * 0x1000000 + (src[position++] << 16) + (src[position++] << 8) + src[position++]
188
- token = dataView.getBigUint64(position)
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
- while ((key = readKey()) != STOP_CODE)
208
- object[key] = read()
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
- while ((key = read()) != STOP_CODE)
217
- map.set(key, read())
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
- for (let i = 0; i < token; i++) {
250
- array[i] = read()
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
- object[readKey()] = read()
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
- map.set(read(), read())
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 ((token >> 8) == RECORD_TAG_ID) { // record structures
273
- let structure = currentStructures[token & 0xff]
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
- } else if (currentDecoder.getStructures) {
279
- let updatedStructures = saveState(() => {
280
- // save the state in case getStructures modifies our buffer
281
- src = null
282
- return currentDecoder.getStructures()
283
- })
284
- if (currentStructures === true)
285
- currentDecoder.structures = currentStructures = updatedStructures
286
- else
287
- currentStructures.splice.apply(currentStructures, [0, updatedStructures.length].concat(updatedStructures))
288
- structure = currentStructures[token & 0xff]
289
- if (structure) {
290
- if (!structure.read)
291
- structure.read = createStructureReader(structure)
292
- return structure.read()
293
- } else
294
- return token
295
- } else
296
- return token
297
- } else {
298
- let extension = currentExtensions[token]
299
- if (extension) {
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
- if (readObject.count++ > 2) {
342
- this.read = (new Function('a', 'r', 'return function(){a();return {' + structure.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}}'))(readArrayHeader, read)
343
- return this.read()
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
- readArrayHeader(l)
346
- let object = {}
347
- for (let i = 0; i < l; i++) {
348
- let key = structure[i]
349
- object[key] = read()
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
- readObject.count = 0
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 window == 'object' ? window : global
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
- return new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).getBigUint64(0)
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) - (new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).getBigUint64(0))
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
- let key = structure[i - 2]
750
- object[key] = definition[i]
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
- recordDefinition.handlesRead = true
756
- currentExtensions[RECORD_TAG_ID] = recordDefinition
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[40009] = (id) => {
780
- // id extension (for structured clones)
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[40010] = (id) => {
802
- // pointer extension (for structured clones)
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(packedTable.prefixes[tag - 224], input)
988
+ return combine(getPackedValues().prefixes[tag - 224], input)
828
989
  if (tag >= 28704 && tag <= 32767)
829
- return combine(packedTable.prefixes[tag - 28672], input)
990
+ return combine(getPackedValues().prefixes[tag - 28672], input)
830
991
  if (tag >= 1879052288 && tag <= 2147483647)
831
- return combine(packedTable.prefixes[tag - 1879048192], input)
992
+ return combine(getPackedValues().prefixes[tag - 1879048192], input)
832
993
  if (tag >= 216 && tag <= 223)
833
- return combine(input, packedTable.suffixes[tag - 216])
994
+ return combine(input, getPackedValues().suffixes[tag - 216])
834
995
  if (tag >= 27647 && tag <= 28671)
835
- return combine(input, packedTable.suffixes[tag - 27639])
996
+ return combine(input, getPackedValues().suffixes[tag - 27639])
836
997
  if (tag >= 1811940352 && tag <= 1879048191)
837
- return combine(input, packedTable.suffixes[tag - 1811939328])
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