microcbor 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -74
- package/lib/decode.d.ts +2 -8
- package/lib/decode.js +124 -157
- package/lib/decodeStream.d.ts +2 -0
- package/lib/decodeStream.js +205 -0
- package/lib/encode.d.ts +35 -4
- package/lib/encode.js +184 -176
- package/lib/encodeStream.d.ts +4 -0
- package/lib/encodeStream.js +8 -0
- package/lib/encodingLength.d.ts +2 -0
- package/lib/encodingLength.js +169 -0
- package/lib/index.d.ts +6 -2
- package/lib/index.js +6 -2
- package/lib/types.d.ts +6 -0
- package/lib/types.js +1 -0
- package/lib/utils.d.ts +6 -0
- package/lib/utils.js +8 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/RichardLitt/standard-readme) [](https://opensource.org/licenses/MIT) [](https://www.npmjs.com/package/microcbor)  
|
|
4
4
|
|
|
5
|
-
Encode
|
|
5
|
+
Encode JavaScript values as canonical CBOR.
|
|
6
6
|
|
|
7
|
-
microcbor is a [CBOR](https://cbor.io/) implementation
|
|
7
|
+
microcbor is a minimal JavaScript [CBOR](https://cbor.io/) implementation. You can use microcbor to serialize JavaScript values to CBOR, and to deserialize them back into JavaScript values again. **microcbor doesn't support tags, bigints, typed arrays, non-string keys, or indefinite-length collections.**
|
|
8
8
|
|
|
9
|
-
microcbor
|
|
9
|
+
microcbor follows the [deterministic CBOR encoding requirements](https://www.rfc-editor.org/rfc/rfc8949.html#core-det) - all floating-point numbers are serialized in the smallest possible size without losing precision, and object entries are always sorted by key in byte-wise lexicographic order. `NaN` is always serialized as `0xf97e00`.
|
|
10
10
|
|
|
11
11
|
This library is TypeScript-native, ESM-only, and has just one dependency ([joeltg/fp16](https://github.com/joeltg/fp16) for half-precision floats). It works in Node, the browser, and Deno.
|
|
12
12
|
|
|
@@ -15,11 +15,13 @@ This library is TypeScript-native, ESM-only, and has just one dependency ([joelt
|
|
|
15
15
|
- [Install](#install)
|
|
16
16
|
- [Usage](#usage)
|
|
17
17
|
- [API](#api)
|
|
18
|
+
- [Value types](#value-types)
|
|
18
19
|
- [Encoding](#encoding)
|
|
19
20
|
- [Decoding](#decoding)
|
|
20
|
-
- [
|
|
21
|
-
- [
|
|
21
|
+
- [Encoding length](#encoding-length)
|
|
22
|
+
- [Support](#support)
|
|
22
23
|
- [Testing](#testing)
|
|
24
|
+
- [Benchmarks](#benchmarks)
|
|
23
25
|
- [Contributing](#contributing)
|
|
24
26
|
- [License](#license)
|
|
25
27
|
|
|
@@ -32,7 +34,15 @@ npm i microcbor
|
|
|
32
34
|
Or in Deno:
|
|
33
35
|
|
|
34
36
|
```typescript
|
|
35
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
encode,
|
|
39
|
+
decode,
|
|
40
|
+
encodeStream,
|
|
41
|
+
decodeStream,
|
|
42
|
+
encodingLength,
|
|
43
|
+
CBORValue,
|
|
44
|
+
UnsafeIntegerError,
|
|
45
|
+
} from "https://cdn.skypack.dev/microcbor"
|
|
36
46
|
```
|
|
37
47
|
|
|
38
48
|
## Usage
|
|
@@ -55,91 +65,63 @@ console.log(decode(data))
|
|
|
55
65
|
|
|
56
66
|
## API
|
|
57
67
|
|
|
58
|
-
###
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
### Value types
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
declare type CBORValue =
|
|
72
|
+
| undefined
|
|
73
|
+
| null
|
|
74
|
+
| boolean
|
|
75
|
+
| number
|
|
76
|
+
| string
|
|
77
|
+
| Uint8Array
|
|
78
|
+
| CBORArray
|
|
79
|
+
| CBORMap
|
|
80
|
+
|
|
81
|
+
interface CBORArray extends Array<CBORValue> {}
|
|
82
|
+
interface CBORMap {
|
|
83
|
+
[key: string]: CBORValue
|
|
64
84
|
}
|
|
65
|
-
|
|
66
|
-
declare function encode(value: any, options: EncodeOptions = {}): Uint8Array
|
|
67
85
|
```
|
|
68
86
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
| property | type | default |
|
|
72
|
-
| ------------ | ------- | ------- |
|
|
73
|
-
| `strictJSON` | boolean | false |
|
|
74
|
-
| `chunkSize` | number | 512 |
|
|
75
|
-
|
|
76
|
-
### Decoding
|
|
87
|
+
### Encoding
|
|
77
88
|
|
|
78
89
|
```typescript
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
90
|
+
declare function encode(
|
|
91
|
+
value: CBORValue,
|
|
92
|
+
options: { chunkSize?: number } = {}
|
|
93
|
+
): Uint8Array
|
|
94
|
+
|
|
95
|
+
declare function encodeStream(
|
|
96
|
+
source: AsyncIterable<CBORValue>,
|
|
97
|
+
options?: { chunkSize?: number }
|
|
98
|
+
): AsyncIterable<Uint8Array>
|
|
87
99
|
```
|
|
88
100
|
|
|
89
|
-
`
|
|
90
|
-
|
|
91
|
-
| property | type | default |
|
|
92
|
-
| ------------ | ------- | ------- |
|
|
93
|
-
| `strictJSON` | boolean | false |
|
|
94
|
-
|
|
95
|
-
### Strict mode
|
|
96
|
-
|
|
97
|
-
Technically, neither `NaN` nor `+/- Infinity` are valid JSON numbers. But microcbor functions as a direct interface between JavaScript and CBOR, so by default, you can encode them...
|
|
101
|
+
If not provided, `chunkSize` defaults to 512 bytes. It's only a guideline; `encodeStream` won't break up individual CBOR values like strings or byte arrays that are larger than the provided chunk size.
|
|
98
102
|
|
|
99
|
-
|
|
100
|
-
import { encode } from "microcbor"
|
|
101
|
-
|
|
102
|
-
encode(NaN) // Uint8Array(3) [ 249, 126, 0 ]
|
|
103
|
-
encode(Infinity) // Uint8Array(3) [ 249, 124, 0 ]
|
|
104
|
-
encode(-Infinity) // Uint8Array(3) [ 249, 252, 0 ]
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
... and decode them...
|
|
103
|
+
### Decoding
|
|
108
104
|
|
|
109
|
-
```
|
|
110
|
-
|
|
105
|
+
```typescript
|
|
106
|
+
declare function decode(data: Uint8Array): CBORValue
|
|
111
107
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
108
|
+
declare function decodeStream(
|
|
109
|
+
source: AsyncIterable<Uint8Array>
|
|
110
|
+
): AsyncIterable<CBORValue>
|
|
115
111
|
```
|
|
116
112
|
|
|
117
|
-
|
|
113
|
+
### Encoding length
|
|
118
114
|
|
|
119
|
-
|
|
120
|
-
import { encode } from "microcbor"
|
|
115
|
+
You can measure the byte length that a given value will serialize to without actually allocating anything.
|
|
121
116
|
|
|
122
|
-
|
|
123
|
-
|
|
117
|
+
```ts
|
|
118
|
+
declare function encodingLength(value: CBORValue): number
|
|
124
119
|
```
|
|
125
120
|
|
|
126
|
-
|
|
127
|
-
import { decode } from "microcbor"
|
|
128
|
-
|
|
129
|
-
decode(new Uint8Array([249, 126, 0]), { strictJSON: true })
|
|
130
|
-
// Uncaught Error: cannot decode NaN when strict mode is enabled
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
For reference, `JSON.stringify` returns `"null"` when called with `NaN` or `+/- Infinity`.
|
|
134
|
-
|
|
135
|
-
## Limitations
|
|
136
|
-
|
|
137
|
-
JSON numbers can be arbitrarly large and have unlimited decimal precision. CBOR has explicit types for the standard fixed-size integer and float formats, and separate tags for [arbitrarily large integers](https://www.rfc-editor.org/rfc/rfc8949.html#name-bignums) and [unlimited-precision decimal values](https://www.rfc-editor.org/rfc/rfc8949.html#name-decimal-fractions-and-bigfl). Meanwhile, JavaScript can only represent numbers as 64-bit floats or BigInts. This means there are always tradeoffs in interfacing between JSON, CBOR, and JavaScript.
|
|
138
|
-
|
|
139
|
-
microcbor takes an opinionated, minimal stance:
|
|
121
|
+
## Unsafe integer handling
|
|
140
122
|
|
|
141
123
|
- JavaScript integers below `Number.MIN_SAFE_INTEGER` or greater than `Number.MAX_SAFE_INTEGER` will encode as CBOR floating-point numbers, as per the [suggestion in the CBOR spec](https://www.rfc-editor.org/rfc/rfc8949.html#name-converting-from-json-to-cbo).
|
|
142
|
-
- decoding CBOR integers less than `Number.MIN_SAFE_INTEGER` (major type 1 with uint64 argument greater than `2^53-2`) or greater than `Number.MAX_SAFE_INTEGER` (major type 0 with uint64 argument greater than `2^53-1`) **will throw an error**. The error will be an instance of `UnsafeIntegerError` and will have the out-of-range value as a readonly `.value: bigint` property.
|
|
124
|
+
- decoding **CBOR integers** less than `Number.MIN_SAFE_INTEGER` (major type 1 with uint64 argument greater than `2^53-2`) or greater than `Number.MAX_SAFE_INTEGER` (major type 0 with uint64 argument greater than `2^53-1`) **will throw an error**. The error will be an instance of `UnsafeIntegerError` and will have the out-of-range value as a readonly `.value: bigint` property.
|
|
143
125
|
|
|
144
126
|
```typescript
|
|
145
127
|
declare class UnsafeIntegerError extends RangeError {
|
|
@@ -148,14 +130,52 @@ declare class UnsafeIntegerError extends RangeError {
|
|
|
148
130
|
}
|
|
149
131
|
```
|
|
150
132
|
|
|
133
|
+
## Value mapping
|
|
134
|
+
|
|
135
|
+
| CBOR major type | JavaScript | notes |
|
|
136
|
+
| ---------------------------- | -------------- | -------------------------------------------------------- |
|
|
137
|
+
| `0` (non-negative integer) | `number` | decoding throws an `UnsafeIntegerError` on unsafe values |
|
|
138
|
+
| `1` (negative integer) | `number` | decoding throws an `UnsafeIntegerError` on unsafe values |
|
|
139
|
+
| `2` (byte string) | `Uint8Array` | |
|
|
140
|
+
| `3` (UTF-8 string) | `string` | |
|
|
141
|
+
| `4` (array) | `Array` | |
|
|
142
|
+
| `5` (map) | `Object` | decoding throws an error on non-string keys |
|
|
143
|
+
| `6` (tagged item) | Unsupported ❌ | decoding throws an error on non-string keys |
|
|
144
|
+
| `7` (floating-point numbers) | `number` | |
|
|
145
|
+
| `7` (booleans) | `boolean` | |
|
|
146
|
+
| `7` (null) | `null` | |
|
|
147
|
+
| `7` (undefined) | `undefined` | |
|
|
148
|
+
|
|
151
149
|
## Testing
|
|
152
150
|
|
|
153
|
-
Tests use [AVA
|
|
151
|
+
Tests use [AVA](https://github.com/avajs/ava) and live in the [test](./test/) directory. Tests use [node-cbor](https://github.com/hildjj/node-cbor/) to validate encoding results. More tests are always welcome!
|
|
154
152
|
|
|
155
153
|
```
|
|
156
154
|
npm run test
|
|
157
155
|
```
|
|
158
156
|
|
|
157
|
+
## Benchmarks
|
|
158
|
+
|
|
159
|
+
Basic testing in [src/benchmarks.test.js](src/benchmarks.test.js) indicate that microcbor is about **2x as fast** as node-cbor at encoding and about **1.5x as fast** as node-cbor at decoding.
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
microcbor % npm run test -- test/benchmarks.test.js
|
|
163
|
+
|
|
164
|
+
> microcbor@0.2.0 test
|
|
165
|
+
> ava
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
✔ time encode() (382ms)
|
|
169
|
+
ℹ microcbor: 63.44141721725464 (ms)
|
|
170
|
+
ℹ node-cbor: 152.31466674804688 (ms)
|
|
171
|
+
✔ time decode() (164ms)
|
|
172
|
+
ℹ microcbor: 72.13012504577637 (ms)
|
|
173
|
+
ℹ node-cbor: 87.16287469863892 (ms)
|
|
174
|
+
─
|
|
175
|
+
|
|
176
|
+
2 tests passed
|
|
177
|
+
```
|
|
178
|
+
|
|
159
179
|
## Contributing
|
|
160
180
|
|
|
161
181
|
I don't expect to add any additional features to this library. But if you have suggestions for better interfaces, find a bug, or would like to add more tests, please open an issue to discuss it!
|
package/lib/decode.d.ts
CHANGED
|
@@ -1,8 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
}
|
|
4
|
-
export declare class UnsafeIntegerError extends RangeError {
|
|
5
|
-
readonly value: bigint;
|
|
6
|
-
constructor(message: string, value: bigint);
|
|
7
|
-
}
|
|
8
|
-
export declare function decode<T = any>(data: Uint8Array, options?: DecodeOptions): T;
|
|
1
|
+
import type { CBORValue } from "./types.js";
|
|
2
|
+
export declare function decode(data: Uint8Array): CBORValue;
|
package/lib/decode.js
CHANGED
|
@@ -1,174 +1,141 @@
|
|
|
1
1
|
import { getFloat16 } from "fp16";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const value =
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return value;
|
|
26
|
-
},
|
|
27
|
-
float64(state) {
|
|
28
|
-
const value = state.view.getFloat64(state.offset);
|
|
29
|
-
validateFloat(state, value);
|
|
30
|
-
state.offset += 8;
|
|
31
|
-
return value;
|
|
32
|
-
},
|
|
33
|
-
uint8(state) {
|
|
34
|
-
const value = state.view.getUint8(state.offset);
|
|
35
|
-
state.offset += 1;
|
|
36
|
-
return value;
|
|
37
|
-
},
|
|
38
|
-
uint16(state) {
|
|
39
|
-
const value = state.view.getUint16(state.offset);
|
|
40
|
-
state.offset += 2;
|
|
41
|
-
return value;
|
|
42
|
-
},
|
|
43
|
-
uint32(state) {
|
|
44
|
-
const value = state.view.getUint32(state.offset);
|
|
45
|
-
state.offset += 4;
|
|
46
|
-
return value;
|
|
47
|
-
},
|
|
48
|
-
uint64(state) {
|
|
49
|
-
const value = state.view.getBigUint64(state.offset);
|
|
50
|
-
state.offset += 8;
|
|
2
|
+
import { UnsafeIntegerError, maxSafeInteger, minSafeInteger } from "./utils.js";
|
|
3
|
+
class Decoder {
|
|
4
|
+
constructor(data) {
|
|
5
|
+
this.data = data;
|
|
6
|
+
this.constant = (size, f) => () => {
|
|
7
|
+
const value = f();
|
|
8
|
+
this.offset += size;
|
|
9
|
+
return value;
|
|
10
|
+
};
|
|
11
|
+
this.float16 = this.constant(2, () => getFloat16(this.view, this.offset));
|
|
12
|
+
this.float32 = this.constant(4, () => this.view.getFloat32(this.offset));
|
|
13
|
+
this.float64 = this.constant(8, () => this.view.getFloat64(this.offset));
|
|
14
|
+
this.uint8 = this.constant(1, () => this.view.getUint8(this.offset));
|
|
15
|
+
this.uint16 = this.constant(2, () => this.view.getUint16(this.offset));
|
|
16
|
+
this.uint32 = this.constant(4, () => this.view.getUint32(this.offset));
|
|
17
|
+
this.uint64 = this.constant(8, () => this.view.getBigUint64(this.offset));
|
|
18
|
+
this.offset = 0;
|
|
19
|
+
this.view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
20
|
+
}
|
|
21
|
+
decodeBytes(length) {
|
|
22
|
+
const value = new Uint8Array(length);
|
|
23
|
+
value.set(this.data.subarray(this.offset, this.offset + length), 0);
|
|
24
|
+
this.offset += length;
|
|
51
25
|
return value;
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
function decodeString(state, length) {
|
|
55
|
-
const view = new DataView(state.view.buffer, state.view.byteOffset + state.offset, length);
|
|
56
|
-
state.offset += length;
|
|
57
|
-
return new TextDecoder().decode(view);
|
|
58
|
-
}
|
|
59
|
-
function getArgument(state, additionalInformation) {
|
|
60
|
-
if (additionalInformation < 24) {
|
|
61
|
-
return { value: additionalInformation };
|
|
62
|
-
}
|
|
63
|
-
else if (additionalInformation === 24) {
|
|
64
|
-
return { value: constants.uint8(state) };
|
|
65
26
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return { value: constants.uint32(state) };
|
|
71
|
-
}
|
|
72
|
-
else if (additionalInformation === 27) {
|
|
73
|
-
const uint64 = constants.uint64(state);
|
|
74
|
-
const value = maxSafeInteger < uint64 ? Infinity : Number(uint64);
|
|
75
|
-
return { value, uint64 };
|
|
76
|
-
}
|
|
77
|
-
else if (additionalInformation === 31) {
|
|
78
|
-
throw new Error("microcbor does not support decoding indefinite-length items");
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
throw new Error("invalid argument encoding");
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
export class UnsafeIntegerError extends RangeError {
|
|
85
|
-
constructor(message, value) {
|
|
86
|
-
super(message);
|
|
87
|
-
this.value = value;
|
|
27
|
+
decodeString(length) {
|
|
28
|
+
const value = new TextDecoder().decode(this.data.subarray(this.offset, this.offset + length));
|
|
29
|
+
this.offset += length;
|
|
30
|
+
return value;
|
|
88
31
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const majorType = initialByte >> 5;
|
|
93
|
-
const additionalInformation = initialByte & 0x1f;
|
|
94
|
-
if (majorType === 0) {
|
|
95
|
-
const { value, uint64 } = getArgument(state, additionalInformation);
|
|
96
|
-
if (uint64 !== undefined && maxSafeInteger < uint64) {
|
|
97
|
-
throw new UnsafeIntegerError("cannot decode integers greater than 2^53-1", uint64);
|
|
32
|
+
getArgument(additionalInformation) {
|
|
33
|
+
if (additionalInformation < 24) {
|
|
34
|
+
return { value: additionalInformation };
|
|
98
35
|
}
|
|
99
|
-
else {
|
|
100
|
-
return value;
|
|
36
|
+
else if (additionalInformation === 24) {
|
|
37
|
+
return { value: this.uint8() };
|
|
101
38
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
39
|
+
else if (additionalInformation === 25) {
|
|
40
|
+
return { value: this.uint16() };
|
|
41
|
+
}
|
|
42
|
+
else if (additionalInformation === 26) {
|
|
43
|
+
return { value: this.uint32() };
|
|
44
|
+
}
|
|
45
|
+
else if (additionalInformation === 27) {
|
|
46
|
+
const uint64 = this.uint64();
|
|
47
|
+
const value = maxSafeInteger < uint64 ? Infinity : Number(uint64);
|
|
48
|
+
return { value, uint64 };
|
|
49
|
+
}
|
|
50
|
+
else if (additionalInformation === 31) {
|
|
51
|
+
throw new Error("microcbor does not support decoding indefinite-length items");
|
|
107
52
|
}
|
|
108
53
|
else {
|
|
109
|
-
|
|
54
|
+
throw new Error("invalid argument encoding");
|
|
110
55
|
}
|
|
111
56
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
57
|
+
decodeValue() {
|
|
58
|
+
const initialByte = this.uint8();
|
|
59
|
+
const majorType = initialByte >> 5;
|
|
60
|
+
const additionalInformation = initialByte & 0x1f;
|
|
61
|
+
if (majorType === 0) {
|
|
62
|
+
const { value, uint64 } = this.getArgument(additionalInformation);
|
|
63
|
+
if (uint64 !== undefined && maxSafeInteger < uint64) {
|
|
64
|
+
throw new UnsafeIntegerError("cannot decode integers greater than 2^53-1", uint64);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
return value;
|
|
68
|
+
}
|
|
124
69
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (typeof key !== "string") {
|
|
133
|
-
throw new Error("microcbor only supports string keys in objects");
|
|
70
|
+
else if (majorType === 1) {
|
|
71
|
+
const { value, uint64 } = this.getArgument(additionalInformation);
|
|
72
|
+
if (uint64 !== undefined && -1n - uint64 < minSafeInteger) {
|
|
73
|
+
throw new UnsafeIntegerError("cannot decode integers less than -2^53+1", -1n - uint64);
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
return -1 - value;
|
|
134
77
|
}
|
|
135
|
-
value[key] = decodeValue(state);
|
|
136
78
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
79
|
+
else if (majorType === 2) {
|
|
80
|
+
const { value: length } = this.getArgument(additionalInformation);
|
|
81
|
+
return this.decodeBytes(length);
|
|
82
|
+
}
|
|
83
|
+
else if (majorType === 3) {
|
|
84
|
+
const { value: length } = this.getArgument(additionalInformation);
|
|
85
|
+
return this.decodeString(length);
|
|
86
|
+
}
|
|
87
|
+
else if (majorType === 4) {
|
|
88
|
+
const { value: length } = this.getArgument(additionalInformation);
|
|
89
|
+
const value = new Array(length);
|
|
90
|
+
for (let i = 0; i < length; i++) {
|
|
91
|
+
value[i] = this.decodeValue();
|
|
92
|
+
}
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
else if (majorType === 5) {
|
|
96
|
+
const { value: length } = this.getArgument(additionalInformation);
|
|
97
|
+
const value = {};
|
|
98
|
+
for (let i = 0; i < length; i++) {
|
|
99
|
+
const key = this.decodeValue();
|
|
100
|
+
if (typeof key !== "string") {
|
|
101
|
+
throw new Error("microcbor only supports string keys in objects");
|
|
102
|
+
}
|
|
103
|
+
value[key] = this.decodeValue();
|
|
104
|
+
}
|
|
105
|
+
return value;
|
|
106
|
+
}
|
|
107
|
+
else if (majorType === 6) {
|
|
108
|
+
throw new Error("microcbor does not support tagged data items");
|
|
109
|
+
}
|
|
110
|
+
else if (majorType === 7) {
|
|
111
|
+
switch (additionalInformation) {
|
|
112
|
+
case 20:
|
|
113
|
+
return false;
|
|
114
|
+
case 21:
|
|
115
|
+
return true;
|
|
116
|
+
case 22:
|
|
117
|
+
return null;
|
|
118
|
+
case 23:
|
|
119
|
+
return undefined;
|
|
120
|
+
case 24:
|
|
121
|
+
throw new Error("microcbor does not support decoding unassigned simple values");
|
|
122
|
+
case 25:
|
|
123
|
+
return this.float16();
|
|
124
|
+
case 26:
|
|
125
|
+
return this.float32();
|
|
126
|
+
case 27:
|
|
127
|
+
return this.float64();
|
|
128
|
+
case 31:
|
|
129
|
+
throw new Error("microcbor does not support decoding indefinite-length items");
|
|
130
|
+
default:
|
|
131
|
+
throw new Error("invalid simple value");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
throw new Error("invalid major type");
|
|
164
136
|
}
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
throw new Error("invalid major type");
|
|
168
137
|
}
|
|
169
138
|
}
|
|
170
|
-
export function decode(data
|
|
171
|
-
|
|
172
|
-
const state = { options, offset: 0, view };
|
|
173
|
-
return decodeValue(state);
|
|
139
|
+
export function decode(data) {
|
|
140
|
+
return new Decoder(data).decodeValue();
|
|
174
141
|
}
|