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.
package/lib/encoder.js ADDED
@@ -0,0 +1,1473 @@
1
+ import { LenEncoder, } from "./len-coder.js";
2
+ import { LitCoder } from "./lit-coder.js";
3
+ import { BinTreeMatchFinder } from "./match-finder.js";
4
+ import { createBitTree, G_FAST_POS, getBitPrice, getLenToPosState, INFINITY_PRICE, initArray, initBitModels, PROB_PRICES, stateUpdateChar, } from "./utils.js";
5
+ const bitTreePriceCache = new Map();
6
+ /**
7
+ * Calculate price for direct bit encoding
8
+ */
9
+ function getDirectBitsPrice(numBits) {
10
+ return numBits << 6;
11
+ }
12
+ /**
13
+ * Get price for bit tree encoding with caching
14
+ */
15
+ function getBitTreePrice(bitTree, symbol) {
16
+ const cacheKey = (bitTree.numBitLevels << 16) | symbol;
17
+ if (bitTreePriceCache.has(cacheKey)) {
18
+ return bitTreePriceCache.get(cacheKey);
19
+ }
20
+ let price = 0;
21
+ let modelIndex = 1;
22
+ for (let bitIndex = bitTree.numBitLevels; bitIndex > 0; bitIndex--) {
23
+ const bit = (symbol >>> (bitIndex - 1)) & 1;
24
+ price += getBitPrice(bitTree.models[modelIndex], bit);
25
+ modelIndex = (modelIndex << 1) + bit;
26
+ }
27
+ if (bitTreePriceCache.size < 10000) {
28
+ bitTreePriceCache.set(cacheKey, price);
29
+ }
30
+ return price;
31
+ }
32
+ /**
33
+ * LZMA Encoder State - Encapsulates all encoder state management
34
+ */
35
+ class EncoderState {
36
+ // Core state
37
+ state = 0;
38
+ previousByte = 0;
39
+ position = 0n;
40
+ // Repetition distances (LZ77 back-references)
41
+ repDistances = [0, 0, 0, 0];
42
+ // Match finding state
43
+ longestMatchLength = 0;
44
+ longestMatchWasFound = false;
45
+ additionalOffset = 0;
46
+ // Probability models for different encoding decisions
47
+ isMatch = initArray(0xC0);
48
+ isRep = initArray(0x0C);
49
+ isRepG0 = initArray(0x0C);
50
+ isRepG1 = initArray(0x0C);
51
+ isRepG2 = initArray(0x0C);
52
+ isRep0Long = initArray(0xC0);
53
+ /**
54
+ * Initialize all probability models to default values
55
+ */
56
+ initModels() {
57
+ initBitModels(this.isMatch);
58
+ initBitModels(this.isRep);
59
+ initBitModels(this.isRepG0);
60
+ initBitModels(this.isRepG1);
61
+ initBitModels(this.isRepG2);
62
+ initBitModels(this.isRep0Long);
63
+ }
64
+ /**
65
+ * Update repetition distances when a new match is found
66
+ */
67
+ updateRepDistances(newDistance, repIndex) {
68
+ if (repIndex === 0) {
69
+ // New match becomes rep0, shift others
70
+ this.repDistances[3] = this.repDistances[2];
71
+ this.repDistances[2] = this.repDistances[1];
72
+ this.repDistances[1] = this.repDistances[0];
73
+ this.repDistances[0] = newDistance;
74
+ }
75
+ else {
76
+ // Move specific rep to front, shift others
77
+ const temp = this.repDistances[repIndex];
78
+ for (let i = repIndex; i > 0; i--) {
79
+ this.repDistances[i] = this.repDistances[i - 1];
80
+ }
81
+ this.repDistances[0] = temp;
82
+ }
83
+ }
84
+ }
85
+ /**
86
+ * Position Encoder - Handles position slot and alignment encoding
87
+ */
88
+ class PositionEncoder {
89
+ posSlotEncoder = [];
90
+ posEncoders = initArray(0x72);
91
+ posAlignEncoder;
92
+ constructor() {
93
+ // Initialize position slot encoders for different length states
94
+ for (let lenState = 0; lenState < 4; lenState++) {
95
+ this.posSlotEncoder[lenState] = createBitTree(6);
96
+ }
97
+ this.posAlignEncoder = createBitTree(4);
98
+ }
99
+ /**
100
+ * Initialize all position models
101
+ */
102
+ init() {
103
+ for (const encoder of this.posSlotEncoder) {
104
+ initBitModels(encoder.models);
105
+ }
106
+ initBitModels(this.posEncoders);
107
+ initBitModels(this.posAlignEncoder.models);
108
+ }
109
+ /**
110
+ * Encode position using optimal method
111
+ */
112
+ encodePosition(distance, lenState, rangeEncoder) {
113
+ const posSlot = this.getPosSlot(distance);
114
+ rangeEncoder.encodeBitTree(this.posSlotEncoder[lenState], posSlot);
115
+ if (posSlot >= 4) {
116
+ const footerBits = (posSlot >> 1) - 1;
117
+ const baseVal = (2 | (posSlot & 1)) << footerBits;
118
+ const posReduced = distance - baseVal;
119
+ if (posSlot < 14) {
120
+ // Use position encoders for middle range
121
+ this.encodeReverseBits(posReduced, footerBits, rangeEncoder);
122
+ }
123
+ else {
124
+ // Use direct bits for high range + alignment
125
+ rangeEncoder.encodeDirectBits(posReduced >> 4, footerBits - 4);
126
+ rangeEncoder.encodeBitTree(this.posAlignEncoder, posReduced & 0x0F);
127
+ }
128
+ }
129
+ }
130
+ /**
131
+ * Calculate price for encoding a position
132
+ */
133
+ getPositionPrice(distance, lenState) {
134
+ const posSlot = this.getPosSlot(distance);
135
+ let price = getBitTreePrice(this.posSlotEncoder[lenState], posSlot);
136
+ if (posSlot >= 4) {
137
+ const footerBits = (posSlot >> 1) - 1;
138
+ const baseVal = (2 | (posSlot & 1)) << footerBits;
139
+ const posReduced = distance - baseVal;
140
+ if (posSlot < 14) {
141
+ price += this.getReverseBitsPrice(posReduced, footerBits);
142
+ }
143
+ else {
144
+ price += getDirectBitsPrice(footerBits - 4);
145
+ price += getBitTreePrice(this.posAlignEncoder, posReduced & 0x0F);
146
+ }
147
+ }
148
+ return price;
149
+ }
150
+ getPosSlot(distance) {
151
+ if (distance < 4)
152
+ return distance;
153
+ if (distance < (1 << (31 - 11))) {
154
+ return G_FAST_POS[distance >> 6] + 12;
155
+ }
156
+ return G_FAST_POS[distance >> 26] + 52;
157
+ }
158
+ encodeReverseBits(value, numBits, rangeEncoder) {
159
+ let modelIndex = 1;
160
+ for (let i = 0; i < numBits; i++) {
161
+ const bit = value & 1;
162
+ rangeEncoder.encodeBit(this.posEncoders, modelIndex, bit);
163
+ modelIndex = (modelIndex << 1) | bit;
164
+ value >>>= 1;
165
+ }
166
+ }
167
+ getReverseBitsPrice(value, numBits) {
168
+ let price = 0;
169
+ let modelIndex = 1;
170
+ for (let i = 0; i < numBits; i++) {
171
+ const bit = value & 1;
172
+ price += getBitPrice(this.posEncoders[modelIndex], bit);
173
+ modelIndex = (modelIndex << 1) | bit;
174
+ value >>>= 1;
175
+ }
176
+ return price;
177
+ }
178
+ }
179
+ /**
180
+ * LZMA Encoder class that handles compression operations
181
+ */
182
+ export class Encoder {
183
+ encoderState = new EncoderState();
184
+ positionEncoder = new PositionEncoder();
185
+ // Core state properties
186
+ _state = 0;
187
+ _previousByte = 0;
188
+ _distTableSize = 0;
189
+ _longestMatchWasFound = 0;
190
+ _optimumEndIndex = 0;
191
+ _optimumCurrentIndex = 0;
192
+ _additionalOffset = 0;
193
+ // Dictionary and match finding
194
+ _dictionarySize = 0;
195
+ _matchFinder = null;
196
+ _dictionarySizePrev = 0;
197
+ _numFastBytes = 0;
198
+ // Literal encoding configuration
199
+ _numLiteralContextBits = 0;
200
+ _numLiteralPosStateBits = 0;
201
+ _posStateBits = 0;
202
+ _posStateMask = 0;
203
+ // Stream and processing state
204
+ _needReleaseMFStream = 0;
205
+ _inStream = null;
206
+ _finished = 0;
207
+ nowPos64 = 0n;
208
+ // Distance and repetition arrays
209
+ _repDistances = initArray(4);
210
+ _optimum = [];
211
+ // Range encoder
212
+ _rangeEncoder = {
213
+ stream: null,
214
+ rrange: 0,
215
+ cache: 0,
216
+ low: 0n,
217
+ cacheSize: 0,
218
+ position: 0n,
219
+ encodeBit: () => { },
220
+ encodeBitTree: () => { },
221
+ encodeDirectBits: () => { },
222
+ };
223
+ // Bit model arrays for different types of encoding decisions
224
+ _isMatch = initArray(0xC0);
225
+ _isRep = initArray(0x0C);
226
+ _isRepG0 = initArray(0x0C);
227
+ _isRepG1 = initArray(0x0C);
228
+ _isRepG2 = initArray(0x0C);
229
+ _isRep0Long = initArray(0xC0);
230
+ // Position and alignment encoders
231
+ _posSlotEncoder = [];
232
+ _posEncoders = initArray(0x72);
233
+ _posAlignEncoder = null;
234
+ // Length encoders
235
+ _lenEncoder = null;
236
+ _repMatchLenEncoder = null;
237
+ // Literal encoder
238
+ _literalEncoder = null;
239
+ // Distance and price arrays
240
+ _matchDistances = [];
241
+ _posSlotPrices = [];
242
+ _distancesPrices = [];
243
+ _alignPrices = initArray(0x10);
244
+ _matchPriceCount = 0;
245
+ _alignPriceCount = 0;
246
+ // Optimization arrays
247
+ reps = initArray(4);
248
+ repLens = initArray(4);
249
+ // Processing counters
250
+ processedInSize = [0n];
251
+ processedOutSize = [0n];
252
+ finished = [0];
253
+ properties = new Uint8Array(5);
254
+ tempPrices = initArray(0x80); // 128
255
+ // Match finding properties
256
+ _longestMatchLength = 0;
257
+ _matchFinderType = 1;
258
+ _numDistancePairs = 0;
259
+ _numFastBytesPrev = -1;
260
+ backRes = 0;
261
+ constructor() {
262
+ // Encoder is initialized with default values above
263
+ // Additional initialization will be done through specific init methods
264
+ }
265
+ /**
266
+ * Initialize basic encoder state
267
+ */
268
+ baseInit() {
269
+ this._state = 0;
270
+ this._previousByte = 0;
271
+ for (let i = 0; i < 4; ++i) {
272
+ this._repDistances[i] = 0;
273
+ }
274
+ }
275
+ /**
276
+ * Get optimum array
277
+ */
278
+ getOptimum() {
279
+ return this._optimum;
280
+ }
281
+ /**
282
+ * Get back result
283
+ */
284
+ getBackRes() {
285
+ return this.backRes;
286
+ }
287
+ setBackRes(backRes) {
288
+ this.backRes = backRes;
289
+ }
290
+ init() {
291
+ this.baseInit();
292
+ this.encoderState.initModels();
293
+ this.positionEncoder.init();
294
+ // Initialize optimum array properly
295
+ this._optimum = [];
296
+ for (let i = 0; i < 0x1000; i++) {
297
+ this._optimum[i] = {};
298
+ }
299
+ this.initEncoderState();
300
+ initBitModels(this._isMatch);
301
+ initBitModels(this._isRep0Long);
302
+ initBitModels(this._isRep);
303
+ initBitModels(this._isRepG0);
304
+ initBitModels(this._isRepG1);
305
+ initBitModels(this._isRepG2);
306
+ initBitModels(this._posEncoders);
307
+ this.initLiteralEncoder();
308
+ for (let i = 0; i < 4; ++i) {
309
+ initBitModels(this._posSlotEncoder[i].models);
310
+ }
311
+ if (this._lenEncoder) {
312
+ this._lenEncoder.init(1 << this._posStateBits);
313
+ }
314
+ if (this._repMatchLenEncoder) {
315
+ this._repMatchLenEncoder.init(1 << this._posStateBits);
316
+ }
317
+ if (this._posAlignEncoder) {
318
+ initBitModels(this._posAlignEncoder.models);
319
+ }
320
+ this._longestMatchWasFound = 0;
321
+ this._optimumEndIndex = 0;
322
+ this._optimumCurrentIndex = 0;
323
+ this._additionalOffset = 0;
324
+ }
325
+ /**
326
+ * Initialize encoder range coder
327
+ */
328
+ initEncoderState() {
329
+ this._rangeEncoder.low = 0n;
330
+ this._rangeEncoder.rrange = 0xFFFFFFFF;
331
+ this._rangeEncoder.cacheSize = 1;
332
+ this._rangeEncoder.cache = 0;
333
+ this._rangeEncoder.position = 0n;
334
+ }
335
+ /**
336
+ * Initialize literal encoder
337
+ */
338
+ initLiteralEncoder() {
339
+ const totalStates = 1 << (this._literalEncoder.numPrevBits + this._literalEncoder.numPosBits);
340
+ for (let i = 0; i < totalStates; ++i) {
341
+ initBitModels(this._literalEncoder.coders[i].decoders);
342
+ }
343
+ }
344
+ /**
345
+ * Create optimum structures
346
+ */
347
+ createOptimumStructures() {
348
+ for (let i = 0; i < 0x1000; ++i) {
349
+ this._optimum[i] = {};
350
+ }
351
+ for (let i = 0; i < 4; ++i) {
352
+ this._posSlotEncoder[i] = createBitTree(6);
353
+ }
354
+ }
355
+ /**
356
+ * Create length price table encoder
357
+ */
358
+ createLenPriceTableEncoder() {
359
+ const encoder = new LenEncoder();
360
+ encoder.initPriceTable();
361
+ return encoder;
362
+ }
363
+ /**
364
+ * Create literal encoder encoder2
365
+ */
366
+ createLiteralEncoderEncoder2() {
367
+ const encoder = {
368
+ decoders: initArray(0x300),
369
+ };
370
+ return encoder;
371
+ }
372
+ /**
373
+ * Create literal encoder
374
+ */
375
+ createLiteralEncoder() {
376
+ // Check if we need to recreate the encoder
377
+ if (this._literalEncoder != null
378
+ && this._literalEncoder.numPrevBits == this._numLiteralContextBits
379
+ && this._literalEncoder.numPosBits == this._numLiteralPosStateBits) {
380
+ return;
381
+ }
382
+ // Replace #LZMA_Encoder_LiteralEncoder_Create with LitCoder instantiation
383
+ this._literalEncoder = new LitCoder(this._numLiteralPosStateBits, this._numLiteralContextBits);
384
+ }
385
+ /**
386
+ * Initialize completely with proper encoder state
387
+ */
388
+ initialize() {
389
+ // Initialize encoder structures first
390
+ this._lenEncoder = this.createLenPriceTableEncoder();
391
+ this._repMatchLenEncoder = this.createLenPriceTableEncoder();
392
+ this._posAlignEncoder = createBitTree(0x04);
393
+ // Initialize optimum array
394
+ this._optimum = [];
395
+ this.createOptimumStructures();
396
+ // Create literal encoder
397
+ this.createLiteralEncoder();
398
+ // Now call init to set up the state
399
+ this.init();
400
+ }
401
+ /**
402
+ * Configure encoder settings
403
+ */
404
+ configure(mode) {
405
+ this.setDictionarySize(0x1 << mode.searchDepth);
406
+ this._numFastBytes = mode.filterStrength;
407
+ this._matchFinderType = mode.modeIndex;
408
+ // lc is always 3, lp is always 0, pb is always 2
409
+ this._numLiteralContextBits = 0x3;
410
+ this._numLiteralPosStateBits = 0x0;
411
+ this._posStateBits = 0x2;
412
+ this._posStateMask = 0x3;
413
+ }
414
+ /**
415
+ * Set dictionary size
416
+ */
417
+ setDictionarySize(dictionarySize) {
418
+ this._dictionarySize = dictionarySize;
419
+ let dicLogSize = 0;
420
+ for (; dictionarySize > (1 << dicLogSize); ++dicLogSize)
421
+ ;
422
+ this._distTableSize = dicLogSize * 2;
423
+ }
424
+ /**
425
+ * Encode a bit using range coder
426
+ */
427
+ encodeBit(probs, index, symbol) {
428
+ const rangeEncoder = this._rangeEncoder;
429
+ let newBound, prob = probs[index];
430
+ newBound = (rangeEncoder.rrange >>> 11) * prob;
431
+ if (!symbol) {
432
+ rangeEncoder.rrange = newBound;
433
+ probs[index] = prob + ((2048 - prob) >>> 5);
434
+ }
435
+ else {
436
+ rangeEncoder.low += BigInt(newBound >>> 0);
437
+ rangeEncoder.rrange -= newBound;
438
+ probs[index] = prob - (prob >>> 5);
439
+ }
440
+ if (!(rangeEncoder.rrange & -0x1000000)) {
441
+ rangeEncoder.rrange <<= 8;
442
+ this.shiftLow();
443
+ }
444
+ }
445
+ /**
446
+ * Encode bit tree
447
+ */
448
+ encodeBitTree(encoder, symbol) {
449
+ let bit, bitIndex, m = 1;
450
+ for (bitIndex = encoder.numBitLevels; bitIndex != 0;) {
451
+ bitIndex -= 1;
452
+ bit = symbol >>> bitIndex & 1;
453
+ this.encodeBit(encoder.models, m, bit);
454
+ m = m << 1 | bit;
455
+ }
456
+ }
457
+ /**
458
+ * Encode literal
459
+ */
460
+ encodeLiteral(encoder, symbol) {
461
+ let bit, context = 1;
462
+ for (let i = 7; i >= 0; --i) {
463
+ bit = (symbol >> i) & 1;
464
+ this.encodeBit(encoder.decoders, context, bit);
465
+ context = context << 1 | bit;
466
+ }
467
+ }
468
+ /**
469
+ * Encode matched literal
470
+ */
471
+ encodeMatched(encoder, matchByte, symbol) {
472
+ let bit, matchBit, state, same = true, context = 1;
473
+ for (let i = 7; i >= 0; --i) {
474
+ bit = (symbol >> i) & 1;
475
+ state = context;
476
+ if (same) {
477
+ matchBit = (matchByte >> i) & 1;
478
+ state += (1 + matchBit) << 8;
479
+ same = matchBit === bit;
480
+ }
481
+ this.encodeBit(encoder.decoders, state, bit);
482
+ context = context << 1 | bit;
483
+ }
484
+ }
485
+ /**
486
+ * Encode length using direct method calls
487
+ */
488
+ encodeLength(encoder, symbol, posState) {
489
+ encoder.encode(symbol, posState, this);
490
+ }
491
+ /**
492
+ * Encode direct bits
493
+ */
494
+ encodeDirectBits(valueToEncode, numTotalBits) {
495
+ const rangeEncoder = this._rangeEncoder;
496
+ for (let i = numTotalBits - 1; i >= 0; i -= 1) {
497
+ rangeEncoder.rrange >>>= 1;
498
+ if ((valueToEncode >>> i & 1) == 1) {
499
+ rangeEncoder.low += BigInt(rangeEncoder.rrange >>> 0);
500
+ }
501
+ if (!(rangeEncoder.rrange & -0x1000000)) {
502
+ rangeEncoder.rrange <<= 8;
503
+ this.shiftLow();
504
+ }
505
+ }
506
+ }
507
+ /**
508
+ * Reverse encode
509
+ */
510
+ reverseEncode(symbol) {
511
+ const posAlignEncoder = this._posAlignEncoder;
512
+ if (!posAlignEncoder)
513
+ return;
514
+ let bit, m = 1;
515
+ for (let i = 0; i < posAlignEncoder.numBitLevels; ++i) {
516
+ bit = symbol & 1;
517
+ this.encodeBit(posAlignEncoder.models, m, bit);
518
+ m = m << 1 | bit;
519
+ symbol >>= 1;
520
+ }
521
+ }
522
+ /**
523
+ * Reverse encode range
524
+ */
525
+ reverseEncodeRange(startIndex, numBitLevels, symbol) {
526
+ let bit, m = 1;
527
+ for (let i = 0; i < numBitLevels; ++i) {
528
+ bit = symbol & 1;
529
+ this.encodeBit(this._posEncoders, startIndex + m, bit);
530
+ m = m << 1 | bit;
531
+ symbol >>= 1;
532
+ }
533
+ }
534
+ /**
535
+ * Write end marker
536
+ */
537
+ writeEndMarker(positionState) {
538
+ this.encodeBit(this._isMatch, (this._state << 4) + positionState, 1);
539
+ this.encodeBit(this._isRep, this._state, 0);
540
+ this._state = this._state < 7 ? 7 : 10;
541
+ this.encodeLength(this._lenEncoder, 0, positionState);
542
+ const posSlot = 63;
543
+ const lenToPosState = getLenToPosState(2); // Length to position state for minimum length
544
+ this.encodeBitTree(this._posSlotEncoder[lenToPosState], posSlot);
545
+ this.encodeDirectBits(67108863, 26);
546
+ this.reverseEncode(15);
547
+ }
548
+ /**
549
+ * Encode length with price table update
550
+ */
551
+ encodeLengthWithPriceUpdate(encoder, symbol, posState) {
552
+ encoder.encodeWithUpdate(symbol, posState, this);
553
+ }
554
+ /**
555
+ * Shift low helper (proper implementation) - public method for external access
556
+ */
557
+ shiftLow() {
558
+ const rangeEncoder = this._rangeEncoder;
559
+ const lowHi = Number((rangeEncoder.low >> 32n) & 0xffffffffn);
560
+ const lowLow = Number(rangeEncoder.low & 0xffffffffn);
561
+ if (lowHi != 0 || lowLow < 0xFF000000) {
562
+ rangeEncoder.position += BigInt(rangeEncoder.cacheSize);
563
+ let temp = rangeEncoder.cache;
564
+ do {
565
+ this.writeToStream(rangeEncoder.stream, temp + lowHi);
566
+ temp = 255;
567
+ } while ((rangeEncoder.cacheSize -= 1) != 0);
568
+ rangeEncoder.cache = (lowLow >>> 24) & 0xFF;
569
+ }
570
+ rangeEncoder.cacheSize += 1;
571
+ rangeEncoder.low = BigInt(lowLow & 0xFFFFFF) << 8n;
572
+ }
573
+ /**
574
+ * Write byte to stream
575
+ */
576
+ writeToStream(stream, b) {
577
+ if (!stream)
578
+ return;
579
+ stream.writeByte(b << 24 >> 24);
580
+ }
581
+ initRangeEncoder() {
582
+ this._rangeEncoder.position = 0n;
583
+ this._rangeEncoder.low = 0n;
584
+ this._rangeEncoder.rrange = -1;
585
+ this._rangeEncoder.cacheSize = 1;
586
+ this._rangeEncoder.cache = 0;
587
+ }
588
+ /**
589
+ * Fill alignment prices for position alignment encoder
590
+ */
591
+ fillAlignPrices() {
592
+ for (let i = 0; i < 16; ++i) {
593
+ this._alignPrices[i] = this.reverseGetPrice(this._posAlignEncoder, i);
594
+ }
595
+ this._alignPriceCount = 0;
596
+ }
597
+ /**
598
+ * Fill distance prices for position encoders
599
+ */
600
+ fillDistancesPrices() {
601
+ let baseVal, bitTreeEncoder, footerBits, posSlot, st, st2;
602
+ for (let i = 4; i < 0x80; ++i) {
603
+ posSlot = this.getPosSlot(i);
604
+ footerBits = (posSlot >> 1) - 1;
605
+ baseVal = (2 | (posSlot & 1)) << footerBits;
606
+ this.tempPrices[i] = this.reverseGetPriceArray(this._posEncoders, baseVal - posSlot - 1, footerBits, i - baseVal);
607
+ }
608
+ for (let lenToPosState = 0; lenToPosState < 4; ++lenToPosState) {
609
+ bitTreeEncoder = this._posSlotEncoder[lenToPosState];
610
+ st = lenToPosState << 6;
611
+ for (posSlot = 0; posSlot < this._distTableSize; posSlot += 1) {
612
+ this._posSlotPrices[st + posSlot] = this.getEncoderBitTreePrice(bitTreeEncoder, posSlot);
613
+ }
614
+ for (posSlot = 14; posSlot < this._distTableSize; posSlot += 1) {
615
+ this._posSlotPrices[st + posSlot] += (posSlot >> 1) - 1 - 4 << 6;
616
+ }
617
+ st2 = lenToPosState * 0x80;
618
+ for (let i = 0; i < 4; ++i) {
619
+ this._distancesPrices[st2 + i] = this._posSlotPrices[st + i];
620
+ }
621
+ for (let i = 4; i < 0x80; ++i) {
622
+ this._distancesPrices[st2 + i] = this._posSlotPrices[st + this.getPosSlot(i)] + this.tempPrices[i];
623
+ }
624
+ }
625
+ this._matchPriceCount = 0;
626
+ }
627
+ /**
628
+ * Get position slot for a distance value
629
+ */
630
+ getPosSlot(pos) {
631
+ if (pos < 0x800) {
632
+ return G_FAST_POS[pos];
633
+ }
634
+ if (pos < 0x200000) {
635
+ return G_FAST_POS[pos >> 10] + 20;
636
+ }
637
+ return G_FAST_POS[pos >> 20] + 40;
638
+ }
639
+ /**
640
+ * Get reverse price for bit tree encoder
641
+ */
642
+ reverseGetPrice(encoder, symbol) {
643
+ let bit, m = 1, price = 0;
644
+ for (let i = encoder.numBitLevels; i != 0; i -= 1) {
645
+ bit = symbol & 1;
646
+ symbol >>>= 1;
647
+ price += this.getPrice(encoder.models[m], bit);
648
+ m = m << 1 | bit;
649
+ }
650
+ return price;
651
+ }
652
+ /**
653
+ * Get reverse price for array of models
654
+ */
655
+ reverseGetPriceArray(models, startIndex, numBitLevels, symbol) {
656
+ let bit, m = 1, price = 0;
657
+ for (let i = numBitLevels; i != 0; i -= 1) {
658
+ bit = symbol & 1;
659
+ symbol >>>= 1;
660
+ price += PROB_PRICES[((models[startIndex + m] - bit ^ -bit) & 2047) >>> 2];
661
+ m = m << 1 | bit;
662
+ }
663
+ return price;
664
+ }
665
+ /**
666
+ * Get price for probability model (optimized)
667
+ */
668
+ getPrice(prob, symbol) {
669
+ return getBitPrice(prob, symbol);
670
+ }
671
+ /**
672
+ * Get price for bit tree encoder
673
+ */
674
+ getEncoderBitTreePrice(encoder, symbol) {
675
+ return getBitTreePrice(encoder, symbol);
676
+ }
677
+ /**
678
+ * Create encoder optimization structures (optimized)
679
+ */
680
+ createEncoderStructures() {
681
+ // Pre-allocate optimum array with proper size
682
+ // Initialize optimum array properly
683
+ this._optimum = [];
684
+ for (let i = 0; i < 0x1000; i++) {
685
+ this._optimum[i] = {};
686
+ }
687
+ for (let i = 0; i < 0x1000; ++i) {
688
+ this._optimum[i] = {};
689
+ }
690
+ // Initialize position slot encoders
691
+ this._posSlotEncoder = new Array(4);
692
+ for (let i = 0; i < 4; ++i) {
693
+ this._posSlotEncoder[i] = createBitTree(6);
694
+ }
695
+ }
696
+ /**
697
+ * Get literal encoder subcoder (utility method)
698
+ */
699
+ getSubCoderUtility(pos, prevByte) {
700
+ // Calculate position mask bits
701
+ const posBits = pos & this._literalEncoder.posMask;
702
+ const posShifted = posBits << this._literalEncoder.numPrevBits;
703
+ // Calculate previous byte bits
704
+ const prevByteShift = 0x08 - this._literalEncoder.numPrevBits;
705
+ const prevByteBits = (prevByte & 0xFF) >>> prevByteShift;
706
+ // Combine position and prevByte bits to get final index
707
+ const coderIndex = posShifted + prevByteBits;
708
+ return this._literalEncoder.coders[coderIndex];
709
+ }
710
+ // ── Encoding orchestration methods (moved from LZMA) ──
711
+ makeAsChar(optimum) {
712
+ optimum.backPrev = -1;
713
+ optimum.prev1IsChar = 0;
714
+ }
715
+ makeAsShortRep(optimum) {
716
+ optimum.backPrev = 0;
717
+ optimum.prev1IsChar = 0;
718
+ }
719
+ releaseMFStream() {
720
+ if (this._matchFinder && this._needReleaseMFStream) {
721
+ this._matchFinder._stream = null;
722
+ this._needReleaseMFStream = 0;
723
+ }
724
+ }
725
+ releaseStreams() {
726
+ this.releaseMFStream();
727
+ this._rangeEncoder.stream = null;
728
+ }
729
+ getProcessedSizeAdd() {
730
+ return BigInt(this._rangeEncoder.cacheSize) + this._rangeEncoder.position + 4n;
731
+ }
732
+ getSubCoder(pos, prevByte) {
733
+ const subCoder = this._literalEncoder.getSubCoder(pos, prevByte);
734
+ return { decoders: subCoder.decoders };
735
+ }
736
+ getLiteralPrice(encoder, matchMode, matchByte, symbol) {
737
+ let bit, context = 1, i = 7, matchBit, price = 0;
738
+ if (matchMode) {
739
+ for (; i >= 0; --i) {
740
+ matchBit = (matchByte >> i) & 1;
741
+ bit = (symbol >> i) & 1;
742
+ price += getBitPrice(encoder.decoders[((1 + matchBit) << 8) + context], bit);
743
+ context = context << 1 | bit;
744
+ if (matchBit != bit) {
745
+ --i;
746
+ break;
747
+ }
748
+ }
749
+ }
750
+ for (; i >= 0; --i) {
751
+ bit = symbol >> i & 1;
752
+ price += getBitPrice(encoder.decoders[context], bit);
753
+ context = context << 1 | bit;
754
+ }
755
+ return price;
756
+ }
757
+ getPosLenPrice(pos, len, posState) {
758
+ let price, lenToPosState = getLenToPosState(len);
759
+ if (pos < 128) {
760
+ price = this._distancesPrices[lenToPosState * 128 + pos];
761
+ }
762
+ else {
763
+ const position = (lenToPosState << 6) + this.getPosSlot2(pos);
764
+ price = this._posSlotPrices[position] + this._alignPrices[pos & 15];
765
+ }
766
+ return price + this._lenEncoder.getPrice(len - 2, posState);
767
+ }
768
+ getPureRepPrice(repIndex, state, posState) {
769
+ let price;
770
+ if (!repIndex) {
771
+ price = PROB_PRICES[(this._isRepG0[state]) >>> 2];
772
+ price += PROB_PRICES[0x800 - this._isRep0Long[(state << 4) + posState] >>> 2];
773
+ }
774
+ else {
775
+ price = PROB_PRICES[(0x800 - this._isRepG0[state]) >>> 2];
776
+ if (repIndex == 1) {
777
+ price += PROB_PRICES[(this._isRepG1[state]) >>> 2];
778
+ }
779
+ else {
780
+ price += PROB_PRICES[(0x800 - this._isRepG1[state]) >>> 2];
781
+ price += getBitPrice(this._isRepG2[state], repIndex - 2);
782
+ }
783
+ }
784
+ return price;
785
+ }
786
+ getRepLen1Price(posState) {
787
+ const repG0Price = PROB_PRICES[(this._isRepG0[this._state]) >>> 2];
788
+ const rep0LongPrice = PROB_PRICES[this._isRep0Long[(this._state << 4) + posState] >>> 2];
789
+ return repG0Price + rep0LongPrice;
790
+ }
791
+ getPosSlot2(pos) {
792
+ if (pos < 0x20000) {
793
+ return G_FAST_POS[pos >> 6] + 12;
794
+ }
795
+ if (pos < 0x8000000) {
796
+ return G_FAST_POS[pos >> 16] + 32;
797
+ }
798
+ return G_FAST_POS[pos >> 26] + 52;
799
+ }
800
+ movePosHelper(num) {
801
+ if (num > 0) {
802
+ this._matchFinder.skip(num);
803
+ this._additionalOffset += num;
804
+ }
805
+ }
806
+ readMatchDistances() {
807
+ let lenRes = 0;
808
+ this._numDistancePairs = this._matchFinder.getMatches(this._matchDistances);
809
+ if (this._numDistancePairs > 0) {
810
+ lenRes = this._matchDistances[this._numDistancePairs - 2];
811
+ if (lenRes == this._numFastBytes) {
812
+ lenRes += this._matchFinder.getMatchLen(lenRes - 1, this._matchDistances[this._numDistancePairs - 1], 0x0111 - lenRes);
813
+ }
814
+ }
815
+ this._additionalOffset += 1;
816
+ return lenRes;
817
+ }
818
+ flushEncoding(nowPos) {
819
+ this.releaseMFStream();
820
+ this.writeEndMarker(nowPos & this._posStateMask);
821
+ for (let i = 0; i < 5; ++i) {
822
+ this.shiftLow();
823
+ }
824
+ }
825
+ backward(cur) {
826
+ let backCur, backMem, posMem, posPrev;
827
+ this._optimumEndIndex = cur;
828
+ posMem = this._optimum[cur].posPrev;
829
+ backMem = this._optimum[cur].backPrev;
830
+ do {
831
+ if (this._optimum[cur].prev1IsChar) {
832
+ this.makeAsChar(this._optimum[posMem]);
833
+ this._optimum[posMem].posPrev = posMem - 1;
834
+ if (this._optimum[cur].prev2) {
835
+ this._optimum[posMem - 1].prev1IsChar = 0;
836
+ this._optimum[posMem - 1].posPrev = this._optimum[cur].posPrev2;
837
+ this._optimum[posMem - 1].backPrev = this._optimum[cur].backPrev2;
838
+ }
839
+ }
840
+ posPrev = posMem;
841
+ backCur = backMem;
842
+ backMem = this._optimum[posPrev].backPrev;
843
+ posMem = this._optimum[posPrev].posPrev;
844
+ this._optimum[posPrev].backPrev = backCur;
845
+ this._optimum[posPrev].posPrev = cur;
846
+ cur = posPrev;
847
+ } while (cur > 0);
848
+ this.backRes = this._optimum[0].backPrev;
849
+ this._optimumCurrentIndex = this._optimum[0].posPrev;
850
+ return this._optimumCurrentIndex;
851
+ }
852
+ getOptimumLength(position) {
853
+ let cur, curAnd1Price, curAndLenCharPrice, curAndLenPrice, curBack, curPrice, currentByte, distance, len, lenEnd, lenMain, lenTest, lenTest2, lenTestTemp, matchByte, matchPrice, newLen, nextIsChar, nextMatchPrice, nextOptimum, nextRepMatchPrice, normalMatchPrice, numAvailableBytes, numAvailableBytesFull, numDistancePairs, offs, offset, opt, optimum, pos, posPrev, posState, posStateNext, price_4, repIndex, repLen, repMatchPrice, repMaxIndex, shortRepPrice, startLen, state, state2, t, price, price_0, price_1, price_2, price_3, lenRes;
854
+ if (this._optimumEndIndex != this._optimumCurrentIndex) {
855
+ lenRes = this._optimum[this._optimumCurrentIndex].posPrev - this._optimumCurrentIndex;
856
+ this.backRes = this._optimum[this._optimumCurrentIndex].backPrev;
857
+ this._optimumCurrentIndex = this._optimum[this._optimumCurrentIndex].posPrev;
858
+ return lenRes;
859
+ }
860
+ this._optimumCurrentIndex = this._optimumEndIndex = 0;
861
+ if (this._longestMatchWasFound) {
862
+ lenMain = this._longestMatchLength;
863
+ this._longestMatchWasFound = 0;
864
+ }
865
+ else {
866
+ lenMain = this.readMatchDistances();
867
+ }
868
+ numDistancePairs = this._numDistancePairs;
869
+ numAvailableBytes = this._matchFinder.getNumAvailableBytes() + 1;
870
+ if (numAvailableBytes < 2) {
871
+ this.backRes = -1;
872
+ return 1;
873
+ }
874
+ if (numAvailableBytes > 0x0111) {
875
+ numAvailableBytes = 0x0111;
876
+ }
877
+ repMaxIndex = 0;
878
+ for (let i = 0; i < 4; ++i) {
879
+ this.reps[i] = this._repDistances[i];
880
+ this.repLens[i] = this._matchFinder.getMatchLen(-1, this.reps[i], 0x0111);
881
+ if (this.repLens[i] > this.repLens[repMaxIndex]) {
882
+ repMaxIndex = i;
883
+ }
884
+ }
885
+ if (this.repLens[repMaxIndex] >= this._numFastBytes) {
886
+ this.backRes = repMaxIndex;
887
+ lenRes = this.repLens[repMaxIndex];
888
+ this.movePosHelper(lenRes - 1);
889
+ return lenRes;
890
+ }
891
+ if (lenMain >= this._numFastBytes) {
892
+ this.backRes = this._matchDistances[numDistancePairs - 1] + 4;
893
+ this.movePosHelper(lenMain - 1);
894
+ return lenMain;
895
+ }
896
+ currentByte = this._matchFinder.getIndexByte(-1);
897
+ matchByte = this._matchFinder.getIndexByte(-this._repDistances[0] - 1 - 1);
898
+ if (lenMain < 2 && currentByte != matchByte && this.repLens[repMaxIndex] < 2) {
899
+ this.backRes = -1;
900
+ return 1;
901
+ }
902
+ this._optimum[0].state = this._state;
903
+ posState = position & this._posStateMask;
904
+ this._optimum[1].price = PROB_PRICES[(this._isMatch[(this._state << 4) + posState]) >>> 2] + this.getLiteralPrice(this.getSubCoder(position, this._previousByte), this._state >= 7, matchByte, currentByte);
905
+ this.makeAsChar(this._optimum[1]);
906
+ matchPrice = PROB_PRICES[(2048 - this._isMatch[(this._state << 4) + posState])
907
+ >>> 2];
908
+ repMatchPrice = matchPrice + PROB_PRICES[(2048 - this._isRep[this._state]) >>> 2];
909
+ if (matchByte == currentByte) {
910
+ shortRepPrice = repMatchPrice + this.getRepLen1Price(posState);
911
+ if (shortRepPrice < this._optimum[1].price) {
912
+ this._optimum[1].price = shortRepPrice;
913
+ this.makeAsShortRep(this._optimum[1]);
914
+ }
915
+ }
916
+ lenEnd = lenMain >= this.repLens[repMaxIndex]
917
+ ? lenMain
918
+ : this.repLens[repMaxIndex];
919
+ if (lenEnd < 2) {
920
+ this.backRes = this._optimum[1].backPrev;
921
+ return 1;
922
+ }
923
+ this._optimum[1].posPrev = 0;
924
+ this._optimum[0].backs0 = this.reps[0];
925
+ this._optimum[0].backs1 = this.reps[1];
926
+ this._optimum[0].backs2 = this.reps[2];
927
+ this._optimum[0].backs3 = this.reps[3];
928
+ len = lenEnd;
929
+ do {
930
+ this._optimum[len].price = INFINITY_PRICE;
931
+ len -= 1;
932
+ } while (len >= 2);
933
+ for (let i = 0; i < 4; ++i) {
934
+ repLen = this.repLens[i];
935
+ if (repLen < 2) {
936
+ continue;
937
+ }
938
+ price_4 = repMatchPrice + this.getPureRepPrice(i, this._state, posState);
939
+ do {
940
+ curAndLenPrice = price_4 + this._repMatchLenEncoder.getPrice(repLen - 2, posState);
941
+ optimum = this._optimum[repLen];
942
+ if (curAndLenPrice < optimum.price) {
943
+ optimum.price = curAndLenPrice;
944
+ optimum.posPrev = 0;
945
+ optimum.backPrev = i;
946
+ optimum.prev1IsChar = 0;
947
+ }
948
+ } while ((repLen -= 1) >= 2);
949
+ }
950
+ normalMatchPrice = matchPrice
951
+ + PROB_PRICES[(this._isRep[this._state]) >>> 2];
952
+ len = this.repLens[0] >= 2 ? this.repLens[0] + 1 : 2;
953
+ if (len <= lenMain) {
954
+ offs = 0;
955
+ while (len > this._matchDistances[offs]) {
956
+ offs += 2;
957
+ }
958
+ for (;; len += 1) {
959
+ distance = this._matchDistances[offs + 1];
960
+ curAndLenPrice = normalMatchPrice + this.getPosLenPrice(distance, len, posState);
961
+ optimum = this._optimum[len];
962
+ if (curAndLenPrice < optimum.price) {
963
+ optimum.price = curAndLenPrice;
964
+ optimum.posPrev = 0;
965
+ optimum.backPrev = distance + 4;
966
+ optimum.prev1IsChar = 0;
967
+ }
968
+ if (len == this._matchDistances[offs]) {
969
+ offs += 2;
970
+ if (offs == numDistancePairs) {
971
+ break;
972
+ }
973
+ }
974
+ }
975
+ }
976
+ cur = 0;
977
+ while (1) {
978
+ ++cur;
979
+ if (cur == lenEnd) {
980
+ return this.backward(cur);
981
+ }
982
+ newLen = this.readMatchDistances();
983
+ numDistancePairs = this._numDistancePairs;
984
+ if (newLen >= this._numFastBytes) {
985
+ this._longestMatchLength = newLen;
986
+ this._longestMatchWasFound = 0x01;
987
+ return this.backward(cur);
988
+ }
989
+ position += 0x01;
990
+ posPrev = this._optimum[cur].posPrev;
991
+ if (this._optimum[cur].prev1IsChar) {
992
+ posPrev -= 0x01;
993
+ if (this._optimum[cur].prev2) {
994
+ state = this._optimum[this._optimum[cur].posPrev2].state;
995
+ if (this._optimum[cur].backPrev2 < 0x04) {
996
+ state = (state < 0x07) ? 0x08 : 0x0B;
997
+ }
998
+ else {
999
+ state = (state < 0x07) ? 0x07 : 0x0A;
1000
+ }
1001
+ }
1002
+ else {
1003
+ state = this._optimum[posPrev].state;
1004
+ }
1005
+ state = stateUpdateChar(state);
1006
+ }
1007
+ else {
1008
+ state = this._optimum[posPrev].state;
1009
+ }
1010
+ if (posPrev == cur - 1) {
1011
+ if (!this._optimum[cur].backPrev) {
1012
+ state = state < 7 ? 9 : 11;
1013
+ }
1014
+ else {
1015
+ state = stateUpdateChar(state);
1016
+ }
1017
+ }
1018
+ else {
1019
+ if (this._optimum[cur].prev1IsChar
1020
+ && this._optimum[cur].prev2) {
1021
+ posPrev = this._optimum[cur].posPrev2;
1022
+ pos = this._optimum[cur].backPrev2;
1023
+ state = state < 0x07 ? 0x08 : 0x0B;
1024
+ }
1025
+ else {
1026
+ pos = this._optimum[cur].backPrev;
1027
+ if (pos < 4) {
1028
+ state = state < 0x07 ? 0x08 : 0x0B;
1029
+ }
1030
+ else {
1031
+ state = state < 0x07 ? 0x07 : 0x0A;
1032
+ }
1033
+ }
1034
+ opt = this._optimum[posPrev];
1035
+ if (pos < 4) {
1036
+ if (!pos) {
1037
+ this.reps[0] = opt.backs0;
1038
+ this.reps[1] = opt.backs1;
1039
+ this.reps[2] = opt.backs2;
1040
+ this.reps[3] = opt.backs3;
1041
+ }
1042
+ else if (pos == 1) {
1043
+ this.reps[0] = opt.backs1;
1044
+ this.reps[1] = opt.backs0;
1045
+ this.reps[2] = opt.backs2;
1046
+ this.reps[3] = opt.backs3;
1047
+ }
1048
+ else if (pos == 2) {
1049
+ this.reps[0] = opt.backs2;
1050
+ this.reps[1] = opt.backs0;
1051
+ this.reps[2] = opt.backs1;
1052
+ this.reps[3] = opt.backs3;
1053
+ }
1054
+ else {
1055
+ this.reps[0] = opt.backs3;
1056
+ this.reps[1] = opt.backs0;
1057
+ this.reps[2] = opt.backs1;
1058
+ this.reps[3] = opt.backs2;
1059
+ }
1060
+ }
1061
+ else {
1062
+ this.reps[0] = pos - 4;
1063
+ this.reps[1] = opt.backs0;
1064
+ this.reps[2] = opt.backs1;
1065
+ this.reps[3] = opt.backs2;
1066
+ }
1067
+ }
1068
+ this._optimum[cur].state = state;
1069
+ this._optimum[cur].backs0 = this.reps[0];
1070
+ this._optimum[cur].backs1 = this.reps[1];
1071
+ this._optimum[cur].backs2 = this.reps[2];
1072
+ this._optimum[cur].backs3 = this.reps[3];
1073
+ curPrice = this._optimum[cur].price;
1074
+ currentByte = this._matchFinder.getIndexByte(-0x01);
1075
+ matchByte = this._matchFinder.getIndexByte(-this.reps[0] - 1 - 1);
1076
+ posState = position & this._posStateMask;
1077
+ curAnd1Price = curPrice
1078
+ + PROB_PRICES[(this._isMatch[(state << 0x04) + posState]) >>> 2]
1079
+ + this.getLiteralPrice(this.getSubCoder(position, this._matchFinder.getIndexByte(-2)), state >= 7, matchByte, currentByte);
1080
+ nextOptimum = this._optimum[cur + 1];
1081
+ nextIsChar = 0;
1082
+ if (curAnd1Price < nextOptimum.price) {
1083
+ nextOptimum.price = curAnd1Price;
1084
+ nextOptimum.posPrev = cur;
1085
+ nextOptimum.backPrev = -0x01;
1086
+ nextOptimum.prev1IsChar = 0;
1087
+ nextIsChar = 1;
1088
+ }
1089
+ matchPrice = curPrice + PROB_PRICES[(2048 - this._isMatch[(state << 4) + posState]) >>> 2];
1090
+ repMatchPrice = matchPrice + PROB_PRICES[(2048 - this._isRep[state]) >>> 2];
1091
+ if (matchByte == currentByte && !(nextOptimum.posPrev < cur && !nextOptimum.backPrev)) {
1092
+ shortRepPrice = repMatchPrice
1093
+ + (PROB_PRICES[(this._isRepG0[state]) >>> 0x02] + PROB_PRICES[(this._isRep0Long[(state << 0x04) + posState]) >>> 0x02]);
1094
+ if (shortRepPrice <= nextOptimum.price) {
1095
+ nextOptimum.price = shortRepPrice;
1096
+ nextOptimum.posPrev = cur;
1097
+ nextOptimum.backPrev = 0;
1098
+ nextOptimum.prev1IsChar = 0;
1099
+ nextIsChar = 1;
1100
+ }
1101
+ }
1102
+ numAvailableBytesFull = this._matchFinder.getNumAvailableBytes() + 1;
1103
+ numAvailableBytesFull = 0xFFF - cur < numAvailableBytesFull
1104
+ ? 0xFFF - cur
1105
+ : numAvailableBytesFull;
1106
+ numAvailableBytes = numAvailableBytesFull;
1107
+ if (numAvailableBytes < 2) {
1108
+ continue;
1109
+ }
1110
+ if (numAvailableBytes > this._numFastBytes) {
1111
+ numAvailableBytes = this._numFastBytes;
1112
+ }
1113
+ if (!nextIsChar && matchByte != currentByte) {
1114
+ t = Math.min(numAvailableBytesFull - 1, this._numFastBytes);
1115
+ lenTest2 = this._matchFinder.getMatchLen(0, this.reps[0], t);
1116
+ if (lenTest2 >= 2) {
1117
+ state2 = stateUpdateChar(state);
1118
+ posStateNext = position + 1 & this._posStateMask;
1119
+ nextRepMatchPrice = curAnd1Price
1120
+ + PROB_PRICES[(2048 - this._isMatch[(state2 << 4) + posStateNext]) >>> 2]
1121
+ + PROB_PRICES[(2048 - this._isRep[state2]) >>> 2];
1122
+ offset = cur + 1 + lenTest2;
1123
+ while (lenEnd < offset) {
1124
+ this._optimum[lenEnd += 1].price = INFINITY_PRICE;
1125
+ }
1126
+ curAndLenPrice = nextRepMatchPrice + (price = this._repMatchLenEncoder.getPrice(lenTest2 - 2, posStateNext),
1127
+ price + this.getPureRepPrice(0, state2, posStateNext));
1128
+ optimum = this._optimum[offset];
1129
+ if (curAndLenPrice < optimum.price) {
1130
+ optimum.price = curAndLenPrice;
1131
+ optimum.posPrev = cur + 1;
1132
+ optimum.backPrev = 0;
1133
+ optimum.prev1IsChar = 1;
1134
+ optimum.prev2 = 0;
1135
+ }
1136
+ }
1137
+ }
1138
+ startLen = 0x02;
1139
+ for (repIndex = 0; repIndex < 4; ++repIndex) {
1140
+ lenTest = this._matchFinder.getMatchLen(-0x01, this.reps[repIndex], numAvailableBytes);
1141
+ if (lenTest < 2) {
1142
+ continue;
1143
+ }
1144
+ lenTestTemp = lenTest;
1145
+ do {
1146
+ while (lenEnd < cur + lenTest) {
1147
+ this._optimum[lenEnd += 1].price = INFINITY_PRICE;
1148
+ }
1149
+ curAndLenPrice = repMatchPrice + (price_0 = this._repMatchLenEncoder.getPrice(lenTest - 2, posState),
1150
+ price_0 + this.getPureRepPrice(repIndex, state, posState));
1151
+ optimum = this._optimum[cur + lenTest];
1152
+ if (curAndLenPrice < optimum.price) {
1153
+ optimum.price = curAndLenPrice;
1154
+ optimum.posPrev = cur;
1155
+ optimum.backPrev = repIndex;
1156
+ optimum.prev1IsChar = 0;
1157
+ }
1158
+ } while ((lenTest -= 1) >= 2);
1159
+ lenTest = lenTestTemp;
1160
+ if (!repIndex) {
1161
+ startLen = lenTest + 1;
1162
+ }
1163
+ if (lenTest < numAvailableBytesFull) {
1164
+ t = Math.min(numAvailableBytesFull - 1 - lenTest, this._numFastBytes);
1165
+ lenTest2 = this._matchFinder.getMatchLen(lenTest, this.reps[repIndex], t);
1166
+ if (lenTest2 >= 2) {
1167
+ state2 = state < 7 ? 0x08 : 11;
1168
+ posStateNext = position + lenTest & this._posStateMask;
1169
+ curAndLenCharPrice = repMatchPrice
1170
+ + (price_1 = this._repMatchLenEncoder.getPrice(lenTest - 2, posState), price_1 + this.getPureRepPrice(repIndex, state, posState))
1171
+ + PROB_PRICES[(this._isMatch[(state2 << 4) + posStateNext]) >>> 2]
1172
+ + this.getLiteralPrice(this.getSubCoder(position + lenTest, this._matchFinder.getIndexByte(lenTest - 1 - 1)), true, this._matchFinder.getIndexByte(lenTest - 1 - (this.reps[repIndex] + 1)), this._matchFinder.getIndexByte(lenTest - 1));
1173
+ state2 = stateUpdateChar(state2);
1174
+ posStateNext = position + lenTest + 1 & this._posStateMask;
1175
+ nextMatchPrice = curAndLenCharPrice + PROB_PRICES[(2048 - this._isMatch[(state2 << 4) + posStateNext]) >>> 2];
1176
+ nextRepMatchPrice = nextMatchPrice + PROB_PRICES[(2048 - this._isRep[state2]) >>> 2];
1177
+ offset = lenTest + 1 + lenTest2;
1178
+ while (lenEnd < cur + offset) {
1179
+ this._optimum[lenEnd += 1].price = INFINITY_PRICE;
1180
+ }
1181
+ curAndLenPrice = nextRepMatchPrice + (price_2 = this._repMatchLenEncoder.getPrice(lenTest2 - 2, posStateNext), price_2 + this.getPureRepPrice(0, state2, posStateNext));
1182
+ optimum = this._optimum[cur + offset];
1183
+ if (curAndLenPrice < optimum.price) {
1184
+ optimum.price = curAndLenPrice;
1185
+ optimum.posPrev = cur + lenTest + 1;
1186
+ optimum.backPrev = 0;
1187
+ optimum.prev1IsChar = 1;
1188
+ optimum.prev2 = 1;
1189
+ optimum.posPrev2 = cur;
1190
+ optimum.backPrev2 = repIndex;
1191
+ }
1192
+ }
1193
+ }
1194
+ }
1195
+ if (newLen > numAvailableBytes) {
1196
+ newLen = numAvailableBytes;
1197
+ for (numDistancePairs = 0; newLen > this._matchDistances[numDistancePairs]; numDistancePairs += 2) { }
1198
+ this._matchDistances[numDistancePairs] = newLen;
1199
+ numDistancePairs += 2;
1200
+ }
1201
+ if (newLen >= startLen) {
1202
+ normalMatchPrice = matchPrice + PROB_PRICES[(this._isRep[state]) >>> 2];
1203
+ while (lenEnd < cur + newLen) {
1204
+ this._optimum[lenEnd += 1].price = INFINITY_PRICE;
1205
+ }
1206
+ offs = 0;
1207
+ while (startLen > this._matchDistances[offs]) {
1208
+ offs += 2;
1209
+ }
1210
+ for (lenTest = startLen;; lenTest += 1) {
1211
+ curBack = this._matchDistances[offs + 1];
1212
+ curAndLenPrice = normalMatchPrice + this.getPosLenPrice(curBack, lenTest, posState);
1213
+ optimum = this._optimum[cur + lenTest];
1214
+ if (curAndLenPrice < optimum.price) {
1215
+ optimum.price = curAndLenPrice;
1216
+ optimum.posPrev = cur;
1217
+ optimum.backPrev = curBack + 4;
1218
+ optimum.prev1IsChar = 0;
1219
+ }
1220
+ if (lenTest == this._matchDistances[offs]) {
1221
+ if (lenTest < numAvailableBytesFull) {
1222
+ t = Math.min(numAvailableBytesFull - 1 - lenTest, this._numFastBytes);
1223
+ lenTest2 = this._matchFinder.getMatchLen(lenTest, curBack, t);
1224
+ if (lenTest2 >= 2) {
1225
+ state2 = state < 7 ? 7 : 10;
1226
+ posStateNext = position + lenTest & this._posStateMask;
1227
+ curAndLenCharPrice = curAndLenPrice
1228
+ + PROB_PRICES[(this._isMatch[(state2 << 4) + posStateNext]) >>> 2]
1229
+ + this.getLiteralPrice(this.getSubCoder(position + lenTest, this._matchFinder.getIndexByte(lenTest - 1 - 1)), true, this._matchFinder.getIndexByte(lenTest - (curBack + 1) - 1), this._matchFinder.getIndexByte(lenTest - 1));
1230
+ state2 = stateUpdateChar(state2);
1231
+ posStateNext = position + lenTest + 1 & this._posStateMask;
1232
+ nextMatchPrice = curAndLenCharPrice + PROB_PRICES[(2048 - this._isMatch[(state2 << 4) + posStateNext]) >>> 2];
1233
+ nextRepMatchPrice = nextMatchPrice + PROB_PRICES[(2048 - this._isRep[state2]) >>> 2];
1234
+ offset = lenTest + 1 + lenTest2;
1235
+ while (lenEnd < cur + offset) {
1236
+ this._optimum[lenEnd += 1].price = INFINITY_PRICE;
1237
+ }
1238
+ curAndLenPrice = nextRepMatchPrice + (price_3 = this._repMatchLenEncoder.getPrice(lenTest2 - 2, posStateNext), price_3 + this.getPureRepPrice(0, state2, posStateNext));
1239
+ optimum = this._optimum[cur + offset];
1240
+ if (curAndLenPrice < optimum.price) {
1241
+ optimum.price = curAndLenPrice;
1242
+ optimum.posPrev = cur + lenTest + 1;
1243
+ optimum.backPrev = 0;
1244
+ optimum.prev1IsChar = 1;
1245
+ optimum.prev2 = 1;
1246
+ optimum.posPrev2 = cur;
1247
+ optimum.backPrev2 = curBack + 4;
1248
+ }
1249
+ }
1250
+ }
1251
+ offs += 2;
1252
+ if (offs == numDistancePairs) {
1253
+ break;
1254
+ }
1255
+ }
1256
+ }
1257
+ }
1258
+ }
1259
+ // Fallback return - should not be reached in normal execution
1260
+ return 1;
1261
+ }
1262
+ codeOneBlock() {
1263
+ let baseVal, complexState, curByte, distance, footerBits, len, lenToPosState, matchByte, pos, posReduced, posSlot, posState, progressPosValuePrev, subCoder;
1264
+ this.processedInSize[0] = 0n;
1265
+ this.processedOutSize[0] = 0n;
1266
+ this.finished[0] = 1;
1267
+ progressPosValuePrev = this.nowPos64;
1268
+ if (this._inStream) {
1269
+ this._matchFinder._stream = this._inStream;
1270
+ this._matchFinder.init();
1271
+ this._needReleaseMFStream = 1;
1272
+ this._inStream = null;
1273
+ }
1274
+ if (this._finished) {
1275
+ return;
1276
+ }
1277
+ this._finished = 1;
1278
+ if (this.nowPos64 === 0n) {
1279
+ if (!this._matchFinder.getNumAvailableBytes()) {
1280
+ this.flushEncoding(Number(this.nowPos64 & 0xffffffffn));
1281
+ return;
1282
+ }
1283
+ this.readMatchDistances();
1284
+ posState = Number(this.nowPos64 & 0xffffffffn) & this._posStateMask;
1285
+ this.encodeBit(this._isMatch, (this._state << 4) + posState, 0);
1286
+ this._state = stateUpdateChar(this._state);
1287
+ curByte = this._matchFinder.getIndexByte(-this._additionalOffset);
1288
+ this.encodeLiteral(this.getSubCoder(Number(this.nowPos64 & 0xffffffffn), this._previousByte), curByte);
1289
+ this._previousByte = curByte;
1290
+ this._additionalOffset -= 1;
1291
+ this.nowPos64 += 1n;
1292
+ }
1293
+ if (!this._matchFinder.getNumAvailableBytes()) {
1294
+ this.flushEncoding(Number(this.nowPos64 & 0xffffffffn));
1295
+ return;
1296
+ }
1297
+ while (1) {
1298
+ len = this.getOptimumLength(Number(this.nowPos64 & 0xffffffffn));
1299
+ pos = this.backRes;
1300
+ posState = Number(this.nowPos64 & 0xffffffffn) & this._posStateMask;
1301
+ complexState = (this._state << 4) + posState;
1302
+ if (len == 1 && pos == -1) {
1303
+ this.encodeBit(this._isMatch, complexState, 0);
1304
+ curByte = this._matchFinder.getIndexByte(-this._additionalOffset);
1305
+ subCoder = this.getSubCoder(Number(this.nowPos64 & 0xffffffffn), this._previousByte);
1306
+ if (this._state < 7) {
1307
+ this.encodeLiteral(subCoder, curByte);
1308
+ }
1309
+ else {
1310
+ matchByte = this._matchFinder.getIndexByte(-this._repDistances[0]
1311
+ - 1
1312
+ - this._additionalOffset);
1313
+ this.encodeMatched(subCoder, matchByte, curByte);
1314
+ }
1315
+ this._previousByte = curByte;
1316
+ this._state = stateUpdateChar(this._state);
1317
+ }
1318
+ else {
1319
+ this.encodeBit(this._isMatch, complexState, 1);
1320
+ if (pos < 4) {
1321
+ this.encodeBit(this._isRep, this._state, 1);
1322
+ if (!pos) {
1323
+ this.encodeBit(this._isRepG0, this._state, 0);
1324
+ if (len == 1) {
1325
+ this.encodeBit(this._isRep0Long, complexState, 0);
1326
+ }
1327
+ else {
1328
+ this.encodeBit(this._isRep0Long, complexState, 1);
1329
+ }
1330
+ }
1331
+ else {
1332
+ this.encodeBit(this._isRepG0, this._state, 1);
1333
+ if (pos == 1) {
1334
+ this.encodeBit(this._isRepG1, this._state, 0);
1335
+ }
1336
+ else {
1337
+ this.encodeBit(this._isRepG1, this._state, 1);
1338
+ this.encodeBit(this._isRepG2, this._state, pos - 2);
1339
+ }
1340
+ }
1341
+ if (len == 1) {
1342
+ this._state = this._state < 7 ? 9 : 11;
1343
+ }
1344
+ else {
1345
+ this.encodeLength(this._repMatchLenEncoder, len - 2, posState);
1346
+ this._state = this._state < 7
1347
+ ? 0x08
1348
+ : 11;
1349
+ }
1350
+ distance = this._repDistances[pos];
1351
+ if (pos != 0) {
1352
+ for (let i = pos; i >= 1; --i) {
1353
+ this._repDistances[i] = this._repDistances[i - 1];
1354
+ }
1355
+ this._repDistances[0] = distance;
1356
+ }
1357
+ }
1358
+ else {
1359
+ this.encodeBit(this._isRep, this._state, 0);
1360
+ this._state = this._state < 7 ? 7 : 10;
1361
+ this.encodeLength(this._lenEncoder, len - 0x02, posState);
1362
+ pos -= 0x04;
1363
+ posSlot = this.getPosSlot(pos);
1364
+ lenToPosState = getLenToPosState(len);
1365
+ this.encodeBitTree(this._posSlotEncoder[lenToPosState], posSlot);
1366
+ if (posSlot >= 0x04) {
1367
+ footerBits = (posSlot >> 0x01) - 0x01;
1368
+ baseVal = (0x02 | (posSlot & 0x01)) << footerBits;
1369
+ posReduced = pos - baseVal;
1370
+ if (posSlot < 0x0E) {
1371
+ this.reverseEncodeRange(baseVal - posSlot - 0x01, footerBits, posReduced);
1372
+ }
1373
+ else {
1374
+ this.encodeDirectBits(posReduced >> 0x04, footerBits - 4);
1375
+ this.reverseEncode(posReduced & 0x0F);
1376
+ this._alignPriceCount += 1;
1377
+ }
1378
+ }
1379
+ distance = pos;
1380
+ for (let i = 3; i >= 1; --i) {
1381
+ this._repDistances[i] = this._repDistances[i - 1];
1382
+ }
1383
+ this._repDistances[0] = distance;
1384
+ this._matchPriceCount += 0x01;
1385
+ }
1386
+ this._previousByte = this._matchFinder.getIndexByte(len - 1 - this._additionalOffset);
1387
+ }
1388
+ this._additionalOffset -= len;
1389
+ this.nowPos64 += BigInt(len);
1390
+ if (!this._additionalOffset) {
1391
+ if (this._matchPriceCount >= 0x80) {
1392
+ this.fillDistancesPrices();
1393
+ }
1394
+ if (this._alignPriceCount >= 0x10) {
1395
+ this.fillAlignPrices();
1396
+ }
1397
+ this.processedInSize[0] = this.nowPos64;
1398
+ this.processedOutSize[0] = this.getProcessedSizeAdd();
1399
+ if (!this._matchFinder.getNumAvailableBytes()) {
1400
+ this.flushEncoding(Number(this.nowPos64 & 0xffffffffn));
1401
+ return;
1402
+ }
1403
+ if ((this.nowPos64 - progressPosValuePrev) >= 0x1000n) {
1404
+ this._finished = 0;
1405
+ this.finished[0] = 0;
1406
+ return;
1407
+ }
1408
+ }
1409
+ }
1410
+ }
1411
+ createMatchFinder() {
1412
+ if (!this._matchFinder) {
1413
+ const binTree = new BinTreeMatchFinder();
1414
+ let numHashBytes = 4;
1415
+ if (!this._matchFinderType) {
1416
+ numHashBytes = 2;
1417
+ }
1418
+ binTree.setType(numHashBytes);
1419
+ this._matchFinder = binTree;
1420
+ }
1421
+ this.createLiteralEncoder();
1422
+ if (this._dictionarySize == this._dictionarySizePrev
1423
+ && this._numFastBytesPrev == this._numFastBytes) {
1424
+ return;
1425
+ }
1426
+ this._matchFinder.create(this._dictionarySize, this._numFastBytes, 0x1000, 0x0112);
1427
+ this._dictionarySizePrev = this._dictionarySize;
1428
+ this._numFastBytesPrev = this._numFastBytes;
1429
+ }
1430
+ writeHeaderProperties(output) {
1431
+ this.properties[0] = ((this._posStateBits * 5 + this._numLiteralPosStateBits) * 9 + this._numLiteralContextBits) & 0xFF;
1432
+ for (let byteIndex = 0; byteIndex < 4; byteIndex++) {
1433
+ this.properties[1 + byteIndex] = (this._dictionarySize >> (0x08 * byteIndex)) & 0xFF;
1434
+ }
1435
+ for (let i = 0; i < 5; i++) {
1436
+ output.writeByte(this.properties[i]);
1437
+ }
1438
+ }
1439
+ initCompression(input, output, len, mode) {
1440
+ if (len < -1n) {
1441
+ throw new Error("invalid length " + len);
1442
+ }
1443
+ this.initialize();
1444
+ this.configure(mode);
1445
+ this.writeHeaderProperties(output);
1446
+ for (let i = 0; i < 64; i += 8) {
1447
+ output.writeByte((Number((len >> BigInt(i)) & 0xffn)) << 24 >> 24);
1448
+ }
1449
+ this._needReleaseMFStream = 0;
1450
+ this._inStream = input;
1451
+ this._finished = 0;
1452
+ this.createMatchFinder();
1453
+ this._rangeEncoder.stream = output;
1454
+ this.init();
1455
+ this.fillDistancesPrices();
1456
+ this.fillAlignPrices();
1457
+ this._lenEncoder.setTableSize(this._numFastBytes + 1 - 2);
1458
+ this._lenEncoder.updateTables(1 << this._posStateBits);
1459
+ this._repMatchLenEncoder.setTableSize(this._numFastBytes + 1 - 2);
1460
+ this._repMatchLenEncoder.updateTables(1 << this._posStateBits);
1461
+ this.nowPos64 = 0n;
1462
+ }
1463
+ compress(input, output, mode) {
1464
+ this.initCompression(input, output, BigInt(input.count), mode);
1465
+ do {
1466
+ this.codeOneBlock();
1467
+ if (this.finished[0]) {
1468
+ this.releaseStreams();
1469
+ break;
1470
+ }
1471
+ } while (true);
1472
+ }
1473
+ }