cbor-x 0.9.4 → 1.2.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 +55 -21
- package/decode.d.ts +3 -0
- package/decode.js +355 -119
- package/dist/index.js +670 -342
- package/dist/index.min.js +99 -108
- package/dist/node-index.js +93 -0
- package/dist/node.cjs +672 -337
- package/dist/test.js +100 -8
- package/encode.d.ts +1 -1
- package/encode.js +312 -155
- package/index.js +0 -2
- 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 -596
package/dist/index.js
CHANGED
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
let src;
|
|
12
12
|
let srcEnd;
|
|
13
13
|
let position = 0;
|
|
14
|
-
const
|
|
14
|
+
const LEGACY_RECORD_INLINE_ID = 105;
|
|
15
|
+
const RECORD_DEFINITIONS_ID = 0xdffe;
|
|
16
|
+
const RECORD_INLINE_ID = 0xdfff; // temporary first-come first-serve tag // proposed tag: 0x7265 // 're'
|
|
17
|
+
const BUNDLED_STRINGS_ID = 0xdff9;
|
|
15
18
|
const PACKED_REFERENCE_TAG_ID = 6;
|
|
16
19
|
const STOP_CODE = {};
|
|
17
20
|
let currentDecoder = {};
|
|
@@ -19,6 +22,7 @@
|
|
|
19
22
|
let srcString;
|
|
20
23
|
let srcStringStart = 0;
|
|
21
24
|
let srcStringEnd = 0;
|
|
25
|
+
let bundledStrings;
|
|
22
26
|
let referenceMap;
|
|
23
27
|
let currentExtensions = [];
|
|
24
28
|
let currentExtensionRanges = [];
|
|
@@ -34,13 +38,70 @@
|
|
|
34
38
|
class Decoder {
|
|
35
39
|
constructor(options) {
|
|
36
40
|
if (options) {
|
|
41
|
+
if ((options.keyMap || options._keyMap) && !options.useRecords) {
|
|
42
|
+
options.useRecords = false;
|
|
43
|
+
options.mapsAsObjects = true;
|
|
44
|
+
}
|
|
37
45
|
if (options.useRecords === false && options.mapsAsObjects === undefined)
|
|
38
46
|
options.mapsAsObjects = true;
|
|
39
|
-
if (options.getStructures
|
|
47
|
+
if (options.getStructures)
|
|
48
|
+
options.getShared = options.getStructures;
|
|
49
|
+
if (options.getShared && !options.structures)
|
|
40
50
|
(options.structures = []).uninitialized = true; // this is what we use to denote an uninitialized structures
|
|
51
|
+
if (options.keyMap) {
|
|
52
|
+
this.mapKey = new Map();
|
|
53
|
+
for (let [k,v] of Object.entries(options.keyMap)) this.mapKey.set(v,k);
|
|
54
|
+
}
|
|
41
55
|
}
|
|
42
56
|
Object.assign(this, options);
|
|
43
57
|
}
|
|
58
|
+
/*
|
|
59
|
+
decodeKey(key) {
|
|
60
|
+
return this.keyMap
|
|
61
|
+
? Object.keys(this.keyMap)[Object.values(this.keyMap).indexOf(key)] || key
|
|
62
|
+
: key
|
|
63
|
+
}
|
|
64
|
+
*/
|
|
65
|
+
decodeKey(key) {
|
|
66
|
+
return this.keyMap ? this.mapKey.get(key) || key : key
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
encodeKey(key) {
|
|
70
|
+
return this.keyMap && this.keyMap.hasOwnProperty(key) ? this.keyMap[key] : key
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
encodeKeys(rec) {
|
|
74
|
+
if (!this._keyMap) return rec
|
|
75
|
+
let map = new Map();
|
|
76
|
+
for (let [k,v] of Object.entries(rec)) map.set((this._keyMap.hasOwnProperty(k) ? this._keyMap[k] : k), v);
|
|
77
|
+
return map
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
decodeKeys(map) {
|
|
81
|
+
if (!this._keyMap || map.constructor.name != 'Map') return map
|
|
82
|
+
if (!this._mapKey) {
|
|
83
|
+
this._mapKey = new Map();
|
|
84
|
+
for (let [k,v] of Object.entries(this._keyMap)) this._mapKey.set(v,k);
|
|
85
|
+
}
|
|
86
|
+
let res = {};
|
|
87
|
+
//map.forEach((v,k) => res[Object.keys(this._keyMap)[Object.values(this._keyMap).indexOf(k)] || k] = v)
|
|
88
|
+
map.forEach((v,k) => res[this._mapKey.has(k) ? this._mapKey.get(k) : k] = v);
|
|
89
|
+
return res
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
mapDecode(source, end) {
|
|
93
|
+
|
|
94
|
+
let res = this.decode(source);
|
|
95
|
+
if (this._keyMap) {
|
|
96
|
+
//Experiemntal support for Optimised KeyMap decoding
|
|
97
|
+
switch (res.constructor.name) {
|
|
98
|
+
case 'Array': return res.map(r => this.decodeKeys(r))
|
|
99
|
+
//case 'Map': return this.decodeKeys(res)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return res
|
|
103
|
+
}
|
|
104
|
+
|
|
44
105
|
decode(source, end) {
|
|
45
106
|
if (src) {
|
|
46
107
|
// re-entrant execution, save the state and restore it after we do this decode
|
|
@@ -53,6 +114,7 @@
|
|
|
53
114
|
position = 0;
|
|
54
115
|
srcStringEnd = 0;
|
|
55
116
|
srcString = null;
|
|
117
|
+
bundledStrings = null;
|
|
56
118
|
src = source;
|
|
57
119
|
// this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
|
|
58
120
|
// technique for getting data from a database where it can be copied into an existing buffer instead of creating
|
|
@@ -123,6 +185,9 @@
|
|
|
123
185
|
function checkedRead() {
|
|
124
186
|
try {
|
|
125
187
|
let result = read();
|
|
188
|
+
if (bundledStrings) // bundled strings to skip past
|
|
189
|
+
position = bundledStrings.postBundlePosition;
|
|
190
|
+
|
|
126
191
|
if (position == srcEnd) {
|
|
127
192
|
// finished reading this source, cleanup references
|
|
128
193
|
currentStructures = null;
|
|
@@ -185,7 +250,11 @@
|
|
|
185
250
|
position += 8;
|
|
186
251
|
return value
|
|
187
252
|
}
|
|
188
|
-
if (
|
|
253
|
+
if (majorType > 1) {
|
|
254
|
+
if (dataView.getUint32(position) > 0)
|
|
255
|
+
throw new Error('JavaScript does not support arrays, maps, or strings with length over 4294967295')
|
|
256
|
+
token = dataView.getUint32(position + 4);
|
|
257
|
+
} else if (currentDecoder.int64AsNumber) {
|
|
189
258
|
token = dataView.getUint32(position) * 0x100000000;
|
|
190
259
|
token += dataView.getUint32(position + 4);
|
|
191
260
|
} else
|
|
@@ -197,6 +266,7 @@
|
|
|
197
266
|
switch(majorType) {
|
|
198
267
|
case 2: // byte string
|
|
199
268
|
case 3: // text string
|
|
269
|
+
throw new Error('Indefinite length not supported for byte or text strings')
|
|
200
270
|
case 4: // array
|
|
201
271
|
let array = [];
|
|
202
272
|
let value, i = 0;
|
|
@@ -208,8 +278,8 @@
|
|
|
208
278
|
let key;
|
|
209
279
|
if (currentDecoder.mapsAsObjects) {
|
|
210
280
|
let object = {};
|
|
211
|
-
|
|
212
|
-
|
|
281
|
+
if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) object[currentDecoder.decodeKey(key)] = read();
|
|
282
|
+
else while ((key = read()) != STOP_CODE) object[key] = read();
|
|
213
283
|
return object
|
|
214
284
|
} else {
|
|
215
285
|
if (restoreMapsAsObject) {
|
|
@@ -217,8 +287,8 @@
|
|
|
217
287
|
restoreMapsAsObject = false;
|
|
218
288
|
}
|
|
219
289
|
let map = new Map();
|
|
220
|
-
|
|
221
|
-
|
|
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());
|
|
222
292
|
return map
|
|
223
293
|
}
|
|
224
294
|
case 7:
|
|
@@ -250,16 +320,15 @@
|
|
|
250
320
|
return readFixedString(token)
|
|
251
321
|
case 4: // array
|
|
252
322
|
let array = new Array(token);
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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();
|
|
256
326
|
return array
|
|
257
327
|
case 5: // map
|
|
258
328
|
if (currentDecoder.mapsAsObjects) {
|
|
259
329
|
let object = {};
|
|
260
|
-
for (let i = 0; i < token; i++)
|
|
261
|
-
|
|
262
|
-
}
|
|
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();
|
|
263
332
|
return object
|
|
264
333
|
} else {
|
|
265
334
|
if (restoreMapsAsObject) {
|
|
@@ -267,63 +336,66 @@
|
|
|
267
336
|
restoreMapsAsObject = false;
|
|
268
337
|
}
|
|
269
338
|
let map = new Map();
|
|
270
|
-
for (let i = 0; i < token; i++)
|
|
271
|
-
|
|
272
|
-
}
|
|
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());
|
|
273
341
|
return map
|
|
274
342
|
}
|
|
275
343
|
case 6: // extension
|
|
276
|
-
if (
|
|
277
|
-
let structure = currentStructures[token &
|
|
344
|
+
if (token >= BUNDLED_STRINGS_ID) {
|
|
345
|
+
let structure = currentStructures[token & 0x1fff]; // check record structures first
|
|
346
|
+
// At some point we may provide an option for dynamic tag assignment with a range like token >= 8 && (token < 16 || (token > 0x80 && token < 0xc0) || (token > 0x130 && token < 0x4000))
|
|
278
347
|
if (structure) {
|
|
279
|
-
if (!structure.read)
|
|
280
|
-
structure.read = createStructureReader(structure);
|
|
348
|
+
if (!structure.read) structure.read = createStructureReader(structure);
|
|
281
349
|
return structure.read()
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
if (
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (extension.handlesRead)
|
|
305
|
-
return extension(read)
|
|
306
|
-
else
|
|
307
|
-
return extension(read())
|
|
308
|
-
} else {
|
|
309
|
-
let input = read();
|
|
310
|
-
for (let i = 0; i < currentExtensionRanges.length; i++) {
|
|
311
|
-
let value = currentExtensionRanges[i](token, input);
|
|
312
|
-
if (value !== undefined)
|
|
313
|
-
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
|
+
}
|
|
314
372
|
}
|
|
315
|
-
return new Tag(input)
|
|
316
373
|
}
|
|
317
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
|
+
}
|
|
318
390
|
case 7: // fixed value
|
|
319
391
|
switch (token) {
|
|
320
392
|
case 0x14: return false
|
|
321
393
|
case 0x15: return true
|
|
322
394
|
case 0x16: return null
|
|
323
395
|
case 0x17: return; // undefined
|
|
324
|
-
case 0x1f:
|
|
396
|
+
case 0x1f:
|
|
325
397
|
default:
|
|
326
|
-
let packedValue = packedValues[token];
|
|
398
|
+
let packedValue = (packedValues || getPackedValues())[token];
|
|
327
399
|
if (packedValue !== undefined)
|
|
328
400
|
return packedValue
|
|
329
401
|
throw new Error('Unknown token ' + token)
|
|
@@ -339,41 +411,56 @@
|
|
|
339
411
|
}
|
|
340
412
|
const validName = /^[a-zA-Z_$][a-zA-Z\d_$]*$/;
|
|
341
413
|
function createStructureReader(structure) {
|
|
342
|
-
let l = structure.length;
|
|
343
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
|
+
}
|
|
344
436
|
// This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
437
|
+
let compiledReader = this.compiledReader; // first look to see if we have the fast compiled function
|
|
438
|
+
while(compiledReader) {
|
|
439
|
+
// we have a fast compiled object literal reader
|
|
440
|
+
if (compiledReader.propertyCount === length)
|
|
441
|
+
return compiledReader(read) // with the right length, so we use it
|
|
442
|
+
compiledReader = compiledReader.next; // see if there is another reader with the right length
|
|
348
443
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
444
|
+
if (this.slowReads++ >= 3) { // create a fast compiled reader
|
|
445
|
+
let array = this.length == length ? this : this.slice(0, length);
|
|
446
|
+
compiledReader = currentDecoder.keyMap
|
|
447
|
+
? new Function('r', 'return {' + array.map(k => currentDecoder.decodeKey(k)).map(k => validName.test(k) ? k + ':r()' : ('[' + JSON.stringify(k) + ']:r()')).join(',') + '}')
|
|
448
|
+
: new Function('r', 'return {' + array.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}');
|
|
449
|
+
if (this.compiledReader)
|
|
450
|
+
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
|
|
451
|
+
compiledReader.propertyCount = length;
|
|
452
|
+
this.compiledReader = compiledReader;
|
|
453
|
+
return compiledReader(read)
|
|
354
454
|
}
|
|
455
|
+
let object = {};
|
|
456
|
+
if (currentDecoder.keyMap) for (let i = 0; i < length; i++) object[currentDecoder.decodeKey(this[i])] = read();
|
|
457
|
+
else for (let i = 0; i < length; i++) object[this[i]] = read();
|
|
355
458
|
return object
|
|
356
459
|
}
|
|
357
|
-
|
|
460
|
+
structure.slowReads = 0;
|
|
358
461
|
return readObject
|
|
359
462
|
}
|
|
360
463
|
|
|
361
|
-
function readArrayHeader(expectedLength) {
|
|
362
|
-
// consume the array header, TODO: check expected length
|
|
363
|
-
let token = src[position++];
|
|
364
|
-
//let majorType = token >> 5
|
|
365
|
-
token = token & 0x1f;
|
|
366
|
-
if (token > 0x17) {
|
|
367
|
-
switch (token) {
|
|
368
|
-
case 0x18: position++;
|
|
369
|
-
break
|
|
370
|
-
case 0x19: position += 2;
|
|
371
|
-
break
|
|
372
|
-
case 0x1a: position += 4;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
464
|
let readFixedString = readStringJS;
|
|
378
465
|
|
|
379
466
|
let isNativeAccelerationEnabled = false;
|
|
@@ -605,76 +692,15 @@
|
|
|
605
692
|
}
|
|
606
693
|
|
|
607
694
|
let keyCache = new Array(4096);
|
|
608
|
-
function readKey() {
|
|
609
|
-
let length = src[position++];
|
|
610
|
-
if (length >= 0x60 && length < 0x78) {
|
|
611
|
-
// fixstr, potentially use key cache
|
|
612
|
-
length = length - 0x60;
|
|
613
|
-
if (srcStringEnd >= position) // if it has been extracted, must use it (and faster anyway)
|
|
614
|
-
return srcString.slice(position - srcStringStart, (position += length) - srcStringStart)
|
|
615
|
-
else if (!(srcStringEnd == 0 && srcEnd < 180))
|
|
616
|
-
return readFixedString(length)
|
|
617
|
-
} else { // not cacheable, go back and do a standard read
|
|
618
|
-
position--;
|
|
619
|
-
return read()
|
|
620
|
-
}
|
|
621
|
-
let key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position) : length > 0 ? src[position] : 0)) & 0xfff;
|
|
622
|
-
let entry = keyCache[key];
|
|
623
|
-
let checkPosition = position;
|
|
624
|
-
let end = position + length - 3;
|
|
625
|
-
let chunk;
|
|
626
|
-
let i = 0;
|
|
627
|
-
if (entry && entry.bytes == length) {
|
|
628
|
-
while (checkPosition < end) {
|
|
629
|
-
chunk = dataView.getUint32(checkPosition);
|
|
630
|
-
if (chunk != entry[i++]) {
|
|
631
|
-
checkPosition = 0x70000000;
|
|
632
|
-
break
|
|
633
|
-
}
|
|
634
|
-
checkPosition += 4;
|
|
635
|
-
}
|
|
636
|
-
end += 3;
|
|
637
|
-
while (checkPosition < end) {
|
|
638
|
-
chunk = src[checkPosition++];
|
|
639
|
-
if (chunk != entry[i++]) {
|
|
640
|
-
checkPosition = 0x70000000;
|
|
641
|
-
break
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
if (checkPosition === end) {
|
|
645
|
-
position = checkPosition;
|
|
646
|
-
return entry.string
|
|
647
|
-
}
|
|
648
|
-
end -= 3;
|
|
649
|
-
checkPosition = position;
|
|
650
|
-
}
|
|
651
|
-
entry = [];
|
|
652
|
-
keyCache[key] = entry;
|
|
653
|
-
entry.bytes = length;
|
|
654
|
-
while (checkPosition < end) {
|
|
655
|
-
chunk = dataView.getUint32(checkPosition);
|
|
656
|
-
entry.push(chunk);
|
|
657
|
-
checkPosition += 4;
|
|
658
|
-
}
|
|
659
|
-
end += 3;
|
|
660
|
-
while (checkPosition < end) {
|
|
661
|
-
chunk = src[checkPosition++];
|
|
662
|
-
entry.push(chunk);
|
|
663
|
-
}
|
|
664
|
-
// for small blocks, avoiding the overhead of the extract call is helpful
|
|
665
|
-
let string = length < 16 ? shortStringInJS(length) : longStringInJS(length);
|
|
666
|
-
if (string != null)
|
|
667
|
-
return entry.string = string
|
|
668
|
-
return entry.string = readFixedString(length)
|
|
669
|
-
}
|
|
670
695
|
|
|
671
696
|
class Tag {
|
|
672
|
-
constructor(value) {
|
|
697
|
+
constructor(value, tag) {
|
|
673
698
|
this.value = value;
|
|
699
|
+
this.tag = tag;
|
|
674
700
|
}
|
|
675
701
|
}
|
|
676
702
|
|
|
677
|
-
let glbl = typeof
|
|
703
|
+
let glbl = typeof self == 'object' ? self : global;
|
|
678
704
|
|
|
679
705
|
currentExtensions[0] = (dateString) => {
|
|
680
706
|
// string date extension
|
|
@@ -688,38 +714,67 @@
|
|
|
688
714
|
|
|
689
715
|
currentExtensions[2] = (buffer) => {
|
|
690
716
|
// bigint extension
|
|
691
|
-
|
|
717
|
+
let value = BigInt(0);
|
|
718
|
+
for (let i = 0, l = buffer.byteLength; i < l; i++) {
|
|
719
|
+
value = BigInt(buffer[i]) + value << BigInt(8);
|
|
720
|
+
}
|
|
721
|
+
return value
|
|
692
722
|
};
|
|
693
723
|
|
|
694
724
|
currentExtensions[3] = (buffer) => {
|
|
695
725
|
// negative bigint extension
|
|
696
|
-
return BigInt(-1) - (
|
|
726
|
+
return BigInt(-1) - currentExtensions[2](buffer)
|
|
727
|
+
};
|
|
728
|
+
currentExtensions[4] = (fraction) => {
|
|
729
|
+
// best to reparse to maintain accuracy
|
|
730
|
+
return +(fraction[1] + 'e' + fraction[0])
|
|
697
731
|
};
|
|
698
732
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
733
|
+
currentExtensions[5] = (fraction) => {
|
|
734
|
+
// probably not sufficiently accurate
|
|
735
|
+
return fraction[1] * Math.exp(fraction[0] * Math.log(2))
|
|
736
|
+
};
|
|
737
|
+
|
|
738
|
+
// the registration of the record definition extension
|
|
739
|
+
const recordDefinition = (definition) => {
|
|
740
|
+
let id = definition[0] - 0xe000;
|
|
741
|
+
let structure = definition[1];
|
|
742
|
+
let existingStructure = currentStructures[id];
|
|
743
|
+
if (existingStructure && existingStructure.isShared) {
|
|
744
|
+
(currentStructures.restoreStructures || (currentStructures.restoreStructures = []))[id] = existingStructure;
|
|
745
|
+
}
|
|
746
|
+
currentStructures[id] = structure;
|
|
747
|
+
|
|
705
748
|
structure.read = createStructureReader(structure);
|
|
706
749
|
let object = {};
|
|
707
|
-
for (let i = 2,l = definition.length; i < l; i++) {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
750
|
+
if (currentDecoder.keyMap) for (let i = 2,l = definition.length; i < l; i++) {
|
|
751
|
+
let key = currentDecoder.decodeKey(structure[i - 2]);
|
|
752
|
+
object[key] = definition[i];
|
|
753
|
+
}
|
|
754
|
+
else for (let i = 2,l = definition.length; i < l; i++) {
|
|
755
|
+
let key = structure[i - 2];
|
|
756
|
+
object[key] = definition[i];
|
|
757
|
+
}
|
|
711
758
|
return object
|
|
712
759
|
};
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
760
|
+
currentExtensions[LEGACY_RECORD_INLINE_ID] = recordDefinition;
|
|
761
|
+
currentExtensions[14] = (value) => {
|
|
762
|
+
if (bundledStrings)
|
|
763
|
+
return bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 += value)
|
|
764
|
+
return new Tag(value, 14)
|
|
765
|
+
};
|
|
766
|
+
currentExtensions[15] = (value) => {
|
|
767
|
+
if (bundledStrings)
|
|
768
|
+
return bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)
|
|
769
|
+
return new Tag(value, 15)
|
|
770
|
+
};
|
|
716
771
|
|
|
717
772
|
currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
|
|
718
773
|
return (glbl[data[0]] || Error)(data[1], data[2])
|
|
719
774
|
};
|
|
720
775
|
const packedTable = (read) => {
|
|
721
776
|
if (src[position++] != 0x84)
|
|
722
|
-
throw new Error('Packed values structure must be followed by 4 element array')
|
|
777
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
723
778
|
let newPackedValues = read(); // packed values
|
|
724
779
|
packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
|
|
725
780
|
packedValues.prefixes = read();
|
|
@@ -730,15 +785,36 @@
|
|
|
730
785
|
currentExtensions[51] = packedTable;
|
|
731
786
|
|
|
732
787
|
currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
|
|
788
|
+
if (!packedValues) {
|
|
789
|
+
if (currentDecoder.getShared)
|
|
790
|
+
loadShared();
|
|
791
|
+
else
|
|
792
|
+
return new Tag(data, PACKED_REFERENCE_TAG_ID)
|
|
793
|
+
}
|
|
733
794
|
if (typeof data == 'number')
|
|
734
795
|
return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
|
|
735
796
|
throw new Error('No support for non-integer packed references yet')
|
|
736
797
|
};
|
|
798
|
+
currentExtensions[25] = (id) => {
|
|
799
|
+
return stringRefs[id]
|
|
800
|
+
};
|
|
801
|
+
currentExtensions[256] = (read) => {
|
|
802
|
+
stringRefs = [];
|
|
803
|
+
try {
|
|
804
|
+
return read()
|
|
805
|
+
} finally {
|
|
806
|
+
stringRefs = null;
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
currentExtensions[256].handlesRead = true;
|
|
737
810
|
|
|
738
|
-
currentExtensions[
|
|
739
|
-
//
|
|
740
|
-
if (!referenceMap)
|
|
811
|
+
currentExtensions[28] = (read) => {
|
|
812
|
+
// shareable http://cbor.schmorp.de/value-sharing (for structured clones)
|
|
813
|
+
if (!referenceMap) {
|
|
741
814
|
referenceMap = new Map();
|
|
815
|
+
referenceMap.id = 0;
|
|
816
|
+
}
|
|
817
|
+
let id = referenceMap.id++;
|
|
742
818
|
let token = src[position];
|
|
743
819
|
let target;
|
|
744
820
|
// TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
|
|
@@ -756,9 +832,10 @@
|
|
|
756
832
|
refEntry.target = targetProperties; // the placeholder wasn't used, replace with the deserialized one
|
|
757
833
|
return targetProperties // no cycle, can just use the returned read object
|
|
758
834
|
};
|
|
835
|
+
currentExtensions[28].handlesRead = true;
|
|
759
836
|
|
|
760
|
-
currentExtensions[
|
|
761
|
-
//
|
|
837
|
+
currentExtensions[29] = (id) => {
|
|
838
|
+
// sharedref http://cbor.schmorp.de/value-sharing (for structured clones)
|
|
762
839
|
let refEntry = referenceMap.get(id);
|
|
763
840
|
refEntry.used = true;
|
|
764
841
|
return refEntry.target
|
|
@@ -781,33 +858,126 @@
|
|
|
781
858
|
return a.concat(b)
|
|
782
859
|
return Object.assign({}, a, b)
|
|
783
860
|
}
|
|
861
|
+
function getPackedValues() {
|
|
862
|
+
if (!packedValues) {
|
|
863
|
+
if (currentDecoder.getShared)
|
|
864
|
+
loadShared();
|
|
865
|
+
else
|
|
866
|
+
throw new Error('No packed values available')
|
|
867
|
+
}
|
|
868
|
+
return packedValues
|
|
869
|
+
}
|
|
870
|
+
const SHARED_DATA_TAG_ID = 0x53687264; // ascii 'Shrd'
|
|
784
871
|
currentExtensionRanges.push((tag, input) => {
|
|
785
872
|
if (tag >= 225 && tag <= 255)
|
|
786
|
-
return combine(
|
|
873
|
+
return combine(getPackedValues().prefixes[tag - 224], input)
|
|
787
874
|
if (tag >= 28704 && tag <= 32767)
|
|
788
|
-
return combine(
|
|
875
|
+
return combine(getPackedValues().prefixes[tag - 28672], input)
|
|
789
876
|
if (tag >= 1879052288 && tag <= 2147483647)
|
|
790
|
-
return combine(
|
|
877
|
+
return combine(getPackedValues().prefixes[tag - 1879048192], input)
|
|
791
878
|
if (tag >= 216 && tag <= 223)
|
|
792
|
-
return combine(input,
|
|
879
|
+
return combine(input, getPackedValues().suffixes[tag - 216])
|
|
793
880
|
if (tag >= 27647 && tag <= 28671)
|
|
794
|
-
return combine(input,
|
|
881
|
+
return combine(input, getPackedValues().suffixes[tag - 27639])
|
|
795
882
|
if (tag >= 1811940352 && tag <= 1879048191)
|
|
796
|
-
return combine(input,
|
|
883
|
+
return combine(input, getPackedValues().suffixes[tag - 1811939328])
|
|
884
|
+
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)
|
|
885
|
+
return {
|
|
886
|
+
packedValues: packedValues,
|
|
887
|
+
structures: currentStructures.slice(0),
|
|
888
|
+
version: input,
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
if (tag == 55799) // self-descriptive CBOR tag, just return input value
|
|
892
|
+
return input
|
|
797
893
|
});
|
|
798
894
|
|
|
799
|
-
const
|
|
800
|
-
const
|
|
895
|
+
const isLittleEndianMachine = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1;
|
|
896
|
+
const typedArrays = ['Uint8', 'Uint8Clamped', 'Uint16', 'Uint32', 'BigUint64','Int8', 'Int16', 'Int32', 'BigInt64', 'Float32', 'Float64'];
|
|
897
|
+
const typedArrayTags = [64, 68, 69, 70, 71, 72, 77, 78, 79, 85, 86];
|
|
801
898
|
for (let i = 0; i < typedArrays.length; i++) {
|
|
802
899
|
registerTypedArray(typedArrays[i], typedArrayTags[i]);
|
|
803
900
|
}
|
|
804
|
-
function registerTypedArray(
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
901
|
+
function registerTypedArray(typedArrayId, tag, littleEndian) {
|
|
902
|
+
let TypedArray = glbl[typedArrayId + 'Array'];
|
|
903
|
+
let bytesPerElement = TypedArray.BYTES_PER_ELEMENT;
|
|
904
|
+
for (let littleEndian = 0; littleEndian < 2; littleEndian++) {
|
|
905
|
+
if (!littleEndian && bytesPerElement == 1)
|
|
906
|
+
continue
|
|
907
|
+
let sizeShift = bytesPerElement == 2 ? 1 : bytesPerElement == 4 ? 2 : 3;
|
|
908
|
+
currentExtensions[littleEndian ? tag : (tag - 4)] = (bytesPerElement == 1 || littleEndian == isLittleEndianMachine) ? (buffer) => {
|
|
909
|
+
if (!TypedArray)
|
|
910
|
+
throw new Error('Could not find typed array for code ' + tag)
|
|
911
|
+
// we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned
|
|
912
|
+
return new TypedArray(Uint8Array.prototype.slice.call(buffer, 0).buffer)
|
|
913
|
+
} : buffer => {
|
|
914
|
+
if (!TypedArray)
|
|
915
|
+
throw new Error('Could not find typed array for code ' + tag)
|
|
916
|
+
let dv = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
917
|
+
let elements = buffer.length >> sizeShift;
|
|
918
|
+
let ta = new TypedArray(elements);
|
|
919
|
+
let method = dv['get' + typedArrayId];
|
|
920
|
+
for (let i = 0; i < elements; i++) {
|
|
921
|
+
ta[i] = method.call(dv, i << sizeShift, littleEndian);
|
|
922
|
+
}
|
|
923
|
+
return ta
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
function readBundleExt() {
|
|
929
|
+
let length = readJustLength();
|
|
930
|
+
let bundlePosition = position + read();
|
|
931
|
+
for (let i = 2; i < length; i++) {
|
|
932
|
+
// skip past bundles that were already read
|
|
933
|
+
let bundleLength = readJustLength(); // this will increment position, so must add to position afterwards
|
|
934
|
+
position += bundleLength;
|
|
935
|
+
}
|
|
936
|
+
let dataPosition = position;
|
|
937
|
+
position = bundlePosition;
|
|
938
|
+
bundledStrings = [readStringJS(readJustLength()), readStringJS(readJustLength())];
|
|
939
|
+
bundledStrings.position0 = 0;
|
|
940
|
+
bundledStrings.position1 = 0;
|
|
941
|
+
bundledStrings.postBundlePosition = position;
|
|
942
|
+
position = dataPosition;
|
|
943
|
+
return read()
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
function readJustLength() {
|
|
947
|
+
let token = src[position++] & 0x1f;
|
|
948
|
+
if (token > 0x17) {
|
|
949
|
+
switch (token) {
|
|
950
|
+
case 0x18:
|
|
951
|
+
token = src[position++];
|
|
952
|
+
break
|
|
953
|
+
case 0x19:
|
|
954
|
+
token = dataView.getUint16(position);
|
|
955
|
+
position += 2;
|
|
956
|
+
break
|
|
957
|
+
case 0x1a:
|
|
958
|
+
token = dataView.getUint32(position);
|
|
959
|
+
position += 4;
|
|
960
|
+
break
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
return token
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
function loadShared() {
|
|
967
|
+
if (currentDecoder.getShared) {
|
|
968
|
+
let sharedData = saveState(() => {
|
|
969
|
+
// save the state in case getShared modifies our buffer
|
|
970
|
+
src = null;
|
|
971
|
+
return currentDecoder.getShared()
|
|
972
|
+
}) || {};
|
|
973
|
+
let updatedStructures = sharedData.structures || [];
|
|
974
|
+
currentDecoder.sharedVersion = sharedData.version;
|
|
975
|
+
packedValues = currentDecoder.sharedValues = sharedData.packedValues;
|
|
976
|
+
if (currentStructures === true)
|
|
977
|
+
currentDecoder.structures = currentStructures = updatedStructures;
|
|
978
|
+
else
|
|
979
|
+
currentStructures.splice.apply(currentStructures, [0, updatedStructures.length].concat(updatedStructures));
|
|
980
|
+
}
|
|
811
981
|
}
|
|
812
982
|
|
|
813
983
|
function saveState(callback) {
|
|
@@ -817,6 +987,8 @@
|
|
|
817
987
|
let savedSrcStringEnd = srcStringEnd;
|
|
818
988
|
let savedSrcString = srcString;
|
|
819
989
|
let savedReferenceMap = referenceMap;
|
|
990
|
+
let savedBundledStrings = bundledStrings;
|
|
991
|
+
|
|
820
992
|
// TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
|
|
821
993
|
let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
|
|
822
994
|
let savedStructures = currentStructures;
|
|
@@ -829,6 +1001,7 @@
|
|
|
829
1001
|
srcStringEnd = savedSrcStringEnd;
|
|
830
1002
|
srcString = savedSrcString;
|
|
831
1003
|
referenceMap = savedReferenceMap;
|
|
1004
|
+
bundledStrings = savedBundledStrings;
|
|
832
1005
|
src = savedSrc;
|
|
833
1006
|
sequentialMode = savedSequentialMode;
|
|
834
1007
|
currentStructures = savedStructures;
|
|
@@ -875,13 +1048,15 @@
|
|
|
875
1048
|
const hasNodeBuffer = typeof Buffer !== 'undefined';
|
|
876
1049
|
const ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array;
|
|
877
1050
|
const ByteArray = hasNodeBuffer ? Buffer : Uint8Array;
|
|
878
|
-
const RECORD_STARTING_ID_PREFIX = 0x69; // tag 105/0x69
|
|
879
1051
|
const MAX_STRUCTURES = 0x100;
|
|
880
1052
|
const MAX_BUFFER_SIZE = hasNodeBuffer ? 0x100000000 : 0x7fd00000;
|
|
881
1053
|
let target;
|
|
882
1054
|
let targetView;
|
|
883
1055
|
let position$1 = 0;
|
|
884
1056
|
let safeEnd;
|
|
1057
|
+
let bundledStrings$1 = null;
|
|
1058
|
+
const MAX_BUNDLE_SIZE = 0xf000;
|
|
1059
|
+
const hasNonLatin = /[\u0080-\uFFFF]/;
|
|
885
1060
|
const RECORD_SYMBOL = Symbol('record-id');
|
|
886
1061
|
class Encoder extends Decoder {
|
|
887
1062
|
constructor(options) {
|
|
@@ -893,7 +1068,6 @@
|
|
|
893
1068
|
let structures;
|
|
894
1069
|
let referenceMap;
|
|
895
1070
|
options = options || {};
|
|
896
|
-
let lastSharedStructuresLength = 0;
|
|
897
1071
|
let encodeUtf8 = ByteArray.prototype.utf8Write ? function(string, position, maxBytes) {
|
|
898
1072
|
return target.utf8Write(string, position, maxBytes)
|
|
899
1073
|
} : (textEncoder && textEncoder.encodeInto) ?
|
|
@@ -902,12 +1076,20 @@
|
|
|
902
1076
|
} : false;
|
|
903
1077
|
|
|
904
1078
|
let encoder = this;
|
|
905
|
-
let
|
|
1079
|
+
let hasSharedStructures = options.structures || options.saveStructures;
|
|
1080
|
+
let maxSharedStructures = options.maxSharedStructures;
|
|
1081
|
+
if (maxSharedStructures == null)
|
|
1082
|
+
maxSharedStructures = hasSharedStructures ? 128 : 0;
|
|
1083
|
+
if (maxSharedStructures > 8190)
|
|
1084
|
+
throw new Error('Maximum maxSharedStructure is 8190')
|
|
906
1085
|
let isSequential = options.sequential;
|
|
907
1086
|
if (isSequential) {
|
|
908
1087
|
maxSharedStructures = 0;
|
|
909
|
-
this.structures = [];
|
|
910
1088
|
}
|
|
1089
|
+
if (!this.structures)
|
|
1090
|
+
this.structures = [];
|
|
1091
|
+
if (this.saveStructures)
|
|
1092
|
+
this.saveShared = this.saveStructures;
|
|
911
1093
|
let samplingPackedValues, packedObjectMap, sharedValues = options.sharedValues;
|
|
912
1094
|
let sharedPackedObjectMap;
|
|
913
1095
|
if (sharedValues) {
|
|
@@ -915,13 +1097,29 @@
|
|
|
915
1097
|
for (let i = 0, l = sharedValues.length; i < l; i++) {
|
|
916
1098
|
sharedPackedObjectMap[sharedValues[i]] = i;
|
|
917
1099
|
}
|
|
918
|
-
|
|
919
1100
|
}
|
|
920
1101
|
let recordIdsToRemove = [];
|
|
921
1102
|
let transitionsCount = 0;
|
|
922
1103
|
let serializationsSinceTransitionRebuild = 0;
|
|
923
|
-
|
|
924
|
-
this.
|
|
1104
|
+
|
|
1105
|
+
this.mapEncode = function(value, encodeOptions) {
|
|
1106
|
+
// Experimental support for premapping keys using _keyMap instad of keyMap - not optiimised yet)
|
|
1107
|
+
if (this._keyMap && !this._mapped) {
|
|
1108
|
+
//console.log('encoding ', value)
|
|
1109
|
+
switch (value.constructor.name) {
|
|
1110
|
+
case 'Array':
|
|
1111
|
+
value = value.map(r => this.encodeKeys(r));
|
|
1112
|
+
break
|
|
1113
|
+
//case 'Map':
|
|
1114
|
+
// value = this.encodeKeys(value)
|
|
1115
|
+
// break
|
|
1116
|
+
}
|
|
1117
|
+
//this._mapped = true
|
|
1118
|
+
}
|
|
1119
|
+
return this.encode(value, encodeOptions)
|
|
1120
|
+
};
|
|
1121
|
+
|
|
1122
|
+
this.encode = function(value, encodeOptions) {
|
|
925
1123
|
if (!target) {
|
|
926
1124
|
target = new ByteArrayAllocate(8192);
|
|
927
1125
|
targetView = new DataView(target.buffer, 0, 8192);
|
|
@@ -937,11 +1135,30 @@
|
|
|
937
1135
|
} else if (encodeOptions === REUSE_BUFFER_MODE)
|
|
938
1136
|
position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
|
|
939
1137
|
start = position$1;
|
|
1138
|
+
if (encoder.useSelfDescribedHeader) {
|
|
1139
|
+
targetView.setUint32(position$1, 0xd9d9f700); // tag two byte, then self-descriptive tag
|
|
1140
|
+
position$1 += 3;
|
|
1141
|
+
}
|
|
940
1142
|
referenceMap = encoder.structuredClone ? new Map() : null;
|
|
1143
|
+
if (encoder.bundleStrings && typeof value !== 'string') {
|
|
1144
|
+
bundledStrings$1 = [];
|
|
1145
|
+
bundledStrings$1.size = Infinity; // force a new bundle start on first string
|
|
1146
|
+
} else
|
|
1147
|
+
bundledStrings$1 = null;
|
|
1148
|
+
|
|
941
1149
|
sharedStructures = encoder.structures;
|
|
942
1150
|
if (sharedStructures) {
|
|
943
|
-
if (sharedStructures.uninitialized)
|
|
944
|
-
|
|
1151
|
+
if (sharedStructures.uninitialized) {
|
|
1152
|
+
let sharedData = encoder.getShared() || {};
|
|
1153
|
+
encoder.structures = sharedStructures = sharedData.structures || [];
|
|
1154
|
+
encoder.sharedVersion = sharedData.version;
|
|
1155
|
+
let sharedValues = encoder.sharedValues = sharedData.packedValues;
|
|
1156
|
+
if (sharedValues) {
|
|
1157
|
+
sharedPackedObjectMap = {};
|
|
1158
|
+
for (let i = 0, l = sharedValues.length; i < l; i++)
|
|
1159
|
+
sharedPackedObjectMap[sharedValues[i]] = i;
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
945
1162
|
let sharedStructuresLength = sharedStructures.length;
|
|
946
1163
|
if (sharedStructuresLength > maxSharedStructures && !isSequential)
|
|
947
1164
|
sharedStructuresLength = maxSharedStructures;
|
|
@@ -950,10 +1167,13 @@
|
|
|
950
1167
|
sharedStructures.transitions = Object.create(null);
|
|
951
1168
|
for (let i = 0; i < sharedStructuresLength; i++) {
|
|
952
1169
|
let keys = sharedStructures[i];
|
|
1170
|
+
//console.log('shared struct keys:', keys)
|
|
953
1171
|
if (!keys)
|
|
954
1172
|
continue
|
|
955
1173
|
let nextTransition, transition = sharedStructures.transitions;
|
|
956
1174
|
for (let j = 0, l = keys.length; j < l; j++) {
|
|
1175
|
+
if (transition[RECORD_SYMBOL] === undefined)
|
|
1176
|
+
transition[RECORD_SYMBOL] = i;
|
|
957
1177
|
let key = keys[j];
|
|
958
1178
|
nextTransition = transition[key];
|
|
959
1179
|
if (!nextTransition) {
|
|
@@ -961,9 +1181,8 @@
|
|
|
961
1181
|
}
|
|
962
1182
|
transition = nextTransition;
|
|
963
1183
|
}
|
|
964
|
-
transition[RECORD_SYMBOL] = i;
|
|
1184
|
+
transition[RECORD_SYMBOL] = i | 0x100000;
|
|
965
1185
|
}
|
|
966
|
-
lastSharedStructuresLength = sharedStructures.length;
|
|
967
1186
|
}
|
|
968
1187
|
if (!isSequential)
|
|
969
1188
|
sharedStructures.nextId = sharedStructuresLength;
|
|
@@ -996,9 +1215,12 @@
|
|
|
996
1215
|
}
|
|
997
1216
|
try {
|
|
998
1217
|
encode(value);
|
|
1218
|
+
if (bundledStrings$1) {
|
|
1219
|
+
writeBundles(start, encode);
|
|
1220
|
+
}
|
|
999
1221
|
encoder.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|
|
1000
1222
|
if (referenceMap && referenceMap.idsToInsert) {
|
|
1001
|
-
position$1 += referenceMap.idsToInsert.length *
|
|
1223
|
+
position$1 += referenceMap.idsToInsert.length * 2;
|
|
1002
1224
|
if (position$1 > safeEnd)
|
|
1003
1225
|
makeRoom(position$1);
|
|
1004
1226
|
encoder.offset = position$1;
|
|
@@ -1006,16 +1228,18 @@
|
|
|
1006
1228
|
referenceMap = null;
|
|
1007
1229
|
return serialized
|
|
1008
1230
|
}
|
|
1009
|
-
if (encodeOptions
|
|
1231
|
+
if (encodeOptions & REUSE_BUFFER_MODE) {
|
|
1010
1232
|
target.start = start;
|
|
1011
1233
|
target.end = position$1;
|
|
1012
1234
|
return target
|
|
1013
1235
|
}
|
|
1014
|
-
return target.subarray(start, position$1) // position can change if we call
|
|
1236
|
+
return target.subarray(start, position$1) // position can change if we call encode again in saveShared, so we get the buffer now
|
|
1015
1237
|
} finally {
|
|
1016
1238
|
if (sharedStructures) {
|
|
1017
1239
|
if (serializationsSinceTransitionRebuild < 10)
|
|
1018
1240
|
serializationsSinceTransitionRebuild++;
|
|
1241
|
+
if (sharedStructures.length > maxSharedStructures)
|
|
1242
|
+
sharedStructures.length = maxSharedStructures;
|
|
1019
1243
|
if (transitionsCount > 10000) {
|
|
1020
1244
|
// force a rebuild occasionally after a lot of transitions so it can get cleaned up
|
|
1021
1245
|
sharedStructures.transitions = null;
|
|
@@ -1028,35 +1252,29 @@
|
|
|
1028
1252
|
recordIdsToRemove[i][RECORD_SYMBOL] = undefined;
|
|
1029
1253
|
}
|
|
1030
1254
|
recordIdsToRemove = [];
|
|
1255
|
+
//sharedStructures.nextId = maxSharedStructures
|
|
1031
1256
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
1037
|
-
let returnBuffer = target.subarray(start, position$1);
|
|
1038
|
-
let shared = encoder.structures || [];
|
|
1039
|
-
if (sharedValues) {
|
|
1040
|
-
shared = shared.concat(sharedValues);
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
if (encoder.saveStructures(encoder.structures, lastSharedStructuresLength) === false) {
|
|
1044
|
-
// get updated structures and try again if the update failed
|
|
1045
|
-
encoder.structures = encoder.getStructures() || [];
|
|
1046
|
-
return encoder.encode(value)
|
|
1047
|
-
}
|
|
1048
|
-
lastSharedStructuresLength = shared.length;
|
|
1049
|
-
return returnBuffer
|
|
1257
|
+
}
|
|
1258
|
+
if (hasSharedUpdate && encoder.saveShared) {
|
|
1259
|
+
if (encoder.structures.length > maxSharedStructures) {
|
|
1260
|
+
encoder.structures = encoder.structures.slice(0, maxSharedStructures);
|
|
1050
1261
|
}
|
|
1262
|
+
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
1263
|
+
let returnBuffer = target.subarray(start, position$1);
|
|
1264
|
+
if (encoder.updateSharedData() === false)
|
|
1265
|
+
return encoder.encode(value) // re-encode if it fails
|
|
1266
|
+
return returnBuffer
|
|
1051
1267
|
}
|
|
1268
|
+
if (encodeOptions & RESET_BUFFER_MODE)
|
|
1269
|
+
position$1 = start;
|
|
1052
1270
|
}
|
|
1053
1271
|
};
|
|
1054
1272
|
this.findCommonStringsToPack = () => {
|
|
1055
1273
|
samplingPackedValues = new Map();
|
|
1056
1274
|
if (!sharedPackedObjectMap)
|
|
1057
1275
|
sharedPackedObjectMap = Object.create(null);
|
|
1058
|
-
return (
|
|
1059
|
-
threshold = threshold || 4;
|
|
1276
|
+
return (options) => {
|
|
1277
|
+
let threshold = options && options.threshold || 4;
|
|
1060
1278
|
let position = this.pack ? options.maxPrivatePackedValues || 16 : 0;
|
|
1061
1279
|
if (!sharedValues)
|
|
1062
1280
|
sharedValues = this.sharedValues = [];
|
|
@@ -1067,6 +1285,7 @@
|
|
|
1067
1285
|
hasSharedUpdate = true;
|
|
1068
1286
|
}
|
|
1069
1287
|
}
|
|
1288
|
+
while (this.saveShared && this.updateSharedData() === false) {}
|
|
1070
1289
|
samplingPackedValues = null;
|
|
1071
1290
|
}
|
|
1072
1291
|
};
|
|
@@ -1115,6 +1334,33 @@
|
|
|
1115
1334
|
}
|
|
1116
1335
|
}
|
|
1117
1336
|
let strLength = value.length;
|
|
1337
|
+
if (bundledStrings$1 && strLength >= 4 && strLength < 0x400) {
|
|
1338
|
+
if ((bundledStrings$1.size += strLength) > MAX_BUNDLE_SIZE) {
|
|
1339
|
+
let extStart;
|
|
1340
|
+
let maxBytes = (bundledStrings$1[0] ? bundledStrings$1[0].length * 3 + bundledStrings$1[1].length : 0) + 10;
|
|
1341
|
+
if (position$1 + maxBytes > safeEnd)
|
|
1342
|
+
target = makeRoom(position$1 + maxBytes);
|
|
1343
|
+
target[position$1++] = 0xd9; // tag 16-bit
|
|
1344
|
+
target[position$1++] = 0xdf; // tag 0xdff9
|
|
1345
|
+
target[position$1++] = 0xf9;
|
|
1346
|
+
// TODO: If we only have one bundle with any string data, only write one string bundle
|
|
1347
|
+
target[position$1++] = bundledStrings$1.position ? 0x84 : 0x82; // array of 4 or 2 elements depending on if we write bundles
|
|
1348
|
+
target[position$1++] = 0x1a; // 32-bit unsigned int
|
|
1349
|
+
extStart = position$1 - start;
|
|
1350
|
+
position$1 += 4; // reserve for writing bundle reference
|
|
1351
|
+
if (bundledStrings$1.position) {
|
|
1352
|
+
writeBundles(start, encode); // write the last bundles
|
|
1353
|
+
}
|
|
1354
|
+
bundledStrings$1 = ['', '']; // create new ones
|
|
1355
|
+
bundledStrings$1.size = 0;
|
|
1356
|
+
bundledStrings$1.position = extStart;
|
|
1357
|
+
}
|
|
1358
|
+
let twoByte = hasNonLatin.test(value);
|
|
1359
|
+
bundledStrings$1[twoByte ? 0 : 1] += value;
|
|
1360
|
+
target[position$1++] = twoByte ? 0xce : 0xcf;
|
|
1361
|
+
encode(strLength);
|
|
1362
|
+
return
|
|
1363
|
+
}
|
|
1118
1364
|
let headerSize;
|
|
1119
1365
|
// first we estimate the header size, so we can write to the correct location
|
|
1120
1366
|
if (strLength < 0x20) {
|
|
@@ -1241,16 +1487,16 @@
|
|
|
1241
1487
|
if (referenceMap) {
|
|
1242
1488
|
let referee = referenceMap.get(value);
|
|
1243
1489
|
if (referee) {
|
|
1244
|
-
|
|
1490
|
+
target[position$1++] = 0xd8;
|
|
1491
|
+
target[position$1++] = 29; // http://cbor.schmorp.de/value-sharing
|
|
1492
|
+
target[position$1++] = 0x19; // 16-bit uint
|
|
1493
|
+
if (!referee.references) {
|
|
1245
1494
|
let idsToInsert = referenceMap.idsToInsert || (referenceMap.idsToInsert = []);
|
|
1246
|
-
referee.
|
|
1495
|
+
referee.references = [];
|
|
1496
|
+
idsToInsert.push(referee);
|
|
1247
1497
|
}
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
target[position$1++] = 40010 & 0xff;
|
|
1251
|
-
target[position$1++] = 0x1a; // uint32
|
|
1252
|
-
targetView.setUint32(position$1, referee.id);
|
|
1253
|
-
position$1 += 4;
|
|
1498
|
+
referee.references.push(position$1 - start);
|
|
1499
|
+
position$1 += 2; // TODO: also support 32-bit
|
|
1254
1500
|
return
|
|
1255
1501
|
} else
|
|
1256
1502
|
referenceMap.set(value, { offset: position$1 - start });
|
|
@@ -1290,16 +1536,23 @@
|
|
|
1290
1536
|
targetView.setUint32(position$1, length);
|
|
1291
1537
|
position$1 += 4;
|
|
1292
1538
|
}
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1539
|
+
if (encoder.keyMap) {
|
|
1540
|
+
for (let [ key, entryValue ] of value) {
|
|
1541
|
+
encode(encoder.encodeKey(key));
|
|
1542
|
+
encode(entryValue);
|
|
1543
|
+
}
|
|
1544
|
+
} else {
|
|
1545
|
+
for (let [ key, entryValue ] of value) {
|
|
1546
|
+
encode(key);
|
|
1547
|
+
encode(entryValue);
|
|
1548
|
+
}
|
|
1296
1549
|
}
|
|
1297
|
-
} else {
|
|
1550
|
+
} else {
|
|
1298
1551
|
for (let i = 0, l = extensions.length; i < l; i++) {
|
|
1299
1552
|
let extensionClass = extensionClasses[i];
|
|
1300
1553
|
if (value instanceof extensionClass) {
|
|
1301
1554
|
let extension = extensions[i];
|
|
1302
|
-
let tag = extension.tag;
|
|
1555
|
+
let tag = extension.tag || extension.getTag && extension.getTag(value);
|
|
1303
1556
|
if (tag < 0x18) {
|
|
1304
1557
|
target[position$1++] = 0xc0 | tag;
|
|
1305
1558
|
} else if (tag < 0x100) {
|
|
@@ -1361,6 +1614,7 @@
|
|
|
1361
1614
|
const writeObject = this.useRecords === false ? this.variableMapSize ? (object) => {
|
|
1362
1615
|
// this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects)
|
|
1363
1616
|
let keys = Object.keys(object);
|
|
1617
|
+
let vals = Object.values(object);
|
|
1364
1618
|
let length = keys.length;
|
|
1365
1619
|
if (length < 0x18) {
|
|
1366
1620
|
target[position$1++] = 0xa0 | length;
|
|
@@ -1376,10 +1630,16 @@
|
|
|
1376
1630
|
targetView.setUint32(position$1, length);
|
|
1377
1631
|
position$1 += 4;
|
|
1378
1632
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1633
|
+
if (encoder.keyMap) {
|
|
1634
|
+
for (let i = 0; i < length; i++) {
|
|
1635
|
+
encode(encodeKey(keys[i]));
|
|
1636
|
+
encode(vals[i]);
|
|
1637
|
+
}
|
|
1638
|
+
} else {
|
|
1639
|
+
for (let i = 0; i < length; i++) {
|
|
1640
|
+
encode(keys[i]);
|
|
1641
|
+
encode(vals[i]);
|
|
1642
|
+
}
|
|
1383
1643
|
}
|
|
1384
1644
|
} :
|
|
1385
1645
|
(object, safePrototype) => {
|
|
@@ -1387,95 +1647,92 @@
|
|
|
1387
1647
|
let objectOffset = position$1 - start;
|
|
1388
1648
|
position$1 += 2;
|
|
1389
1649
|
let size = 0;
|
|
1390
|
-
|
|
1391
|
-
if (safePrototype || object.hasOwnProperty(key)) {
|
|
1392
|
-
encode(key);
|
|
1650
|
+
if (encoder.keyMap) {
|
|
1651
|
+
for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
|
|
1652
|
+
encode(encoder.encodeKey(key));
|
|
1393
1653
|
encode(object[key]);
|
|
1394
1654
|
size++;
|
|
1395
1655
|
}
|
|
1656
|
+
} else {
|
|
1657
|
+
for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
|
|
1658
|
+
encode(key);
|
|
1659
|
+
encode(object[key]);
|
|
1660
|
+
size++;
|
|
1661
|
+
}
|
|
1396
1662
|
}
|
|
1397
1663
|
target[objectOffset++ + start] = size >> 8;
|
|
1398
1664
|
target[objectOffset + start] = size & 0xff;
|
|
1399
1665
|
} :
|
|
1400
|
-
|
|
1401
|
-
/* sharedStructures ? // For highly stable structures, using for-in can a little bit faster
|
|
1402
1666
|
(object, safePrototype) => {
|
|
1403
|
-
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))
|
|
1404
|
-
let
|
|
1405
|
-
let
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1667
|
+
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
|
|
1668
|
+
let newTransitions = 0;
|
|
1669
|
+
let length = 0;
|
|
1670
|
+
let parentRecordId;
|
|
1671
|
+
let keys;
|
|
1672
|
+
if (this.keyMap) {
|
|
1673
|
+
keys = Object.keys(object).map(k => this.encodeKey(k));
|
|
1674
|
+
length = keys.length;
|
|
1675
|
+
for (let i = 0; i < length; i++) {
|
|
1676
|
+
let key = keys[i];
|
|
1677
|
+
nextTransition = transition[key];
|
|
1409
1678
|
if (!nextTransition) {
|
|
1410
|
-
nextTransition = transition[key] = Object.create(null)
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
nextTransition.__keys__ = keys.slice(0, i + 1)
|
|
1422
|
-
}
|
|
1679
|
+
nextTransition = transition[key] = Object.create(null);
|
|
1680
|
+
newTransitions++;
|
|
1681
|
+
}
|
|
1682
|
+
transition = nextTransition;
|
|
1683
|
+
}
|
|
1684
|
+
} else {
|
|
1685
|
+
for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
|
|
1686
|
+
nextTransition = transition[key];
|
|
1687
|
+
if (!nextTransition) {
|
|
1688
|
+
if (transition[RECORD_SYMBOL] & 0x100000) {// this indicates it is a brancheable/extendable terminal node, so we will use this record id and extend it
|
|
1689
|
+
parentRecordId = transition[RECORD_SYMBOL] & 0xffff;
|
|
1423
1690
|
}
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
target.copy(target, )
|
|
1427
|
-
objectOffset
|
|
1691
|
+
nextTransition = transition[key] = Object.create(null);
|
|
1692
|
+
newTransitions++;
|
|
1428
1693
|
}
|
|
1429
|
-
transition = nextTransition
|
|
1430
|
-
|
|
1694
|
+
transition = nextTransition;
|
|
1695
|
+
length++;
|
|
1431
1696
|
}
|
|
1432
1697
|
}
|
|
1433
|
-
let id = transition.id
|
|
1434
|
-
if (!id) {
|
|
1435
|
-
id = transition.id = structures.push(transition.__keys__) + 63
|
|
1436
|
-
if (sharedStructures.onUpdate)
|
|
1437
|
-
sharedStructures.onUpdate(id, transition.__keys__)
|
|
1438
|
-
}
|
|
1439
|
-
target[objectOffset + start] = id
|
|
1440
|
-
}*/
|
|
1441
|
-
(object) => {
|
|
1442
|
-
let keys = Object.keys(object);
|
|
1443
|
-
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
|
|
1444
|
-
let newTransitions = 0;
|
|
1445
|
-
let length = keys.length;
|
|
1446
|
-
for (let i = 0; i < length; i++) {
|
|
1447
|
-
let key = keys[i];
|
|
1448
|
-
nextTransition = transition[key];
|
|
1449
|
-
if (!nextTransition) {
|
|
1450
|
-
nextTransition = transition[key] = Object.create(null);
|
|
1451
|
-
newTransitions++;
|
|
1452
|
-
}
|
|
1453
|
-
transition = nextTransition;
|
|
1454
|
-
}
|
|
1455
1698
|
let recordId = transition[RECORD_SYMBOL];
|
|
1456
1699
|
if (recordId !== undefined) {
|
|
1457
|
-
|
|
1458
|
-
target[position$1++] =
|
|
1459
|
-
target[position$1++] = recordId;
|
|
1700
|
+
recordId &= 0xffff;
|
|
1701
|
+
target[position$1++] = 0xd9;
|
|
1702
|
+
target[position$1++] = (recordId >> 8) | 0xe0;
|
|
1703
|
+
target[position$1++] = recordId & 0xff;
|
|
1460
1704
|
} else {
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
structures.nextId
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1705
|
+
if (!keys)
|
|
1706
|
+
keys = transition.__keys__ || (transition.__keys__ = Object.keys(object));
|
|
1707
|
+
if (parentRecordId === undefined) {
|
|
1708
|
+
recordId = structures.nextId++;
|
|
1709
|
+
if (!recordId) {
|
|
1710
|
+
recordId = 0;
|
|
1711
|
+
structures.nextId = 1;
|
|
1712
|
+
}
|
|
1713
|
+
if (recordId >= MAX_STRUCTURES) {// cycle back around
|
|
1714
|
+
structures.nextId = (recordId = maxSharedStructures) + 1;
|
|
1715
|
+
}
|
|
1716
|
+
} else {
|
|
1717
|
+
recordId = parentRecordId;
|
|
1468
1718
|
}
|
|
1469
|
-
transition[RECORD_SYMBOL] = recordId;
|
|
1470
1719
|
structures[recordId] = keys;
|
|
1471
|
-
if (
|
|
1472
|
-
target[position$1++] = 0xd9;
|
|
1473
|
-
target[position$1++] =
|
|
1474
|
-
target[position$1++] = recordId
|
|
1720
|
+
if (recordId < maxSharedStructures) {
|
|
1721
|
+
target[position$1++] = 0xd9;
|
|
1722
|
+
target[position$1++] = (recordId >> 8) | 0xe0;
|
|
1723
|
+
target[position$1++] = recordId & 0xff;
|
|
1724
|
+
transition = structures.transitions;
|
|
1725
|
+
for (let i = 0; i < length; i++) {
|
|
1726
|
+
if (transition[RECORD_SYMBOL] === undefined || (transition[RECORD_SYMBOL] & 0x100000))
|
|
1727
|
+
transition[RECORD_SYMBOL] = recordId;
|
|
1728
|
+
transition = transition[keys[i]];
|
|
1729
|
+
}
|
|
1730
|
+
transition[RECORD_SYMBOL] = recordId | 0x100000; // indicates it is a extendable terminal
|
|
1475
1731
|
hasSharedUpdate = true;
|
|
1476
1732
|
} else {
|
|
1477
|
-
|
|
1478
|
-
|
|
1733
|
+
transition[RECORD_SYMBOL] = recordId;
|
|
1734
|
+
targetView.setUint32(position$1, 0xd9dfff00); // tag two byte, then record definition id
|
|
1735
|
+
position$1 += 3;
|
|
1479
1736
|
if (newTransitions)
|
|
1480
1737
|
transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
|
|
1481
1738
|
// record the removal of the id, we can maintain our shared structure
|
|
@@ -1483,13 +1740,9 @@
|
|
|
1483
1740
|
recordIdsToRemove.shift()[RECORD_SYMBOL] = undefined; // we are cycling back through, and have to remove old ones
|
|
1484
1741
|
recordIdsToRemove.push(transition);
|
|
1485
1742
|
writeArrayHeader(length + 2);
|
|
1743
|
+
encode(0xe000 + recordId);
|
|
1486
1744
|
encode(keys);
|
|
1487
|
-
|
|
1488
|
-
target[position$1++] = RECORD_STARTING_ID_PREFIX;
|
|
1489
|
-
target[position$1++] = recordId;
|
|
1490
|
-
// now write the values
|
|
1491
|
-
for (let i =0; i < length; i++)
|
|
1492
|
-
encode(object[keys[i]]);
|
|
1745
|
+
for (let v of Object.values(object)) encode(v);
|
|
1493
1746
|
return
|
|
1494
1747
|
}
|
|
1495
1748
|
}
|
|
@@ -1498,8 +1751,9 @@
|
|
|
1498
1751
|
} else {
|
|
1499
1752
|
writeArrayHeader(length);
|
|
1500
1753
|
}
|
|
1501
|
-
for (let
|
|
1502
|
-
|
|
1754
|
+
for (let key in object)
|
|
1755
|
+
if (safePrototype || object.hasOwnProperty(key))
|
|
1756
|
+
encode(object[key]);
|
|
1503
1757
|
};
|
|
1504
1758
|
const makeRoom = (end) => {
|
|
1505
1759
|
let newSize;
|
|
@@ -1529,6 +1783,40 @@
|
|
|
1529
1783
|
targetView = new DataView(target.buffer, target.byteOffset, target.byteLength);
|
|
1530
1784
|
position$1 = 0;
|
|
1531
1785
|
}
|
|
1786
|
+
clearSharedData() {
|
|
1787
|
+
if (this.structures)
|
|
1788
|
+
this.structures = [];
|
|
1789
|
+
if (this.sharedValues)
|
|
1790
|
+
this.sharedValues = undefined;
|
|
1791
|
+
}
|
|
1792
|
+
updateSharedData() {
|
|
1793
|
+
let lastVersion = this.sharedVersion || 0;
|
|
1794
|
+
this.sharedVersion = lastVersion + 1;
|
|
1795
|
+
let structuresCopy = this.structures.slice(0);
|
|
1796
|
+
let sharedData = new SharedData(structuresCopy, this.sharedValues, this.sharedVersion);
|
|
1797
|
+
let saveResults = this.saveShared(sharedData,
|
|
1798
|
+
existingShared => (existingShared && existingShared.version || 0) == lastVersion);
|
|
1799
|
+
if (saveResults === false) {
|
|
1800
|
+
// get updated structures and try again if the update failed
|
|
1801
|
+
sharedData = this.getShared() || {};
|
|
1802
|
+
this.structures = sharedData.structures || [];
|
|
1803
|
+
this.sharedValues = sharedData.packedValues;
|
|
1804
|
+
this.sharedVersion = sharedData.version;
|
|
1805
|
+
this.structures.nextId = this.structures.length;
|
|
1806
|
+
} else {
|
|
1807
|
+
// restore structures
|
|
1808
|
+
structuresCopy.forEach((structure, i) => this.structures[i] = structure);
|
|
1809
|
+
}
|
|
1810
|
+
// saveShared may fail to write and reload, or may have reloaded to check compatibility and overwrite saved data, either way load the correct shared data
|
|
1811
|
+
return saveResults
|
|
1812
|
+
}
|
|
1813
|
+
}
|
|
1814
|
+
class SharedData {
|
|
1815
|
+
constructor(structures, values, version) {
|
|
1816
|
+
this.structures = structures;
|
|
1817
|
+
this.packedValues = values;
|
|
1818
|
+
this.version = version;
|
|
1819
|
+
}
|
|
1532
1820
|
}
|
|
1533
1821
|
|
|
1534
1822
|
function writeArrayHeader(length) {
|
|
@@ -1597,12 +1885,12 @@
|
|
|
1597
1885
|
case 'function': console.log(value);
|
|
1598
1886
|
}
|
|
1599
1887
|
}
|
|
1600
|
-
|
|
1601
|
-
extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, ByteArray,
|
|
1888
|
+
const isLittleEndianMachine$1 = new Uint8Array(new Uint16Array([1]).buffer)[0] == 1;
|
|
1889
|
+
extensionClasses = [ Date, Set, Error, RegExp, Tag, ArrayBuffer, ByteArray,
|
|
1602
1890
|
Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array,
|
|
1603
1891
|
typeof BigUint64Array == 'undefined' ? function() {} : BigUint64Array, Int8Array, Int16Array, Int32Array,
|
|
1604
1892
|
typeof BigInt64Array == 'undefined' ? function() {} : BigInt64Array,
|
|
1605
|
-
Float32Array, Float64Array];
|
|
1893
|
+
Float32Array, Float64Array, SharedData];
|
|
1606
1894
|
|
|
1607
1895
|
//Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/
|
|
1608
1896
|
extensions = [{
|
|
@@ -1637,6 +1925,13 @@
|
|
|
1637
1925
|
encode(regex, encode) {
|
|
1638
1926
|
encode([ 'RegExp', regex.source, regex.flags ]);
|
|
1639
1927
|
}
|
|
1928
|
+
}, {
|
|
1929
|
+
getTag(tag) {
|
|
1930
|
+
return tag.tag
|
|
1931
|
+
},
|
|
1932
|
+
encode(tag, encode) {
|
|
1933
|
+
encode(tag.value);
|
|
1934
|
+
}
|
|
1640
1935
|
}, {
|
|
1641
1936
|
encode(arrayBuffer, encode, makeRoom) {
|
|
1642
1937
|
writeBuffer(arrayBuffer, makeRoom);
|
|
@@ -1645,19 +1940,48 @@
|
|
|
1645
1940
|
encode(arrayBuffer, encode, makeRoom) {
|
|
1646
1941
|
writeBuffer(arrayBuffer, makeRoom);
|
|
1647
1942
|
}
|
|
1648
|
-
}, typedArrayEncoder(64),
|
|
1649
|
-
typedArrayEncoder(68),
|
|
1650
|
-
typedArrayEncoder(69),
|
|
1651
|
-
typedArrayEncoder(70),
|
|
1652
|
-
typedArrayEncoder(71),
|
|
1653
|
-
typedArrayEncoder(72),
|
|
1654
|
-
typedArrayEncoder(77),
|
|
1655
|
-
typedArrayEncoder(78),
|
|
1656
|
-
typedArrayEncoder(79),
|
|
1657
|
-
typedArrayEncoder(
|
|
1658
|
-
typedArrayEncoder(
|
|
1659
|
-
|
|
1660
|
-
|
|
1943
|
+
}, typedArrayEncoder(64, 1),
|
|
1944
|
+
typedArrayEncoder(68, 1),
|
|
1945
|
+
typedArrayEncoder(69, 2),
|
|
1946
|
+
typedArrayEncoder(70, 4),
|
|
1947
|
+
typedArrayEncoder(71, 8),
|
|
1948
|
+
typedArrayEncoder(72, 1),
|
|
1949
|
+
typedArrayEncoder(77, 2),
|
|
1950
|
+
typedArrayEncoder(78, 4),
|
|
1951
|
+
typedArrayEncoder(79, 8),
|
|
1952
|
+
typedArrayEncoder(85, 4),
|
|
1953
|
+
typedArrayEncoder(86, 8),
|
|
1954
|
+
{
|
|
1955
|
+
encode(sharedData, encode) { // write SharedData
|
|
1956
|
+
let packedValues = sharedData.packedValues || [];
|
|
1957
|
+
let sharedStructures = sharedData.structures || [];
|
|
1958
|
+
if (packedValues.values.length > 0) {
|
|
1959
|
+
target[position$1++] = 0xd8; // one-byte tag
|
|
1960
|
+
target[position$1++] = 51; // tag 51 for packed shared structures https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
|
|
1961
|
+
writeArrayHeader(4);
|
|
1962
|
+
let valuesArray = packedValues.values;
|
|
1963
|
+
encode(valuesArray);
|
|
1964
|
+
writeArrayHeader(0); // prefixes
|
|
1965
|
+
writeArrayHeader(0); // suffixes
|
|
1966
|
+
packedObjectMap = Object.create(sharedPackedObjectMap || null);
|
|
1967
|
+
for (let i = 0, l = valuesArray.length; i < l; i++) {
|
|
1968
|
+
packedObjectMap[valuesArray[i]] = i;
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
if (sharedStructures) {
|
|
1972
|
+
targetView.setUint32(position$1, 0xd9dffe00);
|
|
1973
|
+
position$1 += 3;
|
|
1974
|
+
let definitions = sharedStructures.slice(0);
|
|
1975
|
+
definitions.unshift(0xe000);
|
|
1976
|
+
definitions.push(new Tag(sharedData.version, 0x53687264));
|
|
1977
|
+
encode(definitions);
|
|
1978
|
+
} else
|
|
1979
|
+
encode(new Tag(sharedData.version, 0x53687264));
|
|
1980
|
+
}
|
|
1981
|
+
}];
|
|
1982
|
+
function typedArrayEncoder(tag, size) {
|
|
1983
|
+
if (!isLittleEndianMachine$1 && size > 1)
|
|
1984
|
+
tag -= 4; // the big endian equivalents are 4 less
|
|
1661
1985
|
return {
|
|
1662
1986
|
tag: tag,
|
|
1663
1987
|
encode: function writeExtBuffer(typedArray, encode) {
|
|
@@ -1695,27 +2019,35 @@
|
|
|
1695
2019
|
function insertIds(serialized, idsToInsert) {
|
|
1696
2020
|
// insert the ids that need to be referenced for structured clones
|
|
1697
2021
|
let nextId;
|
|
1698
|
-
let distanceToMove = idsToInsert.length *
|
|
2022
|
+
let distanceToMove = idsToInsert.length * 2;
|
|
1699
2023
|
let lastEnd = serialized.length - distanceToMove;
|
|
1700
2024
|
idsToInsert.sort((a, b) => a.offset > b.offset ? 1 : -1);
|
|
2025
|
+
for (let id = 0; id < idsToInsert.length; id++) {
|
|
2026
|
+
let referee = idsToInsert[id];
|
|
2027
|
+
referee.id = id;
|
|
2028
|
+
for (let position of referee.references) {
|
|
2029
|
+
serialized[position++] = id >> 8;
|
|
2030
|
+
serialized[position] = id & 0xff;
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
1701
2033
|
while (nextId = idsToInsert.pop()) {
|
|
1702
2034
|
let offset = nextId.offset;
|
|
1703
|
-
let id = nextId.id;
|
|
1704
2035
|
serialized.copyWithin(offset + distanceToMove, offset, lastEnd);
|
|
1705
|
-
distanceToMove -=
|
|
2036
|
+
distanceToMove -= 2;
|
|
1706
2037
|
let position = offset + distanceToMove;
|
|
1707
|
-
serialized[position++] =
|
|
1708
|
-
serialized[position++] =
|
|
1709
|
-
serialized[position++] = 40009 & 0xff;
|
|
1710
|
-
serialized[position++] = 0x1a; // uint32
|
|
1711
|
-
serialized[position++] = id >> 24;
|
|
1712
|
-
serialized[position++] = (id >> 16) & 0xff;
|
|
1713
|
-
serialized[position++] = (id >> 8) & 0xff;
|
|
1714
|
-
serialized[position++] = id & 0xff;
|
|
2038
|
+
serialized[position++] = 0xd8;
|
|
2039
|
+
serialized[position++] = 28; // http://cbor.schmorp.de/value-sharing
|
|
1715
2040
|
lastEnd = offset;
|
|
1716
2041
|
}
|
|
1717
2042
|
return serialized
|
|
1718
2043
|
}
|
|
2044
|
+
function writeBundles(start, encode) {
|
|
2045
|
+
targetView.setUint32(bundledStrings$1.position + start, position$1 - bundledStrings$1.position - start + 1); // the offset to bundle
|
|
2046
|
+
let writeStrings = bundledStrings$1;
|
|
2047
|
+
bundledStrings$1 = null;
|
|
2048
|
+
encode(writeStrings[0]);
|
|
2049
|
+
encode(writeStrings[1]);
|
|
2050
|
+
}
|
|
1719
2051
|
|
|
1720
2052
|
function addExtension$1(extension) {
|
|
1721
2053
|
if (extension.Class) {
|
|
@@ -1729,7 +2061,8 @@
|
|
|
1729
2061
|
let defaultEncoder = new Encoder({ useRecords: false });
|
|
1730
2062
|
const encode = defaultEncoder.encode;
|
|
1731
2063
|
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1732
|
-
const REUSE_BUFFER_MODE =
|
|
2064
|
+
const REUSE_BUFFER_MODE = 512;
|
|
2065
|
+
const RESET_BUFFER_MODE = 1024;
|
|
1733
2066
|
|
|
1734
2067
|
/**
|
|
1735
2068
|
* Given an Iterable first argument, returns an Iterable where each value is encoded as a Buffer
|
|
@@ -1814,9 +2147,6 @@
|
|
|
1814
2147
|
}
|
|
1815
2148
|
}
|
|
1816
2149
|
|
|
1817
|
-
const useRecords = false;
|
|
1818
|
-
const mapsAsObjects = true;
|
|
1819
|
-
|
|
1820
2150
|
exports.ALWAYS = ALWAYS;
|
|
1821
2151
|
exports.DECIMAL_FIT = DECIMAL_FIT;
|
|
1822
2152
|
exports.DECIMAL_ROUND = DECIMAL_ROUND;
|
|
@@ -1834,9 +2164,7 @@
|
|
|
1834
2164
|
exports.encode = encode;
|
|
1835
2165
|
exports.encodeIter = encodeIter;
|
|
1836
2166
|
exports.isNativeAccelerationEnabled = isNativeAccelerationEnabled;
|
|
1837
|
-
exports.mapsAsObjects = mapsAsObjects;
|
|
1838
2167
|
exports.roundFloat32 = roundFloat32;
|
|
1839
|
-
exports.useRecords = useRecords;
|
|
1840
2168
|
|
|
1841
2169
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
1842
2170
|
|