Skip to content

Commit b711cd8

Browse files
committed
refactor file structure
1 parent ab62af7 commit b711cd8

File tree

8 files changed

+539
-562
lines changed

8 files changed

+539
-562
lines changed

src/BufferType.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export type BufferType = ArrayLike<number> | Uint8Array;
1+
export type BufferType = ReadonlyArray<number> | Uint8Array;

src/Decoder.ts

Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
import { prettyByte } from "./utils/prettyByte";
2+
import { ExtensionCodecType } from "./ExtensionCodec";
3+
import { decodeUint32, decodeInt64 } from "./utils/int";
4+
import { BufferType } from "./BufferType";
5+
6+
export class Decoder {
7+
pos = 0;
8+
constructor(readonly buffer: BufferType, readonly extensionCodec: ExtensionCodecType) {}
9+
decode() {
10+
const type = this.next8();
11+
if (type >= 0xe0) {
12+
// negative fixint (111x xxxx) 0xe0 - 0xff
13+
return type - 0x100;
14+
} else if (type < 0xc0) {
15+
if (type < 0x80) {
16+
// positive fixint (0xxx xxxx) 0x00 - 0x7f
17+
return type;
18+
} else if (type < 0x90) {
19+
// fixmap (1000 xxxx) 0x80 - 0x8f
20+
const size = type - 0x80;
21+
return this.decodeMap(size);
22+
} else if (type < 0xa0) {
23+
// fixarray (1001 xxxx) 0x90 - 0x9f
24+
const size = type - 0x90;
25+
return this.decodeArray(size);
26+
} else {
27+
// fixstr (101x xxxx) 0xa0 - 0xbf
28+
const length = type - 0xa0;
29+
return this.decodeUtf8String(length);
30+
}
31+
}
32+
if (type === 0xc0) {
33+
// nil
34+
return null;
35+
} else if (type === 0xc2) {
36+
// false
37+
return false;
38+
} else if (type === 0xc3) {
39+
// true
40+
return true;
41+
} else if (type === 0xc4) {
42+
// bin 8
43+
const size = this.next8();
44+
return this.decodeBinary(size);
45+
} else if (type === 0xc5) {
46+
// bin 16
47+
const size = this.next16();
48+
return this.decodeBinary(size);
49+
} else if (type === 0xc6) {
50+
// bin 32
51+
const size = this.next32();
52+
return this.decodeBinary(size);
53+
} else if (type === 0xc7) {
54+
// ext 8
55+
const size = this.next8();
56+
return this.decodeExtension(size);
57+
} else if (type === 0xc8) {
58+
// ext 16
59+
const size = this.next16();
60+
return this.decodeExtension(size);
61+
} else if (type === 0xc9) {
62+
// ext 32
63+
const size = this.next32();
64+
return this.decodeExtension(size);
65+
} else if (type === 0xca) {
66+
// float 32
67+
return this.decodeFloat(23, 4);
68+
} else if (type === 0xcb) {
69+
// float 64
70+
return this.decodeFloat(52, 8);
71+
} else if (type === 0xcc) {
72+
// uint 8
73+
return this.next8();
74+
} else if (type === 0xcd) {
75+
// uint 16
76+
return this.next16();
77+
} else if (type === 0xce) {
78+
// uint 32
79+
return this.next32();
80+
} else if (type === 0xcf) {
81+
// uint 64
82+
return this.next64();
83+
} else if (type === 0xd0) {
84+
// int 8
85+
const v = this.next8();
86+
return v < 0x80 ? v : v - 0x100;
87+
} else if (type === 0xd1) {
88+
// int 16
89+
const v = this.next16();
90+
return v < 0x8000 ? v : v - 0x10000;
91+
} else if (type === 0xd2) {
92+
// int 32
93+
const v = this.next32();
94+
return v < 0x80000000 ? v : v - 0x100000000;
95+
} else if (type === 0xd3) {
96+
// int 64
97+
const b1 = this.next8();
98+
const b2 = this.next8();
99+
const b3 = this.next8();
100+
const b4 = this.next8();
101+
const b5 = this.next8();
102+
const b6 = this.next8();
103+
const b7 = this.next8();
104+
const b8 = this.next8();
105+
return decodeInt64(b1, b2, b3, b4, b5, b6, b7, b8);
106+
} else if (type === 0xd4) {
107+
// fixext 1
108+
return this.decodeExtension(1);
109+
} else if (type === 0xd5) {
110+
// fixext 2
111+
return this.decodeExtension(2);
112+
} else if (type === 0xd6) {
113+
// fixext 4
114+
return this.decodeExtension(4);
115+
} else if (type === 0xd7) {
116+
// fixext 8
117+
return this.decodeExtension(8);
118+
} else if (type === 0xd8) {
119+
// fixext 16
120+
return this.decodeExtension(16);
121+
} else if (type === 0xd9) {
122+
// str 8
123+
const length = this.next8();
124+
return this.decodeUtf8String(length);
125+
} else if (type === 0xda) {
126+
// str 16
127+
const length = this.next16();
128+
return this.decodeUtf8String(length);
129+
} else if (type === 0xdb) {
130+
// str 32
131+
const length = this.next32();
132+
return this.decodeUtf8String(length);
133+
} else if (type === 0xdc) {
134+
// array 16
135+
const size = this.next16();
136+
return this.decodeArray(size);
137+
} else if (type === 0xdd) {
138+
// array 32
139+
const size = this.next32();
140+
return this.decodeArray(size);
141+
} else if (type === 0xde) {
142+
// map 16
143+
const size = this.next16();
144+
return this.decodeMap(size);
145+
} else if (type === 0xdf) {
146+
// map 32
147+
const size = this.next32();
148+
return this.decodeMap(size);
149+
} else if (type === 0xc7) {
150+
// ext 8
151+
} else {
152+
throw new Error(`Unrecognized type byte: ${prettyByte(type)}`);
153+
}
154+
}
155+
decodeBinary(size: number): ArrayLike<number> {
156+
const start = this.pos;
157+
this.pos += size;
158+
return this.buffer.slice(start, start + size);
159+
}
160+
decodeFloat(mLen: number, nBytes: number): number {
161+
const eLen = nBytes * 8 - mLen - 1;
162+
const eMax = (1 << eLen) - 1;
163+
const eBias = eMax >> 1;
164+
let nBits = -7;
165+
const byte = this.next8();
166+
const sign = byte >> -nBits;
167+
let exp = byte & ((1 << -nBits) - 1);
168+
nBits += eLen;
169+
while (nBits > 0) {
170+
exp = exp * 256 + this.next8();
171+
nBits -= 8;
172+
}
173+
let frac = exp & ((1 << -nBits) - 1);
174+
exp >>= -nBits;
175+
nBits += mLen;
176+
while (nBits > 0) {
177+
frac = frac * 256 + this.next8();
178+
nBits -= 8;
179+
}
180+
if (exp === 0) {
181+
exp = 1 - eBias;
182+
} else if (exp === eMax) {
183+
return frac ? NaN : sign ? -Infinity : Infinity;
184+
} else {
185+
frac = frac + Math.pow(2, mLen);
186+
exp = exp - eBias;
187+
}
188+
const value = frac * Math.pow(2, exp - mLen);
189+
return sign ? -value : value;
190+
}
191+
decodeUtf8String(length: number): string {
192+
const out: Array<number> = [];
193+
const end = this.pos + length;
194+
while (this.pos < end) {
195+
const byte1 = this.next8();
196+
if (byte1 == null) {
197+
throw new Error(`Invalid null at ${this.pos} in decoding ${length} bytes of buffer`);
198+
}
199+
if ((byte1 & 0x80) === 0) {
200+
// 1 byte
201+
out.push(byte1);
202+
} else if ((byte1 & 0xe0) === 0xc0) {
203+
// 2 bytes
204+
const byte2 = this.next8() & 0x3f;
205+
out.push(((byte1 & 0x1f) << 6) | byte2);
206+
} else if ((byte1 & 0xf0) === 0xe0) {
207+
// 3 bytes
208+
const byte2 = this.next8() & 0x3f;
209+
const byte3 = this.next8() & 0x3f;
210+
out.push(((byte1 & 0x1f) << 12) | (byte2 << 6) | byte3);
211+
} else if ((byte1 & 0xf8) === 0xf0) {
212+
// 4 bytes
213+
const byte2 = this.next8() & 0x3f;
214+
const byte3 = this.next8() & 0x3f;
215+
const byte4 = this.next8() & 0x3f;
216+
let codepoint = ((byte1 & 0x07) << 0x12) | (byte2 << 0x0c) | (byte3 << 0x06) | byte4;
217+
if (codepoint > 0xffff) {
218+
codepoint -= 0x10000;
219+
out.push(((codepoint >>> 10) & 0x3ff) | 0xd800);
220+
codepoint = 0xdc00 | (codepoint & 0x3ff);
221+
}
222+
out.push(codepoint);
223+
} else {
224+
throw new Error(`Invalid UTF-8 byte ${prettyByte(byte1)} at ${this.pos}`);
225+
}
226+
}
227+
return String.fromCharCode(...out);
228+
}
229+
decodeMap(size: number): Record<string, any> {
230+
const result: Record<string, any> = {};
231+
for (let i = 0; i < size; i++) {
232+
const key = this.decode();
233+
if (typeof key !== "string") {
234+
throw new Error(`Unsupported map key type: ${typeof key}`);
235+
}
236+
const value = this.decode();
237+
result[key] = value;
238+
}
239+
return result;
240+
}
241+
decodeArray(size: number): Array<any> {
242+
const result = new Array<any>(size);
243+
for (let i = 0; i < size; i++) {
244+
result[i] = this.decode();
245+
}
246+
return result;
247+
}
248+
decodeExtension(size: number) {
249+
const byte = this.next8();
250+
const extType = byte < 0x80 ? byte : byte - 0x100;
251+
const data = new Array<number>(size);
252+
for (let i = 0; i < size; i++) {
253+
data[i] = this.next8();
254+
}
255+
return this.extensionCodec.decode(extType, data);
256+
}
257+
next8(): number {
258+
return this.buffer[this.pos++];
259+
}
260+
next16(): number {
261+
const b1 = this.next8();
262+
const b2 = this.next8();
263+
return (b1 << 8) + b2;
264+
}
265+
next32(): number {
266+
const b1 = this.next8();
267+
const b2 = this.next8();
268+
const b3 = this.next8();
269+
const b4 = this.next8();
270+
return decodeUint32(b1, b2, b3, b4);
271+
}
272+
next64(): number {
273+
const high = this.next32();
274+
const low = this.next32();
275+
return high * 0x100000000 + low;
276+
}
277+
}

0 commit comments

Comments
 (0)