cbor-x 1.4.0 → 1.5.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 +21 -1
- package/decode.js +56 -34
- package/dist/decode-no-eval.cjs +1137 -0
- package/dist/decode-no-eval.cjs.map +1 -0
- package/dist/index-no-eval.cjs +2376 -0
- package/dist/index-no-eval.cjs.map +1 -0
- package/dist/index-no-eval.min.js +2 -0
- package/dist/index-no-eval.min.js.map +1 -0
- package/dist/index.js +549 -363
- package/dist/index.js.map +1 -0
- package/dist/index.min.js +2 -135
- package/dist/index.min.js.map +1 -0
- package/dist/node.cjs +556 -368
- package/dist/node.cjs.map +1 -0
- package/dist/test.js +181 -31
- package/dist/test.js.map +1 -0
- package/encode.d.ts +1 -1
- package/encode.js +165 -2
- package/index.d.ts +9 -5
- package/index.js +1 -1
- package/node-index.js +1 -1
- package/package.json +7 -6
- package/rollup.config.js +51 -8
- package/stream.js +4 -2
package/README.md
CHANGED
|
@@ -52,6 +52,26 @@ receivingStream.on('data', (data) => {
|
|
|
52
52
|
```
|
|
53
53
|
The `EncoderStream` and `DecoderStream` instances will have also the record structure extension enabled by default (see below).
|
|
54
54
|
|
|
55
|
+
### Iterables
|
|
56
|
+
In addition to using CBOR with streams, CBOR can also encode to an iterable that can be iterated as a sequence of binary chunks with `encodeAsIterable`, which facilitates progressive encoding:
|
|
57
|
+
```JavaScript
|
|
58
|
+
import { encodeAsIterable } from 'cbor-x';
|
|
59
|
+
|
|
60
|
+
for (let binaryChunk of encodeAsIterable(data)){
|
|
61
|
+
// progressively get binary chunks as data is encoded
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
And `encodeAsAsyncIterable` is also available, which returns an async iterable, and can be used to encode data from async iterables as well as Blob data.
|
|
65
|
+
|
|
66
|
+
```JavaScript
|
|
67
|
+
import { encodeAsAsyncIterable } from 'cbor-x';
|
|
68
|
+
|
|
69
|
+
let data = { blob: new Blob(...) };
|
|
70
|
+
for await (let binaryChunk of encodeAsAsyncIterable(data)){
|
|
71
|
+
// progressively get binary chunks as asynchronous data source is encoded
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
55
75
|
## Deno Usage
|
|
56
76
|
Cbor-x modules are standard ESM modules and can be loaded directly from the [deno.land registry for cbor](https://deno.land/x/cbor) for use in Deno. The standard pack/encode and unpack/decode functionality is available on Deno, like other platforms.
|
|
57
77
|
|
|
@@ -168,7 +188,7 @@ assert.deepEqual(senmlEncoder.decode(senmlBuff), data)
|
|
|
168
188
|
```
|
|
169
189
|
|
|
170
190
|
### CBOR Packing
|
|
171
|
-
[Packed CBOR](https://datatracker.ietf.org/doc/html/draft-ietf-cbor-packed) is additional specification for CBOR which allows for compact encoding of data that has repeated values. Cbor-x supports decoding packed CBOR, no or
|
|
191
|
+
[Packed CBOR](https://datatracker.ietf.org/doc/html/draft-ietf-cbor-packed) is additional specification for CBOR which allows for compact encoding of data that has repeated values. Cbor-x supports decoding packed CBOR, no flags or options needed. Cbor-x can also optionally generate packed CBOR (with the `pack` option), which will cause the encoder to look for repeated strings in a data structure that is being encoded, and store the strings in a packed table that can be referenced, to reduce encoding size. This involves extra overhead and reduces encoding performance, and generally does not yield as much compaction as standard compression tools. However, this is can be much faster than encoding plus compression, while still providing some level of reduction in encoding size. In addition to size reduction, packed CBOR is also usually faster to decode (assuming that some repetitive values could be found/packed).
|
|
172
192
|
|
|
173
193
|
Cbor-x also has in-progress effort to support shared packed tables.
|
|
174
194
|
|
package/decode.js
CHANGED
|
@@ -84,7 +84,7 @@ export class Decoder {
|
|
|
84
84
|
}
|
|
85
85
|
let res = {}
|
|
86
86
|
//map.forEach((v,k) => res[Object.keys(this._keyMap)[Object.values(this._keyMap).indexOf(k)] || k] = v)
|
|
87
|
-
map.forEach((v,k) => res[this._mapKey.has(k) ? this._mapKey.get(k) : k] = v)
|
|
87
|
+
map.forEach((v,k) => res[safeKey(this._mapKey.has(k) ? this._mapKey.get(k) : k)] = v)
|
|
88
88
|
return res
|
|
89
89
|
}
|
|
90
90
|
|
|
@@ -197,6 +197,7 @@ export function checkedRead() {
|
|
|
197
197
|
}
|
|
198
198
|
// bundled strings to skip past
|
|
199
199
|
position = bundledStrings.postBundlePosition;
|
|
200
|
+
bundledStrings = null;
|
|
200
201
|
}
|
|
201
202
|
|
|
202
203
|
if (position == srcEnd) {
|
|
@@ -289,8 +290,8 @@ export function read() {
|
|
|
289
290
|
let key
|
|
290
291
|
if (currentDecoder.mapsAsObjects) {
|
|
291
292
|
let object = {}
|
|
292
|
-
if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) object[currentDecoder.decodeKey(key)] = read()
|
|
293
|
-
else while ((key = read()) != STOP_CODE) object[key] = read()
|
|
293
|
+
if (currentDecoder.keyMap) while((key = read()) != STOP_CODE) object[safeKey(currentDecoder.decodeKey(key))] = read()
|
|
294
|
+
else while ((key = read()) != STOP_CODE) object[safeKey(key)] = read()
|
|
294
295
|
return object
|
|
295
296
|
} else {
|
|
296
297
|
if (restoreMapsAsObject) {
|
|
@@ -338,8 +339,8 @@ export function read() {
|
|
|
338
339
|
case 5: // map
|
|
339
340
|
if (currentDecoder.mapsAsObjects) {
|
|
340
341
|
let object = {}
|
|
341
|
-
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[currentDecoder.decodeKey(read())] = read()
|
|
342
|
-
else for (let i = 0; i < token; i++) object[read()] = read()
|
|
342
|
+
if (currentDecoder.keyMap) for (let i = 0; i < token; i++) object[safeKey(currentDecoder.decodeKey(read()))] = read()
|
|
343
|
+
else for (let i = 0; i < token; i++) object[safeKey(read())] = read()
|
|
343
344
|
return object
|
|
344
345
|
} else {
|
|
345
346
|
if (restoreMapsAsObject) {
|
|
@@ -455,8 +456,8 @@ function createStructureReader(structure) {
|
|
|
455
456
|
if (this.slowReads++ >= 3) { // create a fast compiled reader
|
|
456
457
|
let array = this.length == length ? this : this.slice(0, length)
|
|
457
458
|
compiledReader = currentDecoder.keyMap
|
|
458
|
-
? new Function('r', 'return {' + array.map(k => currentDecoder.decodeKey(k)).map(k => validName.test(k) ? k + ':r()' : ('[' + JSON.stringify(k) + ']:r()')).join(',') + '}')
|
|
459
|
-
: new Function('r', 'return {' + array.map(key => validName.test(key) ? key + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}')
|
|
459
|
+
? new Function('r', 'return {' + array.map(k => currentDecoder.decodeKey(k)).map(k => validName.test(k) ? safeKey(k) + ':r()' : ('[' + JSON.stringify(k) + ']:r()')).join(',') + '}')
|
|
460
|
+
: new Function('r', 'return {' + array.map(key => validName.test(key) ? safeKey(key) + ':r()' : ('[' + JSON.stringify(key) + ']:r()')).join(',') + '}')
|
|
460
461
|
if (this.compiledReader)
|
|
461
462
|
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
|
|
462
463
|
compiledReader.propertyCount = length
|
|
@@ -464,14 +465,20 @@ function createStructureReader(structure) {
|
|
|
464
465
|
return compiledReader(read)
|
|
465
466
|
}
|
|
466
467
|
let object = {}
|
|
467
|
-
if (currentDecoder.keyMap) for (let i = 0; i < length; i++) object[currentDecoder.decodeKey(this[i])] = read()
|
|
468
|
-
else for (let i = 0; i < length; i++)
|
|
468
|
+
if (currentDecoder.keyMap) for (let i = 0; i < length; i++) object[safeKey(currentDecoder.decodeKey(this[i]))] = read()
|
|
469
|
+
else for (let i = 0; i < length; i++) {
|
|
470
|
+
object[safeKey(this[i])] = read();
|
|
471
|
+
}
|
|
469
472
|
return object
|
|
470
473
|
}
|
|
471
474
|
structure.slowReads = 0
|
|
472
475
|
return readObject
|
|
473
476
|
}
|
|
474
477
|
|
|
478
|
+
function safeKey(key) {
|
|
479
|
+
return key === '__proto__' ? '__proto_' : key
|
|
480
|
+
}
|
|
481
|
+
|
|
475
482
|
let readFixedString = readStringJS
|
|
476
483
|
let readString8 = readStringJS
|
|
477
484
|
let readString16 = readStringJS
|
|
@@ -737,18 +744,30 @@ function readExt(length) {
|
|
|
737
744
|
else
|
|
738
745
|
throw new Error('Unknown extension type ' + type)
|
|
739
746
|
}
|
|
740
|
-
|
|
747
|
+
let f32Array = new Float32Array(1)
|
|
748
|
+
let u8Array = new Uint8Array(f32Array.buffer, 0, 4)
|
|
741
749
|
function getFloat16() {
|
|
742
750
|
let byte0 = src[position++]
|
|
743
751
|
let byte1 = src[position++]
|
|
744
|
-
let
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
+
let exponent = (byte0 & 0x7f) >> 2;
|
|
753
|
+
if (exponent === 0x1f) { // specials
|
|
754
|
+
if (byte1 || (byte0 & 3))
|
|
755
|
+
return NaN;
|
|
756
|
+
return (byte0 & 0x80) ? -Infinity : Infinity;
|
|
757
|
+
}
|
|
758
|
+
if (exponent === 0) { // sub-normals
|
|
759
|
+
// significand with 10 fractional bits and divided by 2^14
|
|
760
|
+
let abs = (((byte0 & 3) << 8) | byte1) / (1 << 24)
|
|
761
|
+
return (byte0 & 0x80) ? -abs : abs
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
u8Array[3] = (byte0 & 0x80) | // sign bit
|
|
765
|
+
((exponent >> 1) + 56) // 4 of 5 of the exponent bits, re-offset-ed
|
|
766
|
+
u8Array[2] = ((byte0 & 7) << 5) | // last exponent bit and first two mantissa bits
|
|
767
|
+
(byte1 >> 3) // next 5 bits of mantissa
|
|
768
|
+
u8Array[1] = byte1 << 5; // last three bits of mantissa
|
|
769
|
+
u8Array[0] = 0;
|
|
770
|
+
return f32Array[0];
|
|
752
771
|
}
|
|
753
772
|
|
|
754
773
|
let keyCache = new Array(4096)
|
|
@@ -869,11 +888,11 @@ const recordDefinition = (definition) => {
|
|
|
869
888
|
let object = {}
|
|
870
889
|
if (currentDecoder.keyMap) for (let i = 2,l = definition.length; i < l; i++) {
|
|
871
890
|
let key = currentDecoder.decodeKey(structure[i - 2])
|
|
872
|
-
object[key] = definition[i]
|
|
891
|
+
object[safeKey(key)] = definition[i]
|
|
873
892
|
}
|
|
874
893
|
else for (let i = 2,l = definition.length; i < l; i++) {
|
|
875
894
|
let key = structure[i - 2]
|
|
876
|
-
object[key] = definition[i]
|
|
895
|
+
object[safeKey(key)] = definition[i]
|
|
877
896
|
}
|
|
878
897
|
return object
|
|
879
898
|
}
|
|
@@ -915,18 +934,23 @@ currentExtensions[PACKED_REFERENCE_TAG_ID] = (data) => { // packed reference
|
|
|
915
934
|
return packedValues[16 + (data >= 0 ? 2 * data : (-2 * data - 1))]
|
|
916
935
|
throw new Error('No support for non-integer packed references yet')
|
|
917
936
|
}
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
937
|
+
|
|
938
|
+
// The following code is an incomplete implementation of http://cbor.schmorp.de/stringref
|
|
939
|
+
// the real thing would need to implemennt more logic to populate the stringRefs table and
|
|
940
|
+
// maintain a stack of stringRef "namespaces".
|
|
941
|
+
//
|
|
942
|
+
// currentExtensions[25] = (id) => {
|
|
943
|
+
// return stringRefs[id]
|
|
944
|
+
// }
|
|
945
|
+
// currentExtensions[256] = (read) => {
|
|
946
|
+
// stringRefs = []
|
|
947
|
+
// try {
|
|
948
|
+
// return read()
|
|
949
|
+
// } finally {
|
|
950
|
+
// stringRefs = null
|
|
951
|
+
// }
|
|
952
|
+
// }
|
|
953
|
+
// currentExtensions[256].handlesRead = true
|
|
930
954
|
|
|
931
955
|
currentExtensions[28] = (read) => {
|
|
932
956
|
// shareable http://cbor.schmorp.de/value-sharing (for structured clones)
|
|
@@ -1160,8 +1184,6 @@ export const FLOAT32_OPTIONS = {
|
|
|
1160
1184
|
DECIMAL_ROUND: 3,
|
|
1161
1185
|
DECIMAL_FIT: 4
|
|
1162
1186
|
}
|
|
1163
|
-
let f32Array = new Float32Array(1)
|
|
1164
|
-
let u8Array = new Uint8Array(f32Array.buffer, 0, 4)
|
|
1165
1187
|
export function roundFloat32(float32Number) {
|
|
1166
1188
|
f32Array[0] = float32Number
|
|
1167
1189
|
let multiplier = mult10[((u8Array[3] & 0x7f) << 1) | (u8Array[2] >> 7)]
|