lzma1 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/encoder.ts ADDED
@@ -0,0 +1,2108 @@
1
+ import {
2
+ LenEncoder,
3
+ type RangeEncoder as LenRangeEncoder,
4
+ } from "./len-coder.js";
5
+ import { LitCoder } from "./lit-coder.js";
6
+ import { BinTreeMatchFinder } from "./match-finder.js";
7
+ import type {
8
+ InputBuffer,
9
+ OutputBuffer,
10
+ } from "./streams.js";
11
+ import type { LiteralDecoderEncoder2 } from "./utils.js";
12
+ import {
13
+ type BitTree,
14
+ createBitTree,
15
+ G_FAST_POS,
16
+ getBitPrice,
17
+ getLenToPosState,
18
+ INFINITY_PRICE,
19
+ initArray,
20
+ initBitModels,
21
+ PROB_PRICES,
22
+ stateUpdateChar,
23
+ } from "./utils.js";
24
+
25
+ const bitTreePriceCache = new Map<number, number>();
26
+
27
+ /**
28
+ * Calculate price for direct bit encoding
29
+ */
30
+ function getDirectBitsPrice(numBits: number): number {
31
+ return numBits << 6;
32
+ }
33
+
34
+ /**
35
+ * Get price for bit tree encoding with caching
36
+ */
37
+ function getBitTreePrice(bitTree: BitTree, symbol: number): number {
38
+ const cacheKey = (bitTree.numBitLevels << 16) | symbol;
39
+
40
+ if (bitTreePriceCache.has(cacheKey)) {
41
+ return bitTreePriceCache.get(cacheKey)!;
42
+ }
43
+
44
+ let price = 0;
45
+ let modelIndex = 1;
46
+
47
+ for (let bitIndex = bitTree.numBitLevels; bitIndex > 0; bitIndex--) {
48
+ const bit = (symbol >>> (bitIndex - 1)) & 1;
49
+ price += getBitPrice(bitTree.models[modelIndex], bit);
50
+ modelIndex = (modelIndex << 1) + bit;
51
+ }
52
+
53
+ if (bitTreePriceCache.size < 10000) {
54
+ bitTreePriceCache.set(cacheKey, price);
55
+ }
56
+
57
+ return price;
58
+ }
59
+
60
+ export interface Optimum {
61
+ state?: number;
62
+ price?: number;
63
+ posPrev?: number;
64
+ backPrev?: number;
65
+ prev1IsChar?: number;
66
+ prev2?: number;
67
+ posPrev2?: number;
68
+ backPrev2?: number;
69
+ backs0?: number;
70
+ backs1?: number;
71
+ backs2?: number;
72
+ backs3?: number;
73
+ }
74
+
75
+ interface RangeEncoder {
76
+ stream: OutputBuffer | null;
77
+ rrange: number;
78
+ cache: number;
79
+ low: bigint;
80
+ cacheSize: number;
81
+ position: bigint;
82
+ encodeBit(probs: number[], index: number, bit: number): void;
83
+ encodeBitTree(tree: BitTree, symbol: number): void;
84
+ encodeDirectBits(value: number, bits: number): void;
85
+ }
86
+
87
+ /**
88
+ * LZMA Encoder State - Encapsulates all encoder state management
89
+ */
90
+ class EncoderState {
91
+ // Core state
92
+ public state: number = 0;
93
+ public previousByte: number = 0;
94
+ public position: bigint = 0n;
95
+
96
+ // Repetition distances (LZ77 back-references)
97
+ public repDistances: [number, number, number, number] = [0, 0, 0, 0];
98
+
99
+ // Match finding state
100
+ public longestMatchLength: number = 0;
101
+ public longestMatchWasFound: boolean = false;
102
+ public additionalOffset: number = 0;
103
+
104
+ // Probability models for different encoding decisions
105
+ public isMatch: number[] = initArray(0xC0);
106
+ public isRep: number[] = initArray(0x0C);
107
+ public isRepG0: number[] = initArray(0x0C);
108
+ public isRepG1: number[] = initArray(0x0C);
109
+ public isRepG2: number[] = initArray(0x0C);
110
+ public isRep0Long: number[] = initArray(0xC0);
111
+
112
+ /**
113
+ * Initialize all probability models to default values
114
+ */
115
+ initModels(): void {
116
+ initBitModels(this.isMatch);
117
+ initBitModels(this.isRep);
118
+ initBitModels(this.isRepG0);
119
+ initBitModels(this.isRepG1);
120
+ initBitModels(this.isRepG2);
121
+ initBitModels(this.isRep0Long);
122
+ }
123
+
124
+ /**
125
+ * Update repetition distances when a new match is found
126
+ */
127
+ updateRepDistances(newDistance: number, repIndex: number): void {
128
+ if (repIndex === 0) {
129
+ // New match becomes rep0, shift others
130
+ this.repDistances[3] = this.repDistances[2];
131
+ this.repDistances[2] = this.repDistances[1];
132
+ this.repDistances[1] = this.repDistances[0];
133
+ this.repDistances[0] = newDistance;
134
+ } else {
135
+ // Move specific rep to front, shift others
136
+ const temp = this.repDistances[repIndex];
137
+ for (let i = repIndex; i > 0; i--) {
138
+ this.repDistances[i] = this.repDistances[i - 1];
139
+ }
140
+ this.repDistances[0] = temp;
141
+ }
142
+ }
143
+ }
144
+
145
+ /**
146
+ * Position Encoder - Handles position slot and alignment encoding
147
+ */
148
+ class PositionEncoder {
149
+ private posSlotEncoder: BitTree[] = [];
150
+ private posEncoders: number[] = initArray(0x72);
151
+ private posAlignEncoder: BitTree;
152
+
153
+ constructor() {
154
+ // Initialize position slot encoders for different length states
155
+ for (let lenState = 0; lenState < 4; lenState++) {
156
+ this.posSlotEncoder[lenState] = createBitTree(6);
157
+ }
158
+ this.posAlignEncoder = createBitTree(4);
159
+ }
160
+
161
+ /**
162
+ * Initialize all position models
163
+ */
164
+ init(): void {
165
+ for (const encoder of this.posSlotEncoder) {
166
+ initBitModels(encoder.models);
167
+ }
168
+ initBitModels(this.posEncoders);
169
+ initBitModels(this.posAlignEncoder.models);
170
+ }
171
+
172
+ /**
173
+ * Encode position using optimal method
174
+ */
175
+ encodePosition(
176
+ distance: number,
177
+ lenState: number,
178
+ rangeEncoder: RangeEncoder,
179
+ ): void {
180
+ const posSlot = this.getPosSlot(distance);
181
+ rangeEncoder.encodeBitTree(this.posSlotEncoder[lenState], posSlot);
182
+
183
+ if (posSlot >= 4) {
184
+ const footerBits = (posSlot >> 1) - 1;
185
+ const baseVal = (2 | (posSlot & 1)) << footerBits;
186
+ const posReduced = distance - baseVal;
187
+
188
+ if (posSlot < 14) {
189
+ // Use position encoders for middle range
190
+ this.encodeReverseBits(posReduced, footerBits, rangeEncoder);
191
+ } else {
192
+ // Use direct bits for high range + alignment
193
+ rangeEncoder.encodeDirectBits(posReduced >> 4, footerBits - 4);
194
+ rangeEncoder.encodeBitTree(this.posAlignEncoder, posReduced & 0x0F);
195
+ }
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Calculate price for encoding a position
201
+ */
202
+ getPositionPrice(distance: number, lenState: number): number {
203
+ const posSlot = this.getPosSlot(distance);
204
+ let price = getBitTreePrice(this.posSlotEncoder[lenState], posSlot);
205
+
206
+ if (posSlot >= 4) {
207
+ const footerBits = (posSlot >> 1) - 1;
208
+ const baseVal = (2 | (posSlot & 1)) << footerBits;
209
+ const posReduced = distance - baseVal;
210
+
211
+ if (posSlot < 14) {
212
+ price += this.getReverseBitsPrice(posReduced, footerBits);
213
+ } else {
214
+ price += getDirectBitsPrice(footerBits - 4);
215
+ price += getBitTreePrice(this.posAlignEncoder, posReduced & 0x0F);
216
+ }
217
+ }
218
+
219
+ return price;
220
+ }
221
+
222
+ private getPosSlot(distance: number): number {
223
+ if (distance < 4) return distance;
224
+ if (distance < (1 << (31 - 11))) {
225
+ return G_FAST_POS[distance >> 6] + 12;
226
+ }
227
+ return G_FAST_POS[distance >> 26] + 52;
228
+ }
229
+
230
+ private encodeReverseBits(
231
+ value: number,
232
+ numBits: number,
233
+ rangeEncoder: RangeEncoder,
234
+ ): void {
235
+ let modelIndex = 1;
236
+ for (let i = 0; i < numBits; i++) {
237
+ const bit = value & 1;
238
+ rangeEncoder.encodeBit(this.posEncoders, modelIndex, bit);
239
+ modelIndex = (modelIndex << 1) | bit;
240
+ value >>>= 1;
241
+ }
242
+ }
243
+
244
+ private getReverseBitsPrice(value: number, numBits: number): number {
245
+ let price = 0;
246
+ let modelIndex = 1;
247
+ for (let i = 0; i < numBits; i++) {
248
+ const bit = value & 1;
249
+ price += getBitPrice(this.posEncoders[modelIndex], bit);
250
+ modelIndex = (modelIndex << 1) | bit;
251
+ value >>>= 1;
252
+ }
253
+ return price;
254
+ }
255
+ }
256
+
257
+ /**
258
+ * LZMA Encoder class that handles compression operations
259
+ */
260
+ export class Encoder implements LenRangeEncoder {
261
+ private encoderState = new EncoderState();
262
+ private positionEncoder = new PositionEncoder();
263
+
264
+ // Core state properties
265
+ _state: number = 0;
266
+ _previousByte: number = 0;
267
+ _distTableSize: number = 0;
268
+ _longestMatchWasFound: number = 0;
269
+ _optimumEndIndex: number = 0;
270
+ _optimumCurrentIndex: number = 0;
271
+ _additionalOffset: number = 0;
272
+
273
+ // Dictionary and match finding
274
+ _dictionarySize: number = 0;
275
+ _matchFinder: BinTreeMatchFinder | null = null;
276
+ _dictionarySizePrev: number = 0;
277
+ _numFastBytes: number = 0;
278
+
279
+ // Literal encoding configuration
280
+ _numLiteralContextBits: number = 0;
281
+ _numLiteralPosStateBits: number = 0;
282
+ _posStateBits: number = 0;
283
+ _posStateMask: number = 0;
284
+
285
+ // Stream and processing state
286
+ _needReleaseMFStream: number = 0;
287
+ _inStream: InputBuffer | null = null;
288
+ _finished: number = 0;
289
+ nowPos64: bigint = 0n;
290
+
291
+ // Distance and repetition arrays
292
+ _repDistances: number[] = initArray(4);
293
+ _optimum: Optimum[] = [];
294
+
295
+ // Range encoder
296
+ _rangeEncoder: RangeEncoder = {
297
+ stream: null,
298
+ rrange: 0,
299
+ cache: 0,
300
+ low: 0n,
301
+ cacheSize: 0,
302
+ position: 0n,
303
+ encodeBit: () => {},
304
+ encodeBitTree: () => {},
305
+ encodeDirectBits: () => {},
306
+ };
307
+
308
+ // Bit model arrays for different types of encoding decisions
309
+ _isMatch: number[] = initArray(0xC0);
310
+ _isRep: number[] = initArray(0x0C);
311
+ _isRepG0: number[] = initArray(0x0C);
312
+ _isRepG1: number[] = initArray(0x0C);
313
+ _isRepG2: number[] = initArray(0x0C);
314
+ _isRep0Long: number[] = initArray(0xC0);
315
+
316
+ // Position and alignment encoders
317
+ _posSlotEncoder: BitTree[] = [];
318
+ _posEncoders: number[] = initArray(0x72);
319
+ _posAlignEncoder: BitTree | null = null;
320
+
321
+ // Length encoders
322
+ _lenEncoder: LenEncoder | null = null;
323
+ _repMatchLenEncoder: LenEncoder | null = null;
324
+
325
+ // Literal encoder
326
+ _literalEncoder: LitCoder | null = null;
327
+
328
+ // Distance and price arrays
329
+ _matchDistances: number[] = [];
330
+ _posSlotPrices: number[] = [];
331
+ _distancesPrices: number[] = [];
332
+ _alignPrices: number[] = initArray(0x10);
333
+ _matchPriceCount: number = 0;
334
+ _alignPriceCount: number = 0;
335
+
336
+ // Optimization arrays
337
+ reps: number[] = initArray(4);
338
+ repLens: number[] = initArray(4);
339
+
340
+ // Processing counters
341
+ processedInSize: bigint[] = [0n];
342
+ processedOutSize: bigint[] = [0n];
343
+ finished: number[] = [0];
344
+ properties = new Uint8Array(5);
345
+ tempPrices: number[] = initArray(0x80); // 128
346
+
347
+ // Match finding properties
348
+ _longestMatchLength: number = 0;
349
+ _matchFinderType: number = 1;
350
+ _numDistancePairs: number = 0;
351
+ _numFastBytesPrev: number = -1;
352
+ backRes: number = 0;
353
+
354
+ constructor() {
355
+ // Encoder is initialized with default values above
356
+ // Additional initialization will be done through specific init methods
357
+ }
358
+
359
+ /**
360
+ * Initialize basic encoder state
361
+ */
362
+ baseInit(): void {
363
+ this._state = 0;
364
+ this._previousByte = 0;
365
+
366
+ for (let i = 0; i < 4; ++i) {
367
+ this._repDistances[i] = 0;
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Get optimum array
373
+ */
374
+ getOptimum(): Optimum[] {
375
+ return this._optimum;
376
+ }
377
+
378
+ /**
379
+ * Get back result
380
+ */
381
+ getBackRes(): number {
382
+ return this.backRes;
383
+ }
384
+
385
+ setBackRes(backRes: number): void {
386
+ this.backRes = backRes;
387
+ }
388
+
389
+ init(): void {
390
+ this.baseInit();
391
+
392
+ this.encoderState.initModels();
393
+ this.positionEncoder.init();
394
+
395
+ // Initialize optimum array properly
396
+ this._optimum = [];
397
+ for (let i = 0; i < 0x1000; i++) {
398
+ this._optimum[i] = {};
399
+ }
400
+
401
+ this.initEncoderState();
402
+ initBitModels(this._isMatch);
403
+ initBitModels(this._isRep0Long);
404
+ initBitModels(this._isRep);
405
+ initBitModels(this._isRepG0);
406
+ initBitModels(this._isRepG1);
407
+ initBitModels(this._isRepG2);
408
+ initBitModels(this._posEncoders);
409
+
410
+ this.initLiteralEncoder();
411
+ for (let i = 0; i < 4; ++i) {
412
+ initBitModels(this._posSlotEncoder[i].models);
413
+ }
414
+
415
+ if (this._lenEncoder) {
416
+ this._lenEncoder.init(1 << this._posStateBits);
417
+ }
418
+ if (this._repMatchLenEncoder) {
419
+ this._repMatchLenEncoder.init(1 << this._posStateBits);
420
+ }
421
+ if (this._posAlignEncoder) {
422
+ initBitModels(this._posAlignEncoder.models);
423
+ }
424
+
425
+ this._longestMatchWasFound = 0;
426
+ this._optimumEndIndex = 0;
427
+ this._optimumCurrentIndex = 0;
428
+ this._additionalOffset = 0;
429
+ }
430
+
431
+ /**
432
+ * Initialize encoder range coder
433
+ */
434
+ initEncoderState(): void {
435
+ this._rangeEncoder.low = 0n;
436
+ this._rangeEncoder.rrange = 0xFFFFFFFF;
437
+ this._rangeEncoder.cacheSize = 1;
438
+ this._rangeEncoder.cache = 0;
439
+ this._rangeEncoder.position = 0n;
440
+ }
441
+
442
+ /**
443
+ * Initialize literal encoder
444
+ */
445
+ initLiteralEncoder(): void {
446
+ const totalStates = 1 << (this._literalEncoder!.numPrevBits + this._literalEncoder!.numPosBits);
447
+
448
+ for (let i = 0; i < totalStates; ++i) {
449
+ initBitModels(this._literalEncoder!.coders[i].decoders);
450
+ }
451
+ }
452
+
453
+ /**
454
+ * Create optimum structures
455
+ */
456
+ createOptimumStructures(): void {
457
+ for (let i = 0; i < 0x1000; ++i) {
458
+ this._optimum[i] = {};
459
+ }
460
+
461
+ for (let i = 0; i < 4; ++i) {
462
+ this._posSlotEncoder[i] = createBitTree(6);
463
+ }
464
+ }
465
+
466
+ /**
467
+ * Create length price table encoder
468
+ */
469
+ createLenPriceTableEncoder(): LenEncoder {
470
+ const encoder = new LenEncoder();
471
+ encoder.initPriceTable();
472
+ return encoder;
473
+ }
474
+
475
+ /**
476
+ * Create literal encoder encoder2
477
+ */
478
+ createLiteralEncoderEncoder2(): LiteralDecoderEncoder2 {
479
+ const encoder = {
480
+ decoders: initArray(0x300),
481
+ } as LiteralDecoderEncoder2;
482
+
483
+ return encoder;
484
+ }
485
+
486
+ /**
487
+ * Create literal encoder
488
+ */
489
+ createLiteralEncoder(): void {
490
+ // Check if we need to recreate the encoder
491
+ if (
492
+ this._literalEncoder != null
493
+ && this._literalEncoder.numPrevBits == this._numLiteralContextBits
494
+ && this._literalEncoder.numPosBits == this._numLiteralPosStateBits
495
+ ) {
496
+ return;
497
+ }
498
+
499
+ // Replace #LZMA_Encoder_LiteralEncoder_Create with LitCoder instantiation
500
+ this._literalEncoder = new LitCoder(
501
+ this._numLiteralPosStateBits,
502
+ this._numLiteralContextBits,
503
+ );
504
+ }
505
+
506
+ /**
507
+ * Initialize completely with proper encoder state
508
+ */
509
+ initialize(): void {
510
+ // Initialize encoder structures first
511
+ this._lenEncoder = this.createLenPriceTableEncoder();
512
+ this._repMatchLenEncoder = this.createLenPriceTableEncoder();
513
+ this._posAlignEncoder = createBitTree(0x04);
514
+
515
+ // Initialize optimum array
516
+ this._optimum = [];
517
+ this.createOptimumStructures();
518
+
519
+ // Create literal encoder
520
+ this.createLiteralEncoder();
521
+
522
+ // Now call init to set up the state
523
+ this.init();
524
+ }
525
+
526
+ /**
527
+ * Configure encoder settings
528
+ */
529
+ configure(mode: { searchDepth: number; filterStrength: number; modeIndex: number; }): void {
530
+ this.setDictionarySize(0x1 << mode.searchDepth);
531
+ this._numFastBytes = mode.filterStrength;
532
+ this._matchFinderType = mode.modeIndex;
533
+
534
+ // lc is always 3, lp is always 0, pb is always 2
535
+ this._numLiteralContextBits = 0x3;
536
+ this._numLiteralPosStateBits = 0x0;
537
+ this._posStateBits = 0x2;
538
+ this._posStateMask = 0x3;
539
+ }
540
+
541
+ /**
542
+ * Set dictionary size
543
+ */
544
+ setDictionarySize(dictionarySize: number): void {
545
+ this._dictionarySize = dictionarySize;
546
+
547
+ let dicLogSize = 0;
548
+ for (; dictionarySize > (1 << dicLogSize); ++dicLogSize);
549
+
550
+ this._distTableSize = dicLogSize * 2;
551
+ }
552
+
553
+ /**
554
+ * Encode a bit using range coder
555
+ */
556
+ encodeBit(probs: number[], index: number, symbol: number): void {
557
+ const rangeEncoder = this._rangeEncoder;
558
+
559
+ let newBound, prob = probs[index];
560
+ newBound = (rangeEncoder.rrange >>> 11) * prob;
561
+
562
+ if (!symbol) {
563
+ rangeEncoder.rrange = newBound;
564
+ probs[index] = prob + ((2048 - prob) >>> 5);
565
+ } else {
566
+ rangeEncoder.low += BigInt(newBound >>> 0);
567
+ rangeEncoder.rrange -= newBound;
568
+ probs[index] = prob - (prob >>> 5);
569
+ }
570
+
571
+ if (!(rangeEncoder.rrange & -0x1000000)) {
572
+ rangeEncoder.rrange <<= 8;
573
+ this.shiftLow();
574
+ }
575
+ }
576
+
577
+ /**
578
+ * Encode bit tree
579
+ */
580
+ encodeBitTree(encoder: BitTree, symbol: number): void {
581
+ let bit, bitIndex, m = 1;
582
+
583
+ for (bitIndex = encoder.numBitLevels; bitIndex != 0;) {
584
+ bitIndex -= 1;
585
+ bit = symbol >>> bitIndex & 1;
586
+ this.encodeBit(encoder.models, m, bit);
587
+ m = m << 1 | bit;
588
+ }
589
+ }
590
+
591
+ /**
592
+ * Encode literal
593
+ */
594
+ encodeLiteral(encoder: LiteralDecoderEncoder2, symbol: number): void {
595
+ let bit, context = 1;
596
+
597
+ for (let i = 7; i >= 0; --i) {
598
+ bit = (symbol >> i) & 1;
599
+ this.encodeBit(encoder.decoders, context, bit);
600
+ context = context << 1 | bit;
601
+ }
602
+ }
603
+
604
+ /**
605
+ * Encode matched literal
606
+ */
607
+ encodeMatched(encoder: LiteralDecoderEncoder2, matchByte: number, symbol: number): void {
608
+ let bit, matchBit, state, same = true, context = 1;
609
+
610
+ for (let i = 7; i >= 0; --i) {
611
+ bit = (symbol >> i) & 1;
612
+ state = context;
613
+
614
+ if (same) {
615
+ matchBit = (matchByte >> i) & 1;
616
+ state += (1 + matchBit) << 8;
617
+ same = matchBit === bit;
618
+ }
619
+
620
+ this.encodeBit(encoder.decoders, state, bit);
621
+ context = context << 1 | bit;
622
+ }
623
+ }
624
+
625
+ /**
626
+ * Encode length using direct method calls
627
+ */
628
+ encodeLength(encoder: LenEncoder, symbol: number, posState: number): void {
629
+ encoder.encode(symbol, posState, this);
630
+ }
631
+
632
+ /**
633
+ * Encode direct bits
634
+ */
635
+ encodeDirectBits(valueToEncode: number, numTotalBits: number): void {
636
+ const rangeEncoder = this._rangeEncoder;
637
+
638
+ for (let i = numTotalBits - 1; i >= 0; i -= 1) {
639
+ rangeEncoder.rrange >>>= 1;
640
+ if ((valueToEncode >>> i & 1) == 1) {
641
+ rangeEncoder.low += BigInt(rangeEncoder.rrange >>> 0);
642
+ }
643
+ if (!(rangeEncoder.rrange & -0x1000000)) {
644
+ rangeEncoder.rrange <<= 8;
645
+ this.shiftLow();
646
+ }
647
+ }
648
+ }
649
+
650
+ /**
651
+ * Reverse encode
652
+ */
653
+ reverseEncode(symbol: number): void {
654
+ const posAlignEncoder = this._posAlignEncoder;
655
+ if (!posAlignEncoder) return;
656
+
657
+ let bit, m = 1;
658
+
659
+ for (let i = 0; i < posAlignEncoder.numBitLevels; ++i) {
660
+ bit = symbol & 1;
661
+ this.encodeBit(posAlignEncoder.models, m, bit);
662
+ m = m << 1 | bit;
663
+ symbol >>= 1;
664
+ }
665
+ }
666
+
667
+ /**
668
+ * Reverse encode range
669
+ */
670
+ reverseEncodeRange(
671
+ startIndex: number,
672
+ numBitLevels: number,
673
+ symbol: number,
674
+ ): void {
675
+ let bit, m = 1;
676
+
677
+ for (let i = 0; i < numBitLevels; ++i) {
678
+ bit = symbol & 1;
679
+ this.encodeBit(this._posEncoders, startIndex + m, bit);
680
+ m = m << 1 | bit;
681
+ symbol >>= 1;
682
+ }
683
+ }
684
+
685
+ /**
686
+ * Write end marker
687
+ */
688
+ writeEndMarker(positionState: number): void {
689
+ this.encodeBit(
690
+ this._isMatch,
691
+ (this._state << 4) + positionState,
692
+ 1,
693
+ );
694
+
695
+ this.encodeBit(
696
+ this._isRep,
697
+ this._state,
698
+ 0,
699
+ );
700
+
701
+ this._state = this._state < 7 ? 7 : 10;
702
+ this.encodeLength(this._lenEncoder!, 0, positionState);
703
+
704
+ const posSlot = 63;
705
+ const lenToPosState = getLenToPosState(2); // Length to position state for minimum length
706
+
707
+ this.encodeBitTree(this._posSlotEncoder[lenToPosState], posSlot);
708
+
709
+ this.encodeDirectBits(67108863, 26);
710
+ this.reverseEncode(15);
711
+ }
712
+
713
+ /**
714
+ * Encode length with price table update
715
+ */
716
+ encodeLengthWithPriceUpdate(encoder: LenEncoder, symbol: number, posState: number): void {
717
+ encoder.encodeWithUpdate(symbol, posState, this);
718
+ }
719
+
720
+ /**
721
+ * Shift low helper (proper implementation) - public method for external access
722
+ */
723
+ shiftLow(): void {
724
+ const rangeEncoder = this._rangeEncoder;
725
+
726
+ const lowHi = Number((rangeEncoder.low >> 32n) & 0xFFFFFFFFn);
727
+ const lowLow = Number(rangeEncoder.low & 0xFFFFFFFFn);
728
+ if (lowHi != 0 || lowLow < 0xFF000000) {
729
+ rangeEncoder.position += BigInt(rangeEncoder.cacheSize);
730
+
731
+ let temp = rangeEncoder.cache;
732
+ do {
733
+ this.writeToStream(rangeEncoder.stream, temp + lowHi);
734
+ temp = 255;
735
+ } while ((rangeEncoder.cacheSize -= 1) != 0);
736
+
737
+ rangeEncoder.cache = (lowLow >>> 24) & 0xFF;
738
+ }
739
+
740
+ rangeEncoder.cacheSize += 1;
741
+ rangeEncoder.low = BigInt(lowLow & 0xFFFFFF) << 8n;
742
+ }
743
+
744
+ /**
745
+ * Write byte to stream
746
+ */
747
+ private writeToStream(stream: OutputBuffer | null, b: number): void {
748
+ if (!stream) return;
749
+ stream.writeByte(b << 24 >> 24);
750
+ }
751
+
752
+ initRangeEncoder(): void {
753
+ this._rangeEncoder.position = 0n;
754
+ this._rangeEncoder.low = 0n;
755
+ this._rangeEncoder.rrange = -1;
756
+ this._rangeEncoder.cacheSize = 1;
757
+ this._rangeEncoder.cache = 0;
758
+ }
759
+
760
+ /**
761
+ * Fill alignment prices for position alignment encoder
762
+ */
763
+ fillAlignPrices(): void {
764
+ for (let i = 0; i < 16; ++i) {
765
+ this._alignPrices[i] = this.reverseGetPrice(this._posAlignEncoder!, i);
766
+ }
767
+ this._alignPriceCount = 0;
768
+ }
769
+
770
+ /**
771
+ * Fill distance prices for position encoders
772
+ */
773
+ fillDistancesPrices(): void {
774
+ let baseVal, bitTreeEncoder: BitTree, footerBits, posSlot, st, st2;
775
+
776
+ for (let i = 4; i < 0x80; ++i) {
777
+ posSlot = this.getPosSlot(i);
778
+ footerBits = (posSlot >> 1) - 1;
779
+ baseVal = (2 | (posSlot & 1)) << footerBits;
780
+
781
+ this.tempPrices[i] = this.reverseGetPriceArray(
782
+ this._posEncoders,
783
+ baseVal - posSlot - 1,
784
+ footerBits,
785
+ i - baseVal,
786
+ );
787
+ }
788
+
789
+ for (let lenToPosState = 0; lenToPosState < 4; ++lenToPosState) {
790
+ bitTreeEncoder = this._posSlotEncoder[lenToPosState];
791
+ st = lenToPosState << 6;
792
+
793
+ for (posSlot = 0; posSlot < this._distTableSize; posSlot += 1) {
794
+ this._posSlotPrices[st + posSlot] = this.getEncoderBitTreePrice(bitTreeEncoder, posSlot);
795
+ }
796
+
797
+ for (posSlot = 14; posSlot < this._distTableSize; posSlot += 1) {
798
+ this._posSlotPrices[st + posSlot] += (posSlot >> 1) - 1 - 4 << 6;
799
+ }
800
+
801
+ st2 = lenToPosState * 0x80;
802
+ for (let i = 0; i < 4; ++i) {
803
+ this._distancesPrices[st2 + i] = this._posSlotPrices[st + i];
804
+ }
805
+
806
+ for (let i = 4; i < 0x80; ++i) {
807
+ this._distancesPrices[st2 + i] = this._posSlotPrices[st + this.getPosSlot(i)] + this.tempPrices[i];
808
+ }
809
+ }
810
+
811
+ this._matchPriceCount = 0;
812
+ }
813
+
814
+ /**
815
+ * Get position slot for a distance value
816
+ */
817
+ getPosSlot(pos: number): number {
818
+ if (pos < 0x800) {
819
+ return G_FAST_POS[pos];
820
+ }
821
+
822
+ if (pos < 0x200000) {
823
+ return G_FAST_POS[pos >> 10] + 20;
824
+ }
825
+
826
+ return G_FAST_POS[pos >> 20] + 40;
827
+ }
828
+
829
+ /**
830
+ * Get reverse price for bit tree encoder
831
+ */
832
+ reverseGetPrice(encoder: BitTree, symbol: number): number {
833
+ let bit, m = 1, price = 0;
834
+
835
+ for (let i = encoder.numBitLevels; i != 0; i -= 1) {
836
+ bit = symbol & 1;
837
+ symbol >>>= 1;
838
+ price += this.getPrice(encoder.models[m], bit);
839
+ m = m << 1 | bit;
840
+ }
841
+
842
+ return price;
843
+ }
844
+
845
+ /**
846
+ * Get reverse price for array of models
847
+ */
848
+ reverseGetPriceArray(
849
+ models: number[],
850
+ startIndex: number,
851
+ numBitLevels: number,
852
+ symbol: number,
853
+ ): number {
854
+ let bit, m = 1, price = 0;
855
+
856
+ for (let i = numBitLevels; i != 0; i -= 1) {
857
+ bit = symbol & 1;
858
+ symbol >>>= 1;
859
+ price += PROB_PRICES[((models[startIndex + m] - bit ^ -bit) & 2047) >>> 2];
860
+ m = m << 1 | bit;
861
+ }
862
+
863
+ return price;
864
+ }
865
+
866
+ /**
867
+ * Get price for probability model (optimized)
868
+ */
869
+ getPrice(prob: number, symbol: number): number {
870
+ return getBitPrice(prob, symbol);
871
+ }
872
+
873
+ /**
874
+ * Get price for bit tree encoder
875
+ */
876
+ getEncoderBitTreePrice(encoder: BitTree, symbol: number): number {
877
+ return getBitTreePrice(encoder, symbol);
878
+ }
879
+
880
+ /**
881
+ * Create encoder optimization structures (optimized)
882
+ */
883
+ createEncoderStructures(): void {
884
+ // Pre-allocate optimum array with proper size
885
+ // Initialize optimum array properly
886
+ this._optimum = [];
887
+ for (let i = 0; i < 0x1000; i++) {
888
+ this._optimum[i] = {};
889
+ }
890
+ for (let i = 0; i < 0x1000; ++i) {
891
+ this._optimum[i] = {};
892
+ }
893
+
894
+ // Initialize position slot encoders
895
+ this._posSlotEncoder = new Array(4);
896
+ for (let i = 0; i < 4; ++i) {
897
+ this._posSlotEncoder[i] = createBitTree(6);
898
+ }
899
+ }
900
+
901
+ /**
902
+ * Get literal encoder subcoder (utility method)
903
+ */
904
+ getSubCoderUtility(pos: number, prevByte: number): LiteralDecoderEncoder2 {
905
+ // Calculate position mask bits
906
+ const posBits = pos & this._literalEncoder!.posMask;
907
+ const posShifted = posBits << this._literalEncoder!.numPrevBits;
908
+
909
+ // Calculate previous byte bits
910
+ const prevByteShift = 0x08 - this._literalEncoder!.numPrevBits;
911
+ const prevByteBits = (prevByte & 0xFF) >>> prevByteShift;
912
+
913
+ // Combine position and prevByte bits to get final index
914
+ const coderIndex = posShifted + prevByteBits;
915
+
916
+ return this._literalEncoder!.coders[coderIndex];
917
+ }
918
+
919
+ // ── Encoding orchestration methods (moved from LZMA) ──
920
+
921
+ private makeAsChar(optimum: Optimum): void {
922
+ optimum.backPrev = -1;
923
+ optimum.prev1IsChar = 0;
924
+ }
925
+
926
+ private makeAsShortRep(optimum: Optimum): void {
927
+ optimum.backPrev = 0;
928
+ optimum.prev1IsChar = 0;
929
+ }
930
+
931
+ private releaseMFStream(): void {
932
+ if (this._matchFinder && this._needReleaseMFStream) {
933
+ this._matchFinder._stream = null;
934
+ this._needReleaseMFStream = 0;
935
+ }
936
+ }
937
+
938
+ releaseStreams(): void {
939
+ this.releaseMFStream();
940
+ this._rangeEncoder.stream = null;
941
+ }
942
+
943
+ private getProcessedSizeAdd(): bigint {
944
+ return BigInt(this._rangeEncoder.cacheSize) + this._rangeEncoder.position + 4n;
945
+ }
946
+
947
+ private getSubCoder(pos: number, prevByte: number): LiteralDecoderEncoder2 {
948
+ const subCoder = this._literalEncoder!.getSubCoder(pos, prevByte);
949
+ return { decoders: subCoder.decoders } as LiteralDecoderEncoder2;
950
+ }
951
+
952
+ private getLiteralPrice(
953
+ encoder: LiteralDecoderEncoder2,
954
+ matchMode: boolean,
955
+ matchByte: number,
956
+ symbol: number,
957
+ ): number {
958
+ let bit, context = 1, i = 7, matchBit, price = 0;
959
+
960
+ if (matchMode) {
961
+ for (; i >= 0; --i) {
962
+ matchBit = (matchByte >> i) & 1;
963
+ bit = (symbol >> i) & 1;
964
+ price += getBitPrice(
965
+ encoder.decoders[((1 + matchBit) << 8) + context],
966
+ bit,
967
+ );
968
+ context = context << 1 | bit;
969
+
970
+ if (matchBit != bit) {
971
+ --i;
972
+ break;
973
+ }
974
+ }
975
+ }
976
+
977
+ for (; i >= 0; --i) {
978
+ bit = symbol >> i & 1;
979
+ price += getBitPrice(encoder.decoders[context], bit);
980
+ context = context << 1 | bit;
981
+ }
982
+
983
+ return price;
984
+ }
985
+
986
+ private getPosLenPrice(
987
+ pos: number,
988
+ len: number,
989
+ posState: number,
990
+ ): number {
991
+ let price: number, lenToPosState = getLenToPosState(len);
992
+
993
+ if (pos < 128) {
994
+ price = this._distancesPrices[lenToPosState * 128 + pos];
995
+ } else {
996
+ const position = (lenToPosState << 6) + this.getPosSlot2(pos);
997
+ price = this._posSlotPrices[position] + this._alignPrices[pos & 15];
998
+ }
999
+
1000
+ return price + this._lenEncoder!.getPrice(len - 2, posState);
1001
+ }
1002
+
1003
+ private getPureRepPrice(
1004
+ repIndex: number,
1005
+ state: number,
1006
+ posState: number,
1007
+ ): number {
1008
+ let price;
1009
+
1010
+ if (!repIndex) {
1011
+ price = PROB_PRICES[(this._isRepG0[state]) >>> 2];
1012
+ price += PROB_PRICES[
1013
+ 0x800 - this._isRep0Long[(state << 4) + posState] >>> 2
1014
+ ];
1015
+ } else {
1016
+ price = PROB_PRICES[(0x800 - this._isRepG0[state]) >>> 2];
1017
+ if (repIndex == 1) {
1018
+ price += PROB_PRICES[(this._isRepG1[state]) >>> 2];
1019
+ } else {
1020
+ price += PROB_PRICES[(0x800 - this._isRepG1[state]) >>> 2];
1021
+ price += getBitPrice(this._isRepG2[state], repIndex - 2);
1022
+ }
1023
+ }
1024
+
1025
+ return price;
1026
+ }
1027
+
1028
+ private getRepLen1Price(posState: number): number {
1029
+ const repG0Price = PROB_PRICES[(this._isRepG0[this._state]) >>> 2];
1030
+ const rep0LongPrice = PROB_PRICES[this._isRep0Long[(this._state << 4) + posState] >>> 2];
1031
+ return repG0Price + rep0LongPrice;
1032
+ }
1033
+
1034
+ private getPosSlot2(pos: number): number {
1035
+ if (pos < 0x20000) {
1036
+ return G_FAST_POS[pos >> 6] + 12;
1037
+ }
1038
+ if (pos < 0x8000000) {
1039
+ return G_FAST_POS[pos >> 16] + 32;
1040
+ }
1041
+ return G_FAST_POS[pos >> 26] + 52;
1042
+ }
1043
+
1044
+ private movePosHelper(num: number): void {
1045
+ if (num > 0) {
1046
+ this._matchFinder!.skip(num);
1047
+ this._additionalOffset += num;
1048
+ }
1049
+ }
1050
+
1051
+ private readMatchDistances(): number {
1052
+ let lenRes = 0;
1053
+ this._numDistancePairs = this._matchFinder!.getMatches(this._matchDistances);
1054
+
1055
+ if (this._numDistancePairs > 0) {
1056
+ lenRes = this._matchDistances[this._numDistancePairs - 2];
1057
+
1058
+ if (lenRes == this._numFastBytes) {
1059
+ lenRes += this._matchFinder!.getMatchLen(
1060
+ lenRes - 1,
1061
+ this._matchDistances[this._numDistancePairs - 1],
1062
+ 0x0111 - lenRes,
1063
+ );
1064
+ }
1065
+ }
1066
+
1067
+ this._additionalOffset += 1;
1068
+ return lenRes;
1069
+ }
1070
+
1071
+ private flushEncoding(nowPos: number): void {
1072
+ this.releaseMFStream();
1073
+ this.writeEndMarker(nowPos & this._posStateMask);
1074
+ for (let i = 0; i < 5; ++i) {
1075
+ this.shiftLow();
1076
+ }
1077
+ }
1078
+
1079
+ private backward(cur: number): number {
1080
+ let backCur, backMem, posMem, posPrev;
1081
+
1082
+ this._optimumEndIndex = cur;
1083
+ posMem = this._optimum[cur].posPrev;
1084
+ backMem = this._optimum[cur].backPrev;
1085
+
1086
+ do {
1087
+ if (this._optimum[cur].prev1IsChar) {
1088
+ this.makeAsChar(this._optimum[posMem!]);
1089
+ this._optimum[posMem!].posPrev = posMem! - 1;
1090
+
1091
+ if (this._optimum[cur].prev2) {
1092
+ this._optimum[posMem! - 1].prev1IsChar = 0;
1093
+ this._optimum[posMem! - 1].posPrev = this._optimum[cur].posPrev2;
1094
+ this._optimum[posMem! - 1].backPrev = this._optimum[cur].backPrev2;
1095
+ }
1096
+ }
1097
+
1098
+ posPrev = posMem;
1099
+ backCur = backMem;
1100
+ backMem = this._optimum[posPrev!].backPrev;
1101
+ posMem = this._optimum[posPrev!].posPrev;
1102
+ this._optimum[posPrev!].backPrev = backCur;
1103
+ this._optimum[posPrev!].posPrev = cur;
1104
+ cur = posPrev!;
1105
+ } while (cur > 0);
1106
+
1107
+ this.backRes = this._optimum[0].backPrev!;
1108
+ this._optimumCurrentIndex = this._optimum[0].posPrev!;
1109
+ return this._optimumCurrentIndex;
1110
+ }
1111
+
1112
+ private getOptimumLength(position: number): number {
1113
+ let cur,
1114
+ curAnd1Price,
1115
+ curAndLenCharPrice,
1116
+ curAndLenPrice,
1117
+ curBack,
1118
+ curPrice,
1119
+ currentByte,
1120
+ distance,
1121
+ len,
1122
+ lenEnd,
1123
+ lenMain,
1124
+ lenTest,
1125
+ lenTest2,
1126
+ lenTestTemp,
1127
+ matchByte,
1128
+ matchPrice,
1129
+ newLen,
1130
+ nextIsChar,
1131
+ nextMatchPrice,
1132
+ nextOptimum,
1133
+ nextRepMatchPrice,
1134
+ normalMatchPrice,
1135
+ numAvailableBytes,
1136
+ numAvailableBytesFull,
1137
+ numDistancePairs,
1138
+ offs,
1139
+ offset,
1140
+ opt,
1141
+ optimum,
1142
+ pos,
1143
+ posPrev,
1144
+ posState,
1145
+ posStateNext,
1146
+ price_4,
1147
+ repIndex,
1148
+ repLen,
1149
+ repMatchPrice,
1150
+ repMaxIndex,
1151
+ shortRepPrice,
1152
+ startLen,
1153
+ state,
1154
+ state2,
1155
+ t,
1156
+ price,
1157
+ price_0,
1158
+ price_1,
1159
+ price_2,
1160
+ price_3,
1161
+ lenRes;
1162
+
1163
+ if (this._optimumEndIndex != this._optimumCurrentIndex) {
1164
+ lenRes = this._optimum[this._optimumCurrentIndex].posPrev! - this._optimumCurrentIndex;
1165
+ this.backRes = this._optimum[this._optimumCurrentIndex].backPrev!;
1166
+ this._optimumCurrentIndex = this._optimum[this._optimumCurrentIndex].posPrev!;
1167
+ return lenRes;
1168
+ }
1169
+
1170
+ this._optimumCurrentIndex = this._optimumEndIndex = 0;
1171
+ if (this._longestMatchWasFound) {
1172
+ lenMain = this._longestMatchLength;
1173
+ this._longestMatchWasFound = 0;
1174
+ } else {
1175
+ lenMain = this.readMatchDistances();
1176
+ }
1177
+
1178
+ numDistancePairs = this._numDistancePairs;
1179
+ numAvailableBytes = this._matchFinder!.getNumAvailableBytes() + 1;
1180
+
1181
+ if (numAvailableBytes < 2) {
1182
+ this.backRes = -1;
1183
+ return 1;
1184
+ }
1185
+
1186
+ if (numAvailableBytes > 0x0111) {
1187
+ numAvailableBytes = 0x0111;
1188
+ }
1189
+
1190
+ repMaxIndex = 0;
1191
+ for (let i = 0; i < 4; ++i) {
1192
+ this.reps[i] = this._repDistances[i];
1193
+ this.repLens[i] = this._matchFinder!.getMatchLen(-1, this.reps[i], 0x0111);
1194
+
1195
+ if (this.repLens[i] > this.repLens[repMaxIndex]) {
1196
+ repMaxIndex = i;
1197
+ }
1198
+ }
1199
+
1200
+ if (this.repLens[repMaxIndex] >= this._numFastBytes) {
1201
+ this.backRes = repMaxIndex;
1202
+ lenRes = this.repLens[repMaxIndex];
1203
+ this.movePosHelper(lenRes - 1);
1204
+ return lenRes;
1205
+ }
1206
+
1207
+ if (lenMain >= this._numFastBytes) {
1208
+ this.backRes = this._matchDistances[numDistancePairs - 1] + 4;
1209
+ this.movePosHelper(lenMain - 1);
1210
+ return lenMain;
1211
+ }
1212
+
1213
+ currentByte = this._matchFinder!.getIndexByte(-1);
1214
+ matchByte = this._matchFinder!.getIndexByte(-this._repDistances[0] - 1 - 1);
1215
+
1216
+ if (lenMain < 2 && currentByte != matchByte && this.repLens[repMaxIndex] < 2) {
1217
+ this.backRes = -1;
1218
+ return 1;
1219
+ }
1220
+
1221
+ this._optimum[0].state = this._state;
1222
+ posState = position & this._posStateMask;
1223
+ this._optimum[1].price = PROB_PRICES[
1224
+ (this._isMatch[(this._state << 4) + posState]) >>> 2
1225
+ ] + this.getLiteralPrice(
1226
+ this.getSubCoder(position, this._previousByte),
1227
+ this._state >= 7,
1228
+ matchByte,
1229
+ currentByte,
1230
+ );
1231
+
1232
+ this.makeAsChar(this._optimum[1]);
1233
+ matchPrice = PROB_PRICES[
1234
+ (2048 - this._isMatch[(this._state << 4) + posState])
1235
+ >>> 2
1236
+ ];
1237
+
1238
+ repMatchPrice = matchPrice + PROB_PRICES[
1239
+ (2048 - this._isRep[this._state]) >>> 2
1240
+ ];
1241
+
1242
+ if (matchByte == currentByte) {
1243
+ shortRepPrice = repMatchPrice + this.getRepLen1Price(posState);
1244
+ if (shortRepPrice < this._optimum[1].price!) {
1245
+ this._optimum[1].price = shortRepPrice;
1246
+ this.makeAsShortRep(this._optimum[1]);
1247
+ }
1248
+ }
1249
+
1250
+ lenEnd = lenMain >= this.repLens[repMaxIndex]
1251
+ ? lenMain
1252
+ : this.repLens[repMaxIndex];
1253
+
1254
+ if (lenEnd < 2) {
1255
+ this.backRes = this._optimum[1].backPrev!;
1256
+ return 1;
1257
+ }
1258
+
1259
+ this._optimum[1].posPrev = 0;
1260
+ this._optimum[0].backs0 = this.reps[0];
1261
+ this._optimum[0].backs1 = this.reps[1];
1262
+ this._optimum[0].backs2 = this.reps[2];
1263
+ this._optimum[0].backs3 = this.reps[3];
1264
+ len = lenEnd;
1265
+
1266
+ do {
1267
+ this._optimum[len].price = INFINITY_PRICE;
1268
+ len -= 1;
1269
+ } while (len >= 2);
1270
+
1271
+ for (let i = 0; i < 4; ++i) {
1272
+ repLen = this.repLens[i];
1273
+ if (repLen < 2) {
1274
+ continue;
1275
+ }
1276
+ price_4 = repMatchPrice + this.getPureRepPrice(
1277
+ i,
1278
+ this._state,
1279
+ posState,
1280
+ );
1281
+
1282
+ do {
1283
+ curAndLenPrice = price_4 + this._repMatchLenEncoder!.getPrice(
1284
+ repLen - 2,
1285
+ posState,
1286
+ );
1287
+ optimum = this._optimum[repLen];
1288
+ if (curAndLenPrice < optimum.price!) {
1289
+ optimum.price = curAndLenPrice;
1290
+ optimum.posPrev = 0;
1291
+ optimum.backPrev = i;
1292
+ optimum.prev1IsChar = 0;
1293
+ }
1294
+ } while ((repLen -= 1) >= 2);
1295
+ }
1296
+
1297
+ normalMatchPrice = matchPrice
1298
+ + PROB_PRICES[(this._isRep[this._state]) >>> 2];
1299
+
1300
+ len = this.repLens[0] >= 2 ? this.repLens[0] + 1 : 2;
1301
+
1302
+ if (len <= lenMain) {
1303
+ offs = 0;
1304
+ while (len > this._matchDistances[offs]) {
1305
+ offs += 2;
1306
+ }
1307
+
1308
+ for (;; len += 1) {
1309
+ distance = this._matchDistances[offs + 1];
1310
+ curAndLenPrice = normalMatchPrice + this.getPosLenPrice(distance, len, posState);
1311
+ optimum = this._optimum[len];
1312
+
1313
+ if (curAndLenPrice < optimum.price!) {
1314
+ optimum.price = curAndLenPrice;
1315
+ optimum.posPrev = 0;
1316
+ optimum.backPrev = distance + 4;
1317
+ optimum.prev1IsChar = 0;
1318
+ }
1319
+
1320
+ if (len == this._matchDistances[offs]) {
1321
+ offs += 2;
1322
+ if (offs == numDistancePairs) {
1323
+ break;
1324
+ }
1325
+ }
1326
+ }
1327
+ }
1328
+ cur = 0;
1329
+
1330
+ while (1) {
1331
+ ++cur;
1332
+ if (cur == lenEnd) {
1333
+ return this.backward(cur);
1334
+ }
1335
+ newLen = this.readMatchDistances();
1336
+ numDistancePairs = this._numDistancePairs;
1337
+
1338
+ if (newLen >= this._numFastBytes) {
1339
+ this._longestMatchLength = newLen;
1340
+ this._longestMatchWasFound = 0x01;
1341
+
1342
+ return this.backward(cur);
1343
+ }
1344
+ position += 0x01;
1345
+ posPrev = this._optimum[cur].posPrev;
1346
+
1347
+ if (this._optimum[cur].prev1IsChar) {
1348
+ posPrev! -= 0x01;
1349
+ if (this._optimum[cur].prev2) {
1350
+ state = this._optimum[this._optimum[cur].posPrev2!].state;
1351
+ if (this._optimum[cur].backPrev2! < 0x04) {
1352
+ state = (state! < 0x07) ? 0x08 : 0x0B;
1353
+ } else {
1354
+ state = (state! < 0x07) ? 0x07 : 0x0A;
1355
+ }
1356
+ } else {
1357
+ state = this._optimum[posPrev!].state;
1358
+ }
1359
+ state = stateUpdateChar(state!);
1360
+ } else {
1361
+ state = this._optimum[posPrev!].state;
1362
+ }
1363
+
1364
+ if (posPrev! == cur - 1) {
1365
+ if (!this._optimum[cur].backPrev) {
1366
+ state = state! < 7 ? 9 : 11;
1367
+ } else {
1368
+ state = stateUpdateChar(state!);
1369
+ }
1370
+ } else {
1371
+ if (
1372
+ this._optimum[cur].prev1IsChar
1373
+ && this._optimum[cur].prev2
1374
+ ) {
1375
+ posPrev = this._optimum[cur].posPrev2;
1376
+ pos = this._optimum[cur].backPrev2;
1377
+ state = state! < 0x07 ? 0x08 : 0x0B;
1378
+ } else {
1379
+ pos = this._optimum[cur].backPrev;
1380
+ if (pos! < 4) {
1381
+ state = state! < 0x07 ? 0x08 : 0x0B;
1382
+ } else {
1383
+ state = state! < 0x07 ? 0x07 : 0x0A;
1384
+ }
1385
+ }
1386
+ opt = this._optimum[posPrev!];
1387
+
1388
+ if (pos! < 4) {
1389
+ if (!pos) {
1390
+ this.reps[0] = opt.backs0!;
1391
+ this.reps[1] = opt.backs1!;
1392
+ this.reps[2] = opt.backs2!;
1393
+ this.reps[3] = opt.backs3!;
1394
+ } else if (pos == 1) {
1395
+ this.reps[0] = opt.backs1!;
1396
+ this.reps[1] = opt.backs0!;
1397
+ this.reps[2] = opt.backs2!;
1398
+ this.reps[3] = opt.backs3!;
1399
+ } else if (pos == 2) {
1400
+ this.reps[0] = opt.backs2!;
1401
+ this.reps[1] = opt.backs0!;
1402
+ this.reps[2] = opt.backs1!;
1403
+ this.reps[3] = opt.backs3!;
1404
+ } else {
1405
+ this.reps[0] = opt.backs3!;
1406
+ this.reps[1] = opt.backs0!;
1407
+ this.reps[2] = opt.backs1!;
1408
+ this.reps[3] = opt.backs2!;
1409
+ }
1410
+ } else {
1411
+ this.reps[0] = pos! - 4;
1412
+ this.reps[1] = opt.backs0!;
1413
+ this.reps[2] = opt.backs1!;
1414
+ this.reps[3] = opt.backs2!;
1415
+ }
1416
+ }
1417
+
1418
+ this._optimum[cur].state = state;
1419
+ this._optimum[cur].backs0 = this.reps[0];
1420
+ this._optimum[cur].backs1 = this.reps[1];
1421
+ this._optimum[cur].backs2 = this.reps[2];
1422
+ this._optimum[cur].backs3 = this.reps[3];
1423
+ curPrice = this._optimum[cur].price;
1424
+
1425
+ currentByte = this._matchFinder!.getIndexByte(-0x01);
1426
+ matchByte = this._matchFinder!.getIndexByte(-this.reps[0] - 1 - 1);
1427
+
1428
+ posState = position & this._posStateMask;
1429
+ curAnd1Price = curPrice!
1430
+ + PROB_PRICES[(this._isMatch[(state! << 0x04) + posState]) >>> 2]
1431
+ + this.getLiteralPrice(
1432
+ this.getSubCoder(position, this._matchFinder!.getIndexByte(-2)),
1433
+ state! >= 7,
1434
+ matchByte,
1435
+ currentByte,
1436
+ );
1437
+
1438
+ nextOptimum = this._optimum[cur + 1];
1439
+ nextIsChar = 0;
1440
+
1441
+ if (curAnd1Price < nextOptimum.price!) {
1442
+ nextOptimum.price = curAnd1Price;
1443
+ nextOptimum.posPrev = cur;
1444
+ nextOptimum.backPrev = -0x01;
1445
+ nextOptimum.prev1IsChar = 0;
1446
+ nextIsChar = 1;
1447
+ }
1448
+
1449
+ matchPrice = curPrice! + PROB_PRICES[
1450
+ (2048 - this._isMatch[(state! << 4) + posState]) >>> 2
1451
+ ];
1452
+
1453
+ repMatchPrice = matchPrice + PROB_PRICES[(2048 - this._isRep[state!]) >>> 2];
1454
+
1455
+ if (matchByte == currentByte && !(nextOptimum.posPrev! < cur && !nextOptimum.backPrev)) {
1456
+ shortRepPrice = repMatchPrice
1457
+ + (PROB_PRICES[(this._isRepG0[state!]) >>> 0x02] + PROB_PRICES[(this._isRep0Long[(state! << 0x04) + posState]) >>> 0x02]);
1458
+
1459
+ if (shortRepPrice <= nextOptimum.price!) {
1460
+ nextOptimum.price = shortRepPrice;
1461
+ nextOptimum.posPrev = cur;
1462
+ nextOptimum.backPrev = 0;
1463
+ nextOptimum.prev1IsChar = 0;
1464
+ nextIsChar = 1;
1465
+ }
1466
+ }
1467
+
1468
+ numAvailableBytesFull = this._matchFinder!.getNumAvailableBytes() + 1;
1469
+ numAvailableBytesFull = 0xFFF - cur < numAvailableBytesFull
1470
+ ? 0xFFF - cur
1471
+ : numAvailableBytesFull;
1472
+
1473
+ numAvailableBytes = numAvailableBytesFull;
1474
+
1475
+ if (numAvailableBytes < 2) {
1476
+ continue;
1477
+ }
1478
+
1479
+ if (numAvailableBytes > this._numFastBytes) {
1480
+ numAvailableBytes = this._numFastBytes;
1481
+ }
1482
+
1483
+ if (!nextIsChar && matchByte != currentByte) {
1484
+ t = Math.min(numAvailableBytesFull - 1, this._numFastBytes);
1485
+ lenTest2 = this._matchFinder!.getMatchLen(0, this.reps[0], t);
1486
+
1487
+ if (lenTest2 >= 2) {
1488
+ state2 = stateUpdateChar(state);
1489
+ posStateNext = position + 1 & this._posStateMask;
1490
+ nextRepMatchPrice = curAnd1Price
1491
+ + PROB_PRICES[(2048 - this._isMatch[(state2 << 4) + posStateNext]) >>> 2]
1492
+ + PROB_PRICES[(2048 - this._isRep[state2]) >>> 2];
1493
+
1494
+ offset = cur + 1 + lenTest2;
1495
+
1496
+ while (lenEnd < offset) {
1497
+ this._optimum[lenEnd += 1].price = INFINITY_PRICE;
1498
+ }
1499
+
1500
+ curAndLenPrice = nextRepMatchPrice + (price = this._repMatchLenEncoder!.getPrice(
1501
+ lenTest2 - 2,
1502
+ posStateNext,
1503
+ ),
1504
+ price + this.getPureRepPrice(
1505
+ 0,
1506
+ state2,
1507
+ posStateNext,
1508
+ ));
1509
+ optimum = this._optimum[offset];
1510
+
1511
+ if (curAndLenPrice < optimum.price!) {
1512
+ optimum.price = curAndLenPrice;
1513
+ optimum.posPrev = cur + 1;
1514
+ optimum.backPrev = 0;
1515
+ optimum.prev1IsChar = 1;
1516
+ optimum.prev2 = 0;
1517
+ }
1518
+ }
1519
+ }
1520
+ startLen = 0x02;
1521
+
1522
+ for (repIndex = 0; repIndex < 4; ++repIndex) {
1523
+ lenTest = this._matchFinder!.getMatchLen(
1524
+ -0x01,
1525
+ this.reps[repIndex],
1526
+ numAvailableBytes,
1527
+ );
1528
+
1529
+ if (lenTest < 2) {
1530
+ continue;
1531
+ }
1532
+ lenTestTemp = lenTest;
1533
+
1534
+ do {
1535
+ while (lenEnd < cur + lenTest) {
1536
+ this._optimum[lenEnd += 1].price = INFINITY_PRICE;
1537
+ }
1538
+
1539
+ curAndLenPrice = repMatchPrice + (price_0 = this._repMatchLenEncoder!.getPrice(
1540
+ lenTest - 2,
1541
+ posState,
1542
+ ),
1543
+ price_0 + this.getPureRepPrice(
1544
+ repIndex,
1545
+ state,
1546
+ posState,
1547
+ ));
1548
+
1549
+ optimum = this._optimum[cur + lenTest];
1550
+
1551
+ if (curAndLenPrice < optimum.price!) {
1552
+ optimum.price = curAndLenPrice;
1553
+ optimum.posPrev = cur;
1554
+ optimum.backPrev = repIndex;
1555
+ optimum.prev1IsChar = 0;
1556
+ }
1557
+ } while ((lenTest -= 1) >= 2);
1558
+
1559
+ lenTest = lenTestTemp;
1560
+
1561
+ if (!repIndex) {
1562
+ startLen = lenTest + 1;
1563
+ }
1564
+
1565
+ if (lenTest < numAvailableBytesFull) {
1566
+ t = Math.min(
1567
+ numAvailableBytesFull - 1 - lenTest,
1568
+ this._numFastBytes,
1569
+ );
1570
+ lenTest2 = this._matchFinder!.getMatchLen(
1571
+ lenTest,
1572
+ this.reps[repIndex],
1573
+ t,
1574
+ );
1575
+
1576
+ if (lenTest2 >= 2) {
1577
+ state2 = state < 7 ? 0x08 : 11;
1578
+ posStateNext = position + lenTest & this._posStateMask;
1579
+ curAndLenCharPrice = repMatchPrice
1580
+ + (price_1 = this._repMatchLenEncoder!.getPrice(lenTest - 2, posState), price_1 + this.getPureRepPrice(repIndex, state, posState))
1581
+ + PROB_PRICES[(this._isMatch[(state2 << 4) + posStateNext]) >>> 2]
1582
+ + this.getLiteralPrice(
1583
+ this.getSubCoder(position + lenTest, this._matchFinder!.getIndexByte(lenTest - 1 - 1)),
1584
+ true,
1585
+ this._matchFinder!.getIndexByte(lenTest - 1 - (this.reps[repIndex] + 1)),
1586
+ this._matchFinder!.getIndexByte(lenTest - 1),
1587
+ );
1588
+
1589
+ state2 = stateUpdateChar(state2);
1590
+ posStateNext = position + lenTest + 1 & this._posStateMask;
1591
+
1592
+ nextMatchPrice = curAndLenCharPrice + PROB_PRICES[
1593
+ (2048 - this._isMatch[(state2 << 4) + posStateNext]) >>> 2
1594
+ ];
1595
+
1596
+ nextRepMatchPrice = nextMatchPrice + PROB_PRICES[
1597
+ (2048 - this._isRep[state2]) >>> 2
1598
+ ];
1599
+
1600
+ offset = lenTest + 1 + lenTest2;
1601
+
1602
+ while (lenEnd < cur + offset) {
1603
+ this._optimum[lenEnd += 1].price = INFINITY_PRICE;
1604
+ }
1605
+
1606
+ curAndLenPrice = nextRepMatchPrice + (price_2 = this._repMatchLenEncoder!.getPrice(lenTest2 - 2, posStateNext), price_2 + this.getPureRepPrice(0, state2, posStateNext));
1607
+ optimum = this._optimum[cur + offset];
1608
+
1609
+ if (curAndLenPrice < optimum.price!) {
1610
+ optimum.price = curAndLenPrice;
1611
+ optimum.posPrev = cur + lenTest + 1;
1612
+ optimum.backPrev = 0;
1613
+ optimum.prev1IsChar = 1;
1614
+ optimum.prev2 = 1;
1615
+ optimum.posPrev2 = cur;
1616
+ optimum.backPrev2 = repIndex;
1617
+ }
1618
+ }
1619
+ }
1620
+ }
1621
+
1622
+ if (newLen > numAvailableBytes) {
1623
+ newLen = numAvailableBytes;
1624
+ for (
1625
+ numDistancePairs = 0;
1626
+ newLen > this._matchDistances[numDistancePairs];
1627
+ numDistancePairs += 2
1628
+ ) {}
1629
+ this._matchDistances[numDistancePairs] = newLen;
1630
+ numDistancePairs += 2;
1631
+ }
1632
+
1633
+ if (newLen >= startLen) {
1634
+ normalMatchPrice = matchPrice + PROB_PRICES[(this._isRep[state]) >>> 2];
1635
+
1636
+ while (lenEnd < cur + newLen) {
1637
+ this._optimum[lenEnd += 1].price = INFINITY_PRICE;
1638
+ }
1639
+ offs = 0;
1640
+
1641
+ while (startLen > this._matchDistances[offs]) {
1642
+ offs += 2;
1643
+ }
1644
+ for (lenTest = startLen;; lenTest += 1) {
1645
+ curBack = this._matchDistances[offs + 1];
1646
+ curAndLenPrice = normalMatchPrice + this.getPosLenPrice(curBack, lenTest, posState);
1647
+ optimum = this._optimum[cur + lenTest];
1648
+
1649
+ if (curAndLenPrice < optimum.price!) {
1650
+ optimum.price = curAndLenPrice;
1651
+ optimum.posPrev = cur;
1652
+ optimum.backPrev = curBack + 4;
1653
+ optimum.prev1IsChar = 0;
1654
+ }
1655
+
1656
+ if (lenTest == this._matchDistances[offs]) {
1657
+ if (lenTest < numAvailableBytesFull) {
1658
+ t = Math.min(
1659
+ numAvailableBytesFull - 1 - lenTest,
1660
+ this._numFastBytes,
1661
+ );
1662
+ lenTest2 = this._matchFinder!.getMatchLen(
1663
+ lenTest,
1664
+ curBack,
1665
+ t,
1666
+ );
1667
+
1668
+ if (lenTest2 >= 2) {
1669
+ state2 = state < 7 ? 7 : 10;
1670
+ posStateNext = position + lenTest & this._posStateMask;
1671
+
1672
+ curAndLenCharPrice = curAndLenPrice
1673
+ + PROB_PRICES[(this._isMatch[(state2 << 4) + posStateNext]) >>> 2]
1674
+ + this.getLiteralPrice(
1675
+ this.getSubCoder(
1676
+ position + lenTest,
1677
+ this._matchFinder!.getIndexByte(lenTest - 1 - 1),
1678
+ ),
1679
+ true,
1680
+ this._matchFinder!.getIndexByte(lenTest - (curBack + 1) - 1),
1681
+ this._matchFinder!.getIndexByte(lenTest - 1),
1682
+ );
1683
+
1684
+ state2 = stateUpdateChar(state2);
1685
+ posStateNext = position + lenTest + 1 & this._posStateMask;
1686
+
1687
+ nextMatchPrice = curAndLenCharPrice + PROB_PRICES[
1688
+ (2048 - this._isMatch[(state2 << 4) + posStateNext]) >>> 2
1689
+ ];
1690
+
1691
+ nextRepMatchPrice = nextMatchPrice + PROB_PRICES[
1692
+ (2048 - this._isRep[state2]) >>> 2
1693
+ ];
1694
+ offset = lenTest + 1 + lenTest2;
1695
+
1696
+ while (lenEnd < cur + offset) {
1697
+ this._optimum[lenEnd += 1].price = INFINITY_PRICE;
1698
+ }
1699
+
1700
+ curAndLenPrice = nextRepMatchPrice + (price_3 = this._repMatchLenEncoder!.getPrice(lenTest2 - 2, posStateNext), price_3 + this.getPureRepPrice(0, state2, posStateNext));
1701
+ optimum = this._optimum[cur + offset];
1702
+
1703
+ if (curAndLenPrice < optimum.price!) {
1704
+ optimum.price = curAndLenPrice;
1705
+ optimum.posPrev = cur + lenTest + 1;
1706
+ optimum.backPrev = 0;
1707
+ optimum.prev1IsChar = 1;
1708
+ optimum.prev2 = 1;
1709
+ optimum.posPrev2 = cur;
1710
+ optimum.backPrev2 = curBack + 4;
1711
+ }
1712
+ }
1713
+ }
1714
+ offs += 2;
1715
+
1716
+ if (offs == numDistancePairs) {
1717
+ break;
1718
+ }
1719
+ }
1720
+ }
1721
+ }
1722
+ }
1723
+
1724
+ // Fallback return - should not be reached in normal execution
1725
+ return 1;
1726
+ }
1727
+
1728
+ codeOneBlock(): void {
1729
+ let baseVal,
1730
+ complexState,
1731
+ curByte,
1732
+ distance,
1733
+ footerBits,
1734
+ len,
1735
+ lenToPosState,
1736
+ matchByte,
1737
+ pos,
1738
+ posReduced,
1739
+ posSlot,
1740
+ posState,
1741
+ progressPosValuePrev,
1742
+ subCoder;
1743
+
1744
+ this.processedInSize[0] = 0n;
1745
+ this.processedOutSize[0] = 0n;
1746
+ this.finished[0] = 1;
1747
+ progressPosValuePrev = this.nowPos64;
1748
+
1749
+ if (this._inStream) {
1750
+ this._matchFinder!._stream = this._inStream;
1751
+ this._matchFinder!.init();
1752
+ this._needReleaseMFStream = 1;
1753
+ this._inStream = null;
1754
+ }
1755
+
1756
+ if (this._finished) {
1757
+ return;
1758
+ }
1759
+
1760
+ this._finished = 1;
1761
+
1762
+ if (this.nowPos64 === 0n) {
1763
+ if (!this._matchFinder!.getNumAvailableBytes()) {
1764
+ this.flushEncoding(Number(this.nowPos64 & 0xFFFFFFFFn));
1765
+ return;
1766
+ }
1767
+
1768
+ this.readMatchDistances();
1769
+ posState = Number(this.nowPos64 & 0xFFFFFFFFn) & this._posStateMask;
1770
+
1771
+ this.encodeBit(
1772
+ this._isMatch,
1773
+ (this._state << 4) + posState,
1774
+ 0,
1775
+ );
1776
+
1777
+ this._state = stateUpdateChar(this._state);
1778
+ curByte = this._matchFinder!.getIndexByte(
1779
+ -this._additionalOffset,
1780
+ );
1781
+
1782
+ this.encodeLiteral(
1783
+ this.getSubCoder(
1784
+ Number(this.nowPos64 & 0xFFFFFFFFn),
1785
+ this._previousByte,
1786
+ ),
1787
+ curByte,
1788
+ );
1789
+
1790
+ this._previousByte = curByte;
1791
+ this._additionalOffset -= 1;
1792
+ this.nowPos64 += 1n;
1793
+ }
1794
+
1795
+ if (!this._matchFinder!.getNumAvailableBytes()) {
1796
+ this.flushEncoding(Number(this.nowPos64 & 0xFFFFFFFFn));
1797
+ return;
1798
+ }
1799
+
1800
+ while (1) {
1801
+ len = this.getOptimumLength(Number(this.nowPos64 & 0xFFFFFFFFn));
1802
+ pos = this.backRes;
1803
+ posState = Number(this.nowPos64 & 0xFFFFFFFFn) & this._posStateMask;
1804
+ complexState = (this._state << 4) + posState;
1805
+
1806
+ if (len == 1 && pos == -1) {
1807
+ this.encodeBit(
1808
+ this._isMatch,
1809
+ complexState,
1810
+ 0,
1811
+ );
1812
+
1813
+ curByte = this._matchFinder!.getIndexByte(
1814
+ -this._additionalOffset,
1815
+ );
1816
+
1817
+ subCoder = this.getSubCoder(
1818
+ Number(this.nowPos64 & 0xFFFFFFFFn),
1819
+ this._previousByte,
1820
+ );
1821
+
1822
+ if (this._state < 7) {
1823
+ this.encodeLiteral(subCoder, curByte);
1824
+ } else {
1825
+ matchByte = this._matchFinder!.getIndexByte(
1826
+ -this._repDistances[0]
1827
+ - 1
1828
+ - this._additionalOffset,
1829
+ );
1830
+
1831
+ this.encodeMatched(
1832
+ subCoder,
1833
+ matchByte,
1834
+ curByte,
1835
+ );
1836
+ }
1837
+ this._previousByte = curByte;
1838
+ this._state = stateUpdateChar(this._state);
1839
+ } else {
1840
+ this.encodeBit(
1841
+ this._isMatch,
1842
+ complexState,
1843
+ 1,
1844
+ );
1845
+ if (pos < 4) {
1846
+ this.encodeBit(
1847
+ this._isRep,
1848
+ this._state,
1849
+ 1,
1850
+ );
1851
+
1852
+ if (!pos) {
1853
+ this.encodeBit(
1854
+ this._isRepG0,
1855
+ this._state,
1856
+ 0,
1857
+ );
1858
+
1859
+ if (len == 1) {
1860
+ this.encodeBit(
1861
+ this._isRep0Long,
1862
+ complexState,
1863
+ 0,
1864
+ );
1865
+ } else {
1866
+ this.encodeBit(
1867
+ this._isRep0Long,
1868
+ complexState,
1869
+ 1,
1870
+ );
1871
+ }
1872
+ } else {
1873
+ this.encodeBit(
1874
+ this._isRepG0,
1875
+ this._state,
1876
+ 1,
1877
+ );
1878
+
1879
+ if (pos == 1) {
1880
+ this.encodeBit(
1881
+ this._isRepG1,
1882
+ this._state,
1883
+ 0,
1884
+ );
1885
+ } else {
1886
+ this.encodeBit(
1887
+ this._isRepG1,
1888
+ this._state,
1889
+ 1,
1890
+ );
1891
+ this.encodeBit(
1892
+ this._isRepG2,
1893
+ this._state,
1894
+ pos - 2,
1895
+ );
1896
+ }
1897
+ }
1898
+
1899
+ if (len == 1) {
1900
+ this._state = this._state < 7 ? 9 : 11;
1901
+ } else {
1902
+ this.encodeLength(
1903
+ this._repMatchLenEncoder!,
1904
+ len - 2,
1905
+ posState,
1906
+ );
1907
+ this._state = this._state < 7
1908
+ ? 0x08
1909
+ : 11;
1910
+ }
1911
+ distance = this._repDistances[pos];
1912
+ if (pos != 0) {
1913
+ for (let i = pos; i >= 1; --i) {
1914
+ this._repDistances[i] = this._repDistances[i - 1];
1915
+ }
1916
+ this._repDistances[0] = distance;
1917
+ }
1918
+ } else {
1919
+ this.encodeBit(
1920
+ this._isRep,
1921
+ this._state,
1922
+ 0,
1923
+ );
1924
+
1925
+ this._state = this._state < 7 ? 7 : 10;
1926
+ this.encodeLength(
1927
+ this._lenEncoder!,
1928
+ len - 0x02,
1929
+ posState,
1930
+ );
1931
+
1932
+ pos -= 0x04;
1933
+ posSlot = this.getPosSlot(pos);
1934
+ lenToPosState = getLenToPosState(len);
1935
+ this.encodeBitTree(
1936
+ this._posSlotEncoder[lenToPosState],
1937
+ posSlot,
1938
+ );
1939
+
1940
+ if (posSlot >= 0x04) {
1941
+ footerBits = (posSlot >> 0x01) - 0x01;
1942
+ baseVal = (0x02 | (posSlot & 0x01)) << footerBits;
1943
+ posReduced = pos - baseVal;
1944
+
1945
+ if (posSlot < 0x0E) {
1946
+ this.reverseEncodeRange(
1947
+ baseVal - posSlot - 0x01,
1948
+ footerBits,
1949
+ posReduced,
1950
+ );
1951
+ } else {
1952
+ this.encodeDirectBits(posReduced >> 0x04, footerBits - 4);
1953
+ this.reverseEncode(posReduced & 0x0F);
1954
+ this._alignPriceCount += 1;
1955
+ }
1956
+ }
1957
+ distance = pos;
1958
+ for (let i = 3; i >= 1; --i) {
1959
+ this._repDistances[i] = this._repDistances[i - 1];
1960
+ }
1961
+
1962
+ this._repDistances[0] = distance;
1963
+ this._matchPriceCount += 0x01;
1964
+ }
1965
+
1966
+ this._previousByte = this._matchFinder!.getIndexByte(
1967
+ len - 1 - this._additionalOffset,
1968
+ );
1969
+ }
1970
+
1971
+ this._additionalOffset -= len;
1972
+ this.nowPos64 += BigInt(len);
1973
+
1974
+ if (!this._additionalOffset) {
1975
+ if (this._matchPriceCount >= 0x80) {
1976
+ this.fillDistancesPrices();
1977
+ }
1978
+
1979
+ if (this._alignPriceCount >= 0x10) {
1980
+ this.fillAlignPrices();
1981
+ }
1982
+
1983
+ this.processedInSize[0] = this.nowPos64;
1984
+ this.processedOutSize[0] = this.getProcessedSizeAdd();
1985
+
1986
+ if (!this._matchFinder!.getNumAvailableBytes()) {
1987
+ this.flushEncoding(Number(this.nowPos64 & 0xFFFFFFFFn));
1988
+
1989
+ return;
1990
+ }
1991
+
1992
+ if (
1993
+ (this.nowPos64 - progressPosValuePrev) >= 0x1000n
1994
+ ) {
1995
+ this._finished = 0;
1996
+ this.finished[0] = 0;
1997
+
1998
+ return;
1999
+ }
2000
+ }
2001
+ }
2002
+ }
2003
+
2004
+ createMatchFinder(): void {
2005
+ if (!this._matchFinder) {
2006
+ const binTree = new BinTreeMatchFinder();
2007
+ let numHashBytes = 4;
2008
+
2009
+ if (!this._matchFinderType) {
2010
+ numHashBytes = 2;
2011
+ }
2012
+
2013
+ binTree.setType(numHashBytes);
2014
+ this._matchFinder = binTree;
2015
+ }
2016
+ this.createLiteralEncoder();
2017
+
2018
+ if (
2019
+ this._dictionarySize == this._dictionarySizePrev
2020
+ && this._numFastBytesPrev == this._numFastBytes
2021
+ ) {
2022
+ return;
2023
+ }
2024
+
2025
+ this._matchFinder!.create(
2026
+ this._dictionarySize,
2027
+ this._numFastBytes,
2028
+ 0x1000,
2029
+ 0x0112,
2030
+ );
2031
+
2032
+ this._dictionarySizePrev = this._dictionarySize;
2033
+ this._numFastBytesPrev = this._numFastBytes;
2034
+ }
2035
+
2036
+ writeHeaderProperties(output: OutputBuffer): void {
2037
+ this.properties[0] = (
2038
+ (this._posStateBits * 5 + this._numLiteralPosStateBits) * 9 + this._numLiteralContextBits
2039
+ ) & 0xFF;
2040
+
2041
+ for (let byteIndex = 0; byteIndex < 4; byteIndex++) {
2042
+ this.properties[1 + byteIndex] = (
2043
+ this._dictionarySize >> (0x08 * byteIndex)
2044
+ ) & 0xFF;
2045
+ }
2046
+
2047
+ for (let i = 0; i < 5; i++) {
2048
+ output.writeByte(this.properties[i]);
2049
+ }
2050
+ }
2051
+
2052
+ initCompression(
2053
+ input: InputBuffer,
2054
+ output: OutputBuffer,
2055
+ len: bigint,
2056
+ mode: { searchDepth: number; filterStrength: number; modeIndex: number; },
2057
+ ): void {
2058
+ if (len < -1n) {
2059
+ throw new Error("invalid length " + len);
2060
+ }
2061
+
2062
+ this.initialize();
2063
+ this.configure(mode);
2064
+
2065
+ this.writeHeaderProperties(output);
2066
+
2067
+ for (let i = 0; i < 64; i += 8) {
2068
+ output.writeByte(
2069
+ (Number((len >> BigInt(i)) & 0xFFn)) << 24 >> 24,
2070
+ );
2071
+ }
2072
+
2073
+ this._needReleaseMFStream = 0;
2074
+ this._inStream = input;
2075
+ this._finished = 0;
2076
+
2077
+ this.createMatchFinder();
2078
+ this._rangeEncoder.stream = output;
2079
+ this.init();
2080
+
2081
+ this.fillDistancesPrices();
2082
+ this.fillAlignPrices();
2083
+
2084
+ this._lenEncoder!.setTableSize(this._numFastBytes + 1 - 2);
2085
+ this._lenEncoder!.updateTables(1 << this._posStateBits);
2086
+
2087
+ this._repMatchLenEncoder!.setTableSize(this._numFastBytes + 1 - 2);
2088
+ this._repMatchLenEncoder!.updateTables(1 << this._posStateBits);
2089
+
2090
+ this.nowPos64 = 0n;
2091
+ }
2092
+
2093
+ compress(
2094
+ input: InputBuffer,
2095
+ output: OutputBuffer,
2096
+ mode: { searchDepth: number; filterStrength: number; modeIndex: number; },
2097
+ ): void {
2098
+ this.initCompression(input, output, BigInt(input.count), mode);
2099
+
2100
+ do {
2101
+ this.codeOneBlock();
2102
+ if (this.finished[0]) {
2103
+ this.releaseStreams();
2104
+ break;
2105
+ }
2106
+ } while (true);
2107
+ }
2108
+ }