@atcute/cbor 2.0.0 → 2.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 +3 -6
- package/dist/decode.js +63 -62
- package/dist/decode.js.map +1 -1
- package/dist/encode.js +186 -142
- package/dist/encode.js.map +1 -1
- package/lib/decode.ts +65 -75
- package/lib/encode.ts +209 -162
- package/package.json +14 -8
package/README.md
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
# @atcute/cbor
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
lightweight [DASL dCBOR42 (deterministic CBOR with tag 42)][dasl-dcbor42] codec library for AT
|
|
4
|
+
Protocol.
|
|
4
5
|
|
|
5
|
-
-
|
|
6
|
-
- No `Map` objects, it will always be plain objects with string keys
|
|
7
|
-
- No `undefined` values, it will be skipped or will throw an error
|
|
8
|
-
- No tagged value support other than CID, which gets converted to a cid-link interface
|
|
9
|
-
- Same goes for byte arrays, gets converted to a byte interface
|
|
6
|
+
[dasl-dcbor42]: https://dasl.ing/dcbor42.html
|
|
10
7
|
|
|
11
8
|
```ts
|
|
12
9
|
import { encode } from '@atcute/cbor';
|
package/dist/decode.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CidLinkWrapper } from '@atcute/cid';
|
|
2
|
+
import { decodeUtf8From } from '@atcute/uint8array';
|
|
2
3
|
import { toBytes } from './bytes.js';
|
|
3
|
-
const utf8d = new TextDecoder();
|
|
4
4
|
const readArgument = (state, info) => {
|
|
5
5
|
if (info < 24) {
|
|
6
6
|
return info;
|
|
@@ -23,9 +23,7 @@ const readFloat64 = (state) => {
|
|
|
23
23
|
return value;
|
|
24
24
|
};
|
|
25
25
|
const readUint8 = (state) => {
|
|
26
|
-
|
|
27
|
-
state.p += 1;
|
|
28
|
-
return value;
|
|
26
|
+
return state.b[state.p++];
|
|
29
27
|
};
|
|
30
28
|
const readUint16 = (state) => {
|
|
31
29
|
const value = state.v.getUint16(state.p);
|
|
@@ -49,13 +47,18 @@ const readUint64 = (state) => {
|
|
|
49
47
|
return value;
|
|
50
48
|
};
|
|
51
49
|
const readString = (state, length) => {
|
|
52
|
-
const
|
|
53
|
-
|
|
50
|
+
const string = decodeUtf8From(state.b, state.p, length);
|
|
51
|
+
state.p += length;
|
|
52
|
+
return string;
|
|
54
53
|
};
|
|
55
54
|
const readBytes = (state, length) => {
|
|
56
55
|
const slice = state.b.subarray(state.p, (state.p += length));
|
|
57
56
|
return toBytes(slice);
|
|
58
57
|
};
|
|
58
|
+
const readTypeInfo = (state) => {
|
|
59
|
+
const prelude = readUint8(state);
|
|
60
|
+
return [prelude >> 5, prelude & 0x1f];
|
|
61
|
+
};
|
|
59
62
|
const readCid = (state, length) => {
|
|
60
63
|
// CID bytes are prefixed with 0x00 for historical reasons, apparently.
|
|
61
64
|
const slice = state.b.subarray(state.p + 1, (state.p += length));
|
|
@@ -65,68 +68,66 @@ const readValue = (state) => {
|
|
|
65
68
|
const prelude = readUint8(state);
|
|
66
69
|
const type = prelude >> 5;
|
|
67
70
|
const info = prelude & 0x1f;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if (type === 1) {
|
|
73
|
-
const value = readArgument(state, info);
|
|
74
|
-
return -1 - value;
|
|
75
|
-
}
|
|
76
|
-
if (type === 2) {
|
|
77
|
-
const len = readArgument(state, info);
|
|
78
|
-
return readBytes(state, len);
|
|
79
|
-
}
|
|
80
|
-
if (type === 3) {
|
|
81
|
-
const len = readArgument(state, info);
|
|
82
|
-
return readString(state, len);
|
|
83
|
-
}
|
|
84
|
-
if (type === 4) {
|
|
85
|
-
const len = readArgument(state, info);
|
|
86
|
-
const array = new Array(len);
|
|
87
|
-
for (let idx = 0; idx < len; idx++) {
|
|
88
|
-
array[idx] = readValue(state);
|
|
71
|
+
const arg = type < 7 ? readArgument(state, info) : 0;
|
|
72
|
+
switch (type) {
|
|
73
|
+
case 0: {
|
|
74
|
+
return arg;
|
|
89
75
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
76
|
+
case 1: {
|
|
77
|
+
return -1 - arg;
|
|
78
|
+
}
|
|
79
|
+
case 2: {
|
|
80
|
+
return readBytes(state, arg);
|
|
81
|
+
}
|
|
82
|
+
case 3: {
|
|
83
|
+
return readString(state, arg);
|
|
84
|
+
}
|
|
85
|
+
case 4: {
|
|
86
|
+
const array = new Array(arg);
|
|
87
|
+
for (let idx = 0; idx < arg; idx++) {
|
|
88
|
+
array[idx] = readValue(state);
|
|
99
89
|
}
|
|
100
|
-
|
|
90
|
+
return array;
|
|
101
91
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
92
|
+
case 5: {
|
|
93
|
+
const object = {};
|
|
94
|
+
for (let idx = 0; idx < arg; idx++) {
|
|
95
|
+
const [type, info] = readTypeInfo(state);
|
|
96
|
+
if (type !== 3) {
|
|
97
|
+
throw new TypeError(`expected map to only have string keys; got type ${type}`);
|
|
98
|
+
}
|
|
99
|
+
const len = readArgument(state, info);
|
|
100
|
+
const key = readString(state, len);
|
|
101
|
+
if (key === '__proto__')
|
|
102
|
+
// Guard against prototype pollution. CWE-1321
|
|
103
|
+
Object.defineProperty(object, key, { enumerable: true, configurable: true, writable: true });
|
|
104
|
+
object[key] = readValue(state);
|
|
112
105
|
}
|
|
113
|
-
|
|
114
|
-
return readCid(state, len);
|
|
106
|
+
return object;
|
|
115
107
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
return
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
108
|
+
case 6: {
|
|
109
|
+
if (arg === 42) {
|
|
110
|
+
const [type, info] = readTypeInfo(state);
|
|
111
|
+
if (type !== 2) {
|
|
112
|
+
throw new TypeError(`expected cid-link to be type 2 (bytes); got type ${type}`);
|
|
113
|
+
}
|
|
114
|
+
const len = readArgument(state, info);
|
|
115
|
+
return readCid(state, len);
|
|
116
|
+
}
|
|
117
|
+
throw new TypeError(`unsupported tag; got ${arg}`);
|
|
118
|
+
}
|
|
119
|
+
case 7: {
|
|
120
|
+
switch (info) {
|
|
121
|
+
case 20:
|
|
122
|
+
case 21:
|
|
123
|
+
return info === 21;
|
|
124
|
+
case 22:
|
|
125
|
+
return null;
|
|
126
|
+
case 27:
|
|
127
|
+
return readFloat64(state);
|
|
128
|
+
}
|
|
129
|
+
throw new Error(`invalid simple value; got ${info}`);
|
|
128
130
|
}
|
|
129
|
-
throw new Error(`invalid simple value; got ${info}`);
|
|
130
131
|
}
|
|
131
132
|
throw new TypeError(`invalid type; got ${type}`);
|
|
132
133
|
};
|
package/dist/decode.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decode.js","sourceRoot":"","sources":["../lib/decode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAgB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"decode.js","sourceRoot":"","sources":["../lib/decode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAgB,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,OAAO,EAAE,OAAO,EAAc,MAAM,YAAY,CAAC;AAQjD,MAAM,YAAY,GAAG,CAAC,KAAY,EAAE,IAAY,EAAU,EAAE;IAC3D,IAAI,IAAI,GAAG,EAAE,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACb,CAAC;IAED,QAAQ,IAAI,EAAE,CAAC;QACd,KAAK,EAAE;YACN,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;QACzB,KAAK,EAAE;YACN,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;QAC1B,KAAK,EAAE;YACN,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;QAC1B,KAAK,EAAE;YACN,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,EAAE,CAAC,CAAC;AAC3D,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,KAAY,EAAU,EAAE;IAC5C,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE1C,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;IACb,OAAO,KAAK,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,KAAY,EAAU,EAAE;IAC1C,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;AAC3B,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,KAAY,EAAU,EAAE;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEzC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;IACb,OAAO,KAAK,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,KAAY,EAAU,EAAE;IAC3C,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEzC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;IACb,OAAO,KAAK,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,KAAY,EAAU,EAAE;IAC3C,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAE1C,IAAI,EAAE,GAAG,QAAQ,EAAE,CAAC;QACnB,MAAM,IAAI,UAAU,CAAC,iDAAiD,CAAC,CAAC;IACzE,CAAC;IAED,kBAAkB;IAClB,MAAM,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;IAEpC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;IACb,OAAO,KAAK,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,KAAY,EAAE,MAAc,EAAU,EAAE;IAC3D,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACxD,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC;IAElB,OAAO,MAAM,CAAC;AACf,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,KAAY,EAAE,MAAc,EAAS,EAAE;IACzD,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC;IAE7D,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,KAAY,EAAoB,EAAE;IACvD,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IACjC,OAAO,CAAC,OAAO,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,CAAC;AACvC,CAAC,CAAC;AAEF,MAAM,OAAO,GAAG,CAAC,KAAY,EAAE,MAAc,EAAW,EAAE;IACzD,uEAAuE;IACvE,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC;IAEjE,OAAO,IAAI,cAAc,CAAC,KAAK,CAAC,CAAC;AAClC,CAAC,CAAC;AAEF,MAAM,SAAS,GAAG,CAAC,KAAY,EAAO,EAAE;IACvC,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAEjC,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG,OAAO,GAAG,IAAI,CAAC;IAC5B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAErD,QAAQ,IAAI,EAAE,CAAC;QACd,KAAK,CAAC,CAAC,CAAC,CAAC;YACR,OAAO,GAAG,CAAC;QACZ,CAAC;QACD,KAAK,CAAC,CAAC,CAAC,CAAC;YACR,OAAO,CAAC,CAAC,GAAG,GAAG,CAAC;QACjB,CAAC;QACD,KAAK,CAAC,CAAC,CAAC,CAAC;YACR,OAAO,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC9B,CAAC;QACD,KAAK,CAAC,CAAC,CAAC,CAAC;YACR,OAAO,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC/B,CAAC;QACD,KAAK,CAAC,CAAC,CAAC,CAAC;YACR,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;YAE7B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;gBACpC,KAAK,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;YAC/B,CAAC;YAED,OAAO,KAAK,CAAC;QACd,CAAC;QACD,KAAK,CAAC,CAAC,CAAC,CAAC;YACR,MAAM,MAAM,GAA4B,EAAE,CAAC;YAE3C,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;gBACpC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;gBACzC,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBAChB,MAAM,IAAI,SAAS,CAAC,mDAAmD,IAAI,EAAE,CAAC,CAAC;gBAChF,CAAC;gBAED,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;gBACtC,MAAM,GAAG,GAAG,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;gBAEnC,IAAI,GAAG,KAAK,WAAW;oBACtB,8CAA8C;oBAC9C,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;gBAE9F,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC;YAED,OAAO,MAAM,CAAC;QACf,CAAC;QACD,KAAK,CAAC,CAAC,CAAC,CAAC;YACR,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;gBAChB,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;gBACzC,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBAChB,MAAM,IAAI,SAAS,CAAC,oDAAoD,IAAI,EAAE,CAAC,CAAC;gBACjF,CAAC;gBAED,MAAM,GAAG,GAAG,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;gBACtC,OAAO,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YAC5B,CAAC;YAED,MAAM,IAAI,SAAS,CAAC,wBAAwB,GAAG,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,KAAK,CAAC,CAAC,CAAC,CAAC;YACR,QAAQ,IAAI,EAAE,CAAC;gBACd,KAAK,EAAE,CAAC;gBACR,KAAK,EAAE;oBACN,OAAO,IAAI,KAAK,EAAE,CAAC;gBACpB,KAAK,EAAE;oBACN,OAAO,IAAI,CAAC;gBACb,KAAK,EAAE;oBACN,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;YAED,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;IACF,CAAC;IAED,MAAM,IAAI,SAAS,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC;AAClD,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAe,EAAuC,EAAE;IACnF,MAAM,KAAK,GAAU;QACpB,CAAC,EAAE,GAAG;QACN,CAAC,EAAE,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,UAAU,CAAC;QAC3D,CAAC,EAAE,CAAC;KACJ,CAAC;IAEF,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAExC,OAAO,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AAC3B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,GAAe,EAAO,EAAE;IAC9C,MAAM,CAAC,KAAK,EAAE,SAAS,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC,CAAC"}
|
package/dist/encode.js
CHANGED
|
@@ -1,77 +1,104 @@
|
|
|
1
1
|
import { CidLinkWrapper, fromString } from '@atcute/cid';
|
|
2
|
+
import { allocUnsafe, concat, encodeUtf8Into } from '@atcute/uint8array';
|
|
2
3
|
import { BytesWrapper, fromBytes } from './bytes.js';
|
|
4
|
+
const MAX_TYPE_ARG_LEN = 9;
|
|
3
5
|
const CHUNK_SIZE = 1024;
|
|
4
|
-
const
|
|
6
|
+
const _abs = Math.abs;
|
|
7
|
+
const _floor = Math.floor;
|
|
8
|
+
const _log2 = Math.log2;
|
|
9
|
+
const _max = Math.max;
|
|
10
|
+
const _isInteger = Number.isInteger;
|
|
11
|
+
const _isNaN = Number.isNaN;
|
|
12
|
+
const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER;
|
|
13
|
+
const MIN_SAFE_INTEGER = Number.MIN_SAFE_INTEGER;
|
|
5
14
|
const resizeIfNeeded = (state, needed) => {
|
|
6
15
|
const buf = state.b;
|
|
7
16
|
const pos = state.p;
|
|
8
17
|
if (buf.byteLength < pos + needed) {
|
|
9
|
-
state.c.push(
|
|
10
|
-
state.
|
|
11
|
-
state.
|
|
18
|
+
state.c.push(buf.subarray(0, pos));
|
|
19
|
+
state.l += pos;
|
|
20
|
+
state.b = allocUnsafe(_max(CHUNK_SIZE, needed));
|
|
12
21
|
state.p = 0;
|
|
13
22
|
}
|
|
14
23
|
};
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
return arg;
|
|
18
|
-
}
|
|
19
|
-
else if (arg < 0x100) {
|
|
20
|
-
return 24;
|
|
21
|
-
}
|
|
22
|
-
else if (arg < 0x10000) {
|
|
23
|
-
return 25;
|
|
24
|
-
}
|
|
25
|
-
else if (arg < 0x100000000) {
|
|
26
|
-
return 26;
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
return 27;
|
|
30
|
-
}
|
|
24
|
+
const getTypeInfoLength = (arg) => {
|
|
25
|
+
return arg < 24 ? 1 : arg < 0x100 ? 2 : arg < 0x10000 ? 3 : arg < 0x100000000 ? 5 : 9;
|
|
31
26
|
};
|
|
32
27
|
const writeFloat64 = (state, val) => {
|
|
33
|
-
|
|
34
|
-
state.
|
|
35
|
-
|
|
28
|
+
let pos = state.p;
|
|
29
|
+
const buf = state.b;
|
|
30
|
+
const sign = val < 0 ? 1 : 0;
|
|
31
|
+
val = _abs(val);
|
|
32
|
+
const exp = _floor(_log2(val));
|
|
33
|
+
let frac = val / 2 ** exp - 1;
|
|
34
|
+
const biasedExp = exp + 1023;
|
|
35
|
+
buf[pos++] = (sign << 7) | (biasedExp >>> 4);
|
|
36
|
+
buf[pos++] = ((biasedExp & 0xf) << 4) | ((frac * 16) >>> 0);
|
|
37
|
+
frac *= 16;
|
|
38
|
+
for (let i = 0; i < 6; i++) {
|
|
39
|
+
frac = (frac % 1) * 256;
|
|
40
|
+
buf[pos++] = frac >>> 0;
|
|
41
|
+
}
|
|
42
|
+
state.p = pos;
|
|
36
43
|
};
|
|
37
44
|
const writeUint8 = (state, val) => {
|
|
38
|
-
|
|
39
|
-
state.v.setUint8(state.p, val);
|
|
40
|
-
state.p += 1;
|
|
45
|
+
state.b[state.p++] = val;
|
|
41
46
|
};
|
|
42
47
|
const writeUint16 = (state, val) => {
|
|
43
|
-
|
|
44
|
-
state.
|
|
45
|
-
|
|
48
|
+
let pos = state.p;
|
|
49
|
+
const buf = state.b;
|
|
50
|
+
buf[pos++] = val >>> 8;
|
|
51
|
+
buf[pos++] = val & 0xff;
|
|
52
|
+
state.p = pos;
|
|
46
53
|
};
|
|
47
54
|
const writeUint32 = (state, val) => {
|
|
48
|
-
|
|
49
|
-
state.
|
|
50
|
-
|
|
55
|
+
let pos = state.p;
|
|
56
|
+
const buf = state.b;
|
|
57
|
+
buf[pos++] = val >>> 24;
|
|
58
|
+
buf[pos++] = (val >>> 16) & 0xff;
|
|
59
|
+
buf[pos++] = (val >>> 8) & 0xff;
|
|
60
|
+
buf[pos++] = val & 0xff;
|
|
61
|
+
state.p = pos;
|
|
51
62
|
};
|
|
52
63
|
const writeUint64 = (state, val) => {
|
|
64
|
+
let pos = state.p;
|
|
65
|
+
const buf = state.b;
|
|
53
66
|
const hi = (val / 2 ** 32) | 0;
|
|
54
67
|
const lo = val >>> 0;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
68
|
+
buf[pos++] = hi >>> 24;
|
|
69
|
+
buf[pos++] = (hi >>> 16) & 0xff;
|
|
70
|
+
buf[pos++] = (hi >>> 8) & 0xff;
|
|
71
|
+
buf[pos++] = hi & 0xff;
|
|
72
|
+
buf[pos++] = lo >>> 24;
|
|
73
|
+
buf[pos++] = (lo >>> 16) & 0xff;
|
|
74
|
+
buf[pos++] = (lo >>> 8) & 0xff;
|
|
75
|
+
buf[pos++] = lo & 0xff;
|
|
76
|
+
state.p = pos;
|
|
59
77
|
};
|
|
60
78
|
const writeTypeAndArgument = (state, type, arg) => {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
79
|
+
if (arg < 24) {
|
|
80
|
+
writeUint8(state, (type << 5) | arg);
|
|
81
|
+
}
|
|
82
|
+
else if (arg < 0x100) {
|
|
83
|
+
writeUint8(state, (type << 5) | 24);
|
|
84
|
+
writeUint8(state, arg);
|
|
85
|
+
}
|
|
86
|
+
else if (arg < 0x10000) {
|
|
87
|
+
writeUint8(state, (type << 5) | 25);
|
|
88
|
+
writeUint16(state, arg);
|
|
89
|
+
}
|
|
90
|
+
else if (arg < 0x100000000) {
|
|
91
|
+
writeUint8(state, (type << 5) | 26);
|
|
92
|
+
writeUint32(state, arg);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
writeUint8(state, (type << 5) | 27);
|
|
96
|
+
writeUint64(state, arg);
|
|
72
97
|
}
|
|
73
98
|
};
|
|
99
|
+
// --- Functions below MUST be cautious about ensuring there's enough room in the buffer!!
|
|
74
100
|
const writeInteger = (state, val) => {
|
|
101
|
+
resizeIfNeeded(state, MAX_TYPE_ARG_LEN);
|
|
75
102
|
if (val < 0) {
|
|
76
103
|
writeTypeAndArgument(state, 1, -val - 1);
|
|
77
104
|
}
|
|
@@ -80,154 +107,171 @@ const writeInteger = (state, val) => {
|
|
|
80
107
|
}
|
|
81
108
|
};
|
|
82
109
|
const writeFloat = (state, val) => {
|
|
110
|
+
resizeIfNeeded(state, 9);
|
|
83
111
|
writeUint8(state, 0xe0 | 27);
|
|
84
112
|
writeFloat64(state, val);
|
|
85
113
|
};
|
|
86
114
|
const writeNumber = (state, val) => {
|
|
87
|
-
if (
|
|
115
|
+
if (_isNaN(val)) {
|
|
88
116
|
throw new RangeError(`NaN values not supported`);
|
|
89
117
|
}
|
|
90
|
-
if (val >
|
|
118
|
+
if (val > MAX_SAFE_INTEGER || val < MIN_SAFE_INTEGER) {
|
|
91
119
|
throw new RangeError(`can't encode numbers beyond safe integer range`);
|
|
92
120
|
}
|
|
93
|
-
if (
|
|
121
|
+
if (_isInteger(val)) {
|
|
94
122
|
writeInteger(state, val);
|
|
95
123
|
}
|
|
96
124
|
else {
|
|
125
|
+
// Note: https://atproto.com/specs/data-model#:~:text=not%20allowed%20in%20atproto
|
|
97
126
|
writeFloat(state, val);
|
|
98
127
|
}
|
|
99
128
|
};
|
|
100
129
|
const writeString = (state, val) => {
|
|
101
|
-
|
|
102
|
-
|
|
130
|
+
// JS strings are UTF-16 (ECMA spec)
|
|
131
|
+
// Therefore, worst case length of UTF-8 is length * 3. (plus 9 bytes of CBOR header)
|
|
132
|
+
// Greatly overshoots in practice, but doesn't matter. (alloc is O(1)+ anyway)
|
|
133
|
+
const strLength = val.length;
|
|
134
|
+
resizeIfNeeded(state, strLength * 3 + MAX_TYPE_ARG_LEN);
|
|
135
|
+
// Credit: method used by cbor-x
|
|
136
|
+
// Rather than allocate a buffer and then copy it back to the destination buffer:
|
|
137
|
+
// - Estimate the length of the header based on the UTF-16 size of the string.
|
|
138
|
+
// Should be accurate most of the time, see last point for when it isn't.
|
|
139
|
+
// - Directly write the string at the estimated location, retrieving with it the actual length.
|
|
140
|
+
// - Write the header now that the length is available.
|
|
141
|
+
// - If the estimation happened to be wrong, correct the placement of the string.
|
|
142
|
+
// While it's costly, it's actually roughly the same cost as if we encoded it separately + copy.
|
|
143
|
+
const estimatedHeaderSize = getTypeInfoLength(strLength);
|
|
144
|
+
const estimatedPosition = state.p + estimatedHeaderSize;
|
|
145
|
+
const len = encodeUtf8Into(state.b, val, estimatedPosition);
|
|
146
|
+
const headerSize = getTypeInfoLength(len);
|
|
147
|
+
if (estimatedHeaderSize !== headerSize) {
|
|
148
|
+
// Estimation was incorrect, move the bytes to the real place.
|
|
149
|
+
state.b.copyWithin(state.p + headerSize, estimatedPosition, estimatedPosition + len);
|
|
150
|
+
}
|
|
103
151
|
writeTypeAndArgument(state, 3, len);
|
|
104
|
-
resizeIfNeeded(state, len);
|
|
105
|
-
new Uint8Array(state.b, state.p).set(buf);
|
|
106
152
|
state.p += len;
|
|
107
153
|
};
|
|
108
154
|
const writeBytes = (state, val) => {
|
|
109
155
|
const buf = fromBytes(val);
|
|
110
156
|
const len = buf.byteLength;
|
|
157
|
+
resizeIfNeeded(state, len + MAX_TYPE_ARG_LEN);
|
|
111
158
|
writeTypeAndArgument(state, 2, len);
|
|
112
|
-
|
|
113
|
-
new Uint8Array(state.b, state.p, len).set(buf);
|
|
159
|
+
state.b.set(buf, state.p);
|
|
114
160
|
state.p += len;
|
|
115
161
|
};
|
|
116
162
|
const writeCid = (state, val) => {
|
|
117
163
|
// CID bytes are prefixed with 0x00 for historical reasons, apparently.
|
|
118
164
|
const buf = val instanceof CidLinkWrapper ? val.bytes : fromString(val.$link).bytes;
|
|
119
165
|
const len = buf.byteLength + 1;
|
|
166
|
+
resizeIfNeeded(state, len + 2 * MAX_TYPE_ARG_LEN);
|
|
120
167
|
writeTypeAndArgument(state, 6, 42);
|
|
121
168
|
writeTypeAndArgument(state, 2, len);
|
|
122
|
-
|
|
123
|
-
|
|
169
|
+
state.b[state.p] = 0;
|
|
170
|
+
state.b.set(buf, state.p + 1);
|
|
124
171
|
state.p += len;
|
|
125
172
|
};
|
|
126
173
|
const writeValue = (state, val) => {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return writeUint8(state, 0xf6);
|
|
132
|
-
}
|
|
133
|
-
if (val === false) {
|
|
134
|
-
return writeUint8(state, 0xf4);
|
|
135
|
-
}
|
|
136
|
-
if (val === true) {
|
|
137
|
-
return writeUint8(state, 0xf5);
|
|
138
|
-
}
|
|
139
|
-
if (typeof val === 'number') {
|
|
140
|
-
return writeNumber(state, val);
|
|
141
|
-
}
|
|
142
|
-
if (typeof val === 'string') {
|
|
143
|
-
return writeString(state, val);
|
|
144
|
-
}
|
|
145
|
-
if (typeof val === 'object') {
|
|
146
|
-
if (isArray(val)) {
|
|
147
|
-
const len = val.length;
|
|
148
|
-
writeTypeAndArgument(state, 4, len);
|
|
149
|
-
for (let idx = 0; idx < len; idx++) {
|
|
150
|
-
const v = val[idx];
|
|
151
|
-
writeValue(state, v);
|
|
152
|
-
}
|
|
153
|
-
return;
|
|
174
|
+
switch (typeof val) {
|
|
175
|
+
case 'boolean': {
|
|
176
|
+
resizeIfNeeded(state, 1);
|
|
177
|
+
return writeUint8(state, 0xf4 + +val);
|
|
154
178
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
throw new TypeError(`unexpected cid-link value`);
|
|
179
|
+
case 'number': {
|
|
180
|
+
return writeNumber(state, val);
|
|
181
|
+
}
|
|
182
|
+
case 'string': {
|
|
183
|
+
return writeString(state, val);
|
|
161
184
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
185
|
+
case 'object': {
|
|
186
|
+
// case: null
|
|
187
|
+
if (val === null) {
|
|
188
|
+
resizeIfNeeded(state, 1);
|
|
189
|
+
return writeUint8(state, 0xf6);
|
|
190
|
+
}
|
|
191
|
+
// case: array
|
|
192
|
+
if (Array.isArray(val)) {
|
|
193
|
+
const len = val.length;
|
|
194
|
+
resizeIfNeeded(state, MAX_TYPE_ARG_LEN);
|
|
195
|
+
writeTypeAndArgument(state, 4, len);
|
|
196
|
+
for (let idx = 0; idx < len; idx++) {
|
|
197
|
+
writeValue(state, val[idx]);
|
|
198
|
+
}
|
|
165
199
|
return;
|
|
166
200
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
201
|
+
// case: cid-link
|
|
202
|
+
if ('$link' in val) {
|
|
203
|
+
if (val instanceof CidLinkWrapper || typeof val.$link === 'string') {
|
|
204
|
+
writeCid(state, val);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
throw new TypeError(`unexpected cid-link value`);
|
|
208
|
+
}
|
|
209
|
+
// case: bytes
|
|
210
|
+
if ('$bytes' in val) {
|
|
211
|
+
if (val instanceof BytesWrapper || typeof val.$bytes === 'string') {
|
|
212
|
+
writeBytes(state, val);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
throw new TypeError(`unexpected bytes value`);
|
|
216
|
+
}
|
|
217
|
+
// case: POJO
|
|
218
|
+
if (val.constructor === Object) {
|
|
219
|
+
const keys = getOrderedObjectKeys(val);
|
|
220
|
+
const len = keys.length;
|
|
221
|
+
resizeIfNeeded(state, MAX_TYPE_ARG_LEN);
|
|
222
|
+
writeTypeAndArgument(state, 5, len);
|
|
223
|
+
for (let idx = 0; idx < len; idx++) {
|
|
224
|
+
const key = keys[idx];
|
|
225
|
+
writeString(state, key);
|
|
226
|
+
writeValue(state, val[key]);
|
|
227
|
+
}
|
|
228
|
+
return;
|
|
179
229
|
}
|
|
180
|
-
return;
|
|
181
230
|
}
|
|
182
231
|
}
|
|
183
232
|
throw new TypeError(`unsupported type: ${val}`);
|
|
184
233
|
};
|
|
185
234
|
const createState = () => {
|
|
186
|
-
const buf =
|
|
235
|
+
const buf = allocUnsafe(CHUNK_SIZE);
|
|
187
236
|
return {
|
|
188
237
|
c: [],
|
|
189
238
|
b: buf,
|
|
190
|
-
v: new DataView(buf),
|
|
191
239
|
p: 0,
|
|
240
|
+
l: 0,
|
|
192
241
|
};
|
|
193
242
|
};
|
|
194
243
|
export const encode = (value) => {
|
|
195
244
|
const state = createState();
|
|
196
|
-
const chunks = state.c;
|
|
197
245
|
writeValue(state, value);
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
let written = 0;
|
|
201
|
-
let len = chunks.length;
|
|
202
|
-
let idx;
|
|
203
|
-
for (idx = 0; idx < len; idx++) {
|
|
204
|
-
size += chunks[idx].byteLength;
|
|
205
|
-
}
|
|
206
|
-
const u8 = new Uint8Array(size);
|
|
207
|
-
for (idx = 0; idx < len; idx++) {
|
|
208
|
-
const chunk = chunks[idx];
|
|
209
|
-
u8.set(chunk, written);
|
|
210
|
-
written += chunk.byteLength;
|
|
211
|
-
}
|
|
212
|
-
return u8;
|
|
213
|
-
};
|
|
214
|
-
const isArray = Array.isArray;
|
|
215
|
-
const isPlainObject = (v) => {
|
|
216
|
-
if (typeof v !== 'object' || v === null) {
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
const proto = Object.getPrototypeOf(v);
|
|
220
|
-
return proto === Object.prototype || proto === null;
|
|
246
|
+
state.c.push(state.b.subarray(0, state.p));
|
|
247
|
+
return concat(state.c, state.l + state.p);
|
|
221
248
|
};
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
249
|
+
/** @internal */
|
|
250
|
+
export const getOrderedObjectKeys = (obj) => {
|
|
251
|
+
const keys = Object.keys(obj);
|
|
252
|
+
for (let i = 1, len = keys.length, j = 0; i < len; j = i++) {
|
|
253
|
+
const valA = keys[i];
|
|
254
|
+
// Tuck in undefined value filtering here to avoid extra iterations.
|
|
255
|
+
if (obj[valA] === undefined) {
|
|
256
|
+
// A lot of things are tucked in here xd
|
|
257
|
+
// - Pull the currently last item in the keys array at the current place
|
|
258
|
+
// - Update saved value of array length
|
|
259
|
+
// - Decrease i by 1
|
|
260
|
+
keys[i--] = keys[--len];
|
|
261
|
+
keys.length = len;
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
for (; j >= 0; j--) {
|
|
265
|
+
const valB = keys[j];
|
|
266
|
+
// Note: Don't need to check for equality, keys are always distinct.
|
|
267
|
+
const cmp = valA.length - valB.length || +(valA > valB);
|
|
268
|
+
if (cmp > 0)
|
|
269
|
+
break;
|
|
270
|
+
keys[j + 1] = valB;
|
|
271
|
+
}
|
|
272
|
+
keys[j + 1] = valA;
|
|
273
|
+
}
|
|
231
274
|
}
|
|
275
|
+
return keys;
|
|
232
276
|
};
|
|
233
277
|
//# sourceMappingURL=encode.js.map
|