lzma1 0.1.2 → 0.2.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/lib/encoder.js ADDED
@@ -0,0 +1,822 @@
1
+ import { LenEncoder, } from "./len-coder.js";
2
+ import { LitCoder } from "./lit-coder.js";
3
+ import { add64, compare64, create64, createBitTree, fromInt64, G_FAST_POS, getBitPrice, getLenToPosState, initArray, initBitModels, lowBits64, PROB_PRICES, } from "./utils.js";
4
+ const bitTreePriceCache = new Map();
5
+ /**
6
+ * Calculate price for direct bit encoding
7
+ */
8
+ function getDirectBitsPrice(numBits) {
9
+ return numBits << 6;
10
+ }
11
+ /**
12
+ * Get price for bit tree encoding with caching
13
+ */
14
+ function getBitTreePrice(bitTree, symbol) {
15
+ const cacheKey = `${bitTree.numBitLevels}-${symbol}`;
16
+ if (bitTreePriceCache.has(cacheKey)) {
17
+ return bitTreePriceCache.get(cacheKey);
18
+ }
19
+ let price = 0;
20
+ let modelIndex = 1;
21
+ for (let bitIndex = bitTree.numBitLevels; bitIndex > 0; bitIndex--) {
22
+ const bit = (symbol >>> (bitIndex - 1)) & 1;
23
+ price += getBitPrice(bitTree.models[modelIndex], bit);
24
+ modelIndex = (modelIndex << 1) + bit;
25
+ }
26
+ if (bitTreePriceCache.size < 10000) {
27
+ bitTreePriceCache.set(cacheKey, price);
28
+ }
29
+ return price;
30
+ }
31
+ /**
32
+ * LZMA Encoder State - Encapsulates all encoder state management
33
+ */
34
+ class EncoderState {
35
+ // Core state
36
+ state = 0;
37
+ previousByte = 0;
38
+ position = [0, 0];
39
+ // Repetition distances (LZ77 back-references)
40
+ repDistances = [0, 0, 0, 0];
41
+ // Match finding state
42
+ longestMatchLength = 0;
43
+ longestMatchWasFound = false;
44
+ additionalOffset = 0;
45
+ // Probability models for different encoding decisions
46
+ isMatch = initArray(0xC0);
47
+ isRep = initArray(0x0C);
48
+ isRepG0 = initArray(0x0C);
49
+ isRepG1 = initArray(0x0C);
50
+ isRepG2 = initArray(0x0C);
51
+ isRep0Long = initArray(0xC0);
52
+ /**
53
+ * Initialize all probability models to default values
54
+ */
55
+ initModels() {
56
+ initBitModels(this.isMatch);
57
+ initBitModels(this.isRep);
58
+ initBitModels(this.isRepG0);
59
+ initBitModels(this.isRepG1);
60
+ initBitModels(this.isRepG2);
61
+ initBitModels(this.isRep0Long);
62
+ }
63
+ /**
64
+ * Update repetition distances when a new match is found
65
+ */
66
+ updateRepDistances(newDistance, repIndex) {
67
+ if (repIndex === 0) {
68
+ // New match becomes rep0, shift others
69
+ this.repDistances[3] = this.repDistances[2];
70
+ this.repDistances[2] = this.repDistances[1];
71
+ this.repDistances[1] = this.repDistances[0];
72
+ this.repDistances[0] = newDistance;
73
+ }
74
+ else {
75
+ // Move specific rep to front, shift others
76
+ const temp = this.repDistances[repIndex];
77
+ for (let i = repIndex; i > 0; i--) {
78
+ this.repDistances[i] = this.repDistances[i - 1];
79
+ }
80
+ this.repDistances[0] = temp;
81
+ }
82
+ }
83
+ }
84
+ /**
85
+ * Position Encoder - Handles position slot and alignment encoding
86
+ */
87
+ class PositionEncoder {
88
+ posSlotEncoder = [];
89
+ posEncoders = initArray(0x72);
90
+ posAlignEncoder;
91
+ constructor() {
92
+ // Initialize position slot encoders for different length states
93
+ for (let lenState = 0; lenState < 4; lenState++) {
94
+ this.posSlotEncoder[lenState] = createBitTree(6);
95
+ }
96
+ this.posAlignEncoder = createBitTree(4);
97
+ }
98
+ /**
99
+ * Initialize all position models
100
+ */
101
+ init() {
102
+ for (const encoder of this.posSlotEncoder) {
103
+ initBitModels(encoder.models);
104
+ }
105
+ initBitModels(this.posEncoders);
106
+ initBitModels(this.posAlignEncoder.models);
107
+ }
108
+ /**
109
+ * Encode position using optimal method
110
+ */
111
+ encodePosition(distance, lenState, rangeEncoder) {
112
+ const posSlot = this.getPosSlot(distance);
113
+ rangeEncoder.encodeBitTree(this.posSlotEncoder[lenState], posSlot);
114
+ if (posSlot >= 4) {
115
+ const footerBits = (posSlot >> 1) - 1;
116
+ const baseVal = (2 | (posSlot & 1)) << footerBits;
117
+ const posReduced = distance - baseVal;
118
+ if (posSlot < 14) {
119
+ // Use position encoders for middle range
120
+ this.encodeReverseBits(posReduced, footerBits, rangeEncoder);
121
+ }
122
+ else {
123
+ // Use direct bits for high range + alignment
124
+ rangeEncoder.encodeDirectBits(posReduced >> 4, footerBits - 4);
125
+ rangeEncoder.encodeBitTree(this.posAlignEncoder, posReduced & 0x0F);
126
+ }
127
+ }
128
+ }
129
+ /**
130
+ * Calculate price for encoding a position
131
+ */
132
+ getPositionPrice(distance, lenState) {
133
+ const posSlot = this.getPosSlot(distance);
134
+ let price = getBitTreePrice(this.posSlotEncoder[lenState], posSlot);
135
+ if (posSlot >= 4) {
136
+ const footerBits = (posSlot >> 1) - 1;
137
+ const baseVal = (2 | (posSlot & 1)) << footerBits;
138
+ const posReduced = distance - baseVal;
139
+ if (posSlot < 14) {
140
+ price += this.getReverseBitsPrice(posReduced, footerBits);
141
+ }
142
+ else {
143
+ price += getDirectBitsPrice(footerBits - 4);
144
+ price += getBitTreePrice(this.posAlignEncoder, posReduced & 0x0F);
145
+ }
146
+ }
147
+ return price;
148
+ }
149
+ getPosSlot(distance) {
150
+ if (distance < 4)
151
+ return distance;
152
+ if (distance < (1 << (31 - 11))) {
153
+ return G_FAST_POS[distance >> 6] + 12;
154
+ }
155
+ return G_FAST_POS[distance >> 26] + 52;
156
+ }
157
+ encodeReverseBits(value, numBits, rangeEncoder) {
158
+ let modelIndex = 1;
159
+ for (let i = 0; i < numBits; i++) {
160
+ const bit = value & 1;
161
+ rangeEncoder.encodeBit(this.posEncoders, modelIndex, bit);
162
+ modelIndex = (modelIndex << 1) | bit;
163
+ value >>>= 1;
164
+ }
165
+ }
166
+ getReverseBitsPrice(value, numBits) {
167
+ let price = 0;
168
+ let modelIndex = 1;
169
+ for (let i = 0; i < numBits; i++) {
170
+ const bit = value & 1;
171
+ price += getBitPrice(this.posEncoders[modelIndex], bit);
172
+ modelIndex = (modelIndex << 1) | bit;
173
+ value >>>= 1;
174
+ }
175
+ return price;
176
+ }
177
+ }
178
+ /**
179
+ * LZMA Encoder class that handles compression operations
180
+ */
181
+ export class Encoder {
182
+ encoderState = new EncoderState();
183
+ positionEncoder = new PositionEncoder();
184
+ // Core state properties
185
+ _state = 0;
186
+ _previousByte = 0;
187
+ _distTableSize = 0;
188
+ _longestMatchWasFound = 0;
189
+ _optimumEndIndex = 0;
190
+ _optimumCurrentIndex = 0;
191
+ _additionalOffset = 0;
192
+ // Dictionary and match finding
193
+ _dictionarySize = 0;
194
+ _matchFinder = null;
195
+ _dictionarySizePrev = 0;
196
+ _numFastBytes = 0;
197
+ // Literal encoding configuration
198
+ _numLiteralContextBits = 0;
199
+ _numLiteralPosStateBits = 0;
200
+ _posStateBits = 0;
201
+ _posStateMask = 0;
202
+ // Stream and processing state
203
+ _needReleaseMFStream = 0;
204
+ _inStream = null;
205
+ _finished = 0;
206
+ nowPos64 = [0, 0];
207
+ // Distance and repetition arrays
208
+ _repDistances = initArray(4);
209
+ _optimum = [];
210
+ // Range encoder
211
+ _rangeEncoder = {
212
+ stream: {
213
+ buf: [],
214
+ count: 0,
215
+ },
216
+ rrange: 0,
217
+ cache: 0,
218
+ low: [0, 0],
219
+ cacheSize: 0,
220
+ position: [0, 0],
221
+ encodeBit: () => { },
222
+ encodeBitTree: () => { },
223
+ encodeDirectBits: () => { },
224
+ };
225
+ // Bit model arrays for different types of encoding decisions
226
+ _isMatch = initArray(0xC0);
227
+ _isRep = initArray(0x0C);
228
+ _isRepG0 = initArray(0x0C);
229
+ _isRepG1 = initArray(0x0C);
230
+ _isRepG2 = initArray(0x0C);
231
+ _isRep0Long = initArray(0xC0);
232
+ // Position and alignment encoders
233
+ _posSlotEncoder = [];
234
+ _posEncoders = initArray(0x72);
235
+ _posAlignEncoder = null;
236
+ // Length encoders
237
+ _lenEncoder = null;
238
+ _repMatchLenEncoder = null;
239
+ // Literal encoder
240
+ _literalEncoder = null;
241
+ // Distance and price arrays
242
+ _matchDistances = [];
243
+ _posSlotPrices = [];
244
+ _distancesPrices = [];
245
+ _alignPrices = initArray(0x10);
246
+ _matchPriceCount = 0;
247
+ _alignPriceCount = 0;
248
+ // Optimization arrays
249
+ reps = initArray(4);
250
+ repLens = initArray(4);
251
+ // Processing counters
252
+ processedInSize = [[0, 0]];
253
+ processedOutSize = [[0, 0]];
254
+ finished = [0];
255
+ properties = initArray(5);
256
+ tempPrices = initArray(0x80); // 128
257
+ // Match finding properties
258
+ _longestMatchLength = 0;
259
+ _matchFinderType = 1;
260
+ _numDistancePairs = 0;
261
+ _numFastBytesPrev = -1;
262
+ backRes = 0;
263
+ constructor() {
264
+ // Encoder is initialized with default values above
265
+ // Additional initialization will be done through specific init methods
266
+ }
267
+ /**
268
+ * Initialize basic encoder state
269
+ */
270
+ baseInit() {
271
+ this._state = 0;
272
+ this._previousByte = 0;
273
+ for (let i = 0; i < 4; ++i) {
274
+ this._repDistances[i] = 0;
275
+ }
276
+ }
277
+ /**
278
+ * Get optimum array
279
+ */
280
+ getOptimum() {
281
+ return this._optimum;
282
+ }
283
+ /**
284
+ * Get back result
285
+ */
286
+ getBackRes() {
287
+ return this.backRes;
288
+ }
289
+ setBackRes(backRes) {
290
+ this.backRes = backRes;
291
+ }
292
+ init() {
293
+ this.baseInit();
294
+ this.encoderState.initModels();
295
+ this.positionEncoder.init();
296
+ // Initialize optimum array properly
297
+ this._optimum = [];
298
+ for (let i = 0; i < 0x1000; i++) {
299
+ this._optimum[i] = {};
300
+ }
301
+ this.initEncoderState();
302
+ initBitModels(this._isMatch);
303
+ initBitModels(this._isRep0Long);
304
+ initBitModels(this._isRep);
305
+ initBitModels(this._isRepG0);
306
+ initBitModels(this._isRepG1);
307
+ initBitModels(this._isRepG2);
308
+ initBitModels(this._posEncoders);
309
+ this.initLiteralEncoder();
310
+ for (let i = 0; i < 4; ++i) {
311
+ initBitModels(this._posSlotEncoder[i].models);
312
+ }
313
+ if (this._lenEncoder) {
314
+ this._lenEncoder.init(1 << this._posStateBits);
315
+ }
316
+ if (this._repMatchLenEncoder) {
317
+ this._repMatchLenEncoder.init(1 << this._posStateBits);
318
+ }
319
+ if (this._posAlignEncoder) {
320
+ initBitModels(this._posAlignEncoder.models);
321
+ }
322
+ this._longestMatchWasFound = 0;
323
+ this._optimumEndIndex = 0;
324
+ this._optimumCurrentIndex = 0;
325
+ this._additionalOffset = 0;
326
+ }
327
+ /**
328
+ * Initialize encoder range coder
329
+ */
330
+ initEncoderState() {
331
+ this._rangeEncoder.low = [0, 0];
332
+ this._rangeEncoder.rrange = 0xFFFFFFFF;
333
+ this._rangeEncoder.cacheSize = 1;
334
+ this._rangeEncoder.cache = 0;
335
+ this._rangeEncoder.position = [0, 0];
336
+ }
337
+ /**
338
+ * Initialize literal encoder
339
+ */
340
+ initLiteralEncoder() {
341
+ const totalStates = 1 << (this._literalEncoder.numPrevBits + this._literalEncoder.numPosBits);
342
+ for (let i = 0; i < totalStates; ++i) {
343
+ initBitModels(this._literalEncoder.coders[i].decoders);
344
+ }
345
+ }
346
+ /**
347
+ * Create optimum structures
348
+ */
349
+ createOptimumStructures() {
350
+ for (let i = 0; i < 0x1000; ++i) {
351
+ this._optimum[i] = {};
352
+ }
353
+ for (let i = 0; i < 4; ++i) {
354
+ this._posSlotEncoder[i] = createBitTree(6);
355
+ }
356
+ }
357
+ /**
358
+ * Create length price table encoder
359
+ */
360
+ createLenPriceTableEncoder() {
361
+ const encoder = new LenEncoder();
362
+ encoder.initPriceTable();
363
+ return encoder;
364
+ }
365
+ /**
366
+ * Create literal encoder encoder2
367
+ */
368
+ createLiteralEncoderEncoder2() {
369
+ const encoder = {
370
+ decoders: initArray(0x300),
371
+ };
372
+ return encoder;
373
+ }
374
+ /**
375
+ * Create literal encoder
376
+ */
377
+ createLiteralEncoder() {
378
+ // Check if we need to recreate the encoder
379
+ if (this._literalEncoder != null
380
+ && this._literalEncoder.numPrevBits == this._numLiteralContextBits
381
+ && this._literalEncoder.numPosBits == this._numLiteralPosStateBits) {
382
+ return;
383
+ }
384
+ // Replace #LZMA_Encoder_LiteralEncoder_Create with LitCoder instantiation
385
+ this._literalEncoder = new LitCoder(this._numLiteralPosStateBits, this._numLiteralContextBits);
386
+ }
387
+ /**
388
+ * Initialize completely with proper encoder state
389
+ */
390
+ initialize() {
391
+ // Initialize encoder structures first
392
+ this._lenEncoder = this.createLenPriceTableEncoder();
393
+ this._repMatchLenEncoder = this.createLenPriceTableEncoder();
394
+ this._posAlignEncoder = createBitTree(0x04);
395
+ // Initialize optimum array
396
+ this._optimum = [];
397
+ this.createOptimumStructures();
398
+ // Create literal encoder
399
+ this.createLiteralEncoder();
400
+ // Now call init to set up the state
401
+ this.init();
402
+ }
403
+ /**
404
+ * Configure encoder settings
405
+ */
406
+ configure(mode) {
407
+ this.setDictionarySize(0x1 << mode.searchDepth);
408
+ this._numFastBytes = mode.filterStrength;
409
+ this._matchFinderType = mode.modeIndex;
410
+ // lc is always 3, lp is always 0, pb is always 2
411
+ this._numLiteralContextBits = 0x3;
412
+ this._numLiteralPosStateBits = 0x0;
413
+ this._posStateBits = 0x2;
414
+ this._posStateMask = 0x3;
415
+ }
416
+ /**
417
+ * Set dictionary size
418
+ */
419
+ setDictionarySize(dictionarySize) {
420
+ this._dictionarySize = dictionarySize;
421
+ let dicLogSize = 0;
422
+ for (; dictionarySize > (1 << dicLogSize); ++dicLogSize)
423
+ ;
424
+ this._distTableSize = dicLogSize * 2;
425
+ }
426
+ /**
427
+ * Encode a bit using range coder
428
+ */
429
+ encodeBit(probs, index, symbol) {
430
+ const rangeEncoder = this._rangeEncoder;
431
+ let newBound, prob = probs[index];
432
+ newBound = (rangeEncoder.rrange >>> 11) * prob;
433
+ if (!symbol) {
434
+ rangeEncoder.rrange = newBound;
435
+ probs[index] = prob + (2048 - prob >>> 5) << 16 >> 16;
436
+ }
437
+ else {
438
+ // Need helper methods for 64-bit arithmetic
439
+ rangeEncoder.low = add64(rangeEncoder.low, this.and64(fromInt64(newBound), [0xFFFFFFFF, 0]));
440
+ rangeEncoder.rrange -= newBound;
441
+ probs[index] = prob - (prob >>> 5) << 16 >> 16;
442
+ }
443
+ if (!(rangeEncoder.rrange & -0x1000000)) {
444
+ rangeEncoder.rrange <<= 8;
445
+ this.shiftLow();
446
+ }
447
+ }
448
+ /**
449
+ * Encode bit tree
450
+ */
451
+ encodeBitTree(encoder, symbol) {
452
+ let bit, bitIndex, m = 1;
453
+ for (bitIndex = encoder.numBitLevels; bitIndex != 0;) {
454
+ bitIndex -= 1;
455
+ bit = symbol >>> bitIndex & 1;
456
+ this.encodeBit(encoder.models, m, bit);
457
+ m = m << 1 | bit;
458
+ }
459
+ }
460
+ /**
461
+ * Encode literal
462
+ */
463
+ encodeLiteral(encoder, symbol) {
464
+ let bit, context = 1;
465
+ for (let i = 7; i >= 0; --i) {
466
+ bit = (symbol >> i) & 1;
467
+ this.encodeBit(encoder.decoders, context, bit);
468
+ context = context << 1 | bit;
469
+ }
470
+ }
471
+ /**
472
+ * Encode matched literal
473
+ */
474
+ encodeMatched(encoder, matchByte, symbol) {
475
+ let bit, matchBit, state, same = true, context = 1;
476
+ for (let i = 7; i >= 0; --i) {
477
+ bit = (symbol >> i) & 1;
478
+ state = context;
479
+ if (same) {
480
+ matchBit = (matchByte >> i) & 1;
481
+ state += (1 + matchBit) << 8;
482
+ same = matchBit === bit;
483
+ }
484
+ this.encodeBit(encoder.decoders, state, bit);
485
+ context = context << 1 | bit;
486
+ }
487
+ }
488
+ /**
489
+ * Encode length using direct method calls
490
+ */
491
+ encodeLength(encoder, symbol, posState) {
492
+ encoder.encode(symbol, posState, this);
493
+ }
494
+ /**
495
+ * Encode direct bits
496
+ */
497
+ encodeDirectBits(valueToEncode, numTotalBits) {
498
+ const rangeEncoder = this._rangeEncoder;
499
+ for (let i = numTotalBits - 1; i >= 0; i -= 1) {
500
+ rangeEncoder.rrange >>>= 1;
501
+ if ((valueToEncode >>> i & 1) == 1) {
502
+ rangeEncoder.low = add64(rangeEncoder.low, fromInt64(rangeEncoder.rrange));
503
+ }
504
+ if (!(rangeEncoder.rrange & -0x1000000)) {
505
+ rangeEncoder.rrange <<= 8;
506
+ this.shiftLow();
507
+ }
508
+ }
509
+ }
510
+ /**
511
+ * Reverse encode
512
+ */
513
+ reverseEncode(symbol) {
514
+ const posAlignEncoder = this._posAlignEncoder;
515
+ if (!posAlignEncoder)
516
+ return;
517
+ let bit, m = 1;
518
+ for (let i = 0; i < posAlignEncoder.numBitLevels; ++i) {
519
+ bit = symbol & 1;
520
+ this.encodeBit(posAlignEncoder.models, m, bit);
521
+ m = m << 1 | bit;
522
+ symbol >>= 1;
523
+ }
524
+ }
525
+ /**
526
+ * Reverse encode range
527
+ */
528
+ reverseEncodeRange(startIndex, numBitLevels, symbol) {
529
+ let bit, m = 1;
530
+ for (let i = 0; i < numBitLevels; ++i) {
531
+ bit = symbol & 1;
532
+ this.encodeBit(this._posEncoders, startIndex + m, bit);
533
+ m = m << 1 | bit;
534
+ symbol >>= 1;
535
+ }
536
+ }
537
+ /**
538
+ * Write end marker
539
+ */
540
+ writeEndMarker(positionState) {
541
+ this.encodeBit(this._isMatch, (this._state << 4) + positionState, 1);
542
+ this.encodeBit(this._isRep, this._state, 0);
543
+ this._state = this._state < 7 ? 7 : 10;
544
+ this.encodeLength(this._lenEncoder, 0, positionState);
545
+ const posSlot = 63;
546
+ const lenToPosState = getLenToPosState(2); // Length to position state for minimum length
547
+ this.encodeBitTree(this._posSlotEncoder[lenToPosState], posSlot);
548
+ this.encodeDirectBits(67108863, 26);
549
+ this.reverseEncode(15);
550
+ }
551
+ /**
552
+ * Encode length with price table update
553
+ */
554
+ encodeLengthWithPriceUpdate(encoder, symbol, posState) {
555
+ encoder.encodeWithUpdate(symbol, posState, this);
556
+ }
557
+ and64(a, b) {
558
+ const highBits = ~~Math.max(Math.min(a[1] / 0x100000000, 0x7FFFFFFF), -0x80000000) & ~~Math.max(Math.min(b[1] / 0x100000000, 0x7FFFFFFF), -0x80000000);
559
+ const lowBits = lowBits64(a) & lowBits64(b);
560
+ let high = highBits * 0x100000000;
561
+ let low = lowBits;
562
+ if (lowBits < 0) {
563
+ low += 0x100000000;
564
+ }
565
+ return [low, high];
566
+ }
567
+ shru64(a, n) {
568
+ n &= 0x3F;
569
+ let shiftFact = this.pwrAsDouble(n);
570
+ let sr = create64(Math.floor(a[0] / shiftFact), a[1] / shiftFact);
571
+ if (a[1] < 0) {
572
+ sr = add64(sr, this.shl64([2, 0], 0x3F - n));
573
+ }
574
+ return sr;
575
+ }
576
+ shl64(a, n) {
577
+ let diff, newHigh, newLow, twoToN;
578
+ n &= 0x3F;
579
+ if (a[0] == 0 && a[1] == -9223372036854775808) {
580
+ if (!n) {
581
+ return a;
582
+ }
583
+ return [0, 0];
584
+ }
585
+ if (a[1] < 0) {
586
+ throw new Error("Neg");
587
+ }
588
+ twoToN = this.pwrAsDouble(n);
589
+ newHigh = a[1] * twoToN % 1.8446744073709552E19;
590
+ newLow = a[0] * twoToN;
591
+ diff = newLow - newLow % 0x100000000;
592
+ newHigh += diff;
593
+ newLow -= diff;
594
+ if (newHigh >= 9223372036854775807) {
595
+ newHigh -= 1.8446744073709552E19;
596
+ }
597
+ return [newLow, newHigh];
598
+ }
599
+ pwrAsDouble(n) {
600
+ if (n <= 0x1E) {
601
+ return 1 << n;
602
+ }
603
+ return this.pwrAsDouble(0x1E) * this.pwrAsDouble(n - 0x1E);
604
+ }
605
+ /**
606
+ * Shift low helper (proper implementation) - public method for external access
607
+ */
608
+ shiftLow() {
609
+ const rangeEncoder = this._rangeEncoder;
610
+ const LowHi = lowBits64(this.shru64(rangeEncoder.low, 32));
611
+ if (LowHi != 0 || compare64(rangeEncoder.low, [4278190080, 0]) < 0) {
612
+ rangeEncoder.position = add64(rangeEncoder.position, fromInt64(rangeEncoder.cacheSize));
613
+ let temp = rangeEncoder.cache;
614
+ do {
615
+ this.writeToStream(rangeEncoder.stream, temp + LowHi);
616
+ temp = 255;
617
+ } while ((rangeEncoder.cacheSize -= 1) != 0);
618
+ rangeEncoder.cache = lowBits64(rangeEncoder.low) >>> 24;
619
+ }
620
+ rangeEncoder.cacheSize += 1;
621
+ rangeEncoder.low = this.shl64(this.and64(rangeEncoder.low, [16777215, 0]), 8);
622
+ }
623
+ /**
624
+ * Write byte to stream
625
+ */
626
+ writeToStream(stream, b) {
627
+ if (!stream)
628
+ return;
629
+ // Ensure buffer has enough capacity
630
+ if (stream.count >= stream.buf.length) {
631
+ const newSize = Math.max(stream.buf.length * 2, stream.count + 1);
632
+ const newBuf = new Array(newSize);
633
+ for (let i = 0; i < stream.count; i++) {
634
+ newBuf[i] = stream.buf[i];
635
+ }
636
+ stream.buf = newBuf;
637
+ }
638
+ stream.buf[stream.count++] = b << 24 >> 24;
639
+ }
640
+ initRangeEncoder() {
641
+ this._rangeEncoder.position = [0, 0];
642
+ this._rangeEncoder.low = [0, 0];
643
+ this._rangeEncoder.rrange = -1;
644
+ this._rangeEncoder.cacheSize = 1;
645
+ this._rangeEncoder.cache = 0;
646
+ }
647
+ /**
648
+ * Fill alignment prices for position alignment encoder
649
+ */
650
+ fillAlignPrices() {
651
+ for (let i = 0; i < 16; ++i) {
652
+ this._alignPrices[i] = this.reverseGetPrice(this._posAlignEncoder, i);
653
+ }
654
+ this._alignPriceCount = 0;
655
+ }
656
+ /**
657
+ * Fill distance prices for position encoders
658
+ */
659
+ fillDistancesPrices() {
660
+ let baseVal, bitTreeEncoder, footerBits, posSlot, st, st2;
661
+ for (let i = 4; i < 0x80; ++i) {
662
+ posSlot = this.getPosSlot(i);
663
+ footerBits = (posSlot >> 1) - 1;
664
+ baseVal = (2 | (posSlot & 1)) << footerBits;
665
+ this.tempPrices[i] = this.reverseGetPriceArray(this._posEncoders, baseVal - posSlot - 1, footerBits, i - baseVal);
666
+ }
667
+ for (let lenToPosState = 0; lenToPosState < 4; ++lenToPosState) {
668
+ bitTreeEncoder = this._posSlotEncoder[lenToPosState];
669
+ st = lenToPosState << 6;
670
+ for (posSlot = 0; posSlot < this._distTableSize; posSlot += 1) {
671
+ this._posSlotPrices[st + posSlot] = this.rangeCoder_Encoder_GetPrice_1(bitTreeEncoder, posSlot);
672
+ }
673
+ for (posSlot = 14; posSlot < this._distTableSize; posSlot += 1) {
674
+ this._posSlotPrices[st + posSlot] += (posSlot >> 1) - 1 - 4 << 6;
675
+ }
676
+ st2 = lenToPosState * 0x80;
677
+ for (let i = 0; i < 4; ++i) {
678
+ this._distancesPrices[st2 + i] = this._posSlotPrices[st + i];
679
+ }
680
+ for (let i = 4; i < 0x80; ++i) {
681
+ this._distancesPrices[st2 + i] = this._posSlotPrices[st + this.getPosSlot(i)] + this.tempPrices[i];
682
+ }
683
+ }
684
+ this._matchPriceCount = 0;
685
+ }
686
+ /**
687
+ * Get position slot for a distance value
688
+ */
689
+ getPosSlot(pos) {
690
+ if (pos < 0x800) {
691
+ return G_FAST_POS[pos];
692
+ }
693
+ if (pos < 0x200000) {
694
+ return G_FAST_POS[pos >> 10] + 20;
695
+ }
696
+ return G_FAST_POS[pos >> 20] + 40;
697
+ }
698
+ /**
699
+ * Get reverse price for bit tree encoder
700
+ */
701
+ reverseGetPrice(encoder, symbol) {
702
+ let bit, m = 1, price = 0;
703
+ for (let i = encoder.numBitLevels; i != 0; i -= 1) {
704
+ bit = symbol & 1;
705
+ symbol >>>= 1;
706
+ price += this.getPrice(encoder.models[m], bit);
707
+ m = m << 1 | bit;
708
+ }
709
+ return price;
710
+ }
711
+ /**
712
+ * Get reverse price for array of models
713
+ */
714
+ reverseGetPriceArray(Models, startIndex, NumBitLevels, symbol) {
715
+ let bit, m = 1, price = 0;
716
+ for (let i = NumBitLevels; i != 0; i -= 1) {
717
+ bit = symbol & 1;
718
+ symbol >>>= 1;
719
+ price += PROB_PRICES[((Models[startIndex + m] - bit ^ -bit) & 2047) >>> 2];
720
+ m = m << 1 | bit;
721
+ }
722
+ return price;
723
+ }
724
+ /**
725
+ * Get price for probability model (optimized)
726
+ */
727
+ getPrice(Prob, symbol) {
728
+ return getBitPrice(Prob, symbol);
729
+ }
730
+ /**
731
+ * Get price for bit tree encoder (optimized)
732
+ */
733
+ rangeCoder_Encoder_GetPrice_1(encoder, symbol) {
734
+ return getBitTreePrice(encoder, symbol);
735
+ }
736
+ /**
737
+ * Create encoder optimization structures (optimized)
738
+ */
739
+ createEncoderStructures() {
740
+ // Pre-allocate optimum array with proper size
741
+ // Initialize optimum array properly
742
+ this._optimum = [];
743
+ for (let i = 0; i < 0x1000; i++) {
744
+ this._optimum[i] = {};
745
+ }
746
+ for (let i = 0; i < 0x1000; ++i) {
747
+ this._optimum[i] = {};
748
+ }
749
+ // Initialize position slot encoders
750
+ this._posSlotEncoder = new Array(4);
751
+ for (let i = 0; i < 4; ++i) {
752
+ this._posSlotEncoder[i] = createBitTree(6);
753
+ }
754
+ }
755
+ /**
756
+ * Create match finder and encoder structures (replaces #Create_2)
757
+ */
758
+ createMatchFinderAndStructures() {
759
+ // Create match finder if needed
760
+ if (!this._matchFinder) {
761
+ const binTree = {};
762
+ let numHashBytes = 4;
763
+ if (!this._matchFinderType) {
764
+ numHashBytes = 2;
765
+ }
766
+ // Set match finder type (replaces #SetType)
767
+ binTree.HASH_ARRAY = numHashBytes > 2;
768
+ if (binTree.HASH_ARRAY) {
769
+ binTree.kNumHashDirectBytes = 0;
770
+ binTree.kMinMatchCheck = 4;
771
+ binTree.kFixHashSize = 66560;
772
+ }
773
+ else {
774
+ binTree.kNumHashDirectBytes = 2;
775
+ binTree.kMinMatchCheck = 3;
776
+ binTree.kFixHashSize = 0;
777
+ }
778
+ // Initialize other match finder properties
779
+ binTree._cyclicBufferSize = 0;
780
+ binTree._cyclicBufferPos = 0;
781
+ binTree._streamPos = 0;
782
+ binTree._cutValue = 0xff;
783
+ binTree._matchMaxLen = 0;
784
+ binTree._streamEndWasReached = 0;
785
+ binTree._pos = 0;
786
+ binTree._posLimit = 0;
787
+ binTree._son = [];
788
+ binTree._hash = [];
789
+ binTree._bufferBase = [];
790
+ binTree._blockSize = 0;
791
+ binTree._keepSizeAfter = 0;
792
+ binTree._keepSizeBefore = 0;
793
+ binTree._pointerToLastSafePosition = 0;
794
+ this._matchFinder = binTree;
795
+ }
796
+ // Create literal encoder if needed
797
+ this.createLiteralEncoder();
798
+ // Check if we need to recreate structures
799
+ if (this._dictionarySize == this._dictionarySizePrev
800
+ && this._numFastBytesPrev == this._numFastBytes) {
801
+ return;
802
+ }
803
+ // This would call equivalent of #Create_3(0x1000, 0x0112) logic
804
+ // For now, we'll handle the basic setup
805
+ this._dictionarySizePrev = this._dictionarySize;
806
+ this._numFastBytesPrev = this._numFastBytes;
807
+ }
808
+ /**
809
+ * Get literal encoder subcoder (utility method)
810
+ */
811
+ getSubCoderUtility(pos, prevByte) {
812
+ // Calculate position mask bits
813
+ const posBits = pos & this._literalEncoder.posMask;
814
+ const posShifted = posBits << this._literalEncoder.numPrevBits;
815
+ // Calculate previous byte bits
816
+ const prevByteShift = 0x08 - this._literalEncoder.numPrevBits;
817
+ const prevByteBits = (prevByte & 0xFF) >>> prevByteShift;
818
+ // Combine position and prevByte bits to get final index
819
+ const coderIndex = posShifted + prevByteBits;
820
+ return this._literalEncoder.coders[coderIndex];
821
+ }
822
+ }