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/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,11 @@ 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 (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
- while ((key = readKey()) != STOP_CODE)
208
- object[key] = read()
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
- while ((key = read()) != STOP_CODE)
217
- map.set(key, read())
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
- for (let i = 0; i < token; i++) {
250
- array[i] = read()
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
- object[readKey()] = read()
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
- map.set(read(), read())
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 ((token >> 8) == RECORD_TAG_ID) { // record structures
273
- let structure = currentStructures[token & 0xff]
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
- } 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
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 (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()
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 < l; i++) {
348
- let key = structure[i]
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
- readObject.count = 0
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 window == 'object' ? window : global
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
- return new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).getBigUint64(0)
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) - (new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength).getBigUint64(0))
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 definition = read()
743
- let structure = definition[0]
744
- let id = definition[1]
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
- let key = structure[i - 2]
750
- object[key] = definition[i]
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
- recordDefinition.handlesRead = true
756
- currentExtensions[RECORD_TAG_ID] = recordDefinition
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[40009] = (id) => {
780
- // id extension (for structured clones)
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[40010] = (id) => {
802
- // pointer extension (for structured clones)
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(packedTable.prefixes[tag - 224], input)
970
+ return combine(getPackedValues().prefixes[tag - 224], input)
828
971
  if (tag >= 28704 && tag <= 32767)
829
- return combine(packedTable.prefixes[tag - 28672], input)
972
+ return combine(getPackedValues().prefixes[tag - 28672], input)
830
973
  if (tag >= 1879052288 && tag <= 2147483647)
831
- return combine(packedTable.prefixes[tag - 1879048192], input)
974
+ return combine(getPackedValues().prefixes[tag - 1879048192], input)
832
975
  if (tag >= 216 && tag <= 223)
833
- return combine(input, packedTable.suffixes[tag - 216])
976
+ return combine(input, getPackedValues().suffixes[tag - 216])
834
977
  if (tag >= 27647 && tag <= 28671)
835
- return combine(input, packedTable.suffixes[tag - 27639])
978
+ return combine(input, getPackedValues().suffixes[tag - 27639])
836
979
  if (tag >= 1811940352 && tag <= 1879048191)
837
- return combine(input, packedTable.suffixes[tag - 1811939328])
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