lzma1 0.2.0 → 0.3.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.
@@ -0,0 +1,402 @@
1
+ import { CRC32_TABLE, DICTIONARY_SIZE_THRESHOLD, } from "./utils.js";
2
+ /**
3
+ * BinTreeMatchFinder — Binary tree match finder for LZMA encoding.
4
+ *
5
+ * Combines input window management, hash-based match finding, and
6
+ * binary tree search into a single cohesive class.
7
+ */
8
+ export class BinTreeMatchFinder {
9
+ // Input window fields
10
+ _posLimit = 0;
11
+ _bufferBase = new Uint8Array(0);
12
+ _pos = 0;
13
+ _streamPos = 0;
14
+ _streamEndWasReached = 0;
15
+ _bufferOffset = 0;
16
+ _blockSize = 0;
17
+ _keepSizeBefore = 0;
18
+ _keepSizeAfter = 0;
19
+ _pointerToLastSafePosition = 0;
20
+ _stream = null;
21
+ // Hash and tree fields
22
+ HASH_ARRAY = true;
23
+ kNumHashDirectBytes = 0;
24
+ kMinMatchCheck = 4;
25
+ kFixHashSize = 66560;
26
+ _hashMask = 0;
27
+ _hashSizeSum = 0;
28
+ _hash = new Int32Array(0);
29
+ _cyclicBufferSize = 0;
30
+ _cyclicBufferPos = 0;
31
+ _son = new Int32Array(0);
32
+ _matchMaxLen = 0;
33
+ _cutValue = 0xff;
34
+ // --- LzInWindow methods ---
35
+ getIndexByte(index) {
36
+ return this._bufferBase[this._bufferOffset + this._pos + index];
37
+ }
38
+ getMatchLen(index, distance, limit) {
39
+ if (this._streamEndWasReached) {
40
+ if (this._pos + index + limit > this._streamPos) {
41
+ limit = this._streamPos - (this._pos + index);
42
+ }
43
+ }
44
+ ++distance;
45
+ let i;
46
+ const pby = this._bufferOffset + this._pos + index;
47
+ for (i = 0; i < limit
48
+ && this._bufferBase[pby + i]
49
+ == this._bufferBase[pby + i - distance]; ++i)
50
+ ;
51
+ return i;
52
+ }
53
+ getNumAvailableBytes() {
54
+ return this._streamPos - this._pos;
55
+ }
56
+ moveBlock() {
57
+ let offset = this._bufferOffset + this._pos - this._keepSizeBefore;
58
+ if (offset > 0) {
59
+ --offset;
60
+ }
61
+ const numBytes = this._bufferOffset + this._streamPos - offset;
62
+ this._bufferBase.copyWithin(0, offset, offset + numBytes);
63
+ this._bufferOffset -= offset;
64
+ }
65
+ movePosInWindow() {
66
+ this._pos += 1;
67
+ if (this._pos > this._posLimit) {
68
+ const pointerToPosition = this._bufferOffset + this._pos;
69
+ if (pointerToPosition > this._pointerToLastSafePosition) {
70
+ this.moveBlock();
71
+ }
72
+ this.readBlock();
73
+ }
74
+ }
75
+ readBlock() {
76
+ if (this._streamEndWasReached) {
77
+ return;
78
+ }
79
+ while (true) {
80
+ const size = -this._bufferOffset + this._blockSize - this._streamPos;
81
+ if (!size) {
82
+ return;
83
+ }
84
+ const bytesRead = this.readFromStream(this._bufferOffset + this._streamPos, size);
85
+ if (bytesRead == -1) {
86
+ this._posLimit = this._streamPos;
87
+ const pointerToPosition = this._bufferOffset + this._posLimit;
88
+ if (pointerToPosition > this._pointerToLastSafePosition) {
89
+ this._posLimit = this._pointerToLastSafePosition - this._bufferOffset;
90
+ }
91
+ this._streamEndWasReached = 1;
92
+ return;
93
+ }
94
+ this._streamPos += bytesRead;
95
+ if (this._streamPos >= this._pos + this._keepSizeAfter) {
96
+ this._posLimit = this._streamPos - this._keepSizeAfter;
97
+ }
98
+ }
99
+ }
100
+ reduceOffsets(subValue) {
101
+ this._bufferOffset += subValue;
102
+ this._posLimit -= subValue;
103
+ this._pos -= subValue;
104
+ this._streamPos -= subValue;
105
+ }
106
+ readFromStream(off, len) {
107
+ const stream = this._stream;
108
+ const buffer = this._bufferBase;
109
+ return stream.readBytes(buffer, off, len);
110
+ }
111
+ // --- Match finder configuration methods ---
112
+ createBuffers(keepSizeBefore, keepSizeAfter, keepSizeReserv) {
113
+ this._keepSizeBefore = keepSizeBefore;
114
+ this._keepSizeAfter = keepSizeAfter;
115
+ const blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
116
+ if (this._blockSize != blockSize) {
117
+ this._bufferBase = new Uint8Array(blockSize);
118
+ this._blockSize = blockSize;
119
+ }
120
+ this._pointerToLastSafePosition = this._blockSize - keepSizeAfter;
121
+ }
122
+ create(dictionarySize, numFastBytes, keepAddBufferBefore, keepAddBufferAfter) {
123
+ if (dictionarySize < DICTIONARY_SIZE_THRESHOLD) {
124
+ this._cutValue = 0x10 + (numFastBytes >> 1);
125
+ const windowReservSize = ~~((dictionarySize + keepAddBufferBefore + numFastBytes + keepAddBufferAfter) / 2) + 0x100;
126
+ this.createBuffers(dictionarySize + keepAddBufferBefore, numFastBytes + keepAddBufferAfter, windowReservSize);
127
+ this._matchMaxLen = numFastBytes;
128
+ // Ensure cyclic buffer
129
+ const cyclicBufferSize = dictionarySize + 1;
130
+ if (this._cyclicBufferSize !== cyclicBufferSize) {
131
+ this._cyclicBufferSize = cyclicBufferSize;
132
+ this._son = new Int32Array(cyclicBufferSize * 2);
133
+ }
134
+ // Compute hash size
135
+ let hs = 0x10000;
136
+ if (this.HASH_ARRAY) {
137
+ hs = dictionarySize - 1;
138
+ hs |= hs >> 1;
139
+ hs |= hs >> 2;
140
+ hs |= hs >> 4;
141
+ hs |= hs >> 0x08;
142
+ hs >>= 1;
143
+ hs |= 0xFFFF;
144
+ if (hs > 0x1000000) {
145
+ hs >>= 1;
146
+ }
147
+ this._hashMask = hs;
148
+ hs += 1;
149
+ const finalHashSizeSum = hs + this.kFixHashSize;
150
+ if (finalHashSizeSum !== this._hashSizeSum) {
151
+ this._hashSizeSum = finalHashSizeSum;
152
+ this._hash = new Int32Array(finalHashSizeSum);
153
+ }
154
+ }
155
+ else {
156
+ if (hs !== this._hashSizeSum) {
157
+ this._hashSizeSum = hs;
158
+ this._hash = new Int32Array(hs);
159
+ }
160
+ }
161
+ }
162
+ }
163
+ // --- Match finding methods ---
164
+ getMatches(distances) {
165
+ let count, cur, curMatch, curMatch2, curMatch3, cyclicPos, delta, hash2Value, hash3Value, hashValue, len, len0, len1, lenLimit, matchMinPos, maxLen, offset, pby1, ptr0, ptr1, temp;
166
+ if (this._pos + this._matchMaxLen <= this._streamPos) {
167
+ lenLimit = this._matchMaxLen;
168
+ }
169
+ else {
170
+ lenLimit = this._streamPos - this._pos;
171
+ if (lenLimit < this.kMinMatchCheck) {
172
+ this.movePos();
173
+ return 0;
174
+ }
175
+ }
176
+ offset = 0;
177
+ matchMinPos = this._pos > this._cyclicBufferSize
178
+ ? this._pos - this._cyclicBufferSize
179
+ : 0;
180
+ cur = this._bufferOffset + this._pos;
181
+ maxLen = 1;
182
+ hash2Value = 0;
183
+ hash3Value = 0;
184
+ if (this.HASH_ARRAY) {
185
+ temp = CRC32_TABLE[this._bufferBase[cur]] ^ this._bufferBase[cur + 1];
186
+ hash2Value = temp & 0x3FF;
187
+ temp ^= this._bufferBase[cur + 2] << 0x08;
188
+ hash3Value = temp & 0xFFFF;
189
+ hashValue = (temp ^ (CRC32_TABLE[this._bufferBase[cur + 3]] << 5)) & this._hashMask;
190
+ }
191
+ else {
192
+ hashValue = this._bufferBase[cur] ^ (this._bufferBase[cur + 1] << 0x08);
193
+ }
194
+ curMatch = this._hash[this.kFixHashSize + hashValue] || 0;
195
+ if (this.HASH_ARRAY) {
196
+ curMatch2 = this._hash[hash2Value] || 0;
197
+ curMatch3 = this._hash[0x400 + hash3Value] || 0;
198
+ this._hash[hash2Value] = this._pos;
199
+ this._hash[0x400 + hash3Value] = this._pos;
200
+ if (curMatch2 > matchMinPos) {
201
+ if (this._bufferBase[this._bufferOffset + curMatch2] == this._bufferBase[cur]) {
202
+ distances[offset++] = maxLen = 2;
203
+ distances[offset++] = this._pos - curMatch2 - 1;
204
+ }
205
+ }
206
+ if (curMatch3 > matchMinPos) {
207
+ if (this._bufferBase[this._bufferOffset + curMatch3] == this._bufferBase[cur]) {
208
+ if (curMatch3 == curMatch2) {
209
+ offset -= 2;
210
+ }
211
+ distances[offset++] = maxLen = 3;
212
+ distances[offset++] = this._pos - curMatch3 - 1;
213
+ curMatch2 = curMatch3;
214
+ }
215
+ }
216
+ if (offset != 0 && curMatch2 == curMatch) {
217
+ offset -= 2;
218
+ maxLen = 1;
219
+ }
220
+ }
221
+ this._hash[this.kFixHashSize + hashValue] = this._pos;
222
+ ptr0 = (this._cyclicBufferPos << 1) + 1;
223
+ ptr1 = this._cyclicBufferPos << 1;
224
+ len0 = len1 = this.kNumHashDirectBytes;
225
+ if (this.kNumHashDirectBytes != 0) {
226
+ if (curMatch > matchMinPos) {
227
+ if (this._bufferBase[this._bufferOffset + curMatch + this.kNumHashDirectBytes] != this._bufferBase[cur + this.kNumHashDirectBytes]) {
228
+ distances[offset++] = maxLen = this.kNumHashDirectBytes;
229
+ distances[offset++] = this._pos - curMatch - 1;
230
+ }
231
+ }
232
+ }
233
+ count = this._cutValue;
234
+ while (1) {
235
+ if (curMatch <= matchMinPos || count == 0) {
236
+ count -= 1;
237
+ this._son[ptr0] = this._son[ptr1] = 0;
238
+ break;
239
+ }
240
+ delta = this._pos - curMatch;
241
+ cyclicPos = (delta <= this._cyclicBufferPos
242
+ ? this._cyclicBufferPos - delta
243
+ : this._cyclicBufferPos - delta + this._cyclicBufferSize) << 1;
244
+ pby1 = this._bufferOffset + curMatch;
245
+ len = len0 < len1 ? len0 : len1;
246
+ if (this._bufferBase[pby1 + len] == this._bufferBase[cur + len]) {
247
+ while ((len += 1) != lenLimit) {
248
+ if (this._bufferBase[pby1 + len] != this._bufferBase[cur + len]) {
249
+ break;
250
+ }
251
+ }
252
+ if (maxLen < len) {
253
+ distances[offset++] = maxLen = len;
254
+ distances[offset++] = delta - 1;
255
+ if (len == lenLimit) {
256
+ this._son[ptr1] = this._son[cyclicPos];
257
+ this._son[ptr0] = this._son[cyclicPos + 1];
258
+ break;
259
+ }
260
+ }
261
+ }
262
+ if (this._bufferBase[pby1 + len] < this._bufferBase[cur + len]) {
263
+ this._son[ptr1] = curMatch;
264
+ ptr1 = cyclicPos + 1;
265
+ curMatch = this._son[ptr1];
266
+ len1 = len;
267
+ }
268
+ else {
269
+ this._son[ptr0] = curMatch;
270
+ ptr0 = cyclicPos;
271
+ curMatch = this._son[ptr0];
272
+ len0 = len;
273
+ }
274
+ }
275
+ this.movePos();
276
+ return offset;
277
+ }
278
+ skip(num) {
279
+ let count, cur, curMatch, cyclicPos, delta, hash2Value, hash3Value, hashValue, len, len0, len1, lenLimit, matchMinPos, pby1, ptr0, ptr1, temp;
280
+ do {
281
+ if (this._pos + this._matchMaxLen <= this._streamPos) {
282
+ lenLimit = this._matchMaxLen;
283
+ }
284
+ else {
285
+ lenLimit = this._streamPos - this._pos;
286
+ if (lenLimit < this.kMinMatchCheck) {
287
+ this.movePos();
288
+ continue;
289
+ }
290
+ }
291
+ matchMinPos = this._pos > this._cyclicBufferSize
292
+ ? this._pos - this._cyclicBufferSize
293
+ : 0;
294
+ cur = this._bufferOffset + this._pos;
295
+ if (this.HASH_ARRAY) {
296
+ temp = CRC32_TABLE[this._bufferBase[cur]] ^ this._bufferBase[cur + 1];
297
+ hash2Value = temp & 0x3FF;
298
+ this._hash[hash2Value] = this._pos;
299
+ temp ^= this._bufferBase[cur + 2] << 0x08;
300
+ hash3Value = temp & 0xFFFF;
301
+ this._hash[0x400 + hash3Value] = this._pos;
302
+ hashValue = (temp ^ (CRC32_TABLE[this._bufferBase[cur + 3]] << 5)) & this._hashMask;
303
+ }
304
+ else {
305
+ hashValue = this._bufferBase[cur] ^ (this._bufferBase[cur + 1] << 0x08);
306
+ }
307
+ curMatch = this._hash[this.kFixHashSize + hashValue];
308
+ this._hash[this.kFixHashSize + hashValue] = this._pos;
309
+ ptr0 = (this._cyclicBufferPos << 1) + 1;
310
+ ptr1 = this._cyclicBufferPos << 1;
311
+ len0 = len1 = this.kNumHashDirectBytes;
312
+ count = this._cutValue;
313
+ while (1) {
314
+ if (curMatch <= matchMinPos || count == 0) {
315
+ count -= 1;
316
+ this._son[ptr0] = this._son[ptr1] = 0;
317
+ break;
318
+ }
319
+ delta = this._pos - curMatch;
320
+ cyclicPos = (delta <= this._cyclicBufferPos
321
+ ? this._cyclicBufferPos - delta
322
+ : this._cyclicBufferPos - delta + this._cyclicBufferSize) << 1;
323
+ pby1 = this._bufferOffset + curMatch;
324
+ len = len0 < len1 ? len0 : len1;
325
+ if (this._bufferBase[pby1 + len] == this._bufferBase[cur + len]) {
326
+ while ((len += 1) != lenLimit) {
327
+ if (this._bufferBase[pby1 + len] != this._bufferBase[cur + len]) {
328
+ break;
329
+ }
330
+ }
331
+ if (len == lenLimit) {
332
+ this._son[ptr1] = this._son[cyclicPos];
333
+ this._son[ptr0] = this._son[cyclicPos + 1];
334
+ break;
335
+ }
336
+ }
337
+ if (this._bufferBase[pby1 + len] < this._bufferBase[cur + len]) {
338
+ this._son[ptr1] = curMatch;
339
+ ptr1 = cyclicPos + 1;
340
+ curMatch = this._son[ptr1];
341
+ len1 = len;
342
+ }
343
+ else {
344
+ this._son[ptr0] = curMatch;
345
+ ptr0 = cyclicPos;
346
+ curMatch = this._son[ptr0];
347
+ len0 = len;
348
+ }
349
+ }
350
+ this.movePos();
351
+ } while ((num -= 1) != 0);
352
+ }
353
+ movePos() {
354
+ if ((this._cyclicBufferPos += 1) >= this._cyclicBufferSize) {
355
+ this._cyclicBufferPos = 0;
356
+ }
357
+ this.movePosInWindow();
358
+ if (this._pos == DICTIONARY_SIZE_THRESHOLD) {
359
+ const subValue = this._pos - this._cyclicBufferSize;
360
+ this.normalizeLinks(this._son, this._cyclicBufferSize * 2, subValue);
361
+ this.normalizeLinks(this._hash, this._hashSizeSum, subValue);
362
+ this.reduceOffsets(subValue);
363
+ }
364
+ }
365
+ init() {
366
+ this._bufferOffset = 0;
367
+ this._pos = 0;
368
+ this._streamPos = 0;
369
+ this._streamEndWasReached = 0;
370
+ this.readBlock();
371
+ this._cyclicBufferPos = 0;
372
+ this.reduceOffsets(-1);
373
+ }
374
+ /**
375
+ * This is only called after reading one whole gigabyte.
376
+ */
377
+ normalizeLinks(items, numItems, subValue) {
378
+ for (let i = 0; i < numItems; ++i) {
379
+ let value = items[i];
380
+ if (value <= subValue) {
381
+ value = 0;
382
+ }
383
+ else {
384
+ value -= subValue;
385
+ }
386
+ items[i] = value;
387
+ }
388
+ }
389
+ setType(numHashBytes) {
390
+ this.HASH_ARRAY = numHashBytes > 2;
391
+ if (this.HASH_ARRAY) {
392
+ this.kNumHashDirectBytes = 0;
393
+ this.kMinMatchCheck = 4;
394
+ this.kFixHashSize = 66560;
395
+ }
396
+ else {
397
+ this.kNumHashDirectBytes = 2;
398
+ this.kMinMatchCheck = 3;
399
+ this.kFixHashSize = 0;
400
+ }
401
+ }
402
+ }
@@ -26,7 +26,7 @@ export class RangeDecoder {
26
26
  newBound = (this.rrange >>> 11) * prob;
27
27
  if ((this.code ^ -0x80000000) < (newBound ^ -0x80000000)) {
28
28
  this.rrange = newBound;
29
- probs[index] = prob + (2048 - prob >>> 5) << 16 >> 16;
29
+ probs[index] = prob + ((2048 - prob) >>> 5);
30
30
  if (!(this.rrange & -0x1000000)) {
31
31
  this.code = this.code << 8 | this.readFromStream();
32
32
  this.rrange <<= 8;
@@ -36,7 +36,7 @@ export class RangeDecoder {
36
36
  else {
37
37
  this.rrange -= newBound;
38
38
  this.code -= newBound;
39
- probs[index] = prob - (prob >>> 5) << 16 >> 16;
39
+ probs[index] = prob - (prob >>> 5);
40
40
  if (!(this.rrange & -0x1000000)) {
41
41
  this.code = this.code << 8 | this.readFromStream();
42
42
  this.rrange <<= 8;
@@ -80,19 +80,6 @@ export class RangeDecoder {
80
80
  if (!this.stream) {
81
81
  return 0;
82
82
  }
83
- if (this.stream.pos >= this.stream.count) {
84
- return -1;
85
- }
86
- let value;
87
- if (this.stream.buf instanceof ArrayBuffer) {
88
- value = new Uint8Array(this.stream.buf)[this.stream.pos++];
89
- }
90
- else if (this.stream.buf instanceof Uint8Array) {
91
- value = this.stream.buf[this.stream.pos++];
92
- }
93
- else {
94
- value = this.stream.buf[this.stream.pos++];
95
- }
96
- return value & 0xFF;
83
+ return this.stream.readByte();
97
84
  }
98
85
  }
@@ -1,11 +1,10 @@
1
- import { add64, fromInt64, lowBits64, } from "./utils.js";
2
1
  export class RangeEncoder {
3
2
  stream = null;
4
- low = [0, 0];
3
+ low = 0n;
5
4
  rrange = 0;
6
5
  cache = 0;
7
6
  cacheSize = 0;
8
- position = [0, 0];
7
+ position = 0n;
9
8
  constructor() {
10
9
  // Initialize with default values
11
10
  }
@@ -19,8 +18,8 @@ export class RangeEncoder {
19
18
  * Initialize range encoder
20
19
  */
21
20
  init() {
22
- this.position = [0, 0];
23
- this.low = [0, 0];
21
+ this.position = 0n;
22
+ this.low = 0n;
24
23
  this.rrange = -1;
25
24
  this.cacheSize = 1;
26
25
  this.cache = 0;
@@ -33,12 +32,12 @@ export class RangeEncoder {
33
32
  const newBound = (this.rrange >>> 11) * prob;
34
33
  if (bit === 0) {
35
34
  this.rrange = newBound;
36
- probs[index] = prob + ((2048 - prob) >>> 5) << 16 >> 16;
35
+ probs[index] = prob + ((2048 - prob) >>> 5);
37
36
  }
38
37
  else {
39
- this.low = add64(this.low, fromInt64(newBound));
38
+ this.low += BigInt(newBound);
40
39
  this.rrange -= newBound;
41
- probs[index] = prob - (prob >>> 5) << 16 >> 16;
40
+ probs[index] = prob - (prob >>> 5);
42
41
  }
43
42
  if (!(this.rrange & -0x1000000)) {
44
43
  this.rrange <<= 8;
@@ -52,7 +51,7 @@ export class RangeEncoder {
52
51
  for (let i = numTotalBits - 1; i >= 0; i--) {
53
52
  this.rrange >>>= 1;
54
53
  if (((value >>> i) & 1) === 1) {
55
- this.low = add64(this.low, fromInt64(this.rrange));
54
+ this.low += BigInt(this.rrange);
56
55
  }
57
56
  if (!(this.rrange & -0x1000000)) {
58
57
  this.rrange <<= 8;
@@ -95,18 +94,18 @@ export class RangeEncoder {
95
94
  * Shift low value and write to stream
96
95
  */
97
96
  shiftLow() {
98
- const lowHi = lowBits64([this.low[1], 0]);
99
- if (lowHi !== 0 || this.low[0] < 0xFF000000) {
100
- this.position = add64(this.position, fromInt64(this.cacheSize));
97
+ const lowHi = Number((this.low >> 32n) & 0xffffffffn);
98
+ if (lowHi !== 0 || Number(this.low & 0xffffffffn) < 0xFF000000) {
99
+ this.position += BigInt(this.cacheSize);
101
100
  let temp = this.cache;
102
101
  do {
103
102
  this.writeToStream(temp + lowHi);
104
103
  temp = 255;
105
104
  } while (--this.cacheSize !== 0);
106
- this.cache = (this.low[0] >>> 24) & 0xFF;
105
+ this.cache = (Number(this.low & 0xffffffffn) >>> 24) & 0xFF;
107
106
  }
108
107
  this.cacheSize++;
109
- this.low = [(this.low[0] & 0xFFFFFF) << 8, this.low[1]];
108
+ this.low = BigInt(Number(this.low & 0xffffffffn) & 0xFFFFFF) << 8n;
110
109
  }
111
110
  /**
112
111
  * Write byte to output stream
@@ -115,15 +114,6 @@ export class RangeEncoder {
115
114
  if (!this.stream) {
116
115
  return;
117
116
  }
118
- // Ensure buffer has enough capacity
119
- if (this.stream.count >= this.stream.buf.length) {
120
- const newSize = Math.max(this.stream.buf.length * 2, this.stream.count + 1);
121
- const newBuf = new Array(newSize);
122
- for (let i = 0; i < this.stream.count; i++) {
123
- newBuf[i] = this.stream.buf[i];
124
- }
125
- this.stream.buf = newBuf;
126
- }
127
- this.stream.buf[this.stream.count++] = value & 0xFF;
117
+ this.stream.writeByte(value & 0xFF);
128
118
  }
129
119
  }
package/lib/streams.js CHANGED
@@ -1 +1,64 @@
1
- export {};
1
+ /**
2
+ * Read-only input buffer wrapping a Uint8Array.
3
+ */
4
+ export class InputBuffer {
5
+ buf;
6
+ pos = 0;
7
+ count;
8
+ constructor(data) {
9
+ this.buf = data;
10
+ this.count = data.length;
11
+ }
12
+ readByte() {
13
+ if (this.pos >= this.count)
14
+ return -1;
15
+ return this.buf[this.pos++] & 0xFF;
16
+ }
17
+ readBytes(dest, off, len) {
18
+ if (this.pos >= this.count)
19
+ return -1;
20
+ len = Math.min(len, this.count - this.pos);
21
+ dest.set(this.buf.subarray(this.pos, this.pos + len), off);
22
+ this.pos += len;
23
+ return len;
24
+ }
25
+ get remaining() {
26
+ return this.count - this.pos;
27
+ }
28
+ }
29
+ /**
30
+ * Growable output buffer backed by a Uint8Array.
31
+ */
32
+ export class OutputBuffer {
33
+ buf;
34
+ count = 0;
35
+ constructor(capacity = 32) {
36
+ this.buf = new Uint8Array(capacity);
37
+ }
38
+ grow(requiredSize) {
39
+ const newSize = Math.max(this.buf.length * 2, requiredSize);
40
+ const newBuf = new Uint8Array(newSize);
41
+ newBuf.set(this.buf.subarray(0, this.count));
42
+ this.buf = newBuf;
43
+ }
44
+ writeByte(b) {
45
+ if (this.count >= this.buf.length) {
46
+ this.grow(this.count + 1);
47
+ }
48
+ this.buf[this.count++] = b;
49
+ }
50
+ writeBytes(src, off, len) {
51
+ const requiredSize = this.count + len;
52
+ if (requiredSize > this.buf.length) {
53
+ this.grow(requiredSize);
54
+ }
55
+ this.buf.set(src.subarray(off, off + len), this.count);
56
+ this.count += len;
57
+ }
58
+ write(buf) {
59
+ this.writeBytes(buf, 0, buf.length);
60
+ }
61
+ toArray() {
62
+ return this.buf.slice(0, this.count);
63
+ }
64
+ }