cbor-x 0.9.4 → 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,6 +115,7 @@ 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
@@ -128,6 +189,9 @@ export function getPosition() {
128
189
  export function checkedRead() {
129
190
  try {
130
191
  let result = read()
192
+ if (bundledStrings) // bundled strings to skip past
193
+ position = bundledStrings.postBundlePosition
194
+
131
195
  if (position == srcEnd) {
132
196
  // finished reading this source, cleanup references
133
197
  currentStructures = null
@@ -202,6 +266,7 @@ export function read() {
202
266
  switch(majorType) {
203
267
  case 2: // byte string
204
268
  case 3: // text string
269
+ throw new Error('Indefinite length not supported for byte or text strings')
205
270
  case 4: // array
206
271
  let array = []
207
272
  let value, i = 0
@@ -213,8 +278,8 @@ export function read() {
213
278
  let key
214
279
  if (currentDecoder.mapsAsObjects) {
215
280
  let object = {}
216
- while ((key = readKey()) != STOP_CODE)
217
- 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()
218
283
  return object
219
284
  } else {
220
285
  if (restoreMapsAsObject) {
@@ -222,8 +287,8 @@ export function read() {
222
287
  restoreMapsAsObject = false
223
288
  }
224
289
  let map = new Map()
225
- while ((key = read()) != STOP_CODE)
226
- 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())
227
292
  return map
228
293
  }
229
294
  case 7:
@@ -255,16 +320,15 @@ export function read() {
255
320
  return readFixedString(token)
256
321
  case 4: // array
257
322
  let array = new Array(token)
258
- for (let i = 0; i < token; i++) {
259
- array[i] = read()
260
- }
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()
261
326
  return array
262
327
  case 5: // map
263
328
  if (currentDecoder.mapsAsObjects) {
264
329
  let object = {}
265
- for (let i = 0; i < token; i++) {
266
- object[readKey()] = read()
267
- }
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()
268
332
  return object
269
333
  } else {
270
334
  if (restoreMapsAsObject) {
@@ -272,63 +336,66 @@ export function read() {
272
336
  restoreMapsAsObject = false
273
337
  }
274
338
  let map = new Map()
275
- for (let i = 0; i < token; i++) {
276
- map.set(read(), read())
277
- }
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())
278
341
  return map
279
342
  }
280
343
  case 6: // extension
281
- if ((token >> 8) == RECORD_TAG_ID) { // record structures
282
- 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))
283
347
  if (structure) {
284
- if (!structure.read)
285
- structure.read = createStructureReader(structure)
348
+ if (!structure.read) structure.read = createStructureReader(structure)
286
349
  return structure.read()
287
- } else if (currentDecoder.getStructures) {
288
- let updatedStructures = saveState(() => {
289
- // save the state in case getStructures modifies our buffer
290
- src = null
291
- return currentDecoder.getStructures()
292
- })
293
- if (currentStructures === true)
294
- currentDecoder.structures = currentStructures = updatedStructures
295
- else
296
- currentStructures.splice.apply(currentStructures, [0, updatedStructures.length].concat(updatedStructures))
297
- structure = currentStructures[token & 0xff]
298
- if (structure) {
299
- if (!structure.read)
300
- structure.read = createStructureReader(structure)
301
- return structure.read()
302
- } else
303
- return token
304
- } else
305
- return token
306
- } else {
307
- let extension = currentExtensions[token]
308
- if (extension) {
309
- if (extension.handlesRead)
310
- return extension(read)
311
- else
312
- return extension(read())
313
- } else {
314
- let input = read()
315
- for (let i = 0; i < currentExtensionRanges.length; i++) {
316
- let value = currentExtensionRanges[i](token, input)
317
- if (value !== undefined)
318
- 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
+ }
319
372
  }
320
- return new Tag(input)
321
373
  }
322
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
+ }
323
390
  case 7: // fixed value
324
391
  switch (token) {
325
392
  case 0x14: return false
326
393
  case 0x15: return true
327
394
  case 0x16: return null
328
395
  case 0x17: return; // undefined
329
- case 0x1f:
396
+ case 0x1f:
330
397
  default:
331
- let packedValue = packedValues[token]
398
+ let packedValue = (packedValues || getPackedValues())[token]
332
399
  if (packedValue !== undefined)
333
400
  return packedValue
334
401
  throw new Error('Unknown token ' + token)
@@ -344,41 +411,47 @@ export function read() {
344
411
  }
345
412
  const validName = /^[a-zA-Z_$][a-zA-Z\d_$]*$/
346
413
  function createStructureReader(structure) {
347
- let l = structure.length
348
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
+ }
349
436
  // This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
350
- if (readObject.count++ > 2) {
351
- 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)
352
- 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)
353
445
  }
354
- readArrayHeader(l)
355
446
  let object = {}
356
- for (let i = 0; i < l; i++) {
357
- let key = structure[i]
358
- object[key] = read()
359
- }
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()
360
449
  return object
361
450
  }
362
- readObject.count = 0
451
+ structure.count = 0
363
452
  return readObject
364
453
  }
365
454
 
366
- function readArrayHeader(expectedLength) {
367
- // consume the array header, TODO: check expected length
368
- let token = src[position++]
369
- //let majorType = token >> 5
370
- token = token & 0x1f
371
- if (token > 0x17) {
372
- switch (token) {
373
- case 0x18: position++
374
- break
375
- case 0x19: position += 2
376
- break
377
- case 0x1a: position += 4
378
- }
379
- }
380
- }
381
-
382
455
  let readFixedString = readStringJS
383
456
  let readString8 = readStringJS
384
457
  let readString16 = readStringJS
@@ -395,6 +468,8 @@ export function setExtractor(extractStrings) {
395
468
  return function readString(length) {
396
469
  let string = strings[stringPosition++]
397
470
  if (string == null) {
471
+ if (bundledStrings)
472
+ return readStringJS(length)
398
473
  let extraction = extractStrings(position, srcEnd, length, src)
399
474
  if (typeof extraction == 'string') {
400
475
  string = extraction
@@ -721,12 +796,13 @@ function readKey() {
721
796
  }
722
797
 
723
798
  export class Tag {
724
- constructor(value) {
799
+ constructor(value, tag) {
725
800
  this.value = value
801
+ this.tag = tag
726
802
  }
727
803
  }
728
804
 
729
- let glbl = typeof window == 'object' ? window : global
805
+ let glbl = typeof self == 'object' ? self : global
730
806
 
731
807
  currentExtensions[0] = (dateString) => {
732
808
  // string date extension
@@ -740,38 +816,62 @@ currentExtensions[1] = (epochSec) => {
740
816
 
741
817
  currentExtensions[2] = (buffer) => {
742
818
  // bigint extension
743
- 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
744
824
  }
745
825
 
746
826
  currentExtensions[3] = (buffer) => {
747
827
  // negative bigint extension
748
- 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))
749
838
  }
750
839
 
751
840
  // the registration of the record definition extension (tag 105)
752
- const recordDefinition = () => {
753
- let definition = read()
754
- let structure = definition[0]
755
- let id = definition[1]
756
- currentStructures[id & 0xff] = structure
841
+ const recordDefinition = (definition) => {
842
+ let id = definition[0] - 0xe000
843
+ let structure = definition[1]
844
+ currentStructures[id] = structure
757
845
  structure.read = createStructureReader(structure)
758
846
  let object = {}
759
- for (let i = 2,l = definition.length; i < l; i++) {
760
- let key = structure[i - 2]
761
- object[key] = definition[i]
762
- }
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
+ }
763
855
  return object
764
856
  }
765
-
766
- recordDefinition.handlesRead = true
767
- 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
+ }
768
868
 
769
869
  currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
770
870
  return (glbl[data[0]] || Error)(data[1], data[2])
771
871
  }
772
872
  const packedTable = (read) => {
773
873
  if (src[position++] != 0x84)
774
- 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')
775
875
  let newPackedValues = read() // packed values
776
876
  packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues
777
877
  packedValues.prefixes = read()
@@ -782,15 +882,36 @@ packedTable.handlesRead = true
782
882
  currentExtensions[51] = packedTable
783
883
 
784
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
+ }
785
891
  if (typeof data == 'number')
786
892
  return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
787
893
  throw new Error('No support for non-integer packed references yet')
788
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
789
907
 
790
- currentExtensions[40009] = (id) => {
791
- // id extension (for structured clones)
792
- if (!referenceMap)
908
+ currentExtensions[28] = (read) => {
909
+ // shareable http://cbor.schmorp.de/value-sharing (for structured clones)
910
+ if (!referenceMap) {
793
911
  referenceMap = new Map()
912
+ referenceMap.id = 0
913
+ }
914
+ let id = referenceMap.id++
794
915
  let token = src[position]
795
916
  let target
796
917
  // TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
@@ -808,9 +929,10 @@ currentExtensions[40009] = (id) => {
808
929
  refEntry.target = targetProperties // the placeholder wasn't used, replace with the deserialized one
809
930
  return targetProperties // no cycle, can just use the returned read object
810
931
  }
932
+ currentExtensions[28].handlesRead = true
811
933
 
812
- currentExtensions[40010] = (id) => {
813
- // pointer extension (for structured clones)
934
+ currentExtensions[29] = (id) => {
935
+ // sharedref http://cbor.schmorp.de/value-sharing (for structured clones)
814
936
  let refEntry = referenceMap.get(id)
815
937
  refEntry.used = true
816
938
  return refEntry.target
@@ -833,19 +955,36 @@ function combine(a, b) {
833
955
  return a.concat(b)
834
956
  return Object.assign({}, a, b)
835
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'
836
968
  currentExtensionRanges.push((tag, input) => {
837
969
  if (tag >= 225 && tag <= 255)
838
- return combine(packedTable.prefixes[tag - 224], input)
970
+ return combine(getPackedValues().prefixes[tag - 224], input)
839
971
  if (tag >= 28704 && tag <= 32767)
840
- return combine(packedTable.prefixes[tag - 28672], input)
972
+ return combine(getPackedValues().prefixes[tag - 28672], input)
841
973
  if (tag >= 1879052288 && tag <= 2147483647)
842
- return combine(packedTable.prefixes[tag - 1879048192], input)
974
+ return combine(getPackedValues().prefixes[tag - 1879048192], input)
843
975
  if (tag >= 216 && tag <= 223)
844
- return combine(input, packedTable.suffixes[tag - 216])
976
+ return combine(input, getPackedValues().suffixes[tag - 216])
845
977
  if (tag >= 27647 && tag <= 28671)
846
- return combine(input, packedTable.suffixes[tag - 27639])
978
+ return combine(input, getPackedValues().suffixes[tag - 27639])
847
979
  if (tag >= 1811940352 && tag <= 1879048191)
848
- 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
+ }
849
988
  })
850
989
 
851
990
  export const typedArrays = ['Uint8', 'Uint8Clamped', 'Uint16', 'Uint32', 'BigUint64','Int8', 'Int16', 'Int32', 'BigInt64', 'Float32', 'Float64'].map(type => type + 'Array')
@@ -862,6 +1001,61 @@ function registerTypedArray(typedArrayName, tag) {
862
1001
  }
863
1002
  }
864
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
+
865
1059
  function saveState(callback) {
866
1060
  let savedSrcEnd = srcEnd
867
1061
  let savedPosition = position
@@ -871,6 +1065,8 @@ function saveState(callback) {
871
1065
  let savedSrcString = srcString
872
1066
  let savedStrings = strings
873
1067
  let savedReferenceMap = referenceMap
1068
+ let savedBundledStrings = bundledStrings
1069
+
874
1070
  // TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
875
1071
  let savedSrc = new Uint8Array(src.slice(0, srcEnd)) // we copy the data in case it changes while external data is processed
876
1072
  let savedStructures = currentStructures
@@ -885,6 +1081,7 @@ function saveState(callback) {
885
1081
  srcString = savedSrcString
886
1082
  strings = savedStrings
887
1083
  referenceMap = savedReferenceMap
1084
+ bundledStrings = savedBundledStrings
888
1085
  src = savedSrc
889
1086
  sequentialMode = savedSequentialMode
890
1087
  currentStructures = savedStructures