lzma1 0.1.2 → 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
+ }
@@ -0,0 +1,95 @@
1
+ import { getBitPrice, initArray, } from "./utils.js";
2
+ export class RangeBitTreeCoder {
3
+ models;
4
+ numBitLevels;
5
+ constructor(numBitLevels) {
6
+ this.numBitLevels = numBitLevels;
7
+ this.models = initArray(1 << numBitLevels, 1024); // Initialize with default probability
8
+ }
9
+ /**
10
+ * Decode symbol using range decoder
11
+ */
12
+ decode(rd) {
13
+ let res = 1;
14
+ for (let bitIndex = this.numBitLevels; bitIndex !== 0; bitIndex--) {
15
+ const bit = rd.decodeBit(this.models, res);
16
+ res = (res << 1) + bit;
17
+ }
18
+ res -= 1 << this.numBitLevels;
19
+ return res;
20
+ }
21
+ /**
22
+ * Reverse decode symbol using range decoder
23
+ */
24
+ reverseDecode(rd) {
25
+ let index = 1;
26
+ let res = 0;
27
+ for (let bitIndex = 0; bitIndex < this.numBitLevels; bitIndex++) {
28
+ const bit = rd.decodeBit(this.models, index);
29
+ index <<= 1;
30
+ index += bit;
31
+ res |= bit << bitIndex;
32
+ }
33
+ return res;
34
+ }
35
+ /**
36
+ * Encode symbol using range encoder
37
+ */
38
+ encode(re, symbol) {
39
+ let m = 1;
40
+ for (let bitIndex = this.numBitLevels; bitIndex !== 0;) {
41
+ bitIndex--;
42
+ const bit = (symbol >> bitIndex) & 1;
43
+ re.encodeBit(this.models, m, bit);
44
+ m = (m << 1) | bit;
45
+ }
46
+ }
47
+ /**
48
+ * Reverse encode symbol using range encoder
49
+ */
50
+ reverseEncode(re, symbol) {
51
+ let m = 1;
52
+ for (let i = 0; i < this.numBitLevels; i++) {
53
+ const bit = symbol & 1;
54
+ re.encodeBit(this.models, m, bit);
55
+ m = (m << 1) | bit;
56
+ symbol >>= 1;
57
+ }
58
+ }
59
+ /**
60
+ * Get price for encoding symbol
61
+ */
62
+ getPrice(symbol) {
63
+ let res = 0;
64
+ let m = 1;
65
+ for (let bitIndex = this.numBitLevels; bitIndex !== 0;) {
66
+ bitIndex--;
67
+ const bit = (symbol >> bitIndex) & 1;
68
+ res += getBitPrice(this.models[m], bit);
69
+ m = (m << 1) + bit;
70
+ }
71
+ return res;
72
+ }
73
+ /**
74
+ * Get price for reverse encoding symbol
75
+ */
76
+ reverseGetPrice(symbol) {
77
+ let res = 0;
78
+ let m = 1;
79
+ for (let i = this.numBitLevels; i !== 0; i--) {
80
+ const bit = symbol & 1;
81
+ symbol >>= 1;
82
+ res += getBitPrice(this.models[m], bit);
83
+ m = (m << 1) | bit;
84
+ }
85
+ return res;
86
+ }
87
+ /**
88
+ * Reset models to initial state
89
+ */
90
+ reset() {
91
+ for (let i = 0; i < this.models.length; i++) {
92
+ this.models[i] = 1024; // Default probability
93
+ }
94
+ }
95
+ }
@@ -0,0 +1,85 @@
1
+ export class RangeDecoder {
2
+ stream = null;
3
+ code = 0;
4
+ rrange = 0;
5
+ /**
6
+ * Set input stream for decoding
7
+ */
8
+ setStream(stream) {
9
+ this.stream = stream;
10
+ }
11
+ /**
12
+ * Initialize range decoder
13
+ */
14
+ init() {
15
+ this.code = 0;
16
+ this.rrange = -1;
17
+ for (let i = 0; i < 5; ++i) {
18
+ this.code = this.code << 8 | this.readFromStream();
19
+ }
20
+ }
21
+ /**
22
+ * Decode a single bit using probability model
23
+ */
24
+ decodeBit(probs, index) {
25
+ let newBound, prob = probs[index];
26
+ newBound = (this.rrange >>> 11) * prob;
27
+ if ((this.code ^ -0x80000000) < (newBound ^ -0x80000000)) {
28
+ this.rrange = newBound;
29
+ probs[index] = prob + ((2048 - prob) >>> 5);
30
+ if (!(this.rrange & -0x1000000)) {
31
+ this.code = this.code << 8 | this.readFromStream();
32
+ this.rrange <<= 8;
33
+ }
34
+ return 0;
35
+ }
36
+ else {
37
+ this.rrange -= newBound;
38
+ this.code -= newBound;
39
+ probs[index] = prob - (prob >>> 5);
40
+ if (!(this.rrange & -0x1000000)) {
41
+ this.code = this.code << 8 | this.readFromStream();
42
+ this.rrange <<= 8;
43
+ }
44
+ return 1;
45
+ }
46
+ }
47
+ /**
48
+ * Decode direct bits (without probability model)
49
+ */
50
+ decodeDirectBits(numTotalBits) {
51
+ let result = 0;
52
+ for (let i = numTotalBits; i != 0; i -= 1) {
53
+ this.rrange >>>= 1;
54
+ let t = (this.code - this.rrange) >>> 31;
55
+ this.code -= this.rrange & (t - 1);
56
+ result = result << 1 | 1 - t;
57
+ if (!(this.rrange & -0x1000000)) {
58
+ this.code = this.code << 8 | this.readFromStream();
59
+ this.rrange <<= 8;
60
+ }
61
+ }
62
+ return result;
63
+ }
64
+ /**
65
+ * Get current code value (for compatibility)
66
+ */
67
+ get currentCode() {
68
+ return this.code;
69
+ }
70
+ /**
71
+ * Get current range value (for compatibility)
72
+ */
73
+ get currentRange() {
74
+ return this.rrange;
75
+ }
76
+ /**
77
+ * Read a single byte from the input stream
78
+ */
79
+ readFromStream() {
80
+ if (!this.stream) {
81
+ return 0;
82
+ }
83
+ return this.stream.readByte();
84
+ }
85
+ }
@@ -0,0 +1,119 @@
1
+ export class RangeEncoder {
2
+ stream = null;
3
+ low = 0n;
4
+ rrange = 0;
5
+ cache = 0;
6
+ cacheSize = 0;
7
+ position = 0n;
8
+ constructor() {
9
+ // Initialize with default values
10
+ }
11
+ /**
12
+ * Set output stream for encoding
13
+ */
14
+ setStream(stream) {
15
+ this.stream = stream;
16
+ }
17
+ /**
18
+ * Initialize range encoder
19
+ */
20
+ init() {
21
+ this.position = 0n;
22
+ this.low = 0n;
23
+ this.rrange = -1;
24
+ this.cacheSize = 1;
25
+ this.cache = 0;
26
+ }
27
+ /**
28
+ * Encode a single bit using probability model
29
+ */
30
+ encodeBit(probs, index, bit) {
31
+ const prob = probs[index];
32
+ const newBound = (this.rrange >>> 11) * prob;
33
+ if (bit === 0) {
34
+ this.rrange = newBound;
35
+ probs[index] = prob + ((2048 - prob) >>> 5);
36
+ }
37
+ else {
38
+ this.low += BigInt(newBound);
39
+ this.rrange -= newBound;
40
+ probs[index] = prob - (prob >>> 5);
41
+ }
42
+ if (!(this.rrange & -0x1000000)) {
43
+ this.rrange <<= 8;
44
+ this.shiftLow();
45
+ }
46
+ }
47
+ /**
48
+ * Encode direct bits (without probability model)
49
+ */
50
+ encodeDirectBits(value, numTotalBits) {
51
+ for (let i = numTotalBits - 1; i >= 0; i--) {
52
+ this.rrange >>>= 1;
53
+ if (((value >>> i) & 1) === 1) {
54
+ this.low += BigInt(this.rrange);
55
+ }
56
+ if (!(this.rrange & -0x1000000)) {
57
+ this.rrange <<= 8;
58
+ this.shiftLow();
59
+ }
60
+ }
61
+ }
62
+ /**
63
+ * Encode bit tree symbol
64
+ */
65
+ encodeBitTree(numBitLevels, models, symbol, startIndex = 1) {
66
+ let m = 1;
67
+ for (let bitIndex = numBitLevels; bitIndex !== 0; bitIndex--) {
68
+ const bit = (symbol >>> (bitIndex - 1)) & 1;
69
+ this.encodeBit(models, startIndex + m - 1, bit);
70
+ m = (m << 1) | bit;
71
+ }
72
+ }
73
+ /**
74
+ * Reverse encode bits
75
+ */
76
+ reverseEncodeBits(numBitLevels, models, symbol, startIndex) {
77
+ let m = 1;
78
+ for (let i = 0; i < numBitLevels; i++) {
79
+ const bit = symbol & 1;
80
+ this.encodeBit(models, startIndex + m, bit);
81
+ m = (m << 1) | bit;
82
+ symbol >>>= 1;
83
+ }
84
+ }
85
+ /**
86
+ * Finish encoding and flush remaining data
87
+ */
88
+ finish() {
89
+ for (let i = 0; i < 5; i++) {
90
+ this.shiftLow();
91
+ }
92
+ }
93
+ /**
94
+ * Shift low value and write to stream
95
+ */
96
+ shiftLow() {
97
+ const lowHi = Number((this.low >> 32n) & 0xffffffffn);
98
+ if (lowHi !== 0 || Number(this.low & 0xffffffffn) < 0xFF000000) {
99
+ this.position += BigInt(this.cacheSize);
100
+ let temp = this.cache;
101
+ do {
102
+ this.writeToStream(temp + lowHi);
103
+ temp = 255;
104
+ } while (--this.cacheSize !== 0);
105
+ this.cache = (Number(this.low & 0xffffffffn) >>> 24) & 0xFF;
106
+ }
107
+ this.cacheSize++;
108
+ this.low = BigInt(Number(this.low & 0xffffffffn) & 0xFFFFFF) << 8n;
109
+ }
110
+ /**
111
+ * Write byte to output stream
112
+ */
113
+ writeToStream(value) {
114
+ if (!this.stream) {
115
+ return;
116
+ }
117
+ this.stream.writeByte(value & 0xFF);
118
+ }
119
+ }