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/lib/encoder.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { LenEncoder, } from "./len-coder.js";
2
2
  import { LitCoder } from "./lit-coder.js";
3
- import { add64, compare64, create64, createBitTree, fromInt64, G_FAST_POS, getBitPrice, getLenToPosState, initArray, initBitModels, lowBits64, PROB_PRICES, } from "./utils.js";
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";
4
5
  const bitTreePriceCache = new Map();
5
6
  /**
6
7
  * Calculate price for direct bit encoding
@@ -12,7 +13,7 @@ function getDirectBitsPrice(numBits) {
12
13
  * Get price for bit tree encoding with caching
13
14
  */
14
15
  function getBitTreePrice(bitTree, symbol) {
15
- const cacheKey = `${bitTree.numBitLevels}-${symbol}`;
16
+ const cacheKey = (bitTree.numBitLevels << 16) | symbol;
16
17
  if (bitTreePriceCache.has(cacheKey)) {
17
18
  return bitTreePriceCache.get(cacheKey);
18
19
  }
@@ -35,7 +36,7 @@ class EncoderState {
35
36
  // Core state
36
37
  state = 0;
37
38
  previousByte = 0;
38
- position = [0, 0];
39
+ position = 0n;
39
40
  // Repetition distances (LZ77 back-references)
40
41
  repDistances = [0, 0, 0, 0];
41
42
  // Match finding state
@@ -203,21 +204,18 @@ export class Encoder {
203
204
  _needReleaseMFStream = 0;
204
205
  _inStream = null;
205
206
  _finished = 0;
206
- nowPos64 = [0, 0];
207
+ nowPos64 = 0n;
207
208
  // Distance and repetition arrays
208
209
  _repDistances = initArray(4);
209
210
  _optimum = [];
210
211
  // Range encoder
211
212
  _rangeEncoder = {
212
- stream: {
213
- buf: [],
214
- count: 0,
215
- },
213
+ stream: null,
216
214
  rrange: 0,
217
215
  cache: 0,
218
- low: [0, 0],
216
+ low: 0n,
219
217
  cacheSize: 0,
220
- position: [0, 0],
218
+ position: 0n,
221
219
  encodeBit: () => { },
222
220
  encodeBitTree: () => { },
223
221
  encodeDirectBits: () => { },
@@ -249,10 +247,10 @@ export class Encoder {
249
247
  reps = initArray(4);
250
248
  repLens = initArray(4);
251
249
  // Processing counters
252
- processedInSize = [[0, 0]];
253
- processedOutSize = [[0, 0]];
250
+ processedInSize = [0n];
251
+ processedOutSize = [0n];
254
252
  finished = [0];
255
- properties = initArray(5);
253
+ properties = new Uint8Array(5);
256
254
  tempPrices = initArray(0x80); // 128
257
255
  // Match finding properties
258
256
  _longestMatchLength = 0;
@@ -328,11 +326,11 @@ export class Encoder {
328
326
  * Initialize encoder range coder
329
327
  */
330
328
  initEncoderState() {
331
- this._rangeEncoder.low = [0, 0];
329
+ this._rangeEncoder.low = 0n;
332
330
  this._rangeEncoder.rrange = 0xFFFFFFFF;
333
331
  this._rangeEncoder.cacheSize = 1;
334
332
  this._rangeEncoder.cache = 0;
335
- this._rangeEncoder.position = [0, 0];
333
+ this._rangeEncoder.position = 0n;
336
334
  }
337
335
  /**
338
336
  * Initialize literal encoder
@@ -432,13 +430,12 @@ export class Encoder {
432
430
  newBound = (rangeEncoder.rrange >>> 11) * prob;
433
431
  if (!symbol) {
434
432
  rangeEncoder.rrange = newBound;
435
- probs[index] = prob + (2048 - prob >>> 5) << 16 >> 16;
433
+ probs[index] = prob + ((2048 - prob) >>> 5);
436
434
  }
437
435
  else {
438
- // Need helper methods for 64-bit arithmetic
439
- rangeEncoder.low = add64(rangeEncoder.low, this.and64(fromInt64(newBound), [0xFFFFFFFF, 0]));
436
+ rangeEncoder.low += BigInt(newBound >>> 0);
440
437
  rangeEncoder.rrange -= newBound;
441
- probs[index] = prob - (prob >>> 5) << 16 >> 16;
438
+ probs[index] = prob - (prob >>> 5);
442
439
  }
443
440
  if (!(rangeEncoder.rrange & -0x1000000)) {
444
441
  rangeEncoder.rrange <<= 8;
@@ -499,7 +496,7 @@ export class Encoder {
499
496
  for (let i = numTotalBits - 1; i >= 0; i -= 1) {
500
497
  rangeEncoder.rrange >>>= 1;
501
498
  if ((valueToEncode >>> i & 1) == 1) {
502
- rangeEncoder.low = add64(rangeEncoder.low, fromInt64(rangeEncoder.rrange));
499
+ rangeEncoder.low += BigInt(rangeEncoder.rrange >>> 0);
503
500
  }
504
501
  if (!(rangeEncoder.rrange & -0x1000000)) {
505
502
  rangeEncoder.rrange <<= 8;
@@ -554,71 +551,24 @@ export class Encoder {
554
551
  encodeLengthWithPriceUpdate(encoder, symbol, posState) {
555
552
  encoder.encodeWithUpdate(symbol, posState, this);
556
553
  }
557
- and64(a, b) {
558
- const highBits = ~~Math.max(Math.min(a[1] / 0x100000000, 0x7FFFFFFF), -0x80000000) & ~~Math.max(Math.min(b[1] / 0x100000000, 0x7FFFFFFF), -0x80000000);
559
- const lowBits = lowBits64(a) & lowBits64(b);
560
- let high = highBits * 0x100000000;
561
- let low = lowBits;
562
- if (lowBits < 0) {
563
- low += 0x100000000;
564
- }
565
- return [low, high];
566
- }
567
- shru64(a, n) {
568
- n &= 0x3F;
569
- let shiftFact = this.pwrAsDouble(n);
570
- let sr = create64(Math.floor(a[0] / shiftFact), a[1] / shiftFact);
571
- if (a[1] < 0) {
572
- sr = add64(sr, this.shl64([2, 0], 0x3F - n));
573
- }
574
- return sr;
575
- }
576
- shl64(a, n) {
577
- let diff, newHigh, newLow, twoToN;
578
- n &= 0x3F;
579
- if (a[0] == 0 && a[1] == -9223372036854775808) {
580
- if (!n) {
581
- return a;
582
- }
583
- return [0, 0];
584
- }
585
- if (a[1] < 0) {
586
- throw new Error("Neg");
587
- }
588
- twoToN = this.pwrAsDouble(n);
589
- newHigh = a[1] * twoToN % 1.8446744073709552E19;
590
- newLow = a[0] * twoToN;
591
- diff = newLow - newLow % 0x100000000;
592
- newHigh += diff;
593
- newLow -= diff;
594
- if (newHigh >= 9223372036854775807) {
595
- newHigh -= 1.8446744073709552E19;
596
- }
597
- return [newLow, newHigh];
598
- }
599
- pwrAsDouble(n) {
600
- if (n <= 0x1E) {
601
- return 1 << n;
602
- }
603
- return this.pwrAsDouble(0x1E) * this.pwrAsDouble(n - 0x1E);
604
- }
605
554
  /**
606
555
  * Shift low helper (proper implementation) - public method for external access
607
556
  */
608
557
  shiftLow() {
609
558
  const rangeEncoder = this._rangeEncoder;
610
- const LowHi = lowBits64(this.shru64(rangeEncoder.low, 32));
611
- if (LowHi != 0 || compare64(rangeEncoder.low, [4278190080, 0]) < 0) {
612
- rangeEncoder.position = add64(rangeEncoder.position, fromInt64(rangeEncoder.cacheSize));
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);
613
563
  let temp = rangeEncoder.cache;
614
564
  do {
615
- this.writeToStream(rangeEncoder.stream, temp + LowHi);
565
+ this.writeToStream(rangeEncoder.stream, temp + lowHi);
616
566
  temp = 255;
617
567
  } while ((rangeEncoder.cacheSize -= 1) != 0);
618
- rangeEncoder.cache = lowBits64(rangeEncoder.low) >>> 24;
568
+ rangeEncoder.cache = (lowLow >>> 24) & 0xFF;
619
569
  }
620
570
  rangeEncoder.cacheSize += 1;
621
- rangeEncoder.low = this.shl64(this.and64(rangeEncoder.low, [16777215, 0]), 8);
571
+ rangeEncoder.low = BigInt(lowLow & 0xFFFFFF) << 8n;
622
572
  }
623
573
  /**
624
574
  * Write byte to stream
@@ -626,20 +576,11 @@ export class Encoder {
626
576
  writeToStream(stream, b) {
627
577
  if (!stream)
628
578
  return;
629
- // Ensure buffer has enough capacity
630
- if (stream.count >= stream.buf.length) {
631
- const newSize = Math.max(stream.buf.length * 2, stream.count + 1);
632
- const newBuf = new Array(newSize);
633
- for (let i = 0; i < stream.count; i++) {
634
- newBuf[i] = stream.buf[i];
635
- }
636
- stream.buf = newBuf;
637
- }
638
- stream.buf[stream.count++] = b << 24 >> 24;
579
+ stream.writeByte(b << 24 >> 24);
639
580
  }
640
581
  initRangeEncoder() {
641
- this._rangeEncoder.position = [0, 0];
642
- this._rangeEncoder.low = [0, 0];
582
+ this._rangeEncoder.position = 0n;
583
+ this._rangeEncoder.low = 0n;
643
584
  this._rangeEncoder.rrange = -1;
644
585
  this._rangeEncoder.cacheSize = 1;
645
586
  this._rangeEncoder.cache = 0;
@@ -668,7 +609,7 @@ export class Encoder {
668
609
  bitTreeEncoder = this._posSlotEncoder[lenToPosState];
669
610
  st = lenToPosState << 6;
670
611
  for (posSlot = 0; posSlot < this._distTableSize; posSlot += 1) {
671
- this._posSlotPrices[st + posSlot] = this.rangeCoder_Encoder_GetPrice_1(bitTreeEncoder, posSlot);
612
+ this._posSlotPrices[st + posSlot] = this.getEncoderBitTreePrice(bitTreeEncoder, posSlot);
672
613
  }
673
614
  for (posSlot = 14; posSlot < this._distTableSize; posSlot += 1) {
674
615
  this._posSlotPrices[st + posSlot] += (posSlot >> 1) - 1 - 4 << 6;
@@ -711,12 +652,12 @@ export class Encoder {
711
652
  /**
712
653
  * Get reverse price for array of models
713
654
  */
714
- reverseGetPriceArray(Models, startIndex, NumBitLevels, symbol) {
655
+ reverseGetPriceArray(models, startIndex, numBitLevels, symbol) {
715
656
  let bit, m = 1, price = 0;
716
- for (let i = NumBitLevels; i != 0; i -= 1) {
657
+ for (let i = numBitLevels; i != 0; i -= 1) {
717
658
  bit = symbol & 1;
718
659
  symbol >>>= 1;
719
- price += PROB_PRICES[((Models[startIndex + m] - bit ^ -bit) & 2047) >>> 2];
660
+ price += PROB_PRICES[((models[startIndex + m] - bit ^ -bit) & 2047) >>> 2];
720
661
  m = m << 1 | bit;
721
662
  }
722
663
  return price;
@@ -724,13 +665,13 @@ export class Encoder {
724
665
  /**
725
666
  * Get price for probability model (optimized)
726
667
  */
727
- getPrice(Prob, symbol) {
728
- return getBitPrice(Prob, symbol);
668
+ getPrice(prob, symbol) {
669
+ return getBitPrice(prob, symbol);
729
670
  }
730
671
  /**
731
- * Get price for bit tree encoder (optimized)
672
+ * Get price for bit tree encoder
732
673
  */
733
- rangeCoder_Encoder_GetPrice_1(encoder, symbol) {
674
+ getEncoderBitTreePrice(encoder, symbol) {
734
675
  return getBitTreePrice(encoder, symbol);
735
676
  }
736
677
  /**
@@ -753,70 +694,780 @@ export class Encoder {
753
694
  }
754
695
  }
755
696
  /**
756
- * Create match finder and encoder structures (replaces #Create_2)
697
+ * Get literal encoder subcoder (utility method)
757
698
  */
758
- createMatchFinderAndStructures() {
759
- // Create match finder if needed
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() {
760
1412
  if (!this._matchFinder) {
761
- const binTree = {};
1413
+ const binTree = new BinTreeMatchFinder();
762
1414
  let numHashBytes = 4;
763
1415
  if (!this._matchFinderType) {
764
1416
  numHashBytes = 2;
765
1417
  }
766
- // Set match finder type (replaces #SetType)
767
- binTree.HASH_ARRAY = numHashBytes > 2;
768
- if (binTree.HASH_ARRAY) {
769
- binTree.kNumHashDirectBytes = 0;
770
- binTree.kMinMatchCheck = 4;
771
- binTree.kFixHashSize = 66560;
772
- }
773
- else {
774
- binTree.kNumHashDirectBytes = 2;
775
- binTree.kMinMatchCheck = 3;
776
- binTree.kFixHashSize = 0;
777
- }
778
- // Initialize other match finder properties
779
- binTree._cyclicBufferSize = 0;
780
- binTree._cyclicBufferPos = 0;
781
- binTree._streamPos = 0;
782
- binTree._cutValue = 0xff;
783
- binTree._matchMaxLen = 0;
784
- binTree._streamEndWasReached = 0;
785
- binTree._pos = 0;
786
- binTree._posLimit = 0;
787
- binTree._son = [];
788
- binTree._hash = [];
789
- binTree._bufferBase = [];
790
- binTree._blockSize = 0;
791
- binTree._keepSizeAfter = 0;
792
- binTree._keepSizeBefore = 0;
793
- binTree._pointerToLastSafePosition = 0;
1418
+ binTree.setType(numHashBytes);
794
1419
  this._matchFinder = binTree;
795
1420
  }
796
- // Create literal encoder if needed
797
1421
  this.createLiteralEncoder();
798
- // Check if we need to recreate structures
799
1422
  if (this._dictionarySize == this._dictionarySizePrev
800
1423
  && this._numFastBytesPrev == this._numFastBytes) {
801
1424
  return;
802
1425
  }
803
- // This would call equivalent of #Create_3(0x1000, 0x0112) logic
804
- // For now, we'll handle the basic setup
1426
+ this._matchFinder.create(this._dictionarySize, this._numFastBytes, 0x1000, 0x0112);
805
1427
  this._dictionarySizePrev = this._dictionarySize;
806
1428
  this._numFastBytesPrev = this._numFastBytes;
807
1429
  }
808
- /**
809
- * Get literal encoder subcoder (utility method)
810
- */
811
- getSubCoderUtility(pos, prevByte) {
812
- // Calculate position mask bits
813
- const posBits = pos & this._literalEncoder.posMask;
814
- const posShifted = posBits << this._literalEncoder.numPrevBits;
815
- // Calculate previous byte bits
816
- const prevByteShift = 0x08 - this._literalEncoder.numPrevBits;
817
- const prevByteBits = (prevByte & 0xFF) >>> prevByteShift;
818
- // Combine position and prevByte bits to get final index
819
- const coderIndex = posShifted + prevByteBits;
820
- return this._literalEncoder.coders[coderIndex];
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);
821
1472
  }
822
1473
  }