cbor-x 1.6.0 → 1.6.4
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 +8 -7
- package/decode.js +26 -7
- package/dist/decode-no-eval.cjs +26 -7
- package/dist/decode-no-eval.cjs.map +1 -1
- package/dist/index-no-eval.cjs +37 -10
- package/dist/index-no-eval.cjs.map +1 -1
- package/dist/index-no-eval.min.js +1 -1
- package/dist/index-no-eval.min.js.map +1 -1
- package/dist/index.js +37 -10
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/node.cjs +37 -10
- package/dist/node.cjs.map +1 -1
- package/dist/test.js +67 -11
- package/dist/test.js.map +1 -1
- package/encode.js +11 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ This `encode` function will generate standard CBOR without any extensions that s
|
|
|
29
29
|
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 encode and decode functionality is available on Deno, like other platforms.
|
|
30
30
|
|
|
31
31
|
### Streams
|
|
32
|
-
We can use the including streaming functionality (which further improves performance). The `EncoderStream` is a NodeJS transform stream that can be used to serialize objects to a binary stream (writing to network/socket, IPC, etc.), and the `DecoderStream` can be used to deserialize objects from a binary
|
|
32
|
+
We can use the including streaming functionality (which further improves performance). The `EncoderStream` is a NodeJS transform stream that can be used to serialize objects to a binary stream (writing to network/socket, IPC, etc.), and the `DecoderStream` can be used to deserialize objects from a binary stream (reading from network/socket, etc.):
|
|
33
33
|
|
|
34
34
|
```JavaScript
|
|
35
35
|
import { EncoderStream } from 'cbor-x';
|
|
@@ -89,23 +89,22 @@ import { decode } from 'cbor-x/decode' // if you only need to decode
|
|
|
89
89
|
```
|
|
90
90
|
|
|
91
91
|
## Structured Cloning
|
|
92
|
-
You can also use cbor-x for [structured cloning](https://html.spec.whatwg.org/multipage/structured-data.html). By enabling the `structuredClone` option, you can include references to other objects or cyclic references, and object identity will be preserved.
|
|
92
|
+
You can also use cbor-x for [structured cloning](https://html.spec.whatwg.org/multipage/structured-data.html). By enabling the `structuredClone` option, you can include references to other objects or cyclic references, and object identity will be preserved.For example:
|
|
93
93
|
```JavaScript
|
|
94
94
|
let obj = {
|
|
95
|
-
set: new Set(['a', 'b']),
|
|
96
|
-
regular: /a\spattern/
|
|
97
95
|
};
|
|
98
96
|
obj.self = obj;
|
|
99
97
|
let encoder = new Encoder({ structuredClone: true });
|
|
100
98
|
let serialized = encoder.encode(obj);
|
|
101
99
|
let copy = encoder.decode(serialized);
|
|
102
100
|
copy.self === copy // true
|
|
103
|
-
copy.set.has('a') // true
|
|
104
101
|
|
|
105
102
|
```
|
|
106
103
|
|
|
107
104
|
This option is disabled by default because reference checking degrades performance (by about 25-30%). (Note this implementation doesn't serialize every class/type specified in the HTML specification since not all of them make sense for storing across platforms.)
|
|
108
105
|
|
|
106
|
+
cbor-x also preserves certain typed objects like `Error`, `Set`, `RegExp` and TypedArray instances, using [registered CBOR tag extensions](https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml). This works with or without structured cloning enabled.
|
|
107
|
+
|
|
109
108
|
## Record / Object Structures
|
|
110
109
|
There is a critical difference between maps (or dictionaries) that hold an arbitrary set of keys and values (JavaScript `Map` is designed for these), and records or object structures that have a well-defined set of fields. Typical JS objects/records may have many instances re(use) the same structure. By using the record extension, this distinction is preserved in CBOR and the encoding can reuse structures and not only provides better type preservation, but yield much more compact encodings and increase decoding performance by 2-3x. Cbor-x automatically generates record definitions that are reused and referenced by objects with the same structure. Records use CBOR's tags to align well CBOR's tag/extension mechanism. There are a number of ways to use this to our advantage. For large object structures with repeating nested objects with similar structures, simply serializing with the record extension can yield significant benefits. To use the record structures extension, we create a new `Encoder` instance. By default a new `Encoder` instance will have the record extension enabled:
|
|
111
110
|
```JavaScript
|
|
@@ -166,7 +165,7 @@ The principle driver for this feature is to support `application/senml+cbor`cont
|
|
|
166
165
|
Records are also supported in conjunction with keyMaps, but these are disabled by default when keyMaps are specified as use of the two features does not introduce any additional compression efficiency unless that the data arrays are quite large (> 10 items).
|
|
167
166
|
|
|
168
167
|
```JavaScript
|
|
169
|
-
import { Encoder } from 'cbor-x'
|
|
168
|
+
import { Decoder, Encoder } from 'cbor-x'
|
|
170
169
|
const data = [
|
|
171
170
|
{ bn: '/3303/0/5700', bt: 1278887, v: 35.5 },
|
|
172
171
|
{ t: 10, v: 34 },
|
|
@@ -183,7 +182,8 @@ let senmlBuff = senmlCbor.encode(data)
|
|
|
183
182
|
let basicBuff = basicCbor.encode(data)
|
|
184
183
|
console.log('Senml CBOR size:', senmlBuff.length) // 77
|
|
185
184
|
console.log('Basic CBOR size:', basicBuff.length) // 90
|
|
186
|
-
|
|
185
|
+
let senmlDecoder = new Decoder({ keyMap: senmlKeys });
|
|
186
|
+
assert.deepEqual(senmlDecoder.decode(senmlBuff), data)
|
|
187
187
|
|
|
188
188
|
```
|
|
189
189
|
|
|
@@ -213,6 +213,7 @@ The following options properties can be provided to the Encoder or Decoder const
|
|
|
213
213
|
* `useTag259ForMaps` - This flag indicates if [tag 259 (explicit maps)](https://github.com/shanewholloway/js-cbor-codec/blob/master/docs/CBOR-259-spec--explicit-maps.md) should be used to encode JS `Map`s. When using records is enabled, this is disabled by default, since plain objects are encoded with record structures and unambigiously differentiated from `Map`s, which are encoded as CBOR maps. Without using records, this enabled by default and is necessary to distinguish plain objects from `Map`s (but can be disabled by setting this to `false`).
|
|
214
214
|
* `tagUint8Array` - Indicates if tag 64 should be used for `Uint8Array`s.
|
|
215
215
|
* `int64AsNumber` - This will decode uint64 and int64 numbers as standard JS numbers rather than as bigint numbers.
|
|
216
|
+
* `skipFunction` - This skip functions in encode object.
|
|
216
217
|
|
|
217
218
|
### 32-bit Float Options
|
|
218
219
|
By default all non-integer numbers are serialized as 64-bit float (double). This is fast, and ensures maximum precision. However, often real-world data doesn't not need 64-bits of precision, and using 32-bit encoding can be much more space efficient. There are several options that provide more efficient encodings. Using the decimal rounding options for encoding and decoding provides lossless storage of common decimal representations like 7.99, in more efficient 32-bit format (rather than 64-bit). The `useFloat32` property has several possible options, available from the module as constants:
|
package/decode.js
CHANGED
|
@@ -273,6 +273,7 @@ export function read() {
|
|
|
273
273
|
}
|
|
274
274
|
token = dataView.getUint32(position)
|
|
275
275
|
position += 4
|
|
276
|
+
if (majorType === 1) return -1 - token; // can't safely use negation operator here
|
|
276
277
|
break
|
|
277
278
|
case 0x1b:
|
|
278
279
|
if (majorType == 7) {
|
|
@@ -287,8 +288,7 @@ export function read() {
|
|
|
287
288
|
} else if (currentDecoder.int64AsNumber) {
|
|
288
289
|
token = dataView.getUint32(position) * 0x100000000
|
|
289
290
|
token += dataView.getUint32(position + 4)
|
|
290
|
-
} else
|
|
291
|
-
token = dataView.getBigUint64(position)
|
|
291
|
+
} else token = dataView.getBigUint64(position)
|
|
292
292
|
position += 8
|
|
293
293
|
break
|
|
294
294
|
case 0x1f:
|
|
@@ -611,26 +611,45 @@ function readStringJS(length) {
|
|
|
611
611
|
} else if ((byte1 & 0xe0) === 0xc0) {
|
|
612
612
|
// 2 bytes
|
|
613
613
|
const byte2 = src[position++] & 0x3f
|
|
614
|
-
|
|
614
|
+
const codePoint = ((byte1 & 0x1f) << 6) | byte2
|
|
615
|
+
// Reject overlong encoding: 2-byte sequences must encode values >= 0x80
|
|
616
|
+
if (codePoint < 0x80) {
|
|
617
|
+
units.push(0xFFFD) // replacement character
|
|
618
|
+
} else {
|
|
619
|
+
units.push(codePoint)
|
|
620
|
+
}
|
|
615
621
|
} else if ((byte1 & 0xf0) === 0xe0) {
|
|
616
622
|
// 3 bytes
|
|
617
623
|
const byte2 = src[position++] & 0x3f
|
|
618
624
|
const byte3 = src[position++] & 0x3f
|
|
619
|
-
|
|
625
|
+
const codePoint = ((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3
|
|
626
|
+
// Reject overlong encoding: 3-byte sequences must encode values >= 0x800
|
|
627
|
+
// Also reject surrogates (0xD800-0xDFFF)
|
|
628
|
+
if (codePoint < 0x800 || (codePoint >= 0xD800 && codePoint <= 0xDFFF)) {
|
|
629
|
+
units.push(0xFFFD) // replacement character
|
|
630
|
+
} else {
|
|
631
|
+
units.push(codePoint)
|
|
632
|
+
}
|
|
620
633
|
} else if ((byte1 & 0xf8) === 0xf0) {
|
|
621
634
|
// 4 bytes
|
|
622
635
|
const byte2 = src[position++] & 0x3f
|
|
623
636
|
const byte3 = src[position++] & 0x3f
|
|
624
637
|
const byte4 = src[position++] & 0x3f
|
|
625
638
|
let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4
|
|
626
|
-
|
|
639
|
+
// Reject overlong encoding: 4-byte sequences must encode values >= 0x10000
|
|
640
|
+
// Also reject values > 0x10FFFF (maximum valid Unicode)
|
|
641
|
+
if (unit < 0x10000 || unit > 0x10FFFF) {
|
|
642
|
+
units.push(0xFFFD) // replacement character
|
|
643
|
+
} else if (unit > 0xffff) {
|
|
627
644
|
unit -= 0x10000
|
|
628
645
|
units.push(((unit >>> 10) & 0x3ff) | 0xd800)
|
|
629
646
|
unit = 0xdc00 | (unit & 0x3ff)
|
|
647
|
+
units.push(unit)
|
|
648
|
+
} else {
|
|
649
|
+
units.push(unit)
|
|
630
650
|
}
|
|
631
|
-
units.push(unit)
|
|
632
651
|
} else {
|
|
633
|
-
units.push(
|
|
652
|
+
units.push(0xFFFD) // replacement character for invalid lead byte
|
|
634
653
|
}
|
|
635
654
|
|
|
636
655
|
if (units.length >= 0x1000) {
|
package/dist/decode-no-eval.cjs
CHANGED
|
@@ -274,6 +274,7 @@
|
|
|
274
274
|
}
|
|
275
275
|
token = dataView.getUint32(position);
|
|
276
276
|
position += 4;
|
|
277
|
+
if (majorType === 1) return -1 - token; // can't safely use negation operator here
|
|
277
278
|
break
|
|
278
279
|
case 0x1b:
|
|
279
280
|
if (majorType == 7) {
|
|
@@ -288,8 +289,7 @@
|
|
|
288
289
|
} else if (currentDecoder.int64AsNumber) {
|
|
289
290
|
token = dataView.getUint32(position) * 0x100000000;
|
|
290
291
|
token += dataView.getUint32(position + 4);
|
|
291
|
-
} else
|
|
292
|
-
token = dataView.getBigUint64(position);
|
|
292
|
+
} else token = dataView.getBigUint64(position);
|
|
293
293
|
position += 8;
|
|
294
294
|
break
|
|
295
295
|
case 0x1f:
|
|
@@ -606,26 +606,45 @@
|
|
|
606
606
|
} else if ((byte1 & 0xe0) === 0xc0) {
|
|
607
607
|
// 2 bytes
|
|
608
608
|
const byte2 = src[position++] & 0x3f;
|
|
609
|
-
|
|
609
|
+
const codePoint = ((byte1 & 0x1f) << 6) | byte2;
|
|
610
|
+
// Reject overlong encoding: 2-byte sequences must encode values >= 0x80
|
|
611
|
+
if (codePoint < 0x80) {
|
|
612
|
+
units.push(0xFFFD); // replacement character
|
|
613
|
+
} else {
|
|
614
|
+
units.push(codePoint);
|
|
615
|
+
}
|
|
610
616
|
} else if ((byte1 & 0xf0) === 0xe0) {
|
|
611
617
|
// 3 bytes
|
|
612
618
|
const byte2 = src[position++] & 0x3f;
|
|
613
619
|
const byte3 = src[position++] & 0x3f;
|
|
614
|
-
|
|
620
|
+
const codePoint = ((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3;
|
|
621
|
+
// Reject overlong encoding: 3-byte sequences must encode values >= 0x800
|
|
622
|
+
// Also reject surrogates (0xD800-0xDFFF)
|
|
623
|
+
if (codePoint < 0x800 || (codePoint >= 0xD800 && codePoint <= 0xDFFF)) {
|
|
624
|
+
units.push(0xFFFD); // replacement character
|
|
625
|
+
} else {
|
|
626
|
+
units.push(codePoint);
|
|
627
|
+
}
|
|
615
628
|
} else if ((byte1 & 0xf8) === 0xf0) {
|
|
616
629
|
// 4 bytes
|
|
617
630
|
const byte2 = src[position++] & 0x3f;
|
|
618
631
|
const byte3 = src[position++] & 0x3f;
|
|
619
632
|
const byte4 = src[position++] & 0x3f;
|
|
620
633
|
let unit = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4;
|
|
621
|
-
|
|
634
|
+
// Reject overlong encoding: 4-byte sequences must encode values >= 0x10000
|
|
635
|
+
// Also reject values > 0x10FFFF (maximum valid Unicode)
|
|
636
|
+
if (unit < 0x10000 || unit > 0x10FFFF) {
|
|
637
|
+
units.push(0xFFFD); // replacement character
|
|
638
|
+
} else if (unit > 0xffff) {
|
|
622
639
|
unit -= 0x10000;
|
|
623
640
|
units.push(((unit >>> 10) & 0x3ff) | 0xd800);
|
|
624
641
|
unit = 0xdc00 | (unit & 0x3ff);
|
|
642
|
+
units.push(unit);
|
|
643
|
+
} else {
|
|
644
|
+
units.push(unit);
|
|
625
645
|
}
|
|
626
|
-
units.push(unit);
|
|
627
646
|
} else {
|
|
628
|
-
units.push(
|
|
647
|
+
units.push(0xFFFD); // replacement character for invalid lead byte
|
|
629
648
|
}
|
|
630
649
|
|
|
631
650
|
if (units.length >= 0x1000) {
|