cbor-x 0.8.2 → 0.9.2
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/.vscode/launch.json +22 -0
- package/README.md +54 -18
- package/SECURITY.md +11 -0
- package/{unpack.d.ts → decode.d.ts} +12 -11
- package/decode.js +134 -33
- package/dist/index.js +400 -57
- package/dist/index.min.js +83 -53
- package/dist/node.cjs +419 -80
- package/dist/test.js +82 -1
- package/encode.d.ts +6 -0
- package/encode.js +181 -24
- package/index.d.ts +7 -6
- package/index.js +2 -2
- package/iterators.js +85 -0
- package/{node.js → node-index.js} +4 -3
- package/package.json +17 -17
- package/rollup.config.js +2 -2
- package/stream.js +20 -22
- package/tests/benchmark.cjs +48 -8
- package/tests/test-compatibility.cjs +1 -0
- package/tests/test-incomplete.js +41 -0
- package/tests/test-node-iterators.js +72 -0
- package/tests/test-node-stream.js +11 -1
- package/tests/test.js +82 -2
- package/pack.d.ts +0 -9
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
let srcEnd;
|
|
13
13
|
let position = 0;
|
|
14
14
|
const RECORD_TAG_ID = 0x69;
|
|
15
|
+
const PACKED_REFERENCE_TAG_ID = 6;
|
|
15
16
|
const STOP_CODE = {};
|
|
16
17
|
let currentDecoder = {};
|
|
17
18
|
let currentStructures;
|
|
@@ -20,11 +21,15 @@
|
|
|
20
21
|
let srcStringEnd = 0;
|
|
21
22
|
let referenceMap;
|
|
22
23
|
let currentExtensions = [];
|
|
24
|
+
let currentExtensionRanges = [];
|
|
25
|
+
let packedValues;
|
|
23
26
|
let dataView;
|
|
27
|
+
let restoreMapsAsObject;
|
|
24
28
|
let defaultOptions = {
|
|
25
29
|
useRecords: false,
|
|
26
30
|
mapsAsObjects: true
|
|
27
31
|
};
|
|
32
|
+
let sequentialMode = false;
|
|
28
33
|
|
|
29
34
|
class Decoder {
|
|
30
35
|
constructor(options) {
|
|
@@ -36,12 +41,12 @@
|
|
|
36
41
|
}
|
|
37
42
|
Object.assign(this, options);
|
|
38
43
|
}
|
|
39
|
-
decode(source, end
|
|
44
|
+
decode(source, end) {
|
|
40
45
|
if (src) {
|
|
41
46
|
// re-entrant execution, save the state and restore it after we do this decode
|
|
42
47
|
return saveState(() => {
|
|
43
48
|
clearSource();
|
|
44
|
-
return this ? this.decode(source, end
|
|
49
|
+
return this ? this.decode(source, end) : Decoder.prototype.decode.call(defaultOptions, source, end)
|
|
45
50
|
})
|
|
46
51
|
}
|
|
47
52
|
srcEnd = end > -1 ? end : source.length;
|
|
@@ -55,19 +60,12 @@
|
|
|
55
60
|
dataView = source.dataView || (source.dataView = new DataView(source.buffer, source.byteOffset, source.byteLength));
|
|
56
61
|
if (this) {
|
|
57
62
|
currentDecoder = this;
|
|
63
|
+
packedValues = this.sharedValues &&
|
|
64
|
+
(this.pack ? new Array(this.maxPrivatePackedValues || 16).concat(this.sharedValues) :
|
|
65
|
+
this.sharedValues);
|
|
58
66
|
if (this.structures) {
|
|
59
67
|
currentStructures = this.structures;
|
|
60
|
-
|
|
61
|
-
return read()
|
|
62
|
-
} finally {
|
|
63
|
-
if (position >= srcEnd || !continueReading) {
|
|
64
|
-
// finished reading this source, cleanup references
|
|
65
|
-
currentStructures = null;
|
|
66
|
-
src = null;
|
|
67
|
-
if (referenceMap)
|
|
68
|
-
referenceMap = null;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
68
|
+
return checkedRead()
|
|
71
69
|
} else if (!currentStructures || currentStructures.length > 0) {
|
|
72
70
|
currentStructures = [];
|
|
73
71
|
}
|
|
@@ -75,27 +73,23 @@
|
|
|
75
73
|
currentDecoder = defaultOptions;
|
|
76
74
|
if (!currentStructures || currentStructures.length > 0)
|
|
77
75
|
currentStructures = [];
|
|
76
|
+
packedValues = null;
|
|
78
77
|
}
|
|
79
|
-
|
|
80
|
-
return read()
|
|
81
|
-
} finally {
|
|
82
|
-
if (position >= srcEnd || !continueReading) {
|
|
83
|
-
src = null;
|
|
84
|
-
if (referenceMap)
|
|
85
|
-
referenceMap = null;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
78
|
+
return checkedRead()
|
|
88
79
|
}
|
|
89
80
|
decodeMultiple(source, forEach) {
|
|
81
|
+
let values, lastPosition = 0;
|
|
90
82
|
try {
|
|
91
|
-
let decoder = this;
|
|
92
83
|
let size = source.length;
|
|
93
|
-
|
|
94
|
-
let
|
|
84
|
+
sequentialMode = true;
|
|
85
|
+
let value = this ? this.decode(source, size) : defaultDecoder.decode(source, size);
|
|
95
86
|
if (forEach) {
|
|
96
|
-
forEach(value)
|
|
87
|
+
if (forEach(value) === false) {
|
|
88
|
+
return
|
|
89
|
+
}
|
|
97
90
|
while(position < size) {
|
|
98
|
-
|
|
91
|
+
lastPosition = position;
|
|
92
|
+
if (forEach(checkedRead()) === false) {
|
|
99
93
|
return
|
|
100
94
|
}
|
|
101
95
|
}
|
|
@@ -103,15 +97,48 @@
|
|
|
103
97
|
else {
|
|
104
98
|
values = [ value ];
|
|
105
99
|
while(position < size) {
|
|
106
|
-
|
|
100
|
+
lastPosition = position;
|
|
101
|
+
values.push(checkedRead());
|
|
107
102
|
}
|
|
108
103
|
return values
|
|
109
104
|
}
|
|
105
|
+
} catch(error) {
|
|
106
|
+
error.lastPosition = lastPosition;
|
|
107
|
+
error.values = values;
|
|
108
|
+
throw error
|
|
110
109
|
} finally {
|
|
110
|
+
sequentialMode = false;
|
|
111
111
|
clearSource();
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
|
+
function checkedRead() {
|
|
116
|
+
try {
|
|
117
|
+
let result = read();
|
|
118
|
+
if (position == srcEnd) {
|
|
119
|
+
// finished reading this source, cleanup references
|
|
120
|
+
currentStructures = null;
|
|
121
|
+
src = null;
|
|
122
|
+
if (referenceMap)
|
|
123
|
+
referenceMap = null;
|
|
124
|
+
} else if (position > srcEnd) {
|
|
125
|
+
// over read
|
|
126
|
+
let error = new Error('Unexpected end of CBOR data');
|
|
127
|
+
error.incomplete = true;
|
|
128
|
+
throw error
|
|
129
|
+
} else if (!sequentialMode) {
|
|
130
|
+
throw new Error('Data read, but end of buffer not reached')
|
|
131
|
+
}
|
|
132
|
+
// else more to read, but we are reading sequentially, so don't clear source yet
|
|
133
|
+
return result
|
|
134
|
+
} catch(error) {
|
|
135
|
+
clearSource();
|
|
136
|
+
if (error instanceof RangeError || error.message.startsWith('Unexpected end of buffer')) {
|
|
137
|
+
error.incomplete = true;
|
|
138
|
+
}
|
|
139
|
+
throw error
|
|
140
|
+
}
|
|
141
|
+
}
|
|
115
142
|
|
|
116
143
|
function read() {
|
|
117
144
|
let token = src[position++];
|
|
@@ -176,6 +203,10 @@
|
|
|
176
203
|
object[key] = read();
|
|
177
204
|
return object
|
|
178
205
|
} else {
|
|
206
|
+
if (restoreMapsAsObject) {
|
|
207
|
+
currentDecoder.mapsAsObjects = true;
|
|
208
|
+
restoreMapsAsObject = false;
|
|
209
|
+
}
|
|
179
210
|
let map = new Map();
|
|
180
211
|
while ((key = read()) != STOP_CODE)
|
|
181
212
|
map.set(key, read());
|
|
@@ -222,6 +253,10 @@
|
|
|
222
253
|
}
|
|
223
254
|
return object
|
|
224
255
|
} else {
|
|
256
|
+
if (restoreMapsAsObject) {
|
|
257
|
+
currentDecoder.mapsAsObjects = true;
|
|
258
|
+
restoreMapsAsObject = false;
|
|
259
|
+
}
|
|
225
260
|
let map = new Map();
|
|
226
261
|
for (let i = 0; i < token; i++) {
|
|
227
262
|
map.set(read(), read());
|
|
@@ -261,9 +296,15 @@
|
|
|
261
296
|
return extension(read)
|
|
262
297
|
else
|
|
263
298
|
return extension(read())
|
|
299
|
+
} else {
|
|
300
|
+
let input = read();
|
|
301
|
+
for (let i = 0; i < currentExtensionRanges.length; i++) {
|
|
302
|
+
let value = currentExtensionRanges[i](token, input);
|
|
303
|
+
if (value !== undefined)
|
|
304
|
+
return value
|
|
305
|
+
}
|
|
306
|
+
return new Tag(input)
|
|
264
307
|
}
|
|
265
|
-
else
|
|
266
|
-
return new Tag(read())
|
|
267
308
|
}
|
|
268
309
|
case 7: // fixed value
|
|
269
310
|
switch (token) {
|
|
@@ -273,6 +314,9 @@
|
|
|
273
314
|
case 0x17: return; // undefined
|
|
274
315
|
case 0x1f:
|
|
275
316
|
default:
|
|
317
|
+
let packedValue = packedValues[token];
|
|
318
|
+
if (packedValue !== undefined)
|
|
319
|
+
return packedValue
|
|
276
320
|
throw new Error('Unknown token ' + token)
|
|
277
321
|
}
|
|
278
322
|
default: // negative int
|
|
@@ -662,6 +706,23 @@
|
|
|
662
706
|
currentExtensions[27] = (data) => { // http://cbor.schmorp.de/generic-object
|
|
663
707
|
return (glbl[data[0]] || Error)(data[1], data[2])
|
|
664
708
|
};
|
|
709
|
+
const packedTable = (read) => {
|
|
710
|
+
if (src[position++] != 0x84)
|
|
711
|
+
throw new Error('Packed values structure must be followed by 4 element array')
|
|
712
|
+
let newPackedValues = read(); // packed values
|
|
713
|
+
packedValues = packedValues ? newPackedValues.concat(packedValues.slice(newPackedValues.length)) : newPackedValues;
|
|
714
|
+
packedValues.prefixes = read();
|
|
715
|
+
packedValues.suffixes = read();
|
|
716
|
+
return read() // read the rump
|
|
717
|
+
};
|
|
718
|
+
packedTable.handlesRead = true;
|
|
719
|
+
currentExtensions[51] = packedTable;
|
|
720
|
+
|
|
721
|
+
currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
|
|
722
|
+
if (typeof data == 'number')
|
|
723
|
+
return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
|
|
724
|
+
throw new Error('No support for non-integer packed references yet')
|
|
725
|
+
};
|
|
665
726
|
|
|
666
727
|
currentExtensions[40009] = (id) => {
|
|
667
728
|
// id extension (for structured clones)
|
|
@@ -693,6 +754,36 @@
|
|
|
693
754
|
};
|
|
694
755
|
|
|
695
756
|
currentExtensions[258] = (array) => new Set(array); // https://github.com/input-output-hk/cbor-sets-spec/blob/master/CBOR_SETS.md
|
|
757
|
+
(currentExtensions[259] = (read) => {
|
|
758
|
+
// https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec
|
|
759
|
+
// for decoding as a standard Map
|
|
760
|
+
if (currentDecoder.mapsAsObjects) {
|
|
761
|
+
currentDecoder.mapsAsObjects = false;
|
|
762
|
+
restoreMapsAsObject = true;
|
|
763
|
+
}
|
|
764
|
+
return read()
|
|
765
|
+
}).handlesRead = true;
|
|
766
|
+
function combine(a, b) {
|
|
767
|
+
if (typeof a === 'string')
|
|
768
|
+
return a + b
|
|
769
|
+
if (a instanceof Array)
|
|
770
|
+
return a.concat(b)
|
|
771
|
+
return Object.assign({}, a, b)
|
|
772
|
+
}
|
|
773
|
+
currentExtensionRanges.push((tag, input) => {
|
|
774
|
+
if (tag >= 225 && tag <= 255)
|
|
775
|
+
return combine(packedTable.prefixes[tag - 224], input)
|
|
776
|
+
if (tag >= 28704 && tag <= 32767)
|
|
777
|
+
return combine(packedTable.prefixes[tag - 28672], input)
|
|
778
|
+
if (tag >= 1879052288 && tag <= 2147483647)
|
|
779
|
+
return combine(packedTable.prefixes[tag - 1879048192], input)
|
|
780
|
+
if (tag >= 216 && tag <= 223)
|
|
781
|
+
return combine(input, packedTable.suffixes[tag - 216])
|
|
782
|
+
if (tag >= 27647 && tag <= 28671)
|
|
783
|
+
return combine(input, packedTable.suffixes[tag - 27639])
|
|
784
|
+
if (tag >= 1811940352 && tag <= 1879048191)
|
|
785
|
+
return combine(input, packedTable.suffixes[tag - 1811939328])
|
|
786
|
+
});
|
|
696
787
|
|
|
697
788
|
const typedArrays = ['Uint8', 'Uint8Clamped', 'Uint16', 'Uint32', 'BigUint64','Int8', 'Int16', 'Int32', 'BigInt64', 'Float32', 'Float64'].map(type => type + 'Array');
|
|
698
789
|
const typedArrayTags = [64, 68, 69, 70, 71, 72, 77, 78, 79, 81, 82];
|
|
@@ -719,6 +810,7 @@
|
|
|
719
810
|
let savedSrc = new Uint8Array(src.slice(0, srcEnd)); // we copy the data in case it changes while external data is processed
|
|
720
811
|
let savedStructures = currentStructures;
|
|
721
812
|
let savedDecoder = currentDecoder;
|
|
813
|
+
let savedSequentialMode = sequentialMode;
|
|
722
814
|
let value = callback();
|
|
723
815
|
srcEnd = savedSrcEnd;
|
|
724
816
|
position = savedPosition;
|
|
@@ -727,6 +819,7 @@
|
|
|
727
819
|
srcString = savedSrcString;
|
|
728
820
|
referenceMap = savedReferenceMap;
|
|
729
821
|
src = savedSrc;
|
|
822
|
+
sequentialMode = savedSequentialMode;
|
|
730
823
|
currentStructures = savedStructures;
|
|
731
824
|
currentDecoder = savedDecoder;
|
|
732
825
|
dataView = new DataView(src.buffer, src.byteOffset, src.byteLength);
|
|
@@ -742,7 +835,7 @@
|
|
|
742
835
|
currentExtensions[extension.tag] = extension.decode;
|
|
743
836
|
}
|
|
744
837
|
|
|
745
|
-
|
|
838
|
+
const mult10 = new Array(147); // this is a table matching binary exponents to the multiplier to determine significant digit rounding
|
|
746
839
|
for (let i = 0; i < 256; i++) {
|
|
747
840
|
mult10[i] = +('1e' + Math.floor(45.15 - i * 0.30103));
|
|
748
841
|
}
|
|
@@ -754,7 +847,14 @@
|
|
|
754
847
|
ALWAYS: 1,
|
|
755
848
|
DECIMAL_ROUND: 3,
|
|
756
849
|
DECIMAL_FIT: 4
|
|
757
|
-
};
|
|
850
|
+
};
|
|
851
|
+
let f32Array = new Float32Array(1);
|
|
852
|
+
let u8Array = new Uint8Array(f32Array.buffer, 0, 4);
|
|
853
|
+
function roundFloat32(float32Number) {
|
|
854
|
+
f32Array[0] = float32Number;
|
|
855
|
+
let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)];
|
|
856
|
+
return ((multiplier * float32Number + (float32Number > 0 ? 0.5 : -0.5)) >> 0) / multiplier
|
|
857
|
+
}
|
|
758
858
|
|
|
759
859
|
let textEncoder;
|
|
760
860
|
try {
|
|
@@ -781,6 +881,7 @@
|
|
|
781
881
|
let hasSharedUpdate;
|
|
782
882
|
let structures;
|
|
783
883
|
let referenceMap;
|
|
884
|
+
options = options || {};
|
|
784
885
|
let lastSharedStructuresLength = 0;
|
|
785
886
|
let encodeUtf8 = ByteArray.prototype.utf8Write ? function(string, position, maxBytes) {
|
|
786
887
|
return target.utf8Write(string, position, maxBytes)
|
|
@@ -791,19 +892,25 @@
|
|
|
791
892
|
|
|
792
893
|
let encoder = this;
|
|
793
894
|
let maxSharedStructures = 64;
|
|
794
|
-
let isSequential = options
|
|
895
|
+
let isSequential = options.sequential;
|
|
795
896
|
if (isSequential) {
|
|
796
897
|
maxSharedStructures = 0;
|
|
797
898
|
this.structures = [];
|
|
798
899
|
}
|
|
900
|
+
let samplingPackedValues, packedObjectMap, sharedValues = options.sharedValues;
|
|
901
|
+
let sharedPackedObjectMap;
|
|
902
|
+
if (sharedValues) {
|
|
903
|
+
sharedPackedObjectMap = Object.create(null);
|
|
904
|
+
for (let i = 0, l = sharedValues.length; i < l; i++) {
|
|
905
|
+
sharedPackedObjectMap[sharedValues[i]] = i;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
}
|
|
799
909
|
let recordIdsToRemove = [];
|
|
800
910
|
let transitionsCount = 0;
|
|
801
911
|
let serializationsSinceTransitionRebuild = 0;
|
|
802
|
-
if (this.structures && this.structures.length > maxSharedStructures) {
|
|
803
|
-
throw new Error('Too many shared structures')
|
|
804
|
-
}
|
|
805
912
|
|
|
806
|
-
this.encode = function(value) {
|
|
913
|
+
this.encode = function(value, encodeOptions) {
|
|
807
914
|
if (!target) {
|
|
808
915
|
target = new ByteArrayAllocate(8192);
|
|
809
916
|
targetView = new DataView(target.buffer, 0, 8192);
|
|
@@ -816,7 +923,8 @@
|
|
|
816
923
|
targetView = new DataView(target.buffer, 0, target.length);
|
|
817
924
|
safeEnd = target.length - 10;
|
|
818
925
|
position$1 = 0;
|
|
819
|
-
}
|
|
926
|
+
} else if (encodeOptions === REUSE_BUFFER_MODE)
|
|
927
|
+
position$1 = (position$1 + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
|
|
820
928
|
start = position$1;
|
|
821
929
|
referenceMap = encoder.structuredClone ? new Map() : null;
|
|
822
930
|
sharedStructures = encoder.structures;
|
|
@@ -824,7 +932,7 @@
|
|
|
824
932
|
if (sharedStructures.uninitialized)
|
|
825
933
|
encoder.structures = sharedStructures = encoder.getStructures();
|
|
826
934
|
let sharedStructuresLength = sharedStructures.length;
|
|
827
|
-
if (sharedStructuresLength >
|
|
935
|
+
if (sharedStructuresLength > maxSharedStructures && !isSequential)
|
|
828
936
|
sharedStructuresLength = maxSharedStructures;
|
|
829
937
|
if (!sharedStructures.transitions) {
|
|
830
938
|
// rebuild our structure transitions
|
|
@@ -834,8 +942,8 @@
|
|
|
834
942
|
if (!keys)
|
|
835
943
|
continue
|
|
836
944
|
let nextTransition, transition = sharedStructures.transitions;
|
|
837
|
-
for (let
|
|
838
|
-
let key = keys[
|
|
945
|
+
for (let j = 0, l = keys.length; j < l; j++) {
|
|
946
|
+
let key = keys[j];
|
|
839
947
|
nextTransition = transition[key];
|
|
840
948
|
if (!nextTransition) {
|
|
841
949
|
nextTransition = transition[key] = Object.create(null);
|
|
@@ -852,6 +960,29 @@
|
|
|
852
960
|
if (hasSharedUpdate)
|
|
853
961
|
hasSharedUpdate = false;
|
|
854
962
|
structures = sharedStructures || [];
|
|
963
|
+
packedObjectMap = sharedPackedObjectMap;
|
|
964
|
+
if (options.pack) {
|
|
965
|
+
let packedValues = new Map();
|
|
966
|
+
packedValues.values = [];
|
|
967
|
+
packedValues.encoder = encoder;
|
|
968
|
+
packedValues.maxValues = options.maxPrivatePackedValues || (sharedPackedObjectMap ? 16 : Infinity);
|
|
969
|
+
packedValues.objectMap = sharedPackedObjectMap || false;
|
|
970
|
+
packedValues.samplingPackedValues = samplingPackedValues;
|
|
971
|
+
findRepetitiveStrings(value, packedValues);
|
|
972
|
+
if (packedValues.values.length > 0) {
|
|
973
|
+
target[position$1++] = 0xd8; // one-byte tag
|
|
974
|
+
target[position$1++] = 51; // tag 51 for packed shared structures https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
|
|
975
|
+
writeArrayHeader(4);
|
|
976
|
+
let valuesArray = packedValues.values;
|
|
977
|
+
encode(valuesArray);
|
|
978
|
+
writeArrayHeader(0); // prefixes
|
|
979
|
+
writeArrayHeader(0); // suffixes
|
|
980
|
+
packedObjectMap = Object.create(sharedPackedObjectMap || null);
|
|
981
|
+
for (let i = 0, l = valuesArray.length; i < l; i++) {
|
|
982
|
+
packedObjectMap[valuesArray[i]] = i;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}
|
|
855
986
|
try {
|
|
856
987
|
encode(value);
|
|
857
988
|
encoder.offset = position$1; // update the offset so next serialization doesn't write over our buffer, but can continue writing to same buffer sequentially
|
|
@@ -864,7 +995,12 @@
|
|
|
864
995
|
referenceMap = null;
|
|
865
996
|
return serialized
|
|
866
997
|
}
|
|
867
|
-
|
|
998
|
+
if (encodeOptions === REUSE_BUFFER_MODE) {
|
|
999
|
+
target.start = start;
|
|
1000
|
+
target.end = position$1;
|
|
1001
|
+
return target
|
|
1002
|
+
}
|
|
1003
|
+
return target.subarray(start, position$1) // position can change if we call pack again in saveStructures, so we get the buffer now
|
|
868
1004
|
} finally {
|
|
869
1005
|
if (sharedStructures) {
|
|
870
1006
|
if (serializationsSinceTransitionRebuild < 10)
|
|
@@ -878,7 +1014,7 @@
|
|
|
878
1014
|
recordIdsToRemove = [];
|
|
879
1015
|
} else if (recordIdsToRemove.length > 0 && !isSequential) {
|
|
880
1016
|
for (let i = 0, l = recordIdsToRemove.length; i < l; i++) {
|
|
881
|
-
recordIdsToRemove[i][RECORD_SYMBOL] =
|
|
1017
|
+
recordIdsToRemove[i][RECORD_SYMBOL] = undefined;
|
|
882
1018
|
}
|
|
883
1019
|
recordIdsToRemove = [];
|
|
884
1020
|
}
|
|
@@ -886,15 +1022,41 @@
|
|
|
886
1022
|
if (encoder.structures.length > maxSharedStructures) {
|
|
887
1023
|
encoder.structures = encoder.structures.slice(0, maxSharedStructures);
|
|
888
1024
|
}
|
|
1025
|
+
// we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
|
|
1026
|
+
let returnBuffer = target.subarray(start, position$1);
|
|
1027
|
+
let shared = encoder.structures || [];
|
|
1028
|
+
if (sharedValues) {
|
|
1029
|
+
shared = shared.concat(sharedValues);
|
|
1030
|
+
}
|
|
889
1031
|
|
|
890
1032
|
if (encoder.saveStructures(encoder.structures, lastSharedStructuresLength) === false) {
|
|
891
1033
|
// get updated structures and try again if the update failed
|
|
892
1034
|
encoder.structures = encoder.getStructures() || [];
|
|
893
1035
|
return encoder.encode(value)
|
|
894
1036
|
}
|
|
895
|
-
lastSharedStructuresLength =
|
|
1037
|
+
lastSharedStructuresLength = shared.length;
|
|
1038
|
+
return returnBuffer
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
};
|
|
1043
|
+
this.findCommonStringsToPack = () => {
|
|
1044
|
+
samplingPackedValues = new Map();
|
|
1045
|
+
if (!sharedPackedObjectMap)
|
|
1046
|
+
sharedPackedObjectMap = Object.create(null);
|
|
1047
|
+
return ({ threshold }) => {
|
|
1048
|
+
threshold = threshold || 4;
|
|
1049
|
+
let position = this.pack ? options.maxPrivatePackedValues || 16 : 0;
|
|
1050
|
+
if (!sharedValues)
|
|
1051
|
+
sharedValues = this.sharedValues = [];
|
|
1052
|
+
for (let [ key, status ] of samplingPackedValues) {
|
|
1053
|
+
if (status.count > threshold) {
|
|
1054
|
+
sharedPackedObjectMap[key] = position++;
|
|
1055
|
+
sharedValues.push(key);
|
|
1056
|
+
hasSharedUpdate = true;
|
|
896
1057
|
}
|
|
897
1058
|
}
|
|
1059
|
+
samplingPackedValues = null;
|
|
898
1060
|
}
|
|
899
1061
|
};
|
|
900
1062
|
const encode = (value) => {
|
|
@@ -904,6 +1066,43 @@
|
|
|
904
1066
|
var type = typeof value;
|
|
905
1067
|
var length;
|
|
906
1068
|
if (type === 'string') {
|
|
1069
|
+
if (packedObjectMap) {
|
|
1070
|
+
let packedPosition = packedObjectMap[value];
|
|
1071
|
+
if (packedPosition >= 0) {
|
|
1072
|
+
if (packedPosition < 16)
|
|
1073
|
+
target[position$1++] = packedPosition + 0xe0; // simple values, defined in https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
|
|
1074
|
+
else {
|
|
1075
|
+
target[position$1++] = 0xc6; // tag 6 defined in https://www.potaroo.net/ietf/ids/draft-ietf-cbor-packed-03.txt
|
|
1076
|
+
if (packedPosition & 1)
|
|
1077
|
+
encode((15 - packedPosition) >> 1);
|
|
1078
|
+
else
|
|
1079
|
+
encode((packedPosition - 16) >> 1);
|
|
1080
|
+
}
|
|
1081
|
+
return
|
|
1082
|
+
/* } else if (packedStatus.serializationId != serializationId) {
|
|
1083
|
+
packedStatus.serializationId = serializationId
|
|
1084
|
+
packedStatus.count = 1
|
|
1085
|
+
if (options.sharedPack) {
|
|
1086
|
+
let sharedCount = packedStatus.sharedCount = (packedStatus.sharedCount || 0) + 1
|
|
1087
|
+
if (shareCount > (options.sharedPack.threshold || 5)) {
|
|
1088
|
+
let sharedPosition = packedStatus.position = packedStatus.nextSharedPosition
|
|
1089
|
+
hasSharedUpdate = true
|
|
1090
|
+
if (sharedPosition < 16)
|
|
1091
|
+
target[position++] = sharedPosition + 0xc0
|
|
1092
|
+
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
} // else any in-doc incrementation?*/
|
|
1096
|
+
} else if (samplingPackedValues && !options.pack) {
|
|
1097
|
+
let status = samplingPackedValues.get(value);
|
|
1098
|
+
if (status)
|
|
1099
|
+
status.count++;
|
|
1100
|
+
else
|
|
1101
|
+
samplingPackedValues.set(value, {
|
|
1102
|
+
count: 1,
|
|
1103
|
+
});
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
907
1106
|
let strLength = value.length;
|
|
908
1107
|
let headerSize;
|
|
909
1108
|
// first we estimate the header size, so we can write to the correct location
|
|
@@ -1013,7 +1212,7 @@
|
|
|
1013
1212
|
targetView.setFloat32(position$1, value);
|
|
1014
1213
|
let xShifted;
|
|
1015
1214
|
if (useFloat32 < 4 ||
|
|
1016
|
-
|
|
1215
|
+
// this checks for rounding of numbers that were encoded in 32-bit float to nearest significant decimal digit that could be preserved
|
|
1017
1216
|
((xShifted = value * mult10[((target[position$1] & 0x7f) << 1) | (target[position$1 + 1] >> 7)]) >> 0) === xShifted) {
|
|
1018
1217
|
position$1 += 4;
|
|
1019
1218
|
return
|
|
@@ -1059,6 +1258,12 @@
|
|
|
1059
1258
|
encode(value[i]);
|
|
1060
1259
|
}
|
|
1061
1260
|
} else if (constructor === Map) {
|
|
1261
|
+
if (this.mapsAsObjects ? this.useTag259ForMaps !== false : this.useTag259ForMaps) {
|
|
1262
|
+
// use Tag 259 (https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec--explicit-maps.md) for maps if the user wants it that way
|
|
1263
|
+
target[position$1++] = 0xd9;
|
|
1264
|
+
target[position$1++] = 1;
|
|
1265
|
+
target[position$1++] = 3;
|
|
1266
|
+
}
|
|
1062
1267
|
length = value.size;
|
|
1063
1268
|
if (length < 0x18) {
|
|
1064
1269
|
target[position$1++] = 0xa0 | length;
|
|
@@ -1136,10 +1341,9 @@
|
|
|
1136
1341
|
}
|
|
1137
1342
|
position$1 += 8;
|
|
1138
1343
|
} else if (type === 'undefined') {
|
|
1139
|
-
//target[position++] = 0xc1 // this is the "never-used" byte
|
|
1140
1344
|
target[position$1++] = 0xf7;
|
|
1141
1345
|
} else {
|
|
1142
|
-
throw new Error('Unknown type ' + type)
|
|
1346
|
+
throw new Error('Unknown type: ' + type)
|
|
1143
1347
|
}
|
|
1144
1348
|
};
|
|
1145
1349
|
|
|
@@ -1228,7 +1432,7 @@
|
|
|
1228
1432
|
let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
|
|
1229
1433
|
let newTransitions = 0;
|
|
1230
1434
|
let length = keys.length;
|
|
1231
|
-
for (let i =0; i < length; i++) {
|
|
1435
|
+
for (let i = 0; i < length; i++) {
|
|
1232
1436
|
let key = keys[i];
|
|
1233
1437
|
nextTransition = transition[key];
|
|
1234
1438
|
if (!nextTransition) {
|
|
@@ -1238,7 +1442,7 @@
|
|
|
1238
1442
|
transition = nextTransition;
|
|
1239
1443
|
}
|
|
1240
1444
|
let recordId = transition[RECORD_SYMBOL];
|
|
1241
|
-
if (recordId) {
|
|
1445
|
+
if (recordId !== undefined) {
|
|
1242
1446
|
target[position$1++] = 0xd9; // tag two byte
|
|
1243
1447
|
target[position$1++] = RECORD_STARTING_ID_PREFIX;
|
|
1244
1448
|
target[position$1++] = recordId;
|
|
@@ -1265,12 +1469,9 @@
|
|
|
1265
1469
|
transitionsCount += serializationsSinceTransitionRebuild * newTransitions;
|
|
1266
1470
|
// record the removal of the id, we can maintain our shared structure
|
|
1267
1471
|
if (recordIdsToRemove.length >= MAX_STRUCTURES - maxSharedStructures)
|
|
1268
|
-
recordIdsToRemove.shift()[RECORD_SYMBOL] =
|
|
1472
|
+
recordIdsToRemove.shift()[RECORD_SYMBOL] = undefined; // we are cycling back through, and have to remove old ones
|
|
1269
1473
|
recordIdsToRemove.push(transition);
|
|
1270
|
-
|
|
1271
|
-
target[position$1++] = 0x82 + length; // array header, length of values + 2
|
|
1272
|
-
else
|
|
1273
|
-
writeArrayHeader(length + 2);
|
|
1474
|
+
writeArrayHeader(length + 2);
|
|
1274
1475
|
encode(keys);
|
|
1275
1476
|
target[position$1++] = 0x19; // uint16
|
|
1276
1477
|
target[position$1++] = RECORD_STARTING_ID_PREFIX;
|
|
@@ -1320,7 +1521,9 @@
|
|
|
1320
1521
|
}
|
|
1321
1522
|
|
|
1322
1523
|
function writeArrayHeader(length) {
|
|
1323
|
-
if (length <
|
|
1524
|
+
if (length < 0x18)
|
|
1525
|
+
target[position$1++] = 0x80 | length;
|
|
1526
|
+
else if (length < 0x100) {
|
|
1324
1527
|
target[position$1++] = 0x98;
|
|
1325
1528
|
target[position$1++] = length;
|
|
1326
1529
|
} else if (length < 0x10000) {
|
|
@@ -1334,6 +1537,56 @@
|
|
|
1334
1537
|
}
|
|
1335
1538
|
}
|
|
1336
1539
|
|
|
1540
|
+
function findRepetitiveStrings(value, packedValues) {
|
|
1541
|
+
switch(typeof value) {
|
|
1542
|
+
case 'string':
|
|
1543
|
+
if (value.length > 3) {
|
|
1544
|
+
if (packedValues.objectMap[value] > -1 || packedValues.values.length >= packedValues.maxValues)
|
|
1545
|
+
return
|
|
1546
|
+
let packedStatus = packedValues.get(value);
|
|
1547
|
+
if (packedStatus) {
|
|
1548
|
+
if (++packedStatus.count == 2) {
|
|
1549
|
+
packedValues.values.push(value);
|
|
1550
|
+
}
|
|
1551
|
+
} else {
|
|
1552
|
+
packedValues.set(value, {
|
|
1553
|
+
count: 1,
|
|
1554
|
+
});
|
|
1555
|
+
if (packedValues.samplingPackedValues) {
|
|
1556
|
+
let status = packedValues.samplingPackedValues.get(value);
|
|
1557
|
+
if (status)
|
|
1558
|
+
status.count++;
|
|
1559
|
+
else
|
|
1560
|
+
packedValues.samplingPackedValues.set(value, {
|
|
1561
|
+
count: 1,
|
|
1562
|
+
});
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
break
|
|
1567
|
+
case 'object':
|
|
1568
|
+
if (value) {
|
|
1569
|
+
if (value instanceof Array) {
|
|
1570
|
+
for (let i = 0, l = value.length; i < l; i++) {
|
|
1571
|
+
findRepetitiveStrings(value[i], packedValues);
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1574
|
+
} else {
|
|
1575
|
+
let includeKeys = !packedValues.encoder.useRecords;
|
|
1576
|
+
for (var key in value) {
|
|
1577
|
+
if (value.hasOwnProperty(key)) {
|
|
1578
|
+
if (includeKeys)
|
|
1579
|
+
findRepetitiveStrings(key, packedValues);
|
|
1580
|
+
findRepetitiveStrings(value[key], packedValues);
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
break
|
|
1586
|
+
case 'function': console.log(value);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1337
1590
|
extensionClasses = [ Date, Set, Error, RegExp, ArrayBuffer, ByteArray,
|
|
1338
1591
|
Uint8Array, Uint8ClampedArray, Uint16Array, Uint32Array, BigUint64Array, Int8Array, Int16Array, Int32Array, BigInt64Array,
|
|
1339
1592
|
Float32Array, Float64Array];
|
|
@@ -1405,7 +1658,9 @@
|
|
|
1405
1658
|
}
|
|
1406
1659
|
function writeBuffer(buffer, makeRoom) {
|
|
1407
1660
|
let length = buffer.byteLength;
|
|
1408
|
-
if (length <
|
|
1661
|
+
if (length < 0x18) {
|
|
1662
|
+
target[position$1++] = 0x40 + length;
|
|
1663
|
+
} else if (length < 0x100) {
|
|
1409
1664
|
target[position$1++] = 0x58;
|
|
1410
1665
|
target[position$1++] = length;
|
|
1411
1666
|
} else if (length < 0x10000) {
|
|
@@ -1460,7 +1715,91 @@
|
|
|
1460
1715
|
}
|
|
1461
1716
|
let defaultEncoder = new Encoder({ useRecords: false });
|
|
1462
1717
|
const encode = defaultEncoder.encode;
|
|
1463
|
-
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1718
|
+
const { NEVER, ALWAYS, DECIMAL_ROUND, DECIMAL_FIT } = FLOAT32_OPTIONS;
|
|
1719
|
+
const REUSE_BUFFER_MODE = 1000;
|
|
1720
|
+
|
|
1721
|
+
/**
|
|
1722
|
+
* Given an Iterable first argument, returns an Iterable where each value is encoded as a Buffer
|
|
1723
|
+
* If the argument is only Async Iterable, the return value will be an Async Iterable.
|
|
1724
|
+
* @param {Iterable|Iterator|AsyncIterable|AsyncIterator} objectIterator - iterable source, like a Readable object stream, an array, Set, or custom object
|
|
1725
|
+
* @param {options} [options] - cbor-x Encoder options
|
|
1726
|
+
* @returns {IterableIterator|Promise.<AsyncIterableIterator>}
|
|
1727
|
+
*/
|
|
1728
|
+
function encodeIter (objectIterator, options = {}) {
|
|
1729
|
+
if (!objectIterator || typeof objectIterator !== 'object') {
|
|
1730
|
+
throw new Error('first argument must be an Iterable, Async Iterable, or a Promise for an Async Iterable')
|
|
1731
|
+
} else if (typeof objectIterator[Symbol.iterator] === 'function') {
|
|
1732
|
+
return encodeIterSync(objectIterator, options)
|
|
1733
|
+
} else if (typeof objectIterator.then === 'function' || typeof objectIterator[Symbol.asyncIterator] === 'function') {
|
|
1734
|
+
return encodeIterAsync(objectIterator, options)
|
|
1735
|
+
} else {
|
|
1736
|
+
throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a Promise')
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
function * encodeIterSync (objectIterator, options) {
|
|
1741
|
+
const encoder = new Encoder(options);
|
|
1742
|
+
for (const value of objectIterator) {
|
|
1743
|
+
yield encoder.encode(value);
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
async function * encodeIterAsync (objectIterator, options) {
|
|
1748
|
+
const encoder = new Encoder(options);
|
|
1749
|
+
for await (const value of objectIterator) {
|
|
1750
|
+
yield encoder.encode(value);
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
|
|
1754
|
+
/**
|
|
1755
|
+
* Given an Iterable/Iterator input which yields buffers, returns an IterableIterator which yields sync decoded objects
|
|
1756
|
+
* Or, given an Async Iterable/Iterator which yields promises resolving in buffers, returns an AsyncIterableIterator.
|
|
1757
|
+
* @param {Iterable|Iterator|AsyncIterable|AsyncIterableIterator} bufferIterator
|
|
1758
|
+
* @param {object} [options] - Decoder options
|
|
1759
|
+
* @returns {IterableIterator|Promise.<AsyncIterableIterator}
|
|
1760
|
+
*/
|
|
1761
|
+
function decodeIter (bufferIterator, options = {}) {
|
|
1762
|
+
if (!bufferIterator || typeof bufferIterator !== 'object') {
|
|
1763
|
+
throw new Error('first argument must be an Iterable, Async Iterable, Iterator, Async Iterator, or a promise')
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
const decoder = new Decoder(options);
|
|
1767
|
+
let incomplete;
|
|
1768
|
+
const parser = (chunk) => {
|
|
1769
|
+
let yields;
|
|
1770
|
+
// if there's incomplete data from previous chunk, concatinate and try again
|
|
1771
|
+
if (incomplete) {
|
|
1772
|
+
chunk = Buffer.concat([incomplete, chunk]);
|
|
1773
|
+
incomplete = undefined;
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
try {
|
|
1777
|
+
yields = decoder.decodeMultiple(chunk);
|
|
1778
|
+
} catch (err) {
|
|
1779
|
+
if (err.incomplete) {
|
|
1780
|
+
incomplete = chunk.slice(err.lastPosition);
|
|
1781
|
+
yields = err.values;
|
|
1782
|
+
} else {
|
|
1783
|
+
throw err
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
return yields
|
|
1787
|
+
};
|
|
1788
|
+
|
|
1789
|
+
if (typeof bufferIterator[Symbol.iterator] === 'function') {
|
|
1790
|
+
return (function * iter () {
|
|
1791
|
+
for (const value of bufferIterator) {
|
|
1792
|
+
yield * parser(value);
|
|
1793
|
+
}
|
|
1794
|
+
})()
|
|
1795
|
+
} else if (typeof bufferIterator[Symbol.asyncIterator] === 'function') {
|
|
1796
|
+
return (async function * iter () {
|
|
1797
|
+
for await (const value of bufferIterator) {
|
|
1798
|
+
yield * parser(value);
|
|
1799
|
+
}
|
|
1800
|
+
})()
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1464
1803
|
|
|
1465
1804
|
const useRecords = false;
|
|
1466
1805
|
const mapsAsObjects = true;
|
|
@@ -1474,10 +1813,14 @@
|
|
|
1474
1813
|
exports.NEVER = NEVER;
|
|
1475
1814
|
exports.Tag = Tag;
|
|
1476
1815
|
exports.addExtension = addExtension$1;
|
|
1816
|
+
exports.clearSource = clearSource;
|
|
1477
1817
|
exports.decode = decode;
|
|
1818
|
+
exports.decodeIter = decodeIter;
|
|
1478
1819
|
exports.decodeMultiple = decodeMultiple;
|
|
1479
1820
|
exports.encode = encode;
|
|
1821
|
+
exports.encodeIter = encodeIter;
|
|
1480
1822
|
exports.mapsAsObjects = mapsAsObjects;
|
|
1823
|
+
exports.roundFloat32 = roundFloat32;
|
|
1481
1824
|
exports.useRecords = useRecords;
|
|
1482
1825
|
|
|
1483
1826
|
Object.defineProperty(exports, '__esModule', { value: true });
|