@thi.ng/bencode 2.1.83 → 2.1.84
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/CHANGELOG.md +1 -1
- package/README.md +1 -1
- package/decode.js +140 -142
- package/encode.js +53 -55
- package/package.json +12 -9
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
package/decode.js
CHANGED
|
@@ -3,160 +3,158 @@ import { isArray } from "@thi.ng/checks/is-array";
|
|
|
3
3
|
import { assert } from "@thi.ng/errors/assert";
|
|
4
4
|
import { illegalState } from "@thi.ng/errors/illegal-state";
|
|
5
5
|
import { utf8Decode } from "@thi.ng/transducers-binary/utf8";
|
|
6
|
-
var Type
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
})(Type ||
|
|
15
|
-
var Lit
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
})(Lit ||
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
6
|
+
var Type = /* @__PURE__ */ ((Type2) => {
|
|
7
|
+
Type2[Type2["INT"] = 0] = "INT";
|
|
8
|
+
Type2[Type2["FLOAT"] = 1] = "FLOAT";
|
|
9
|
+
Type2[Type2["STR"] = 2] = "STR";
|
|
10
|
+
Type2[Type2["BINARY"] = 3] = "BINARY";
|
|
11
|
+
Type2[Type2["DICT"] = 4] = "DICT";
|
|
12
|
+
Type2[Type2["LIST"] = 5] = "LIST";
|
|
13
|
+
return Type2;
|
|
14
|
+
})(Type || {});
|
|
15
|
+
var Lit = /* @__PURE__ */ ((Lit2) => {
|
|
16
|
+
Lit2[Lit2["MINUS"] = 45] = "MINUS";
|
|
17
|
+
Lit2[Lit2["DOT"] = 46] = "DOT";
|
|
18
|
+
Lit2[Lit2["ZERO"] = 48] = "ZERO";
|
|
19
|
+
Lit2[Lit2["NINE"] = 57] = "NINE";
|
|
20
|
+
Lit2[Lit2["COLON"] = 58] = "COLON";
|
|
21
|
+
Lit2[Lit2["DICT"] = 100] = "DICT";
|
|
22
|
+
Lit2[Lit2["END"] = 101] = "END";
|
|
23
|
+
Lit2[Lit2["FLOAT"] = 102] = "FLOAT";
|
|
24
|
+
Lit2[Lit2["INT"] = 105] = "INT";
|
|
25
|
+
Lit2[Lit2["LIST"] = 108] = "LIST";
|
|
26
|
+
return Lit2;
|
|
27
|
+
})(Lit || {});
|
|
28
|
+
const decode = (buf, utf8 = true) => {
|
|
29
|
+
const iter = buf[Symbol.iterator]();
|
|
30
|
+
const stack = [];
|
|
31
|
+
let i;
|
|
32
|
+
let x;
|
|
33
|
+
while (!(i = iter.next()).done) {
|
|
34
|
+
x = i.value;
|
|
35
|
+
switch (x) {
|
|
36
|
+
case 100 /* DICT */:
|
|
37
|
+
ensureNotKey(stack, "dict");
|
|
38
|
+
stack.push({ type: 4 /* DICT */, val: {} });
|
|
39
|
+
break;
|
|
40
|
+
case 108 /* LIST */:
|
|
41
|
+
ensureNotKey(stack, "list");
|
|
42
|
+
stack.push({ type: 5 /* LIST */, val: [] });
|
|
43
|
+
break;
|
|
44
|
+
case 105 /* INT */:
|
|
45
|
+
x = collect(stack, readInt(iter, 0));
|
|
46
|
+
if (x !== void 0) {
|
|
47
|
+
return x;
|
|
48
|
+
}
|
|
49
|
+
break;
|
|
50
|
+
case 102 /* FLOAT */:
|
|
51
|
+
x = collect(stack, readFloat(iter));
|
|
52
|
+
if (x !== void 0) {
|
|
53
|
+
return x;
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
case 101 /* END */:
|
|
57
|
+
x = stack.pop();
|
|
58
|
+
if (x) {
|
|
59
|
+
const parent = peek(stack);
|
|
60
|
+
if (parent) {
|
|
61
|
+
if (parent.type === 5 /* LIST */) {
|
|
62
|
+
parent.val.push(x.val);
|
|
63
|
+
} else if (parent.type === 4 /* DICT */) {
|
|
64
|
+
parent.val[parent.key] = x.val;
|
|
65
|
+
parent.key = null;
|
|
66
|
+
}
|
|
67
|
+
} else {
|
|
68
|
+
return x.val;
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
illegalState("unmatched end literal");
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
default:
|
|
75
|
+
if (x >= 48 /* ZERO */ && x <= 57 /* NINE */) {
|
|
76
|
+
x = readBytes(
|
|
77
|
+
iter,
|
|
78
|
+
readInt(iter, x - 48 /* ZERO */, 58 /* COLON */)
|
|
79
|
+
);
|
|
80
|
+
x = collect(stack, x, utf8);
|
|
81
|
+
if (x !== void 0) {
|
|
82
|
+
return x;
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
illegalState(
|
|
86
|
+
`unexpected value type: 0x${i.value.toString(16)}`
|
|
87
|
+
);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
|
|
90
|
+
}
|
|
91
|
+
return peek(stack).val;
|
|
91
92
|
};
|
|
92
93
|
const ensureNotKey = (stack, type) => {
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
const x = peek(stack);
|
|
95
|
+
assert(
|
|
96
|
+
!x || x.type !== 4 /* DICT */ || x.key,
|
|
97
|
+
type + " not supported as dict key"
|
|
98
|
+
);
|
|
95
99
|
};
|
|
96
100
|
const collect = (stack, x, utf8 = false) => {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
parent.val[parent.key] = utf8 ? utf8Decode(x) : x;
|
|
109
|
-
parent.key = null;
|
|
110
|
-
}
|
|
101
|
+
const parent = peek(stack);
|
|
102
|
+
if (!parent)
|
|
103
|
+
return x;
|
|
104
|
+
if (parent.type === 5 /* LIST */) {
|
|
105
|
+
parent.val.push(utf8 && isArray(x) ? utf8Decode(x) : x);
|
|
106
|
+
} else {
|
|
107
|
+
if (!parent.key) {
|
|
108
|
+
parent.key = isArray(x) ? utf8Decode(x) : x;
|
|
109
|
+
} else {
|
|
110
|
+
parent.val[parent.key] = utf8 ? utf8Decode(x) : x;
|
|
111
|
+
parent.key = null;
|
|
111
112
|
}
|
|
113
|
+
}
|
|
112
114
|
};
|
|
113
|
-
const readInt = (iter, acc, end =
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
illegalState(`expected digit, got 0x${x.toString(16)}`);
|
|
131
|
-
}
|
|
115
|
+
const readInt = (iter, acc, end = 101 /* END */) => {
|
|
116
|
+
let i;
|
|
117
|
+
let x;
|
|
118
|
+
let isSigned = false;
|
|
119
|
+
while (!(i = iter.next()).done) {
|
|
120
|
+
x = i.value;
|
|
121
|
+
if (x >= 48 /* ZERO */ && x <= 57 /* NINE */) {
|
|
122
|
+
acc = acc * 10 + x - 48 /* ZERO */;
|
|
123
|
+
} else if (x === 45 /* MINUS */) {
|
|
124
|
+
assert(!isSigned, `invalid int literal`);
|
|
125
|
+
isSigned = true;
|
|
126
|
+
} else if (x === end) {
|
|
127
|
+
return isSigned ? -acc : acc;
|
|
128
|
+
} else {
|
|
129
|
+
illegalState(`expected digit, got 0x${x.toString(16)}`);
|
|
132
130
|
}
|
|
133
|
-
|
|
131
|
+
}
|
|
132
|
+
illegalState(`incomplete int`);
|
|
134
133
|
};
|
|
135
134
|
const readFloat = (iter) => {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return parseFloat(acc);
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
illegalState(`expected digit or dot, got 0x${x.toString(16)}`);
|
|
151
|
-
}
|
|
135
|
+
let i;
|
|
136
|
+
let x;
|
|
137
|
+
let acc = "";
|
|
138
|
+
while (!(i = iter.next()).done) {
|
|
139
|
+
x = i.value;
|
|
140
|
+
if (x >= 48 /* ZERO */ && x <= 57 /* NINE */ || x === 46 /* DOT */ || x === 45 /* MINUS */) {
|
|
141
|
+
acc += String.fromCharCode(x);
|
|
142
|
+
} else if (x === 101 /* END */) {
|
|
143
|
+
return parseFloat(acc);
|
|
144
|
+
} else {
|
|
145
|
+
illegalState(`expected digit or dot, got 0x${x.toString(16)}`);
|
|
152
146
|
}
|
|
153
|
-
|
|
147
|
+
}
|
|
148
|
+
illegalState(`incomplete float`);
|
|
154
149
|
};
|
|
155
150
|
const readBytes = (iter, len) => {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
151
|
+
let i;
|
|
152
|
+
let buf = [];
|
|
153
|
+
while (len-- > 0 && !(i = iter.next()).done) {
|
|
154
|
+
buf.push(i.value);
|
|
155
|
+
}
|
|
156
|
+
return len < 0 ? buf : illegalState(`expected string, reached EOF`);
|
|
157
|
+
};
|
|
158
|
+
export {
|
|
159
|
+
decode
|
|
162
160
|
};
|
package/encode.js
CHANGED
|
@@ -9,65 +9,63 @@ import { unsupported } from "@thi.ng/errors/unsupported";
|
|
|
9
9
|
import { bytes, str, u8, u8array } from "@thi.ng/transducers-binary/bytes";
|
|
10
10
|
import { utf8Length } from "@thi.ng/transducers-binary/utf8";
|
|
11
11
|
import { mapcat } from "@thi.ng/transducers/mapcat";
|
|
12
|
-
var Type
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
})(Type ||
|
|
21
|
-
var Lit
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
})(Lit ||
|
|
12
|
+
var Type = /* @__PURE__ */ ((Type2) => {
|
|
13
|
+
Type2[Type2["INT"] = 0] = "INT";
|
|
14
|
+
Type2[Type2["FLOAT"] = 1] = "FLOAT";
|
|
15
|
+
Type2[Type2["STR"] = 2] = "STR";
|
|
16
|
+
Type2[Type2["BINARY"] = 3] = "BINARY";
|
|
17
|
+
Type2[Type2["DICT"] = 4] = "DICT";
|
|
18
|
+
Type2[Type2["LIST"] = 5] = "LIST";
|
|
19
|
+
return Type2;
|
|
20
|
+
})(Type || {});
|
|
21
|
+
var Lit = /* @__PURE__ */ ((Lit2) => {
|
|
22
|
+
Lit2[Lit2["DICT"] = 100] = "DICT";
|
|
23
|
+
Lit2[Lit2["END"] = 101] = "END";
|
|
24
|
+
Lit2[Lit2["LIST"] = 108] = "LIST";
|
|
25
|
+
return Lit2;
|
|
26
|
+
})(Lit || {});
|
|
27
27
|
const FLOAT_RE = /^[0-9.-]+$/;
|
|
28
|
-
|
|
29
|
-
const encodeBin = defmulti(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
? Type.STR
|
|
37
|
-
: x instanceof Uint8Array
|
|
38
|
-
? Type.BINARY
|
|
39
|
-
: isArrayLike(x)
|
|
40
|
-
? Type.LIST
|
|
41
|
-
: isPlainObject(x)
|
|
42
|
-
? Type.DICT
|
|
43
|
-
: unsupported(`unsupported data type: ${x}`), {}, {
|
|
44
|
-
[Type.INT]: (x) => {
|
|
45
|
-
__ensureValidNumber(x);
|
|
46
|
-
return [str(`i${Math.floor(x)}e`)];
|
|
28
|
+
const encode = (x, cap = 1024) => bytes(cap, encodeBin(x));
|
|
29
|
+
const encodeBin = defmulti(
|
|
30
|
+
(x) => isNumber(x) ? Math.floor(x) !== x ? 1 /* FLOAT */ : 0 /* INT */ : isBoolean(x) ? 0 /* INT */ : isString(x) ? 2 /* STR */ : x instanceof Uint8Array ? 3 /* BINARY */ : isArrayLike(x) ? 5 /* LIST */ : isPlainObject(x) ? 4 /* DICT */ : unsupported(`unsupported data type: ${x}`),
|
|
31
|
+
{},
|
|
32
|
+
{
|
|
33
|
+
[0 /* INT */]: (x) => {
|
|
34
|
+
__ensureValidNumber(x);
|
|
35
|
+
return [str(`i${Math.floor(x)}e`)];
|
|
47
36
|
},
|
|
48
|
-
[
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
37
|
+
[1 /* FLOAT */]: (x) => {
|
|
38
|
+
__ensureValidNumber(x);
|
|
39
|
+
assert(
|
|
40
|
+
FLOAT_RE.test(x.toString()),
|
|
41
|
+
`values requiring exponential notation not allowed (${x})`
|
|
42
|
+
);
|
|
43
|
+
return [str(`f${x}e`)];
|
|
52
44
|
},
|
|
53
|
-
[
|
|
54
|
-
|
|
55
|
-
|
|
45
|
+
[3 /* BINARY */]: (buf) => [
|
|
46
|
+
str(buf.length + ":"),
|
|
47
|
+
u8array(buf)
|
|
56
48
|
],
|
|
57
|
-
[
|
|
58
|
-
[
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
49
|
+
[2 /* STR */]: (x) => [str(utf8Length(x) + ":" + x)],
|
|
50
|
+
[5 /* LIST */]: (x) => [
|
|
51
|
+
u8(108 /* LIST */),
|
|
52
|
+
...mapcat(encodeBin, x),
|
|
53
|
+
u8(101 /* END */)
|
|
62
54
|
],
|
|
63
|
-
[
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
55
|
+
[4 /* DICT */]: (x) => [
|
|
56
|
+
u8(100 /* DICT */),
|
|
57
|
+
...mapcat(
|
|
58
|
+
(k) => encodeBin(k).concat(encodeBin(x[k])),
|
|
59
|
+
Object.keys(x).sort()
|
|
60
|
+
),
|
|
61
|
+
u8(101 /* END */)
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
);
|
|
70
65
|
const __ensureValidNumber = (x) => {
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
assert(isFinite(x), `can't encode infinite value`);
|
|
67
|
+
assert(!isNaN(x), `can't encode NaN`);
|
|
68
|
+
};
|
|
69
|
+
export {
|
|
70
|
+
encode
|
|
73
71
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/bencode",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.84",
|
|
4
4
|
"description": "Bencode binary encoder / decoder with optional UTF8 encoding & floating point support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"author": "Karsten Schmidt (https://thi.ng)",
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "yarn
|
|
27
|
+
"build": "yarn build:esbuild && yarn build:decl",
|
|
28
|
+
"build:decl": "tsc --declaration --emitDeclarationOnly",
|
|
29
|
+
"build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
|
|
28
30
|
"clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",
|
|
29
31
|
"doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
|
|
30
32
|
"doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
|
|
@@ -33,15 +35,16 @@
|
|
|
33
35
|
"test": "bun test"
|
|
34
36
|
},
|
|
35
37
|
"dependencies": {
|
|
36
|
-
"@thi.ng/arrays": "^2.7.
|
|
37
|
-
"@thi.ng/checks": "^3.4.
|
|
38
|
-
"@thi.ng/defmulti": "^3.0.
|
|
39
|
-
"@thi.ng/errors": "^2.4.
|
|
40
|
-
"@thi.ng/transducers": "^8.8.
|
|
41
|
-
"@thi.ng/transducers-binary": "^2.1.
|
|
38
|
+
"@thi.ng/arrays": "^2.7.8",
|
|
39
|
+
"@thi.ng/checks": "^3.4.12",
|
|
40
|
+
"@thi.ng/defmulti": "^3.0.10",
|
|
41
|
+
"@thi.ng/errors": "^2.4.6",
|
|
42
|
+
"@thi.ng/transducers": "^8.8.15",
|
|
43
|
+
"@thi.ng/transducers-binary": "^2.1.82"
|
|
42
44
|
},
|
|
43
45
|
"devDependencies": {
|
|
44
46
|
"@microsoft/api-extractor": "^7.38.3",
|
|
47
|
+
"esbuild": "^0.19.8",
|
|
45
48
|
"rimraf": "^5.0.5",
|
|
46
49
|
"tools": "^0.0.1",
|
|
47
50
|
"typedoc": "^0.25.4",
|
|
@@ -77,5 +80,5 @@
|
|
|
77
80
|
"default": "./encode.js"
|
|
78
81
|
}
|
|
79
82
|
},
|
|
80
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\n"
|
|
81
84
|
}
|