@chr33s/pdf-restructure 5.0.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/LICENSE.md +21 -0
- package/README.md +323 -0
- package/dist/array.d.ts +15 -0
- package/dist/array.js +95 -0
- package/dist/array.js.map +1 -0
- package/dist/base.d.ts +4 -0
- package/dist/base.js +16 -0
- package/dist/base.js.map +1 -0
- package/dist/bitfield.d.ts +11 -0
- package/dist/bitfield.js +37 -0
- package/dist/bitfield.js.map +1 -0
- package/dist/boolean.d.ts +10 -0
- package/dist/boolean.js +18 -0
- package/dist/boolean.js.map +1 -0
- package/dist/buffer.d.ts +11 -0
- package/dist/buffer.js +31 -0
- package/dist/buffer.js.map +1 -0
- package/dist/decode-stream.d.ts +26 -0
- package/dist/decode-stream.js +84 -0
- package/dist/decode-stream.js.map +1 -0
- package/dist/encode-stream.d.ts +19 -0
- package/dist/encode-stream.js +137 -0
- package/dist/encode-stream.js.map +1 -0
- package/dist/enum.d.ts +11 -0
- package/dist/enum.js +25 -0
- package/dist/enum.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/lazy-array.d.ts +22 -0
- package/dist/lazy-array.js +75 -0
- package/dist/lazy-array.js.map +1 -0
- package/dist/number.d.ts +51 -0
- package/dist/number.js +76 -0
- package/dist/number.js.map +1 -0
- package/dist/optional.d.ts +14 -0
- package/dist/optional.js +34 -0
- package/dist/optional.js.map +1 -0
- package/dist/pointer.d.ts +28 -0
- package/dist/pointer.js +160 -0
- package/dist/pointer.js.map +1 -0
- package/dist/reserved.d.ts +12 -0
- package/dist/reserved.js +23 -0
- package/dist/reserved.js.map +1 -0
- package/dist/string.d.ts +14 -0
- package/dist/string.js +123 -0
- package/dist/string.js.map +1 -0
- package/dist/struct.d.ts +15 -0
- package/dist/struct.js +93 -0
- package/dist/struct.js.map +1 -0
- package/dist/utils.d.ts +13 -0
- package/dist/utils.js +45 -0
- package/dist/utils.js.map +1 -0
- package/dist/versioned-struct.d.ts +18 -0
- package/dist/versioned-struct.js +129 -0
- package/dist/versioned-struct.js.map +1 -0
- package/package.json +47 -0
- package/src/array.ts +113 -0
- package/src/base.ts +17 -0
- package/src/bitfield.ts +46 -0
- package/src/boolean.ts +24 -0
- package/src/buffer.ts +40 -0
- package/src/decode-stream.ts +97 -0
- package/src/encode-stream.ts +161 -0
- package/src/enum.ts +32 -0
- package/src/index.ts +17 -0
- package/src/lazy-array.ts +91 -0
- package/src/number.ts +88 -0
- package/src/optional.ts +46 -0
- package/src/pointer.ts +204 -0
- package/src/reserved.ts +29 -0
- package/src/string.ts +154 -0
- package/src/struct.ts +127 -0
- package/src/utils.ts +55 -0
- package/src/versioned-struct.ts +174 -0
- package/test/array.test.ts +95 -0
- package/test/bitfield.test.ts +52 -0
- package/test/boolean.test.ts +35 -0
- package/test/buffer.test.ts +49 -0
- package/test/decode-stream.test.ts +104 -0
- package/test/encode-stream.test.ts +111 -0
- package/test/enum.test.ts +30 -0
- package/test/lazy-array.test.ts +70 -0
- package/test/number.test.ts +222 -0
- package/test/optional.test.ts +105 -0
- package/test/pointer.test.ts +248 -0
- package/test/reserved.test.ts +28 -0
- package/test/string.test.ts +114 -0
- package/test/struct.test.ts +164 -0
- package/test/versioned-struct.test.ts +462 -0
- package/tsconfig.json +9 -0
- package/tsconfig.typecheck.json +14 -0
- package/vitest.config.ts +12 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { DecodeStream, EncodeStream, Pointer, Struct, VoidPointer, uint8 } from "../src/index.js";
|
|
3
|
+
|
|
4
|
+
describe("Pointer", () => {
|
|
5
|
+
describe("decode", () => {
|
|
6
|
+
test("should handle null pointers", () => {
|
|
7
|
+
const stream = new DecodeStream(new Uint8Array([0]));
|
|
8
|
+
const pointer = new Pointer(uint8, uint8);
|
|
9
|
+
expect(pointer.decode(stream, { _startOffset: 50 })).to.equal(null);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("should use local offsets from start of parent by default", () => {
|
|
13
|
+
const stream = new DecodeStream(new Uint8Array([1, 53]));
|
|
14
|
+
const pointer = new Pointer(uint8, uint8);
|
|
15
|
+
expect(pointer.decode(stream, { _startOffset: 0 })).to.equal(53);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("should support immediate offsets", () => {
|
|
19
|
+
const stream = new DecodeStream(new Uint8Array([1, 53]));
|
|
20
|
+
const pointer = new Pointer(uint8, uint8, { type: "immediate" });
|
|
21
|
+
expect(pointer.decode(stream, {})).to.equal(53);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test("should support offsets relative to the parent", () => {
|
|
25
|
+
const stream = new DecodeStream(new Uint8Array([0, 0, 1, 53]));
|
|
26
|
+
stream.pos = 2;
|
|
27
|
+
const pointer = new Pointer(uint8, uint8, { type: "parent" });
|
|
28
|
+
expect(pointer.decode(stream, { parent: { _startOffset: 2 } })).to.equal(53);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("should support global offsets", () => {
|
|
32
|
+
const stream = new DecodeStream(new Uint8Array([1, 2, 4, 0, 0, 0, 53]));
|
|
33
|
+
const pointer = new Pointer(uint8, uint8, { type: "global" });
|
|
34
|
+
stream.pos = 2;
|
|
35
|
+
expect(pointer.decode(stream, { parent: { parent: { _startOffset: 2 } } })).to.equal(53);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("should support offsets relative to a property on the parent", () => {
|
|
39
|
+
const stream = new DecodeStream(new Uint8Array([1, 0, 0, 0, 0, 53]));
|
|
40
|
+
const pointer = new Pointer(uint8, uint8, { relativeTo: "parent.ptr" });
|
|
41
|
+
expect(pointer.decode(stream, { _startOffset: 0, parent: { ptr: 4 } })).to.equal(53);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("should support returning pointer if there is no decode type", () => {
|
|
45
|
+
const stream = new DecodeStream(new Uint8Array([4]));
|
|
46
|
+
const pointer = new Pointer(uint8, "void");
|
|
47
|
+
expect(pointer.decode(stream, { _startOffset: 0 })).to.equal(4);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("should support decoding pointers lazily", () => {
|
|
51
|
+
const stream = new DecodeStream(new Uint8Array([1, 53]));
|
|
52
|
+
const struct = new Struct({
|
|
53
|
+
ptr: new Pointer(uint8, uint8, { lazy: true }),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const res = struct.decode(stream);
|
|
57
|
+
const descriptor = Object.getOwnPropertyDescriptor(res, "ptr");
|
|
58
|
+
expect(typeof descriptor?.get).to.equal("function");
|
|
59
|
+
expect(descriptor?.enumerable).to.equal(true);
|
|
60
|
+
expect(res.ptr).to.equal(53);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("size", () => {
|
|
65
|
+
test("should add to local pointerSize", () => {
|
|
66
|
+
const pointer = new Pointer(uint8, uint8);
|
|
67
|
+
const ctx: any = { pointerSize: 0 };
|
|
68
|
+
expect(pointer.size(10, ctx)).to.equal(1);
|
|
69
|
+
expect(ctx.pointerSize).to.equal(1);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("should add to immediate pointerSize", () => {
|
|
73
|
+
const pointer = new Pointer(uint8, uint8, { type: "immediate" });
|
|
74
|
+
const ctx: any = { pointerSize: 0 };
|
|
75
|
+
expect(pointer.size(10, ctx)).to.equal(1);
|
|
76
|
+
expect(ctx.pointerSize).to.equal(1);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("should add to parent pointerSize", () => {
|
|
80
|
+
const pointer = new Pointer(uint8, uint8, { type: "parent" });
|
|
81
|
+
const ctx: any = { parent: { pointerSize: 0 } };
|
|
82
|
+
expect(pointer.size(10, ctx)).to.equal(1);
|
|
83
|
+
expect(ctx.parent.pointerSize).to.equal(1);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("should add to global pointerSize", () => {
|
|
87
|
+
const pointer = new Pointer(uint8, uint8, { type: "global" });
|
|
88
|
+
const ctx: any = { parent: { parent: { parent: { pointerSize: 0 } } } };
|
|
89
|
+
expect(pointer.size(10, ctx)).to.equal(1);
|
|
90
|
+
expect(ctx.parent.parent.parent.pointerSize).to.equal(1);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("should handle void pointers", () => {
|
|
94
|
+
const pointer = new Pointer(uint8, "void");
|
|
95
|
+
const ctx: any = { pointerSize: 0 };
|
|
96
|
+
expect(pointer.size(new VoidPointer(uint8, 50), ctx)).to.equal(1);
|
|
97
|
+
expect(ctx.pointerSize).to.equal(1);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("should throw if no type and not a void pointer", () => {
|
|
101
|
+
const pointer = new Pointer(uint8, "void");
|
|
102
|
+
const ctx: any = { pointerSize: 0 };
|
|
103
|
+
expect(() => pointer.size(30, ctx)).to.throw();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("should return a fixed size without a value", () => {
|
|
107
|
+
const pointer = new Pointer(uint8, uint8);
|
|
108
|
+
expect(pointer.size()).to.equal(1);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe("encode", () => {
|
|
113
|
+
test("should handle null pointers", () => {
|
|
114
|
+
const stream = new EncodeStream(new Uint8Array(1));
|
|
115
|
+
const ptr = new Pointer(uint8, uint8);
|
|
116
|
+
const ctx: any = {
|
|
117
|
+
pointerSize: 0,
|
|
118
|
+
startOffset: 0,
|
|
119
|
+
pointerOffset: 0,
|
|
120
|
+
pointers: [],
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
ptr.encode(stream, null, ctx);
|
|
124
|
+
expect(ctx.pointerSize).to.equal(0);
|
|
125
|
+
expect(stream.buffer.subarray(0, stream.pos)).to.deep.equal(new Uint8Array([0]));
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("should handle local offsets", () => {
|
|
129
|
+
const stream = new EncodeStream(new Uint8Array(1));
|
|
130
|
+
const ptr = new Pointer(uint8, uint8);
|
|
131
|
+
const ctx: any = {
|
|
132
|
+
pointerSize: 0,
|
|
133
|
+
startOffset: 0,
|
|
134
|
+
pointerOffset: 1,
|
|
135
|
+
pointers: [],
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
ptr.encode(stream, 10, ctx);
|
|
139
|
+
expect(ctx.pointerOffset).to.equal(2);
|
|
140
|
+
expect(ctx.pointers).to.deep.equal([{ type: uint8, val: 10, parent: ctx }]);
|
|
141
|
+
expect(stream.buffer.subarray(0, stream.pos)).to.deep.equal(new Uint8Array([1]));
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("should handle immediate offsets", () => {
|
|
145
|
+
const stream = new EncodeStream(new Uint8Array(1));
|
|
146
|
+
const ptr = new Pointer(uint8, uint8, { type: "immediate" });
|
|
147
|
+
const ctx: any = {
|
|
148
|
+
pointerSize: 0,
|
|
149
|
+
startOffset: 0,
|
|
150
|
+
pointerOffset: 1,
|
|
151
|
+
pointers: [],
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
ptr.encode(stream, 10, ctx);
|
|
155
|
+
expect(ctx.pointerOffset).to.equal(2);
|
|
156
|
+
expect(ctx.pointers).to.deep.equal([{ type: uint8, val: 10, parent: ctx }]);
|
|
157
|
+
expect(stream.buffer.subarray(0, stream.pos)).to.deep.equal(new Uint8Array([0]));
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("should handle offsets relative to parent", () => {
|
|
161
|
+
const stream = new EncodeStream(new Uint8Array(1));
|
|
162
|
+
const ptr = new Pointer(uint8, uint8, { type: "parent" });
|
|
163
|
+
const ctx: any = {
|
|
164
|
+
parent: {
|
|
165
|
+
pointerSize: 0,
|
|
166
|
+
startOffset: 3,
|
|
167
|
+
pointerOffset: 5,
|
|
168
|
+
pointers: [],
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
ptr.encode(stream, 10, ctx);
|
|
173
|
+
expect(ctx.parent.pointerOffset).to.equal(6);
|
|
174
|
+
expect(ctx.parent.pointers).to.deep.equal([{ type: uint8, val: 10, parent: ctx }]);
|
|
175
|
+
expect(stream.buffer.subarray(0, stream.pos)).to.deep.equal(new Uint8Array([2]));
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("should handle global offsets", () => {
|
|
179
|
+
const stream = new EncodeStream(new Uint8Array(1));
|
|
180
|
+
const ptr = new Pointer(uint8, uint8, { type: "global" });
|
|
181
|
+
const ctx: any = {
|
|
182
|
+
parent: {
|
|
183
|
+
parent: {
|
|
184
|
+
parent: {
|
|
185
|
+
pointerSize: 0,
|
|
186
|
+
startOffset: 3,
|
|
187
|
+
pointerOffset: 5,
|
|
188
|
+
pointers: [],
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
ptr.encode(stream, 10, ctx);
|
|
195
|
+
expect(ctx.parent.parent.parent.pointerOffset).to.equal(6);
|
|
196
|
+
expect(ctx.parent.parent.parent.pointers).to.deep.equal([
|
|
197
|
+
{ type: uint8, val: 10, parent: ctx },
|
|
198
|
+
]);
|
|
199
|
+
expect(stream.buffer.subarray(0, stream.pos)).to.deep.equal(new Uint8Array([5]));
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
test("should support offsets relative to a property on the parent", () => {
|
|
203
|
+
const stream = new EncodeStream(new Uint8Array(1));
|
|
204
|
+
const ptr = new Pointer(uint8, uint8, { relativeTo: "ptr" });
|
|
205
|
+
const ctx: any = {
|
|
206
|
+
pointerSize: 0,
|
|
207
|
+
startOffset: 0,
|
|
208
|
+
pointerOffset: 10,
|
|
209
|
+
pointers: [],
|
|
210
|
+
val: { ptr: 4 },
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
ptr.encode(stream, 10, ctx);
|
|
214
|
+
expect(ctx.pointerOffset).to.equal(11);
|
|
215
|
+
expect(ctx.pointers).to.deep.equal([{ type: uint8, val: 10, parent: ctx }]);
|
|
216
|
+
expect(stream.buffer.subarray(0, stream.pos)).to.deep.equal(new Uint8Array([6]));
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
test("should support void pointers", () => {
|
|
220
|
+
const stream = new EncodeStream(new Uint8Array(1));
|
|
221
|
+
const ptr = new Pointer(uint8, "void");
|
|
222
|
+
const ctx: any = {
|
|
223
|
+
pointerSize: 0,
|
|
224
|
+
startOffset: 0,
|
|
225
|
+
pointerOffset: 1,
|
|
226
|
+
pointers: [],
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
ptr.encode(stream, new VoidPointer(uint8, 55), ctx);
|
|
230
|
+
expect(ctx.pointerOffset).to.equal(2);
|
|
231
|
+
expect(ctx.pointers).to.deep.equal([{ type: uint8, val: 55, parent: ctx }]);
|
|
232
|
+
expect(stream.buffer.subarray(0, stream.pos)).to.deep.equal(new Uint8Array([1]));
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test("should throw if not a void pointer instance", () => {
|
|
236
|
+
const stream = new EncodeStream(new Uint8Array(10));
|
|
237
|
+
const ptr = new Pointer(uint8, "void");
|
|
238
|
+
const ctx: any = {
|
|
239
|
+
pointerSize: 0,
|
|
240
|
+
startOffset: 0,
|
|
241
|
+
pointerOffset: 1,
|
|
242
|
+
pointers: [],
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
expect(() => ptr.encode(stream, 44, ctx)).to.throw();
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { DecodeStream, EncodeStream, Reserved, uint16, uint8 } from "../src/index.js";
|
|
3
|
+
|
|
4
|
+
describe("Reserved", () => {
|
|
5
|
+
test("should have a default count of 1", () => {
|
|
6
|
+
const reserved = new Reserved(uint8);
|
|
7
|
+
expect(reserved.size()).to.equal(1);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
test("should allow custom counts and types", () => {
|
|
11
|
+
const reserved = new Reserved(uint16, 10);
|
|
12
|
+
expect(reserved.size()).to.equal(20);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("should decode", () => {
|
|
16
|
+
const stream = new DecodeStream(new Uint8Array([0, 0]));
|
|
17
|
+
const reserved = new Reserved(uint16);
|
|
18
|
+
expect(reserved.decode(stream)).to.equal(undefined);
|
|
19
|
+
expect(stream.pos).to.equal(2);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("should encode", () => {
|
|
23
|
+
const reserved = new Reserved(uint16);
|
|
24
|
+
const stream = new EncodeStream(new Uint8Array(2));
|
|
25
|
+
reserved.encode(stream);
|
|
26
|
+
expect(stream.buffer).to.deep.equal(new Uint8Array([0, 0]));
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { describe, expect, test } from "vitest";
|
|
3
|
+
import { DecodeStream, String as StringT, uint8 } from "../src/index.js";
|
|
4
|
+
|
|
5
|
+
describe("String", () => {
|
|
6
|
+
describe("decode", () => {
|
|
7
|
+
test("should decode fixed length", () => {
|
|
8
|
+
const string = new StringT(7);
|
|
9
|
+
expect(string.fromBuffer(Buffer.from("testing"))).to.equal("testing");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("should decode length from parent key", () => {
|
|
13
|
+
const stream = new DecodeStream(Buffer.from("testing"));
|
|
14
|
+
const string = new StringT("len");
|
|
15
|
+
expect(string.decode(stream, { len: 7 })).to.equal("testing");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("should decode length as number before string", () => {
|
|
19
|
+
const string = new StringT(uint8);
|
|
20
|
+
expect(string.fromBuffer(Buffer.from("\x07testing", "binary"))).to.equal("testing");
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("should decode utf8", () => {
|
|
24
|
+
const string = new StringT(4, "utf8");
|
|
25
|
+
expect(string.fromBuffer(Buffer.from("🍻"))).to.equal("🍻");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("should decode encoding computed from function", () => {
|
|
29
|
+
const string = new StringT(4, () => "utf8");
|
|
30
|
+
expect(string.fromBuffer(Buffer.from("🍻"))).to.equal("🍻");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("should decode null-terminated string and read past terminator", () => {
|
|
34
|
+
const stream = new DecodeStream(Buffer.from("🍻\x00"));
|
|
35
|
+
const string = new StringT(undefined, "utf8");
|
|
36
|
+
expect(string.decode(stream)).to.equal("🍻");
|
|
37
|
+
expect(stream.pos).to.equal(5);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("should decode remainder of buffer when null-byte missing", () => {
|
|
41
|
+
const string = new StringT(undefined, "utf8");
|
|
42
|
+
expect(string.fromBuffer(Buffer.from("🍻"))).to.equal("🍻");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe("size", () => {
|
|
47
|
+
test("should use string length", () => {
|
|
48
|
+
const string = new StringT(7);
|
|
49
|
+
expect(string.size("testing")).to.equal(7);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("should use correct encoding", () => {
|
|
53
|
+
const string = new StringT(10, "utf8");
|
|
54
|
+
expect(string.size("🍻")).to.equal(4);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("should use encoding from function", () => {
|
|
58
|
+
const string = new StringT(10, () => "utf8");
|
|
59
|
+
expect(string.size("🍻")).to.equal(4);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("should add size of length field before string", () => {
|
|
63
|
+
const string = new StringT(uint8, "utf8");
|
|
64
|
+
expect(string.size("🍻")).to.equal(5);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
test("should work with utf16be encoding", () => {
|
|
68
|
+
const string = new StringT(10, "utf16be");
|
|
69
|
+
expect(string.size("🍻")).to.equal(4);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("should take null-byte into account", () => {
|
|
73
|
+
const string = new StringT(undefined, "utf8");
|
|
74
|
+
expect(string.size("🍻")).to.equal(5);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("should use defined length if no value given", () => {
|
|
78
|
+
const array = new StringT(10);
|
|
79
|
+
expect(array.size()).to.equal(10);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe("encode", () => {
|
|
84
|
+
test("should encode using string length", () => {
|
|
85
|
+
const string = new StringT(7);
|
|
86
|
+
expect(string.toBuffer("testing")).to.deep.equal(Buffer.from("testing"));
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("should encode length as number before string", () => {
|
|
90
|
+
const string = new StringT(uint8);
|
|
91
|
+
expect(string.toBuffer("testing")).to.deep.equal(Buffer.from("\x07testing", "binary"));
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("should encode length as number before utf8 string", () => {
|
|
95
|
+
const string = new StringT(uint8, "utf8");
|
|
96
|
+
expect(string.toBuffer("testing 😜")).to.deep.equal(Buffer.from("\x0ctesting 😜", "utf8"));
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("should encode utf8", () => {
|
|
100
|
+
const string = new StringT(4, "utf8");
|
|
101
|
+
expect(string.toBuffer("🍻")).to.deep.equal(Buffer.from("🍻"));
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test("should encode encoding computed from function", () => {
|
|
105
|
+
const string = new StringT(4, () => "utf8");
|
|
106
|
+
expect(string.toBuffer("🍻")).to.deep.equal(Buffer.from("🍻"));
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("should encode null-terminated string", () => {
|
|
110
|
+
const string = new StringT(undefined, "utf8");
|
|
111
|
+
expect(string.toBuffer("🍻")).to.deep.equal(Buffer.from("🍻\x00"));
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
DecodeStream,
|
|
4
|
+
EncodeStream,
|
|
5
|
+
Pointer,
|
|
6
|
+
String as StringT,
|
|
7
|
+
Struct,
|
|
8
|
+
uint8,
|
|
9
|
+
} from "../src/index.js";
|
|
10
|
+
|
|
11
|
+
describe("Struct", () => {
|
|
12
|
+
describe("decode", () => {
|
|
13
|
+
test("should decode into an object", () => {
|
|
14
|
+
const stream = new DecodeStream(new Uint8Array([0x05, 0x64, 0x65, 0x76, 0x6f, 0x6e, 0x15])); // \x05devon\x15
|
|
15
|
+
const struct = new Struct({
|
|
16
|
+
name: new StringT(uint8),
|
|
17
|
+
age: uint8,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
expect(struct.decode(stream)).to.deep.equal({ name: "devon", age: 21 });
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test("should support process hook", () => {
|
|
24
|
+
const stream = new DecodeStream(new Uint8Array([0x05, 0x64, 0x65, 0x76, 0x6f, 0x6e, 0x20])); // \x05devon\x20
|
|
25
|
+
const struct = new Struct({
|
|
26
|
+
name: new StringT(uint8),
|
|
27
|
+
age: uint8,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
struct.process = function process() {
|
|
31
|
+
(this as any).canDrink = (this as any).age >= 21;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
expect(struct.decode(stream)).to.deep.equal({
|
|
35
|
+
name: "devon",
|
|
36
|
+
age: 32,
|
|
37
|
+
canDrink: true,
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("should support function keys", () => {
|
|
42
|
+
const stream = new DecodeStream(new Uint8Array([0x05, 0x64, 0x65, 0x76, 0x6f, 0x6e, 0x20])); // \x05devon\x20
|
|
43
|
+
const struct = new Struct({
|
|
44
|
+
name: new StringT(uint8),
|
|
45
|
+
age: uint8,
|
|
46
|
+
canDrink() {
|
|
47
|
+
return (this as any).age >= 21;
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
expect(struct.decode(stream)).to.deep.equal({
|
|
52
|
+
name: "devon",
|
|
53
|
+
age: 32,
|
|
54
|
+
canDrink: true,
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
describe("size", () => {
|
|
60
|
+
test("should compute the correct size", () => {
|
|
61
|
+
const struct = new Struct({
|
|
62
|
+
name: new StringT(uint8),
|
|
63
|
+
age: uint8,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
expect(struct.size({ name: "devon", age: 21 })).to.equal(7);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("should compute the correct size with pointers", () => {
|
|
70
|
+
const struct = new Struct({
|
|
71
|
+
name: new StringT(uint8),
|
|
72
|
+
age: uint8,
|
|
73
|
+
ptr: new Pointer(uint8, new StringT(uint8)),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const size = struct.size({ name: "devon", age: 21, ptr: "hello" });
|
|
77
|
+
expect(size).to.equal(14);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("should get the correct size when no value is given", () => {
|
|
81
|
+
const struct = new Struct({
|
|
82
|
+
name: new StringT(4),
|
|
83
|
+
age: uint8,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
expect(struct.size()).to.equal(5);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("should throw when getting non-fixed length size and no value is given", () => {
|
|
90
|
+
const struct = new Struct({
|
|
91
|
+
name: new StringT(uint8),
|
|
92
|
+
age: uint8,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
expect(() => struct.size()).to.throw(/not a fixed size/i);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe("encode", () => {
|
|
100
|
+
test("should encode objects to buffers", () => {
|
|
101
|
+
const struct = new Struct({
|
|
102
|
+
name: new StringT(uint8),
|
|
103
|
+
age: uint8,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const value = { name: "devon", age: 21 };
|
|
107
|
+
const stream = new EncodeStream(new Uint8Array(struct.size(value)));
|
|
108
|
+
struct.encode(stream, value);
|
|
109
|
+
expect(stream.buffer).to.deep.equal(
|
|
110
|
+
new Uint8Array([0x05, 0x64, 0x65, 0x76, 0x6f, 0x6e, 0x15]),
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("should support preEncode hook", () => {
|
|
115
|
+
const struct = new Struct({
|
|
116
|
+
nameLength: uint8,
|
|
117
|
+
name: new StringT("nameLength"),
|
|
118
|
+
age: uint8,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
struct.preEncode = function preEncode() {
|
|
122
|
+
(this as any).nameLength = (this as any).name.length;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const value = { name: "devon", age: 21 } as any;
|
|
126
|
+
const stream = new EncodeStream(new Uint8Array(struct.size(value)));
|
|
127
|
+
struct.encode(stream, value);
|
|
128
|
+
expect(stream.buffer).to.deep.equal(
|
|
129
|
+
new Uint8Array([0x05, 0x64, 0x65, 0x76, 0x6f, 0x6e, 0x15]),
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("should encode pointer data after structure", () => {
|
|
134
|
+
const struct = new Struct({
|
|
135
|
+
name: new StringT(uint8),
|
|
136
|
+
age: uint8,
|
|
137
|
+
ptr: new Pointer(uint8, new StringT(uint8)),
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const value = { name: "devon", age: 21, ptr: "hello" };
|
|
141
|
+
const stream = new EncodeStream(new Uint8Array(struct.size(value)));
|
|
142
|
+
struct.encode(stream, value);
|
|
143
|
+
// \x05devon\x15\x08\x05hello
|
|
144
|
+
expect(stream.buffer).to.deep.equal(
|
|
145
|
+
new Uint8Array([
|
|
146
|
+
0x05,
|
|
147
|
+
0x64,
|
|
148
|
+
0x65,
|
|
149
|
+
0x76,
|
|
150
|
+
0x6f,
|
|
151
|
+
0x6e, // \x05devon
|
|
152
|
+
0x15, // age: 21
|
|
153
|
+
0x08, // pointer offset
|
|
154
|
+
0x05,
|
|
155
|
+
0x68,
|
|
156
|
+
0x65,
|
|
157
|
+
0x6c,
|
|
158
|
+
0x6c,
|
|
159
|
+
0x6f, // \x05hello
|
|
160
|
+
]),
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|