|
1 | | -const fromCharCode = String.fromCharCode; |
2 | | - |
3 | | -export class StreamingOctetReader { |
4 | | - protected readonly chunks: Uint8Array[] = []; |
5 | | - |
6 | | - /** Total size of all chunks. */ |
7 | | - protected chunkSize: number = 0; |
8 | | - |
9 | | - protected x: number = 0; |
10 | | - |
11 | | - public size(): number { |
12 | | - return this.chunkSize - this.x; |
13 | | - } |
14 | | - |
15 | | - public push(chunk: Uint8Array): void { |
16 | | - this.chunks.push(chunk); |
17 | | - this.chunkSize += chunk.length; |
18 | | - } |
19 | | - |
20 | | - protected assertSize(size: number): void { |
21 | | - if (size > this.size()) throw new RangeError('OUT_OF_BOUNDS'); |
22 | | - } |
23 | | - |
24 | | - public u8(): number { |
25 | | - this.assertSize(1); |
26 | | - const chunk = this.chunks[0]!; |
27 | | - let x = this.x; |
28 | | - const octet = chunk[x++]; |
29 | | - if (x === chunk.length) { |
30 | | - this.chunks.shift(); |
31 | | - this.chunkSize -= chunk.length; |
32 | | - x = 0; |
33 | | - } |
34 | | - this.x = x; |
35 | | - return octet; |
36 | | - } |
37 | | - |
38 | | - public u32(): number { |
39 | | - const octet0 = this.u8(); |
40 | | - const octet1 = this.u8(); |
41 | | - const octet2 = this.u8(); |
42 | | - const octet3 = this.u8(); |
43 | | - return (octet0 * 0x1000000 + (octet1 << 16) + (octet2 << 8)) | octet3; |
44 | | - } |
45 | | - |
46 | | - public copy(size: number, dst: Uint8Array, pos: number): void { |
47 | | - if (!size) return; |
48 | | - this.assertSize(size); |
49 | | - const chunk0 = this.chunks[0]!; |
50 | | - const size0 = Math.min(chunk0.length - this.x, size); |
51 | | - dst.set(chunk0.subarray(this.x, this.x + size0), pos); |
52 | | - size -= size0; |
53 | | - if (size <= 0) { |
54 | | - this.skipUnsafe(size0); |
55 | | - return; |
56 | | - } |
57 | | - let chunkIndex = 1; |
58 | | - while (size > 0) { |
59 | | - const chunk1 = this.chunks[chunkIndex]!; |
60 | | - const size1 = Math.min(chunk1.length, size); |
61 | | - dst.set(chunk1.subarray(0, size1), pos + size0); |
62 | | - size -= size1; |
63 | | - chunkIndex++; |
64 | | - } |
65 | | - this.skipUnsafe(size); |
66 | | - } |
67 | | - |
68 | | - public copyXor( |
69 | | - size: number, |
70 | | - dst: Uint8Array, |
71 | | - pos: number, |
72 | | - mask: [number, number, number, number], |
73 | | - maskIndex: number, |
74 | | - ): void { |
75 | | - if (!size) return; |
76 | | - this.assertSize(size); |
77 | | - const chunk0 = this.chunks[0]!; |
78 | | - let x = this.x; |
79 | | - const size0 = Math.min(chunk0.length - x, size); |
80 | | - const end = x + size0; |
81 | | - for (; x < end; ) dst[pos++] = chunk0[x++] ^ mask[maskIndex++ % 4]; |
82 | | - size -= size0; |
83 | | - if (size <= 0) { |
84 | | - this.skipUnsafe(size0); |
85 | | - return; |
86 | | - } |
87 | | - let chunkIndex = 1; |
88 | | - while (size > 0) { |
89 | | - const chunk1 = this.chunks[chunkIndex++]!; |
90 | | - const size1 = Math.min(chunk1.length, size); |
91 | | - for (let x = 0; x < size1; ) dst[pos++] = chunk1[x++] ^ mask[maskIndex++ % 4]; |
92 | | - size -= size1; |
93 | | - } |
94 | | - this.skipUnsafe(size); |
95 | | - } |
96 | | - |
97 | | - public buf(size: number): Uint8Array { |
98 | | - this.assertSize(size); |
99 | | - const buf = new Uint8Array(size); |
100 | | - this.copy(size, buf, 0); |
101 | | - return buf; |
102 | | - } |
103 | | - |
104 | | - public bufXor(size: number, mask: [number, number, number, number], maskIndex: number): Uint8Array { |
105 | | - this.assertSize(size); |
106 | | - const buf = new Uint8Array(size); |
107 | | - this.copyXor(size, buf, 0, mask, maskIndex); |
108 | | - return buf; |
109 | | - } |
110 | | - |
111 | | - public skipUnsafe(n: number): void { |
112 | | - if (!n) return; |
113 | | - const chunk = this.chunks[0]!; |
114 | | - const chunkLength = chunk.length; |
115 | | - const remaining = chunkLength - this.x; |
116 | | - if (remaining > n) { |
117 | | - this.x = this.x + n; |
118 | | - return; |
119 | | - } |
120 | | - this.x = 0; |
121 | | - this.chunks.shift(); |
122 | | - this.chunkSize -= chunkLength; |
123 | | - n -= remaining; |
124 | | - this.skipUnsafe(n); |
125 | | - } |
126 | | - |
127 | | - public skip(n: number): void { |
128 | | - this.assertSize(n); |
129 | | - this.skipUnsafe(n); |
130 | | - } |
131 | | - |
132 | | - public peek(): number { |
133 | | - this.assertSize(1); |
134 | | - return this.chunks[0]![this.x]; |
135 | | - } |
136 | | - |
137 | | - /** |
138 | | - * Get current byte value without advancing the cursor. |
139 | | - * @deprecated Use peek() instead. |
140 | | - */ |
141 | | - public peak(): number { |
142 | | - return this.peek(); |
143 | | - } |
144 | | - |
145 | | - public utf8(length: number, mask: [number, number, number, number], maskIndex: number): string { |
146 | | - this.assertSize(length); |
147 | | - let i = 0; |
148 | | - const points: number[] = []; |
149 | | - while (i < length) { |
150 | | - let code = this.u8() ^ mask[maskIndex++ % 4]; |
151 | | - i++; |
152 | | - if ((code & 0x80) !== 0) { |
153 | | - const octet2 = (this.u8() ^ mask[maskIndex++ % 4]) & 0x3f; |
154 | | - i++; |
155 | | - if ((code & 0xe0) === 0xc0) { |
156 | | - code = ((code & 0x1f) << 6) | octet2; |
157 | | - } else { |
158 | | - const octet3 = (this.u8() ^ mask[maskIndex++ % 4]) & 0x3f; |
159 | | - i++; |
160 | | - if ((code & 0xf0) === 0xe0) { |
161 | | - code = ((code & 0x1f) << 12) | (octet2 << 6) | octet3; |
162 | | - } else { |
163 | | - if ((code & 0xf8) === 0xf0) { |
164 | | - const octet4 = (this.u8() ^ mask[maskIndex++ % 4]) & 0x3f; |
165 | | - i++; |
166 | | - let unit = ((code & 0x07) << 0x12) | (octet2 << 0x0c) | (octet3 << 0x06) | octet4; |
167 | | - if (unit > 0xffff) { |
168 | | - unit -= 0x10000; |
169 | | - const unit0 = ((unit >>> 10) & 0x3ff) | 0xd800; |
170 | | - code = 0xdc00 | (unit & 0x3ff); |
171 | | - points.push(unit0); |
172 | | - } else { |
173 | | - code = unit; |
174 | | - } |
175 | | - } |
176 | | - } |
177 | | - } |
178 | | - } |
179 | | - points.push(code); |
180 | | - } |
181 | | - return fromCharCode.apply(String, points); |
182 | | - } |
183 | | -} |
| 1 | +export * from '@jsonjoy.com/buffers/lib/StreamingOctetReader'; |
0 commit comments