cbor-x 0.9.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -21
- package/decode.d.ts +5 -0
- package/decode.js +344 -118
- package/dist/index.js +650 -327
- package/dist/index.min.js +100 -107
- package/dist/node-index.js +93 -0
- package/dist/node.cjs +651 -325
- package/dist/test.js +107 -9
- package/encode.d.ts +1 -1
- package/encode.js +302 -144
- package/index.d.ts +1 -1
- package/index.js +2 -4
- package/node-index.js +2 -4
- package/package.json +13 -4
- package/.vscode/launch.json +0 -22
- package/tests/benchmark-stream.cjs +0 -282
- package/tests/benchmark.cjs +0 -245
- package/tests/example.json +0 -52
- package/tests/example2.json +0 -26
- package/tests/example3.json +0 -22
- package/tests/example4.json +0 -1
- package/tests/example5.json +0 -12
- package/tests/floats.json +0 -1
- package/tests/index.html +0 -28
- package/tests/sample-large.json +0 -231
- package/tests/strings2.json +0 -1
- package/tests/test-compatibility.cjs +0 -36
- package/tests/test-incomplete.js +0 -41
- package/tests/test-node-iterators.js +0 -72
- package/tests/test-node-stream.js +0 -60
- package/tests/test.js +0 -586
package/dist/node.cjs
CHANGED
|
@@ -13,7 +13,10 @@ let src;
|
|
|
13
13
|
let srcEnd;
|
|
14
14
|
let position = 0;
|
|
15
15
|
const EMPTY_ARRAY = [];
|
|
16
|
-
const
|
|
16
|
+
const LEGACY_RECORD_INLINE_ID = 105;
|
|
17
|
+
const RECORD_DEFINITIONS_ID = 0xdffe;
|
|
18
|
+
const RECORD_INLINE_ID = 0xdfff; // temporary first-come first-serve tag // proposed tag: 0x7265 // 're'
|
|
19
|
+
const BUNDLED_STRINGS_ID = 0xdff9;
|
|
17
20
|
const PACKED_REFERENCE_TAG_ID = 6;
|
|
18
21
|
const STOP_CODE = {};
|
|
19
22
|
let strings = EMPTY_ARRAY;
|
|
@@ -23,6 +26,7 @@ let currentStructures;
|
|
|
23
26
|
let srcString;
|
|
24
27
|
let srcStringStart = 0;
|
|
25
28
|
let srcStringEnd = 0;
|
|
29
|
+
let bundledStrings;
|
|
26
30
|
let referenceMap;
|
|
27
31
|
let currentExtensions = [];
|
|
28
32
|
let currentExtensionRanges = [];
|
|
@@ -38,13 +42,70 @@ let sequentialMode = false;
|
|
|
38
42
|
class Decoder {
|
|
39
43
|
constructor(options) {
|
|
40
44
|
if (options) {
|
|
45
|
+
if ((options.keyMap || options._keyMap) && !options.useRecords) {
|
|
46
|
+
options.useRecords = false;
|
|
47
|
+
options.mapsAsObjects = true;
|
|
48
|
+
}
|
|
41
49
|
if (options.useRecords === false && options.mapsAsObjects === undefined)
|
|
42
50
|
options.mapsAsObjects = true;
|
|
43
|
-
if (options.getStructures
|
|
51
|
+
if (options.getStructures)
|
|
52
|
+
options.getShared = options.getStructures;
|
|
53
|
+
if (options.getShared && !options.structures)
|
|
44
54
|
(options.structures = []).uninitialized = true; // this is what we use to denote an uninitialized structures
|
|
55
|
+
if (options.keyMap) {
|
|
56
|
+
this.mapKey = new Map();
|
|
57
|
+
for (let [k,v] of Object.entries(options.keyMap)) this.mapKey.set(v,k);
|
|
58
|
+
}
|
|
45
59
|
}
|
|
46
60
|
Object.assign(this, options);
|
|
47
61
|
}
|
|
62
|
+
/*
|
|
63
|
+
decodeKey(key) {
|
|
64
|
+
return this.keyMap
|
|
65
|
+
? Object.keys(this.keyMap)[Object.values(this.keyMap).indexOf(key)] || key
|
|
66
|
+
: key
|
|
67
|
+
}
|
|
68
|
+
*/
|
|
69
|
+
decodeKey(key) {
|
|
70
|
+
return this.keyMap ? this.mapKey.get(key) || key : key
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
encodeKey(key) {
|
|
74
|
+
return this.keyMap && this.keyMap.hasOwnProperty(key) ? this.keyMap[key] : key
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
encodeKeys(rec) {
|
|
78
|
+
if (!this._keyMap) return rec
|
|
79
|
+
let map = new Map();
|
|
80
|
+
for (let [k,v] of Object.entries(rec)) map.set((this._keyMap.hasOwnProperty(k) ? this._keyMap[k] : k), v);
|
|
81
|
+
return map
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
decodeKeys(map) {
|
|
85
|
+
if (!this._keyMap || map.constructor.name != 'Map') return map
|
|
86
|
+
if (!this._mapKey) {
|
|
87
|
+
this._mapKey = new Map();
|
|
88
|
+
for (let [k,v] of Object.entries(this._keyMap)) this._mapKey.set(v,k);
|
|
89
|
+
}
|
|
90
|
+
let res = {};
|
|
91
|
+
//map.forEach((v,k) => res[Object.keys(this._keyMap)[Object.values(this._keyMap).indexOf(k)] || k] = v)
|
|
92
|
+
map.forEach((v,k) => res[this._mapKey.has(k) ? this._mapKey.get(k) : k] = v);
|
|
93
|
+
return res
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
mapDecode(source, end) {
|
|
97
|
+
|
|
98
|
+
let res = this.decode(source);
|
|
99
|
+
if (this._keyMap) {
|
|
100
|
+
//Experiemntal support for Optimised KeyMap decoding
|
|
101
|
+
switch (res.constructor.name) {
|
|
102
|
+
case 'Array': return res.map(r => this.decodeKeys(r))
|
|
103
|
+
//case 'Map': return this.decodeKeys(res)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return res
|
|
107
|
+
}
|
|
108
|
+
|
|
48
109
|
decode(source, end) {
|
|
49
110
|
if (src) {
|
|
50
111
|
// re-entrant execution, save the state and restore it after we do this decode
|
|
@@ -59,12 +120,21 @@ class Decoder {
|
|
|
59
120
|
srcStringEnd = 0;
|
|
60
121
|
srcString = null;
|
|
61
122
|
strings = EMPTY_ARRAY;
|
|
123
|
+
bundledStrings = null;
|
|
62
124
|
src = source;
|
|
63
125
|
// this provides cached access to the data view for a buffer if it is getting reused, which is a recommend
|
|
64
126
|
// technique for getting data from a database where it can be copied into an existing buffer instead of creating
|
|
65
127
|
// new ones
|
|
66
|
-
|
|
67
|
-
|
|
128
|
+
try {
|
|
129
|
+
dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
|
|
130
|
+
} catch(error) {
|
|
131
|
+
// if it doesn't have a buffer, maybe it is the wrong type of object
|
|
132
|
+
src = null;
|
|
133
|
+
if (source instanceof Uint8Array)
|
|
134
|
+
throw error
|
|
135
|
+
throw new Error('Source must be a Uint8Array or Buffer but was a ' + ((source && typeof source == 'object') ? source.constructor.name : typeof source))
|
|
136
|
+
}
|
|
137
|
+
if (this instanceof Decoder) {
|
|
68
138
|
currentDecoder = this;
|
|
69
139
|
packedValues = this.sharedValues &&
|
|
70
140
|
(this.pack ? new Array(this.maxPrivatePackedValues || 16).concat(this.sharedValues) :
|
|
@@ -121,6 +191,9 @@ class Decoder {
|
|
|
121
191
|
function checkedRead() {
|
|
122
192
|
try {
|
|
123
193
|
let result = read();
|
|
194
|
+
if (bundledStrings) // bundled strings to skip past
|
|
195
|
+
position = bundledStrings.postBundlePosition;
|
|
196
|
+
|
|
124
197
|
if (position == srcEnd) {
|
|
125
198
|
// finished reading this source, cleanup references
|
|
126
199
|
currentStructures = null;
|
|
@@ -183,10 +256,15 @@ function read() {
|
|
|
183
256
|
position += 8;
|
|
184
257
|
return value
|
|
185
258
|
}
|
|
186
|
-
if (
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
259
|
+
if (majorType > 1) {
|
|
260
|
+
if (dataView.getUint32(position) > 0)
|
|
261
|
+
throw new Error('JavaScript does not support arrays, maps, or strings with length over 4294967295')
|
|
262
|
+
token = dataView.getUint32(position + 4);
|
|
263
|
+
} else if (currentDecoder.int64AsNumber) {
|
|
264
|
+
token = dataView.getUint32(position) * 0x100000000;
|
|
265
|
+
token += dataView.getUint32(position + 4);
|
|
266
|
+
} else
|
|
267
|
+
token = dataView.getBigUint64(position);
|
|
190
268
|
position += 8;
|
|
191
269
|
break
|
|
192
270
|
case 0x1f:
|
|
@@ -194,6 +272,7 @@ function read() {
|
|
|
194
272
|
switch(majorType) {
|
|
195
273
|
case 2: // byte string
|
|
196
274
|
case 3: // text string
|
|
275
|
+
throw new Error('Indefinite length not supported for byte or text strings')
|
|
197
276
|
case 4: // array
|
|
198
277
|
let array = [];
|
|
199
278
|
let value, i = 0;
|
|
@@ -205,8 +284,8 @@ function read() {
|
|
|
205
284
|
let key;
|
|
206
285
|
if (currentDecoder.mapsAsObjects) {
|
|
207
286
|
let object = {};
|
|
208
|
-
|
|
209
|
-
|
|
287
|
+
if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) object[currentDecoder.decodeKey(key)] = read();
|
|
288
|
+
else while ((key = read()) != STOP_CODE) object[key] = read();
|
|
210
289
|
return object
|
|
211
290
|
} else {
|
|
212
291
|
if (restoreMapsAsObject) {
|
|
@@ -214,8 +293,8 @@ function read() {
|
|
|
214
293
|
restoreMapsAsObject = false;
|
|
215
294
|
}
|
|
216
295
|
let map = new Map();
|
|
217
|
-
|
|
218
|
-
|
|
296
|
+
if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) map.set(currentDecoder.decodeKey(key), read());
|
|
297
|
+
else while ((key = read()) != STOP_CODE) map.set(key, read());
|
|
219
298
|
return map
|
|
220
299
|
}
|
|
221
300
|
case 7:
|
|
@@ -247,16 +326,15 @@ function read() {
|
|
|
247
326
|
return readFixedString(token)
|
|
248
327
|
case 4: // array
|
|
249
328
|
let array = new Array(token);
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
329
|
+
//if (currentDecoder.keyMap) for (let i = 0; i < token; i++) array[i] = currentDecoder.decodeKey(read())
|
|
330
|
+
//else
|
|
331
|
+
for (let i = 0; i < token; i++) array[i] = read();
|
|
253
332
|
return array
|
|
254
333
|
case 5: // map
|
|
255
334
|
if (currentDecoder.mapsAsObjects) {
|
|
256
335
|
let object = {};
|
|
257
|
-
for (let i = 0; i < token; i++)
|
|
258
|
-
|
|
259
|
-
}
|
|
336
|
+
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[currentDecoder.decodeKey(read())] = read();
|
|
337
|
+
else for (let i = 0; i < token; i++) object[read()] = read();
|
|
260
338
|
return object
|
|
261
339
|
} else {
|
|
262
340
|
if (restoreMapsAsObject) {
|
|
@@ -264,63 +342,66 @@ function read() {
|
|
|
264
342
|
restoreMapsAsObject = false;
|
|
265
343
|
}
|
|
266
344
|
let map = new Map();
|
|
267
|
-
for (let i = 0; i < token; i++)
|
|
268
|
-
|
|
269
|
-
}
|
|
345
|
+
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) map.set(currentDecoder.decodeKey(read()),read());
|
|
346
|
+
else for (let i = 0; i < token; i++) map.set(read(), read());
|
|
270
347
|
return map
|
|
271
348
|
}
|
|
272
349
|
case 6: // extension
|
|
273
|
-
if (
|
|
274
|
-
let structure = currentStructures[token &
|
|
350
|
+
if (token >= BUNDLED_STRINGS_ID) {
|
|
351
|
+
let structure = currentStructures[token & 0x1fff]; // check record structures first
|
|
352
|
+
// 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))
|
|
275
353
|
if (structure) {
|
|
276
|
-
if (!structure.read)
|
|
277
|
-
structure.read = createStructureReader(structure);
|
|
354
|
+
if (!structure.read) structure.read = createStructureReader(structure);
|
|
278
355
|
return structure.read()
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
if (
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
if (extension.handlesRead)
|
|
302
|
-
return extension(read)
|
|
303
|
-
else
|
|
304
|
-
return extension(read())
|
|
305
|
-
} else {
|
|
306
|
-
let input = read();
|
|
307
|
-
for (let i = 0; i < currentExtensionRanges.length; i++) {
|
|
308
|
-
let value = currentExtensionRanges[i](token, input);
|
|
309
|
-
if (value !== undefined)
|
|
310
|
-
return value
|
|
356
|
+
}
|
|
357
|
+
if (token < 0x10000) {
|
|
358
|
+
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)
|
|
359
|
+
return recordDefinition(read())
|
|
360
|
+
else if (token == RECORD_DEFINITIONS_ID) {
|
|
361
|
+
let length = readJustLength();
|
|
362
|
+
let id = read();
|
|
363
|
+
for (let i = 2; i < length; i++) {
|
|
364
|
+
recordDefinition([id++, read()]);
|
|
365
|
+
}
|
|
366
|
+
return read()
|
|
367
|
+
} else if (token == BUNDLED_STRINGS_ID) {
|
|
368
|
+
return readBundleExt()
|
|
369
|
+
}
|
|
370
|
+
if (currentDecoder.getShared) {
|
|
371
|
+
loadShared();
|
|
372
|
+
structure = currentStructures[token & 0x1fff];
|
|
373
|
+
if (structure) {
|
|
374
|
+
if (!structure.read)
|
|
375
|
+
structure.read = createStructureReader(structure);
|
|
376
|
+
return structure.read()
|
|
377
|
+
}
|
|
311
378
|
}
|
|
312
|
-
return new Tag(input)
|
|
313
379
|
}
|
|
314
380
|
}
|
|
381
|
+
let extension = currentExtensions[token];
|
|
382
|
+
if (extension) {
|
|
383
|
+
if (extension.handlesRead)
|
|
384
|
+
return extension(read)
|
|
385
|
+
else
|
|
386
|
+
return extension(read())
|
|
387
|
+
} else {
|
|
388
|
+
let input = read();
|
|
389
|
+
for (let i = 0; i < currentExtensionRanges.length; i++) {
|
|
390
|
+
let value = currentExtensionRanges[i](token, input);
|
|
391
|
+
if (value !== undefined)
|
|
392
|
+
return value
|
|
393
|
+
}
|
|
394
|
+
return new Tag(input, token)
|
|
395
|
+
}
|
|
315
396
|
case 7: // fixed value
|
|
316
397
|
switch (token) {
|
|
317
398
|
case 0x14: return false
|
|
318
399
|
case 0x15: return true
|
|
319
400
|
case 0x16: return null
|
|
320
401
|
case 0x17: return; // undefined
|
|
321
|
-
case 0x1f:
|
|
402
|
+
case 0x1f:
|
|
322
403
|
default:
|
|
323
|
-
let packedValue = packedValues[token];
|
|
404
|
+
let packedValue = (packedValues || getPackedValues())[token];
|
|
324
405
|
if (packedValue !== undefined)
|
|
325
406
|
return packedValue
|
|
326
407
|
throw new Error('Unknown token ' + token)
|
|
@@ -336,49 +417,68 @@ function read() {
|
|
|
336
417
|
}
|
|
337
418
|
const validName = /^[a-zA-Z_$][a-zA-Z\d_$]*$/;
|
|
338
419
|
function createStructureReader(structure) {
|
|
339
|
-
let l = structure.length;
|
|
340
420
|
function readObject() {
|
|
421
|
+
// get the array size from the header
|
|
422
|
+
let length = src[position++];
|
|
423
|
+
//let majorType = token >> 5
|
|
424
|
+
length = length & 0x1f;
|
|
425
|
+
if (length > 0x17) {
|
|
426
|
+
switch (length) {
|
|
427
|
+
case 0x18:
|
|
428
|
+
length = src[position++];
|
|
429
|
+
break
|
|
430
|
+
case 0x19:
|
|
431
|
+
length = dataView.getUint16(position);
|
|
432
|
+
position += 2;
|
|
433
|
+
break
|
|
434
|
+
case 0x1a:
|
|
435
|
+
length = dataView.getUint32(position);
|
|
436
|
+
position += 4;
|
|
437
|
+
break
|
|
438
|
+
default:
|
|
439
|
+
throw new Error('Expected array header, but got ' + src[position - 1])
|
|
440
|
+
}
|
|
441
|
+
}
|
|
341
442
|
// This initial function is quick to instantiate, but runs slower. After several iterations pay the cost to build the faster function
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
443
|
+
let compiledReader = this.compiledReader; // first look to see if we have the fast compiled function
|
|
444
|
+
while(compiledReader) {
|
|
445
|
+
// we have a fast compiled object literal reader
|
|
446
|
+
if (compiledReader.propertyCount === length)
|
|
447
|
+
return compiledReader(read) // with the right length, so we use it
|
|
448
|
+
compiledReader = compiledReader.next; // see if there is another reader with the right length
|
|
345
449
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
450
|
+
if (this.slowReads++ >= 3) { // create a fast compiled reader
|
|
451
|
+
let array = this.length == length ? this : this.slice(0, length);
|
|
452
|
+
compiledReader = currentDecoder.keyMap
|
|
453
|
+
? new Function('r', 'return {' + array.map(k => currentDecoder.decodeKey(k)).map(k => validName.test(k) ? k + ':r()' : ('[' + JSON.stringify(k) + ']:r()')).join(',') + '}')
|
|
454
|
+
: new Function('r', 'return {' + array.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}');
|
|
455
|
+
if (this.compiledReader)
|
|
456
|
+
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
|
|
457
|
+
compiledReader.propertyCount = length;
|
|
458
|
+
this.compiledReader = compiledReader;
|
|
459
|
+
return compiledReader(read)
|
|
351
460
|
}
|
|
461
|
+
let object = {};
|
|
462
|
+
if (currentDecoder.keyMap) for (let i = 0; i < length; i++) object[currentDecoder.decodeKey(this[i])] = read();
|
|
463
|
+
else for (let i = 0; i < length; i++) object[this[i]] = read();
|
|
352
464
|
return object
|
|
353
465
|
}
|
|
354
|
-
|
|
466
|
+
structure.slowReads = 0;
|
|
355
467
|
return readObject
|
|
356
468
|
}
|
|
357
469
|
|
|
358
|
-
function readArrayHeader(expectedLength) {
|
|
359
|
-
// consume the array header, TODO: check expected length
|
|
360
|
-
let token = src[position++];
|
|
361
|
-
//let majorType = token >> 5
|
|
362
|
-
token = token & 0x1f;
|
|
363
|
-
if (token > 0x17) {
|
|
364
|
-
switch (token) {
|
|
365
|
-
case 0x18: position++;
|
|
366
|
-
break
|
|
367
|
-
case 0x19: position += 2;
|
|
368
|
-
break
|
|
369
|
-
case 0x1a: position += 4;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
470
|
let readFixedString = readStringJS;
|
|
375
471
|
|
|
472
|
+
exports.isNativeAccelerationEnabled = false;
|
|
376
473
|
function setExtractor(extractStrings) {
|
|
474
|
+
exports.isNativeAccelerationEnabled = true;
|
|
377
475
|
readFixedString = readString();
|
|
378
476
|
function readString(headerLength) {
|
|
379
477
|
return function readString(length) {
|
|
380
478
|
let string = strings[stringPosition++];
|
|
381
479
|
if (string == null) {
|
|
480
|
+
if (bundledStrings)
|
|
481
|
+
return readStringJS(length)
|
|
382
482
|
let extraction = extractStrings(position, srcEnd, length, src);
|
|
383
483
|
if (typeof extraction == 'string') {
|
|
384
484
|
string = extraction;
|
|
@@ -633,76 +733,15 @@ function getFloat16() {
|
|
|
633
733
|
}
|
|
634
734
|
|
|
635
735
|
let keyCache = new Array(4096);
|
|
636
|
-
function readKey() {
|
|
637
|
-
let length = src[position++];
|
|
638
|
-
if (length >= 0x60 && length < 0x78) {
|
|
639
|
-
// fixstr, potentially use key cache
|
|
640
|
-
length = length - 0x60;
|
|
641
|
-
if (srcStringEnd >= position) // if it has been extracted, must use it (and faster anyway)
|
|
642
|
-
return srcString.slice(position - srcStringStart, (position += length) - srcStringStart)
|
|
643
|
-
else if (!(srcStringEnd == 0 && srcEnd < 180))
|
|
644
|
-
return readFixedString(length)
|
|
645
|
-
} else { // not cacheable, go back and do a standard read
|
|
646
|
-
position--;
|
|
647
|
-
return read()
|
|
648
|
-
}
|
|
649
|
-
let key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position) : length > 0 ? src[position] : 0)) & 0xfff;
|
|
650
|
-
let entry = keyCache[key];
|
|
651
|
-
let checkPosition = position;
|
|
652
|
-
let end = position + length - 3;
|
|
653
|
-
let chunk;
|
|
654
|
-
let i = 0;
|
|
655
|
-
if (entry && entry.bytes == length) {
|
|
656
|
-
while (checkPosition < end) {
|
|
657
|
-
chunk = dataView.getUint32(checkPosition);
|
|
658
|
-
if (chunk != entry[i++]) {
|
|
659
|
-
checkPosition = 0x70000000;
|
|
660
|
-
break
|
|
661
|
-
}
|
|
662
|
-
checkPosition += 4;
|
|
663
|
-
}
|
|
664
|
-
end += 3;
|
|
665
|
-
while (checkPosition < end) {
|
|
666
|
-
chunk = src[checkPosition++];
|
|
667
|
-
if (chunk != entry[i++]) {
|
|
668
|
-
checkPosition = 0x70000000;
|
|
669
|
-
break
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
if (checkPosition === end) {
|
|
673
|
-
position = checkPosition;
|
|
674
|
-
return entry.string
|
|
675
|
-
}
|
|
676
|
-
end -= 3;
|
|
677
|
-
checkPosition = position;
|
|
678
|
-
}
|
|
679
|
-
entry = [];
|
|
680
|
-
keyCache[key] = entry;
|
|
681
|
-
entry.bytes = length;
|
|
682
|
-
while (checkPosition < end) {
|
|
683
|
-
chunk = dataView.getUint32(checkPosition);
|
|
684
|
-
entry.push(chunk);
|
|
685
|
-
checkPosition += 4;
|
|
686
|
-
}
|
|
687
|
-
end += 3;
|
|
688
|
-
while (checkPosition < end) {
|
|
689
|
-
chunk = src[checkPosition++];
|
|
690
|
-
entry.push(chunk);
|
|
691
|
-
}
|
|
692
|
-
// for small blocks, avoiding the overhead of the extract call is helpful
|
|
693
|
-
let string = length < 16 ? shortStringInJS(length) : longStringInJS(length);
|
|
694
|
-
if (string != null)
|
|
695
|
-
return entry.string = string
|
|
696
|
-
return entry.string = readFixedString(length)
|
|
697
|
-
}
|
|
698
736
|
|
|
699
737
|
class Tag {
|
|
700
|
-
constructor(value) {
|
|
738
|
+
constructor(value, tag) {
|
|
701
739
|
this.value = value;
|
|
740
|
+
this.tag = tag;
|
|
702
741
|
}
|
|
703
742
|
}
|
|
704
743
|
|
|
705
|
-
let glbl = typeof
|
|
744
|
+
let glbl = typeof self == 'object' ? self : global;
|
|
706
745
|
|
|
707
746
|
currentExtensions[0] = (dateString) => {
|
|
708
747
|
// string date extension
|
|
@@ -716,38 +755,67 @@ currentExtensions[1] = (epochSec) => {
|
|
|
716
755
|
|
|
717
756
|
currentExtensions[2] = (buffer) => {
|
|
718
757
|
// bigint extension
|
|
719
|
-
|
|
758
|
+
let value = BigInt(0);
|
|
759
|
+
for (let i = 0, l = buffer.byteLength; i < l; i++) {
|
|
760
|
+
value = BigInt(buffer[i]) + value << BigInt(8);
|
|
761
|
+
}
|
|
762
|
+
return value
|
|
720
763
|
};
|
|
721
764
|
|
|
722
765
|
currentExtensions[3] = (buffer) => {
|
|
723
766
|
// negative bigint extension
|
|
724
|
-
return BigInt(-1) - (
|
|
767
|
+
return BigInt(-1) - currentExtensions[2](buffer)
|
|
768
|
+
};
|
|
769
|
+
currentExtensions[4] = (fraction) => {
|
|
770
|
+
// best to reparse to maintain accuracy
|
|
771
|
+
return +(fraction[1] + 'e' + fraction[0])
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
currentExtensions[5] = (fraction) => {
|
|
775
|
+
// probably not sufficiently accurate
|
|
776
|
+
return fraction[1] * Math.exp(fraction[0] * Math.log(2))
|
|
725
777
|
};
|
|
726
778
|
|
|
727
|
-
// the registration of the record definition extension
|
|
728
|
-
const recordDefinition = () => {
|
|
729
|
-
let
|
|
730
|
-
let structure = definition[
|
|
731
|
-
let
|
|
732
|
-
|
|
779
|
+
// the registration of the record definition extension
|
|
780
|
+
const recordDefinition = (definition) => {
|
|
781
|
+
let id = definition[0] - 0xe000;
|
|
782
|
+
let structure = definition[1];
|
|
783
|
+
let existingStructure = currentStructures[id];
|
|
784
|
+
if (existingStructure && existingStructure.isShared) {
|
|
785
|
+
(currentStructures.restoreStructures || (currentStructures.restoreStructures = []))[id] = existingStructure;
|
|
786
|
+
}
|
|
787
|
+
currentStructures[id] = structure;
|
|
788
|
+
|
|
733
789
|
structure.read = createStructureReader(structure);
|
|
734
790
|
let object = {};
|
|
735
|
-
for (let i = 2,l = definition.length; i < l; i++) {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
791
|
+
if (currentDecoder.keyMap) for (let i = 2,l = definition.length; i < l; i++) {
|
|
792
|
+
let key = currentDecoder.decodeKey(structure[i - 2]);
|
|
793
|
+
object[key] = definition[i];
|
|
794
|
+
}
|
|
795
|
+
else for (let i = 2,l = definition.length; i < l; i++) {
|
|
796
|
+
let key = structure[i - 2];
|
|
797
|
+
object[key] = definition[i];
|
|
798
|
+
}
|
|
739
799
|
return object
|
|
740
800
|
};
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
801
|
+
currentExtensions[LEGACY_RECORD_INLINE_ID] = recordDefinition;
|
|
802
|
+
currentExtensions[14] = (value) => {
|
|
803
|
+
if (bundledStrings)
|
|
804
|
+
return bundledStrings[0].slice(bundledStrings.position0, bundledStrings.position0 += value)
|
|
805
|
+
return new Tag(value, 14)
|
|
806
|
+
};
|
|
807
|
+
currentExtensions[15] = (value) => {
|
|
808
|
+
if (bundledStrings)
|
|
809
|
+
return bundledStrings[1].slice(bundledStrings.position1, bundledStrings.position1 += value)
|
|
810
|
+
return new Tag(value, 15)
|
|
811
|
+
};
|
|
744
812
|
|
|
745
813
|
currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
|
|
746
814
|
return (glbl[data[0]] || Error)(data[1], data[2])
|
|
747
815
|
};
|
|
748
816
|
const packedTable = (read) => {
|
|
749
817
|
if (src[position++] != 0x84)
|
|
750
|
-
throw new Error('Packed values structure must be followed by 4 element array')
|
|
818
|
+
throw new Error('Packed values structure must be followed by a 4 element array')
|
|
751
819
|
let newPackedValues = read(); // packed values
|
|
752
820
|
packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
|
|
753
821
|
packedValues.prefixes = read();
|
|
@@ -758,15 +826,36 @@ packedTable.handlesRead = true;
|
|
|
758
826
|
currentExtensions[51] = packedTable;
|
|
759
827
|
|
|
760
828
|
currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
|
|
829
|
+
if (!packedValues) {
|
|
830
|
+
if (currentDecoder.getShared)
|
|
831
|
+
loadShared();
|
|
832
|
+
else
|
|
833
|
+
return new Tag(data, PACKED_REFERENCE_TAG_ID)
|
|
834
|
+
}
|
|
761
835
|
if (typeof data == 'number')
|
|
762
836
|
return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
|
|
763
837
|
throw new Error('No support for non-integer packed references yet')
|
|
764
838
|
};
|
|
839
|
+
currentExtensions[25] = (id) => {
|
|
840
|
+
return stringRefs[id]
|
|
841
|
+
};
|
|
842
|
+
currentExtensions[256] = (read) => {
|
|
843
|
+
stringRefs = [];
|
|
844
|
+
try {
|
|
845
|
+
return read()
|
|
846
|
+
} finally {
|
|
847
|
+
stringRefs = null;
|
|
848
|
+
}
|
|
849
|
+
};
|
|
850
|
+
currentExtensions[256].handlesRead = true;
|
|
765
851
|
|
|
766
|
-
currentExtensions[
|
|
767
|
-
//
|
|
768
|
-
if (!referenceMap)
|
|
852
|
+
currentExtensions[28] = (read) => {
|
|
853
|
+
// shareable http://cbor.schmorp.de/value-sharing (for structured clones)
|
|
854
|
+
if (!referenceMap) {
|
|
769
855
|
referenceMap = new Map();
|
|
856
|
+
referenceMap.id = 0;
|
|
857
|
+
}
|
|
858
|
+
let id = referenceMap.id++;
|
|
770
859
|
let token = src[position];
|
|
771
860
|
let target;
|
|
772
861
|
// TODO: handle Maps, Sets, and other types that can cycle; this is complicated, because you potentially need to read
|
|
@@ -784,9 +873,10 @@ currentExtensions[40009] = (id) => {
|
|
|
784
873
|
refEntry.target = targetProperties; // the placeholder wasn't used, replace with the deserialized one
|
|
785
874
|
return targetProperties // no cycle, can just use the returned read object
|
|
786
875
|
};
|
|
876
|
+
currentExtensions[28].handlesRead = true;
|
|
787
877
|
|
|
788
|
-
currentExtensions[
|
|
789
|
-
//
|
|
878
|
+
currentExtensions[29] = (id) => {
|
|
879
|
+
// sharedref http://cbor.schmorp.de/value-sharing (for structured clones)
|
|
790
880
|
let refEntry = referenceMap.get(id);
|
|
791
881
|
refEntry.used = true;
|
|
792
882
|
return refEntry.target
|
|
@@ -809,19 +899,38 @@ function combine(a, b) {
|
|
|
809
899
|
return a.concat(b)
|
|
810
900
|
return Object.assign({}, a, b)
|
|
811
901
|
}
|
|
902
|
+
function getPackedValues() {
|
|
903
|
+
if (!packedValues) {
|
|
904
|
+
if (currentDecoder.getShared)
|
|
905
|
+
loadShared();
|
|
906
|
+
else
|
|
907
|
+
throw new Error('No packed values available')
|
|
908
|
+
}
|
|
909
|
+
return packedValues
|
|
910
|
+
}
|
|
911
|
+
const SHARED_DATA_TAG_ID = 0x53687264; // ascii 'Shrd'
|
|
812
912
|
currentExtensionRanges.push((tag, input) => {
|
|
813
913
|
if (tag >= 225 && tag <= 255)
|
|
814
|
-
return combine(
|
|
914
|
+
return combine(getPackedValues().prefixes[tag - 224], input)
|
|
815
915
|
if (tag >= 28704 && tag <= 32767)
|
|
816
|
-
return combine(
|
|
916
|
+
return combine(getPackedValues().prefixes[tag - 28672], input)
|
|
817
917
|
if (tag >= 1879052288 && tag <= 2147483647)
|
|
818
|
-
return combine(
|
|
918
|
+
return combine(getPackedValues().prefixes[tag - 1879048192], input)
|
|
819
919
|
if (tag >= 216 && tag <= 223)
|
|
820
|
-
return combine(input,
|
|
920
|
+
return combine(input, getPackedValues().suffixes[tag - 216])
|
|
821
921
|
if (tag >= 27647 && tag <= 28671)
|
|
822
|
-
return combine(input,
|
|
922
|
+
return combine(input, getPackedValues().suffixes[tag - 27639])
|
|
823
923
|
if (tag >= 1811940352 && tag <= 1879048191)
|
|
824
|
-
return combine(input,
|
|
924
|
+
return combine(input, getPackedValues().suffixes[tag - 1811939328])
|
|
925
|
+
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)
|
|
926
|
+
return {
|
|
927
|
+
packedValues: packedValues,
|
|
928
|
+
structures: currentStructures.slice(0),
|
|
929
|
+
version: input,
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
if (tag == 55799) // self-descriptive CBOR tag, just return input value
|
|
933
|
+
return input
|
|
825
934
|
});
|
|
826
935
|
|
|
827
936
|
const typedArrays = ['Uint8', 'Uint8Clamped', 'Uint16', 'Uint32', 'BigUint64','Int8', 'Int16', 'Int32', 'BigInt64', 'Float32', 'Float64'].map(type => type + 'Array');
|
|
@@ -838,6 +947,61 @@ function registerTypedArray(typedArrayName, tag) {
|
|
|
838
947
|
};
|
|
839
948
|
}
|
|
840
949
|
|
|
950
|
+
function readBundleExt() {
|
|
951
|
+
let length = readJustLength();
|
|
952
|
+
let bundlePosition = position + read();
|
|
953
|
+
for (let i = 2; i < length; i++) {
|
|
954
|
+
// skip past bundles that were already read
|
|
955
|
+
let bundleLength = readJustLength(); // this will increment position, so must add to position afterwards
|
|
956
|
+
position += bundleLength;
|
|
957
|
+
}
|
|
958
|
+
let dataPosition = position;
|
|
959
|
+
position = bundlePosition;
|
|
960
|
+
bundledStrings = [readStringJS(readJustLength()), readStringJS(readJustLength())];
|
|
961
|
+
bundledStrings.position0 = 0;
|
|
962
|
+
bundledStrings.position1 = 0;
|
|
963
|
+
bundledStrings.postBundlePosition = position;
|
|
964
|
+
position = dataPosition;
|
|
965
|
+
return read()
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
function readJustLength() {
|
|
969
|
+
let token = src[position++] & 0x1f;
|
|
970
|
+
if (token > 0x17) {
|
|
971
|
+
switch (token) {
|
|
972
|
+
case 0x18:
|
|
973
|
+
token = src[position++];
|
|
974
|
+
break
|
|
975
|
+
case 0x19:
|
|
976
|
+
token = dataView.getUint16(position);
|
|
977
|
+
position += 2;
|
|
978
|
+
break
|
|
979
|
+
case 0x1a:
|
|
980
|
+
token = dataView.getUint32(position);
|
|
981
|
+
position += 4;
|
|
982
|
+
break
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
return token
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
function loadShared() {
|
|
989
|
+
if (currentDecoder.getShared) {
|
|
990
|
+
let sharedData = saveState(() => {
|
|
991
|
+
// save the state in case getShared modifies our buffer
|
|
992
|
+
src = null;
|
|
993
|
+
return currentDecoder.getShared()
|
|
994
|
+
}) || {};
|
|
995
|
+
let updatedStructures = sharedData.structures || [];
|
|
996
|
+
currentDecoder.sharedVersion = sharedData.version;
|
|
997
|
+
packedValues = currentDecoder.sharedValues = sharedData.packedValues;
|
|
998
|
+
if (currentStructures === true)
|
|
999
|
+
currentDecoder.structures = currentStructures = updatedStructures;
|
|
1000
|
+
else
|
|
1001
|
+
currentStructures.splice.apply(currentStructures, [0, updatedStructures.length].concat(updatedStructures));
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
841
1005
|
function saveState(callback) {
|
|
842
1006
|
let savedSrcEnd = srcEnd;
|
|
843
1007
|
let savedPosition = position;
|
|
@@ -847,6 +1011,8 @@ function saveState(callback) {
|
|
|
847
1011
|
let savedSrcString = srcString;
|
|
848
1012
|
let savedStrings = strings;
|
|
849
1013
|
let savedReferenceMap = referenceMap;
|
|
1014
|
+
let savedBundledStrings = bundledStrings;
|
|
1015
|
+
|
|
850
1016
|
// TODO: We may need to revisit this if we do more external calls to user code (since it could be slow)
|
|
851
1017
|
let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
|
|
852
1018
|
let savedStructures = currentStructures;
|
|
@@ -861,6 +1027,7 @@ function saveState(callback) {
|
|
|
861
1027
|
srcString = savedSrcString;
|
|
862
1028
|
strings = savedStrings;
|
|
863
1029
|
referenceMap = savedReferenceMap;
|
|
1030
|
+
bundledStrings = savedBundledStrings;
|
|
864
1031
|
src = savedSrc;
|
|
865
1032
|
sequentialMode = savedSequentialMode;
|
|
866
1033
|
currentStructures = savedStructures;
|
|
@@ -907,13 +1074,15 @@ let extensions, extensionClasses;
|
|
|
907
1074
|
const hasNodeBuffer = typeof Buffer !== 'undefined';
|
|
908
1075
|
const ByteArrayAllocate = hasNodeBuffer ? Buffer.allocUnsafeSlow : Uint8Array;
|
|
909
1076
|
const ByteArray = hasNodeBuffer ? Buffer : Uint8Array;
|
|
910
|
-
const RECORD_STARTING_ID_PREFIX = 0x69; // tag 105/0x69
|
|
911
1077
|
const MAX_STRUCTURES = 0x100;
|
|
912
1078
|
const MAX_BUFFER_SIZE = hasNodeBuffer ? 0x100000000 : 0x7fd00000;
|
|
913
1079
|
let target;
|
|
914
1080
|
let targetView;
|
|
915
1081
|
let position$1 = 0;
|
|
916
1082
|
let safeEnd;
|
|
1083
|
+
let bundledStrings$1 = null;
|
|
1084
|
+
const MAX_BUNDLE_SIZE = 0xf000;
|
|
1085
|
+
const hasNonLatin = /[\u0080-\uFFFF]/;
|
|
917
1086
|
const RECORD_SYMBOL = Symbol('record-id');
|
|
918
1087
|
class Encoder extends Decoder {
|
|
919
1088
|
constructor(options) {
|
|
@@ -925,7 +1094,6 @@ class Encoder extends Decoder {
|
|
|
925
1094
|
let structures;
|
|
926
1095
|
let referenceMap;
|
|
927
1096
|
options = options || {};
|
|
928
|
-
let lastSharedStructuresLength = 0;
|
|
929
1097
|
let encodeUtf8 = ByteArray.prototype.utf8Write ? function(string, position, maxBytes) {
|
|
930
1098
|
return target.utf8Write(string, position, maxBytes)
|
|
931
1099
|
} : (textEncoder && textEncoder.encodeInto) ?
|
|
@@ -934,12 +1102,20 @@ class Encoder extends Decoder {
|
|
|
934
1102
|
} : false;
|
|
935
1103
|
|
|
936
1104
|
let encoder = this;
|
|
937
|
-
let
|
|
1105
|
+
let hasSharedStructures = options.structures || options.saveStructures;
|
|
1106
|
+
let maxSharedStructures = options.maxSharedStructures;
|
|
1107
|
+
if (maxSharedStructures == null)
|
|
1108
|
+
maxSharedStructures = hasSharedStructures ? 128 : 0;
|
|
1109
|
+
if (maxSharedStructures > 8190)
|
|
1110
|
+
throw new Error('Maximum maxSharedStructure is 8190')
|
|
938
1111
|
let isSequential = options.sequential;
|
|
939
1112
|
if (isSequential) {
|
|
940
1113
|
maxSharedStructures = 0;
|
|
941
|
-
this.structures = [];
|
|
942
1114
|
}
|
|
1115
|
+
if (!this.structures)
|
|
1116
|
+
this.structures = [];
|
|
1117
|
+
if (this.saveStructures)
|
|
1118
|
+
this.saveShared = this.saveStructures;
|
|
943
1119
|
let samplingPackedValues, packedObjectMap, sharedValues = options.sharedValues;
|
|
944
1120
|
let sharedPackedObjectMap;
|
|
945
1121
|
if (sharedValues) {
|
|
@@ -947,13 +1123,29 @@ class Encoder extends Decoder {
|
|
|
947
1123
|
for (let i = 0, l = sharedValues.length; i < l; i++) {
|
|
948
1124
|
sharedPackedObjectMap[sharedValues[i]] = i;
|
|
949
1125
|
}
|
|
950
|
-
|
|
951
1126
|
}
|
|
952
1127
|
let recordIdsToRemove = [];
|
|
953
1128
|
let transitionsCount = 0;
|
|
954
1129
|
let serializationsSinceTransitionRebuild = 0;
|
|
955
|
-
|
|
956
|
-
this.
|
|
1130
|
+
|
|
1131
|
+
this.mapEncode = function(value, encodeOptions) {
|
|
1132
|
+
// Experimental support for premapping keys using _keyMap instad of keyMap - not optiimised yet)
|
|
1133
|
+
if (this._keyMap && !this._mapped) {
|
|
1134
|
+
//console.log('encoding ', value)
|
|
1135
|
+
switch (value.constructor.name) {
|
|
1136
|
+
case 'Array':
|
|
1137
|
+
value = value.map(r => this.encodeKeys(r));
|
|
1138
|
+
break
|
|
1139
|
+
//case 'Map':
|
|
1140
|
+
// value = this.encodeKeys(value)
|
|
1141
|
+
// break
|
|
1142
|
+
}
|
|
1143
|
+
//this._mapped = true
|
|
1144
|
+
}
|
|
1145
|
+
return this.encode(value, encodeOptions)
|
|
1146
|
+
};
|
|
1147
|
+
|
|
1148
|
+
this.encode = function(value, encodeOptions) {
|
|
957
1149
|
if (!target) {
|
|
958
1150
|
target = new ByteArrayAllocate(8192);
|
|
959
1151
|
targetView = new DataView(target.buffer, 0, 8192);
|
|
@@ -969,11 +1161,30 @@ class Encoder extends Decoder {
|
|
|
969
1161
|
} else if (encodeOptions === REUSE_BUFFER_MODE)
|
|
970
1162
|
position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
|
|
971
1163
|
start = position$1;
|
|
1164
|
+
if (encoder.useSelfDescribedHeader) {
|
|
1165
|
+
targetView.setUint32(position$1, 0xd9d9f700); // tag two byte, then self-descriptive tag
|
|
1166
|
+
position$1 += 3;
|
|
1167
|
+
}
|
|
972
1168
|
referenceMap = encoder.structuredClone ? new Map() : null;
|
|
1169
|
+
if (encoder.bundleStrings && typeof value !== 'string') {
|
|
1170
|
+
bundledStrings$1 = [];
|
|
1171
|
+
bundledStrings$1.size = Infinity; // force a new bundle start on first string
|
|
1172
|
+
} else
|
|
1173
|
+
bundledStrings$1 = null;
|
|
1174
|
+
|
|
973
1175
|
sharedStructures = encoder.structures;
|
|
974
1176
|
if (sharedStructures) {
|
|
975
|
-
if (sharedStructures.uninitialized)
|
|
976
|
-
|
|
1177
|
+
if (sharedStructures.uninitialized) {
|
|
1178
|
+
let sharedData = encoder.getShared() || {};
|
|
1179
|
+
encoder.structures = sharedStructures = sharedData.structures || [];
|
|
1180
|
+
encoder.sharedVersion = sharedData.version;
|
|
1181
|
+
let sharedValues = encoder.sharedValues = sharedData.packedValues;
|
|
1182
|
+
if (sharedValues) {
|
|
1183
|
+
sharedPackedObjectMap = {};
|
|
1184
|
+
for (let i = 0, l = sharedValues.length; i < l; i++)
|
|
1185
|
+
sharedPackedObjectMap[sharedValues[i]] = i;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
977
1188
|
let sharedStructuresLength = sharedStructures.length;
|
|
978
1189
|
if (sharedStructuresLength > maxSharedStructures && !isSequential)
|
|
979
1190
|
sharedStructuresLength = maxSharedStructures;
|
|
@@ -982,10 +1193,13 @@ class Encoder extends Decoder {
|
|
|
982
1193
|
sharedStructures.transitions = Object.create(null);
|
|
983
1194
|
for (let i = 0; i < sharedStructuresLength; i++) {
|
|
984
1195
|
let keys = sharedStructures[i];
|
|
1196
|
+
//console.log('shared struct keys:', keys)
|
|
985
1197
|
if (!keys)
|
|
986
1198
|
continue
|
|
987
1199
|
let nextTransition, transition = sharedStructures.transitions;
|
|
988
1200
|
for (let j = 0, l = keys.length; j < l; j++) {
|
|
1201
|
+
if (transition[RECORD_SYMBOL] === undefined)
|
|
1202
|
+
transition[RECORD_SYMBOL] = i;
|
|
989
1203
|
let key = keys[j];
|
|
990
1204
|
nextTransition = transition[key];
|
|
991
1205
|
if (!nextTransition) {
|
|
@@ -993,9 +1207,8 @@ class Encoder extends Decoder {
|
|
|
993
1207
|
}
|
|
994
1208
|
transition = nextTransition;
|
|
995
1209
|
}
|
|
996
|
-
transition[RECORD_SYMBOL] = i;
|
|
1210
|
+
transition[RECORD_SYMBOL] = i | 0x100000;
|
|
997
1211
|
}
|
|
998
|
-
lastSharedStructuresLength = sharedStructures.length;
|
|
999
1212
|
}
|
|
1000
1213
|
if (!isSequential)
|
|
1001
1214
|
sharedStructures.nextId = sharedStructuresLength;
|
|
@@ -1028,9 +1241,12 @@ class Encoder extends Decoder {
|
|
|
1028
1241
|
}
|
|
1029
1242
|
try {
|
|
1030
1243
|
encode(value);
|
|
1244
|
+
if (bundledStrings$1) {
|
|
1245
|
+
writeBundles(start, encode);
|
|
1246
|
+
}
|
|
1031
1247
|
encoder.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|
|
1032
1248
|
if (referenceMap && referenceMap.idsToInsert) {
|
|
1033
|
-
position$1 += referenceMap.idsToInsert.length *
|
|
1249
|
+
position$1 += referenceMap.idsToInsert.length * 2;
|
|
1034
1250
|
if (position$1 > safeEnd)
|
|
1035
1251
|
makeRoom(position$1);
|
|
1036
1252
|
encoder.offset = position$1;
|
|
@@ -1038,16 +1254,18 @@ class Encoder extends Decoder {
|
|
|
1038
1254
|
referenceMap = null;
|
|
1039
1255
|
return serialized
|
|
1040
1256
|
}
|
|
1041
|
-
if (encodeOptions
|
|
1257
|
+
if (encodeOptions & REUSE_BUFFER_MODE) {
|
|
1042
1258
|
target.start = start;
|
|
1043
1259
|
target.end = position$1;
|
|
1044
1260
|
return target
|
|
1045
1261
|
}
|
|
1046
|
-
return target.subarray(start, position$1) // position can change if we call
|
|
1262
|
+
return target.subarray(start, position$1) // position can change if we call encode again in saveShared, so we get the buffer now
|
|
1047
1263
|
} finally {
|
|
1048
1264
|
if (sharedStructures) {
|
|
1049
1265
|
if (serializationsSinceTransitionRebuild < 10)
|
|
1050
1266
|
serializationsSinceTransitionRebuild++;
|
|
1267
|
+
if (sharedStructures.length > maxSharedStructures)
|
|
1268
|
+
sharedStructures.length = maxSharedStructures;
|
|
1051
1269
|
if (transitionsCount > 10000) {
|
|
1052
1270
|
// force a rebuild occasionally after a lot of transitions so it can get cleaned up
|
|
1053
1271
|
sharedStructures.transitions = null;
|
|
@@ -1060,35 +1278,29 @@ class Encoder extends Decoder {
|
|
|
1060
1278
|
recordIdsToRemove[i][RECORD_SYMBOL] = undefined;
|
|
1061
1279
|
}
|
|
1062
1280
|
recordIdsToRemove = [];
|
|
1281
|
+
//sharedStructures.nextId = maxSharedStructures
|
|
1063
1282
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
1069
|
-
let returnBuffer = target.subarray(start, position$1);
|
|
1070
|
-
let shared = encoder.structures || [];
|
|
1071
|
-
if (sharedValues) {
|
|
1072
|
-
shared = shared.concat(sharedValues);
|
|
1073
|
-
}
|
|
1074
|
-
|
|
1075
|
-
if (encoder.saveStructures(encoder.structures, lastSharedStructuresLength) === false) {
|
|
1076
|
-
// get updated structures and try again if the update failed
|
|
1077
|
-
encoder.structures = encoder.getStructures() || [];
|
|
1078
|
-
return encoder.encode(value)
|
|
1079
|
-
}
|
|
1080
|
-
lastSharedStructuresLength = shared.length;
|
|
1081
|
-
return returnBuffer
|
|
1283
|
+
}
|
|
1284
|
+
if (hasSharedUpdate && encoder.saveShared) {
|
|
1285
|
+
if (encoder.structures.length > maxSharedStructures) {
|
|
1286
|
+
encoder.structures = encoder.structures.slice(0, maxSharedStructures);
|
|
1082
1287
|
}
|
|
1288
|
+
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
1289
|
+
let returnBuffer = target.subarray(start, position$1);
|
|
1290
|
+
if (encoder.updateSharedData() === false)
|
|
1291
|
+
return encoder.encode(value) // re-encode if it fails
|
|
1292
|
+
return returnBuffer
|
|
1083
1293
|
}
|
|
1294
|
+
if (encodeOptions & RESET_BUFFER_MODE)
|
|
1295
|
+
position$1 = start;
|
|
1084
1296
|
}
|
|
1085
1297
|
};
|
|
1086
1298
|
this.findCommonStringsToPack = () => {
|
|
1087
1299
|
samplingPackedValues = new Map();
|
|
1088
1300
|
if (!sharedPackedObjectMap)
|
|
1089
1301
|
sharedPackedObjectMap = Object.create(null);
|
|
1090
|
-
return (
|
|
1091
|
-
threshold = threshold || 4;
|
|
1302
|
+
return (options) => {
|
|
1303
|
+
let threshold = options && options.threshold || 4;
|
|
1092
1304
|
let position = this.pack ? options.maxPrivatePackedValues || 16 : 0;
|
|
1093
1305
|
if (!sharedValues)
|
|
1094
1306
|
sharedValues = this.sharedValues = [];
|
|
@@ -1099,6 +1311,7 @@ class Encoder extends Decoder {
|
|
|
1099
1311
|
hasSharedUpdate = true;
|
|
1100
1312
|
}
|
|
1101
1313
|
}
|
|
1314
|
+
while (this.saveShared && this.updateSharedData() === false) {}
|
|
1102
1315
|
samplingPackedValues = null;
|
|
1103
1316
|
}
|
|
1104
1317
|
};
|
|
@@ -1147,6 +1360,33 @@ class Encoder extends Decoder {
|
|
|
1147
1360
|
}
|
|
1148
1361
|
}
|
|
1149
1362
|
let strLength = value.length;
|
|
1363
|
+
if (bundledStrings$1 && strLength >= 4 && strLength < 0x400) {
|
|
1364
|
+
if ((bundledStrings$1.size += strLength) > MAX_BUNDLE_SIZE) {
|
|
1365
|
+
let extStart;
|
|
1366
|
+
let maxBytes = (bundledStrings$1[0] ? bundledStrings$1[0].length * 3 + bundledStrings$1[1].length : 0) + 10;
|
|
1367
|
+
if (position$1 + maxBytes > safeEnd)
|
|
1368
|
+
target = makeRoom(position$1 + maxBytes);
|
|
1369
|
+
target[position$1++] = 0xd9; // tag 16-bit
|
|
1370
|
+
target[position$1++] = 0xdf; // tag 0xdff9
|
|
1371
|
+
target[position$1++] = 0xf9;
|
|
1372
|
+
// TODO: If we only have one bundle with any string data, only write one string bundle
|
|
1373
|
+
target[position$1++] = bundledStrings$1.position ? 0x84 : 0x82; // array of 4 or 2 elements depending on if we write bundles
|
|
1374
|
+
target[position$1++] = 0x1a; // 32-bit unsigned int
|
|
1375
|
+
extStart = position$1 - start;
|
|
1376
|
+
position$1 += 4; // reserve for writing bundle reference
|
|
1377
|
+
if (bundledStrings$1.position) {
|
|
1378
|
+
writeBundles(start, encode); // write the last bundles
|
|
1379
|
+
}
|
|
1380
|
+
bundledStrings$1 = ['', '']; // create new ones
|
|
1381
|
+
bundledStrings$1.size = 0;
|
|
1382
|
+
bundledStrings$1.position = extStart;
|
|
1383
|
+
}
|
|
1384
|
+
let twoByte = hasNonLatin.test(value);
|
|
1385
|
+
bundledStrings$1[twoByte ? 0 : 1] += value;
|
|
1386
|
+
target[position$1++] = twoByte ? 0xce : 0xcf;
|
|
1387
|
+
encode(strLength);
|
|
1388
|
+
return
|
|
1389
|
+
}
|
|
1150
1390
|
let headerSize;
|
|
1151
1391
|
// first we estimate the header size, so we can write to the correct location
|
|
1152
1392
|
if (strLength < 0x20) {
|
|
@@ -1273,16 +1513,16 @@ class Encoder extends Decoder {
|
|
|
1273
1513
|
if (referenceMap) {
|
|
1274
1514
|
let referee = referenceMap.get(value);
|
|
1275
1515
|
if (referee) {
|
|
1276
|
-
|
|
1516
|
+
target[position$1++] = 0xd8;
|
|
1517
|
+
target[position$1++] = 29; // http://cbor.schmorp.de/value-sharing
|
|
1518
|
+
target[position$1++] = 0x19; // 16-bit uint
|
|
1519
|
+
if (!referee.references) {
|
|
1277
1520
|
let idsToInsert = referenceMap.idsToInsert || (referenceMap.idsToInsert = []);
|
|
1278
|
-
referee.
|
|
1521
|
+
referee.references = [];
|
|
1522
|
+
idsToInsert.push(referee);
|
|
1279
1523
|
}
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
target[position$1++] = 40010 & 0xff;
|
|
1283
|
-
target[position$1++] = 0x1a; // uint32
|
|
1284
|
-
targetView.setUint32(position$1, referee.id);
|
|
1285
|
-
position$1 += 4;
|
|
1524
|
+
referee.references.push(position$1 - start);
|
|
1525
|
+
position$1 += 2; // TODO: also support 32-bit
|
|
1286
1526
|
return
|
|
1287
1527
|
} else
|
|
1288
1528
|
referenceMap.set(value, { offset: position$1 - start });
|
|
@@ -1322,16 +1562,23 @@ class Encoder extends Decoder {
|
|
|
1322
1562
|
targetView.setUint32(position$1, length);
|
|
1323
1563
|
position$1 += 4;
|
|
1324
1564
|
}
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1565
|
+
if (encoder.keyMap) {
|
|
1566
|
+
for (let [ key, entryValue ] of value) {
|
|
1567
|
+
encode(encoder.encodeKey(key));
|
|
1568
|
+
encode(entryValue);
|
|
1569
|
+
}
|
|
1570
|
+
} else {
|
|
1571
|
+
for (let [ key, entryValue ] of value) {
|
|
1572
|
+
encode(key);
|
|
1573
|
+
encode(entryValue);
|
|
1574
|
+
}
|
|
1328
1575
|
}
|
|
1329
|
-
} else {
|
|
1576
|
+
} else {
|
|
1330
1577
|
for (let i = 0, l = extensions.length; i < l; i++) {
|
|
1331
1578
|
let extensionClass = extensionClasses[i];
|
|
1332
1579
|
if (value instanceof extensionClass) {
|
|
1333
1580
|
let extension = extensions[i];
|
|
1334
|
-
let tag = extension.tag;
|
|
1581
|
+
let tag = extension.tag || extension.getTag && extension.getTag(value);
|
|
1335
1582
|
if (tag < 0x18) {
|
|
1336
1583
|
target[position$1++] = 0xc0 | tag;
|
|
1337
1584
|
} else if (tag < 0x100) {
|
|
@@ -1393,6 +1640,7 @@ class Encoder extends Decoder {
|
|
|
1393
1640
|
const writeObject = this.useRecords === false ? this.variableMapSize ? (object) => {
|
|
1394
1641
|
// this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects)
|
|
1395
1642
|
let keys = Object.keys(object);
|
|
1643
|
+
let vals = Object.values(object);
|
|
1396
1644
|
let length = keys.length;
|
|
1397
1645
|
if (length < 0x18) {
|
|
1398
1646
|
target[position$1++] = 0xa0 | length;
|
|
@@ -1408,10 +1656,16 @@ class Encoder extends Decoder {
|
|
|
1408
1656
|
targetView.setUint32(position$1, length);
|
|
1409
1657
|
position$1 += 4;
|
|
1410
1658
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1659
|
+
if (encoder.keyMap) {
|
|
1660
|
+
for (let i = 0; i < length; i++) {
|
|
1661
|
+
encode(encodeKey(keys[i]));
|
|
1662
|
+
encode(vals[i]);
|
|
1663
|
+
}
|
|
1664
|
+
} else {
|
|
1665
|
+
for (let i = 0; i < length; i++) {
|
|
1666
|
+
encode(keys[i]);
|
|
1667
|
+
encode(vals[i]);
|
|
1668
|
+
}
|
|
1415
1669
|
}
|
|
1416
1670
|
} :
|
|
1417
1671
|
(object, safePrototype) => {
|
|
@@ -1419,95 +1673,92 @@ class Encoder extends Decoder {
|
|
|
1419
1673
|
let objectOffset = position$1 - start;
|
|
1420
1674
|
position$1 += 2;
|
|
1421
1675
|
let size = 0;
|
|
1422
|
-
|
|
1423
|
-
if (safePrototype || object.hasOwnProperty(key)) {
|
|
1424
|
-
encode(key);
|
|
1676
|
+
if (encoder.keyMap) {
|
|
1677
|
+
for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
|
|
1678
|
+
encode(encoder.encodeKey(key));
|
|
1425
1679
|
encode(object[key]);
|
|
1426
1680
|
size++;
|
|
1427
1681
|
}
|
|
1682
|
+
} else {
|
|
1683
|
+
for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
|
|
1684
|
+
encode(key);
|
|
1685
|
+
encode(object[key]);
|
|
1686
|
+
size++;
|
|
1687
|
+
}
|
|
1428
1688
|
}
|
|
1429
1689
|
target[objectOffset++ + start] = size >> 8;
|
|
1430
1690
|
target[objectOffset + start] = size & 0xff;
|
|
1431
1691
|
} :
|
|
1432
|
-
|
|
1433
|
-
/* sharedStructures ? // For highly stable structures, using for-in can a little bit faster
|
|
1434
1692
|
(object, safePrototype) => {
|
|
1435
|
-
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null))
|
|
1436
|
-
let
|
|
1437
|
-
let
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1693
|
+
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
|
|
1694
|
+
let newTransitions = 0;
|
|
1695
|
+
let length = 0;
|
|
1696
|
+
let parentRecordId;
|
|
1697
|
+
let keys;
|
|
1698
|
+
if (this.keyMap) {
|
|
1699
|
+
keys = Object.keys(object).map(k => this.encodeKey(k));
|
|
1700
|
+
length = keys.length;
|
|
1701
|
+
for (let i = 0; i < length; i++) {
|
|
1702
|
+
let key = keys[i];
|
|
1703
|
+
nextTransition = transition[key];
|
|
1441
1704
|
if (!nextTransition) {
|
|
1442
|
-
nextTransition = transition[key] = Object.create(null)
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
nextTransition.__keys__ = keys.slice(0, i + 1)
|
|
1454
|
-
}
|
|
1705
|
+
nextTransition = transition[key] = Object.create(null);
|
|
1706
|
+
newTransitions++;
|
|
1707
|
+
}
|
|
1708
|
+
transition = nextTransition;
|
|
1709
|
+
}
|
|
1710
|
+
} else {
|
|
1711
|
+
for (let key in object) if (safePrototype || object.hasOwnProperty(key)) {
|
|
1712
|
+
nextTransition = transition[key];
|
|
1713
|
+
if (!nextTransition) {
|
|
1714
|
+
if (transition[RECORD_SYMBOL] & 0x100000) {// this indicates it is a brancheable/extendable terminal node, so we will use this record id and extend it
|
|
1715
|
+
parentRecordId = transition[RECORD_SYMBOL] & 0xffff;
|
|
1455
1716
|
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
target.copy(target, )
|
|
1459
|
-
objectOffset
|
|
1717
|
+
nextTransition = transition[key] = Object.create(null);
|
|
1718
|
+
newTransitions++;
|
|
1460
1719
|
}
|
|
1461
|
-
transition = nextTransition
|
|
1462
|
-
|
|
1463
|
-
}
|
|
1464
|
-
}
|
|
1465
|
-
let id = transition.id
|
|
1466
|
-
if (!id) {
|
|
1467
|
-
id = transition.id = structures.push(transition.__keys__) + 63
|
|
1468
|
-
if (sharedStructures.onUpdate)
|
|
1469
|
-
sharedStructures.onUpdate(id, transition.__keys__)
|
|
1470
|
-
}
|
|
1471
|
-
target[objectOffset + start] = id
|
|
1472
|
-
}*/
|
|
1473
|
-
(object) => {
|
|
1474
|
-
let keys = Object.keys(object);
|
|
1475
|
-
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
|
|
1476
|
-
let newTransitions = 0;
|
|
1477
|
-
let length = keys.length;
|
|
1478
|
-
for (let i = 0; i < length; i++) {
|
|
1479
|
-
let key = keys[i];
|
|
1480
|
-
nextTransition = transition[key];
|
|
1481
|
-
if (!nextTransition) {
|
|
1482
|
-
nextTransition = transition[key] = Object.create(null);
|
|
1483
|
-
newTransitions++;
|
|
1720
|
+
transition = nextTransition;
|
|
1721
|
+
length++;
|
|
1484
1722
|
}
|
|
1485
|
-
transition = nextTransition;
|
|
1486
1723
|
}
|
|
1487
1724
|
let recordId = transition[RECORD_SYMBOL];
|
|
1488
1725
|
if (recordId !== undefined) {
|
|
1489
|
-
|
|
1490
|
-
target[position$1++] =
|
|
1491
|
-
target[position$1++] = recordId;
|
|
1726
|
+
recordId &= 0xffff;
|
|
1727
|
+
target[position$1++] = 0xd9;
|
|
1728
|
+
target[position$1++] = (recordId >> 8) | 0xe0;
|
|
1729
|
+
target[position$1++] = recordId & 0xff;
|
|
1492
1730
|
} else {
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
structures.nextId
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1731
|
+
if (!keys)
|
|
1732
|
+
keys = transition.__keys__ || (transition.__keys__ = Object.keys(object));
|
|
1733
|
+
if (parentRecordId === undefined) {
|
|
1734
|
+
recordId = structures.nextId++;
|
|
1735
|
+
if (!recordId) {
|
|
1736
|
+
recordId = 0;
|
|
1737
|
+
structures.nextId = 1;
|
|
1738
|
+
}
|
|
1739
|
+
if (recordId >= MAX_STRUCTURES) {// cycle back around
|
|
1740
|
+
structures.nextId = (recordId = maxSharedStructures) + 1;
|
|
1741
|
+
}
|
|
1742
|
+
} else {
|
|
1743
|
+
recordId = parentRecordId;
|
|
1500
1744
|
}
|
|
1501
|
-
transition[RECORD_SYMBOL] = recordId;
|
|
1502
1745
|
structures[recordId] = keys;
|
|
1503
|
-
if (
|
|
1504
|
-
target[position$1++] = 0xd9;
|
|
1505
|
-
target[position$1++] =
|
|
1506
|
-
target[position$1++] = recordId
|
|
1746
|
+
if (recordId < maxSharedStructures) {
|
|
1747
|
+
target[position$1++] = 0xd9;
|
|
1748
|
+
target[position$1++] = (recordId >> 8) | 0xe0;
|
|
1749
|
+
target[position$1++] = recordId & 0xff;
|
|
1750
|
+
transition = structures.transitions;
|
|
1751
|
+
for (let i = 0; i < length; i++) {
|
|
1752
|
+
if (transition[RECORD_SYMBOL] === undefined || (transition[RECORD_SYMBOL] & 0x100000))
|
|
1753
|
+
transition[RECORD_SYMBOL] = recordId;
|
|
1754
|
+
transition = transition[keys[i]];
|
|
1755
|
+
}
|
|
1756
|
+
transition[RECORD_SYMBOL] = recordId | 0x100000; // indicates it is a extendable terminal
|
|
1507
1757
|
hasSharedUpdate = true;
|
|
1508
1758
|
} else {
|
|
1509
|
-
|
|
1510
|
-
|
|
1759
|
+
transition[RECORD_SYMBOL] = recordId;
|
|
1760
|
+
targetView.setUint32(position$1, 0xd9dfff00); // tag two byte, then record definition id
|
|
1761
|
+
position$1 += 3;
|
|
1511
1762
|
if (newTransitions)
|
|
1512
1763
|
transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
|
|
1513
1764
|
// record the removal of the id, we can maintain our shared structure
|
|
@@ -1515,13 +1766,9 @@ class Encoder extends Decoder {
|
|
|
1515
1766
|
recordIdsToRemove.shift()[RECORD_SYMBOL] = undefined; // we are cycling back through, and have to remove old ones
|
|
1516
1767
|
recordIdsToRemove.push(transition);
|
|
1517
1768
|
writeArrayHeader(length + 2);
|
|
1769
|
+
encode(0xe000 + recordId);
|
|
1518
1770
|
encode(keys);
|
|
1519
|
-
|
|
1520
|
-
target[position$1++] = RECORD_STARTING_ID_PREFIX;
|
|
1521
|
-
target[position$1++] = recordId;
|
|
1522
|
-
// now write the values
|
|
1523
|
-
for (let i =0; i < length; i++)
|
|
1524
|
-
encode(object[keys[i]]);
|
|
1771
|
+
for (let v of Object.values(object)) encode(v);
|
|
1525
1772
|
return
|
|
1526
1773
|
}
|
|
1527
1774
|
}
|
|
@@ -1530,8 +1777,9 @@ class Encoder extends Decoder {
|
|
|
1530
1777
|
} else {
|
|
1531
1778
|
writeArrayHeader(length);
|
|
1532
1779
|
}
|
|
1533
|
-
for (let
|
|
1534
|
-
|
|
1780
|
+
for (let key in object)
|
|
1781
|
+
if (safePrototype || object.hasOwnProperty(key))
|
|
1782
|
+
encode(object[key]);
|
|
1535
1783
|
};
|
|
1536
1784
|
const makeRoom = (end) => {
|
|
1537
1785
|
let newSize;
|
|
@@ -1540,7 +1788,7 @@ class Encoder extends Decoder {
|
|
|
1540
1788
|
if ((end - start) > MAX_BUFFER_SIZE)
|
|
1541
1789
|
throw new Error('Encoded buffer would be larger than maximum buffer size')
|
|
1542
1790
|
newSize = Math.min(MAX_BUFFER_SIZE,
|
|
1543
|
-
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2),
|
|
1791
|
+
Math.round(Math.max((end - start) * (end > 0x4000000 ? 1.25 : 2), 0x400000) / 0x1000) * 0x1000);
|
|
1544
1792
|
} else // faster handling for smaller buffers
|
|
1545
1793
|
newSize = ((Math.max((end - start) << 2, target.length - 1) >> 12) + 1) << 12;
|
|
1546
1794
|
let newBuffer = new ByteArrayAllocate(newSize);
|
|
@@ -1561,6 +1809,40 @@ class Encoder extends Decoder {
|
|
|
1561
1809
|
targetView = new DataView(target.buffer, target.byteOffset, target.byteLength);
|
|
1562
1810
|
position$1 = 0;
|
|
1563
1811
|
}
|
|
1812
|
+
clearSharedData() {
|
|
1813
|
+
if (this.structures)
|
|
1814
|
+
this.structures = [];
|
|
1815
|
+
if (this.sharedValues)
|
|
1816
|
+
this.sharedValues = undefined;
|
|
1817
|
+
}
|
|
1818
|
+
updateSharedData() {
|
|
1819
|
+
let lastVersion = this.sharedVersion || 0;
|
|
1820
|
+
this.sharedVersion = lastVersion + 1;
|
|
1821
|
+
let structuresCopy = this.structures.slice(0);
|
|
1822
|
+
let sharedData = new SharedData(structuresCopy, this.sharedValues, this.sharedVersion);
|
|
1823
|
+
let saveResults = this.saveShared(sharedData,
|
|
1824
|
+
existingShared => (existingShared && existingShared.version || 0) == lastVersion);
|
|
1825
|
+
if (saveResults === false) {
|
|
1826
|
+
// get updated structures and try again if the update failed
|
|
1827
|
+
sharedData = this.getShared() || {};
|
|
1828
|
+
this.structures = sharedData.structures || [];
|
|
1829
|
+
this.sharedValues = sharedData.packedValues;
|
|
1830
|
+
this.sharedVersion = sharedData.version;
|
|
1831
|
+
this.structures.nextId = this.structures.length;
|
|
1832
|
+
} else {
|
|
1833
|
+
// restore structures
|
|
1834
|
+
structuresCopy.forEach((structure, i) => this.structures[i] = structure);
|
|
1835
|
+
}
|
|
1836
|
+
// 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
|
|
1837
|
+
return saveResults
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
class SharedData {
|
|
1841
|
+
constructor(structures, values, version) {
|
|
1842
|
+
this.structures = structures;
|
|
1843
|
+
this.packedValues = values;
|
|
1844
|
+
this.version = version;
|
|
1845
|
+
}
|
|
1564
1846
|
}
|
|
1565
1847
|
|
|
1566
1848
|
function writeArrayHeader(length) {
|
|
@@ -1630,9 +1912,11 @@ function findRepetitiveStrings(value, packedValues) {
|
|
|
1630
1912
|
}
|
|
1631
1913
|
}
|
|
1632
1914
|
|
|
1633
|
-
extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, ByteArray,
|
|
1634
|
-
Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array,
|
|
1635
|
-
|
|
1915
|
+
extensionClasses = [ Date, Set, Error, RegExp, Tag, ArrayBuffer, ByteArray,
|
|
1916
|
+
Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array,
|
|
1917
|
+
typeof BigUint64Array == 'undefined' ? function() {} : BigUint64Array, Int8Array, Int16Array, Int32Array,
|
|
1918
|
+
typeof BigInt64Array == 'undefined' ? function() {} : BigInt64Array,
|
|
1919
|
+
Float32Array, Float64Array, SharedData];
|
|
1636
1920
|
|
|
1637
1921
|
//Object.getPrototypeOf(Uint8Array.prototype).constructor /*TypedArray*/
|
|
1638
1922
|
extensions = [{
|
|
@@ -1667,6 +1951,13 @@ extensions = [{
|
|
|
1667
1951
|
encode(regex, encode) {
|
|
1668
1952
|
encode([ 'RegExp', regex.source, regex.flags ]);
|
|
1669
1953
|
}
|
|
1954
|
+
}, {
|
|
1955
|
+
getTag(tag) {
|
|
1956
|
+
return tag.tag
|
|
1957
|
+
},
|
|
1958
|
+
encode(tag, encode) {
|
|
1959
|
+
encode(tag.value);
|
|
1960
|
+
}
|
|
1670
1961
|
}, {
|
|
1671
1962
|
encode(arrayBuffer, encode, makeRoom) {
|
|
1672
1963
|
writeBuffer(arrayBuffer, makeRoom);
|
|
@@ -1685,7 +1976,35 @@ extensions = [{
|
|
|
1685
1976
|
typedArrayEncoder(78),
|
|
1686
1977
|
typedArrayEncoder(79),
|
|
1687
1978
|
typedArrayEncoder(81),
|
|
1688
|
-
typedArrayEncoder(82)
|
|
1979
|
+
typedArrayEncoder(82),
|
|
1980
|
+
{
|
|
1981
|
+
encode(sharedData, encode) { // write SharedData
|
|
1982
|
+
let packedValues = sharedData.packedValues || [];
|
|
1983
|
+
let sharedStructures = sharedData.structures || [];
|
|
1984
|
+
if (packedValues.values.length > 0) {
|
|
1985
|
+
target[position$1++] = 0xd8; // one-byte tag
|
|
1986
|
+
target[position$1++] = 51; // tag 51 for packed shared structures https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
|
|
1987
|
+
writeArrayHeader(4);
|
|
1988
|
+
let valuesArray = packedValues.values;
|
|
1989
|
+
encode(valuesArray);
|
|
1990
|
+
writeArrayHeader(0); // prefixes
|
|
1991
|
+
writeArrayHeader(0); // suffixes
|
|
1992
|
+
packedObjectMap = Object.create(sharedPackedObjectMap || null);
|
|
1993
|
+
for (let i = 0, l = valuesArray.length; i < l; i++) {
|
|
1994
|
+
packedObjectMap[valuesArray[i]] = i;
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
if (sharedStructures) {
|
|
1998
|
+
targetView.setUint32(position$1, 0xd9dffe00);
|
|
1999
|
+
position$1 += 3;
|
|
2000
|
+
let definitions = sharedStructures.slice(0);
|
|
2001
|
+
definitions.unshift(0xe000);
|
|
2002
|
+
definitions.push(new Tag(sharedData.version, 0x53687264));
|
|
2003
|
+
encode(definitions);
|
|
2004
|
+
} else
|
|
2005
|
+
encode(new Tag(sharedData.version, 0x53687264));
|
|
2006
|
+
}
|
|
2007
|
+
}];
|
|
1689
2008
|
|
|
1690
2009
|
function typedArrayEncoder(tag) {
|
|
1691
2010
|
return {
|
|
@@ -1725,27 +2044,35 @@ function writeBuffer(buffer, makeRoom) {
|
|
|
1725
2044
|
function insertIds(serialized, idsToInsert) {
|
|
1726
2045
|
// insert the ids that need to be referenced for structured clones
|
|
1727
2046
|
let nextId;
|
|
1728
|
-
let distanceToMove = idsToInsert.length *
|
|
2047
|
+
let distanceToMove = idsToInsert.length * 2;
|
|
1729
2048
|
let lastEnd = serialized.length - distanceToMove;
|
|
1730
2049
|
idsToInsert.sort((a, b) => a.offset > b.offset ? 1 : -1);
|
|
2050
|
+
for (let id = 0; id < idsToInsert.length; id++) {
|
|
2051
|
+
let referee = idsToInsert[id];
|
|
2052
|
+
referee.id = id;
|
|
2053
|
+
for (let position of referee.references) {
|
|
2054
|
+
serialized[position++] = id >> 8;
|
|
2055
|
+
serialized[position] = id & 0xff;
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
1731
2058
|
while (nextId = idsToInsert.pop()) {
|
|
1732
2059
|
let offset = nextId.offset;
|
|
1733
|
-
let id = nextId.id;
|
|
1734
2060
|
serialized.copyWithin(offset + distanceToMove, offset, lastEnd);
|
|
1735
|
-
distanceToMove -=
|
|
2061
|
+
distanceToMove -= 2;
|
|
1736
2062
|
let position = offset + distanceToMove;
|
|
1737
|
-
serialized[position++] =
|
|
1738
|
-
serialized[position++] =
|
|
1739
|
-
serialized[position++] = 40009 & 0xff;
|
|
1740
|
-
serialized[position++] = 0x1a; // uint32
|
|
1741
|
-
serialized[position++] = id >> 24;
|
|
1742
|
-
serialized[position++] = (id >> 16) & 0xff;
|
|
1743
|
-
serialized[position++] = (id >> 8) & 0xff;
|
|
1744
|
-
serialized[position++] = id & 0xff;
|
|
2063
|
+
serialized[position++] = 0xd8;
|
|
2064
|
+
serialized[position++] = 28; // http://cbor.schmorp.de/value-sharing
|
|
1745
2065
|
lastEnd = offset;
|
|
1746
2066
|
}
|
|
1747
2067
|
return serialized
|
|
1748
2068
|
}
|
|
2069
|
+
function writeBundles(start, encode) {
|
|
2070
|
+
targetView.setUint32(bundledStrings$1.position + start, position$1 - bundledStrings$1.position - start + 1); // the offset to bundle
|
|
2071
|
+
let writeStrings = bundledStrings$1;
|
|
2072
|
+
bundledStrings$1 = null;
|
|
2073
|
+
encode(writeStrings[0]);
|
|
2074
|
+
encode(writeStrings[1]);
|
|
2075
|
+
}
|
|
1749
2076
|
|
|
1750
2077
|
function addExtension$1(extension) {
|
|
1751
2078
|
if (extension.Class) {
|
|
@@ -1759,7 +2086,8 @@ function addExtension$1(extension) {
|
|
|
1759
2086
|
let defaultEncoder = new Encoder({ useRecords: false });
|
|
1760
2087
|
const encode = defaultEncoder.encode;
|
|
1761
2088
|
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1762
|
-
const REUSE_BUFFER_MODE =
|
|
2089
|
+
const REUSE_BUFFER_MODE = 512;
|
|
2090
|
+
const RESET_BUFFER_MODE = 1024;
|
|
1763
2091
|
|
|
1764
2092
|
class EncoderStream extends stream.Transform {
|
|
1765
2093
|
constructor(options) {
|
|
@@ -1909,9 +2237,7 @@ function tryRequire(moduleId) {
|
|
|
1909
2237
|
let require$1 = module$1.createRequire((typeof document === 'undefined' ? new (require('u' + 'rl').URL)('file:' + __filename).href : (document.currentScript && document.currentScript.src || new URL('node.cjs', document.baseURI).href)));
|
|
1910
2238
|
return require$1(moduleId)
|
|
1911
2239
|
} catch (error) {
|
|
1912
|
-
if (typeof window
|
|
1913
|
-
console.warn('Native extraction module not loaded, cbor-x will still run, but with decreased performance. ' + error.message.split('\n')[0]);
|
|
1914
|
-
else
|
|
2240
|
+
if (typeof window != 'undefined')
|
|
1915
2241
|
console.warn('For browser usage, directly use cbor-x/decode or cbor-x/encode modules. ' + error.message.split('\n')[0]);
|
|
1916
2242
|
}
|
|
1917
2243
|
}
|