Upload 2.0.2
[physicsfs] / lzma / Java / SevenZip / Compression / LZMA / Encoder.java
1 package SevenZip.Compression.LZMA;
2
3 import SevenZip.Compression.RangeCoder.BitTreeEncoder;
4 import SevenZip.Compression.LZMA.Base;
5 import SevenZip.Compression.LZ.BinTree;
6 import SevenZip.ICodeProgress;
7 import java.io.IOException;
8
9 public class Encoder
10 {
11         public static final int EMatchFinderTypeBT2 = 0;
12         public static final int EMatchFinderTypeBT4 = 1;
13
14
15
16
17         static final int kIfinityPrice = 0xFFFFFFF;
18
19         static byte[] g_FastPos = new byte[1 << 11];
20
21         static
22         {
23                 int kFastSlots = 22;
24                 int c = 2;
25                 g_FastPos[0] = 0;
26                 g_FastPos[1] = 1;
27                 for (int slotFast = 2; slotFast < kFastSlots; slotFast++)
28                 {
29                         int k = (1 << ((slotFast >> 1) - 1));
30                         for (int j = 0; j < k; j++, c++)
31                                 g_FastPos[c] = (byte)slotFast;
32                 }
33         }
34
35         static int GetPosSlot(int pos)
36         {
37                 if (pos < (1 << 11))
38                         return g_FastPos[pos];
39                 if (pos < (1 << 21))
40                         return (g_FastPos[pos >> 10] + 20);
41                 return (g_FastPos[pos >> 20] + 40);
42         }
43
44         static int GetPosSlot2(int pos)
45         {
46                 if (pos < (1 << 17))
47                         return (g_FastPos[pos >> 6] + 12);
48                 if (pos < (1 << 27))
49                         return (g_FastPos[pos >> 16] + 32);
50                 return (g_FastPos[pos >> 26] + 52);
51         }
52
53         int _state = Base.StateInit();
54         byte _previousByte;
55         int[] _repDistances = new int[Base.kNumRepDistances];
56
57         void BaseInit()
58         {
59                 _state = Base.StateInit();
60                 _previousByte = 0;
61                 for (int i = 0; i < Base.kNumRepDistances; i++)
62                         _repDistances[i] = 0;
63         }
64
65         static final int kDefaultDictionaryLogSize = 22;
66         static final int kNumFastBytesDefault = 0x20;
67
68         class LiteralEncoder
69         {
70                 class Encoder2
71                 {
72                         short[] m_Encoders = new short[0x300];
73
74                         public void Init() { SevenZip.Compression.RangeCoder.Encoder.InitBitModels(m_Encoders); }
75
76
77
78                         public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte symbol) throws IOException
79                         {
80                                 int context = 1;
81                                 for (int i = 7; i >= 0; i--)
82                                 {
83                                         int bit = ((symbol >> i) & 1);
84                                         rangeEncoder.Encode(m_Encoders, context, bit);
85                                         context = (context << 1) | bit;
86                                 }
87                         }
88
89                         public void EncodeMatched(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) throws IOException
90                         {
91                                 int context = 1;
92                                 boolean same = true;
93                                 for (int i = 7; i >= 0; i--)
94                                 {
95                                         int bit = ((symbol >> i) & 1);
96                                         int state = context;
97                                         if (same)
98                                         {
99                                                 int matchBit = ((matchByte >> i) & 1);
100                                                 state += ((1 + matchBit) << 8);
101                                                 same = (matchBit == bit);
102                                         }
103                                         rangeEncoder.Encode(m_Encoders, state, bit);
104                                         context = (context << 1) | bit;
105                                 }
106                         }
107
108                         public int GetPrice(boolean matchMode, byte matchByte, byte symbol)
109                         {
110                                 int price = 0;
111                                 int context = 1;
112                                 int i = 7;
113                                 if (matchMode)
114                                 {
115                                         for (; i >= 0; i--)
116                                         {
117                                                 int matchBit = (matchByte >> i) & 1;
118                                                 int bit = (symbol >> i) & 1;
119                                                 price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(m_Encoders[((1 + matchBit) << 8) + context], bit);
120                                                 context = (context << 1) | bit;
121                                                 if (matchBit != bit)
122                                                 {
123                                                         i--;
124                                                         break;
125                                                 }
126                                         }
127                                 }
128                                 for (; i >= 0; i--)
129                                 {
130                                         int bit = (symbol >> i) & 1;
131                                         price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(m_Encoders[context], bit);
132                                         context = (context << 1) | bit;
133                                 }
134                                 return price;
135                         }
136                 }
137
138                 Encoder2[] m_Coders;
139                 int m_NumPrevBits;
140                 int m_NumPosBits;
141                 int m_PosMask;
142
143                 public void Create(int numPosBits, int numPrevBits)
144                 {
145                         if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)
146                                 return;
147                         m_NumPosBits = numPosBits;
148                         m_PosMask = (1 << numPosBits) - 1;
149                         m_NumPrevBits = numPrevBits;
150                         int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
151                         m_Coders = new Encoder2[numStates];
152                         for (int i = 0; i < numStates; i++)
153                                 m_Coders[i] = new Encoder2();
154                 }
155
156                 public void Init()
157                 {
158                         int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
159                         for (int i = 0; i < numStates; i++)
160                                 m_Coders[i].Init();
161                 }
162
163                 public Encoder2 GetSubCoder(int pos, byte prevByte)
164                 { return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))]; }
165         }
166
167         class LenEncoder
168         {
169                 short[] _choice = new short[2];
170                 BitTreeEncoder[] _lowCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];
171                 BitTreeEncoder[] _midCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];
172                 BitTreeEncoder _highCoder = new BitTreeEncoder(Base.kNumHighLenBits);
173
174
175                 public LenEncoder()
176                 {
177                         for (int posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++)
178                         {
179                                 _lowCoder[posState] = new BitTreeEncoder(Base.kNumLowLenBits);
180                                 _midCoder[posState] = new BitTreeEncoder(Base.kNumMidLenBits);
181                         }
182                 }
183
184                 public void Init(int numPosStates)
185                 {
186                         SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_choice);
187
188                         for (int posState = 0; posState < numPosStates; posState++)
189                         {
190                                 _lowCoder[posState].Init();
191                                 _midCoder[posState].Init();
192                         }
193                         _highCoder.Init();
194                 }
195
196                 public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, int symbol, int posState) throws IOException
197                 {
198                         if (symbol < Base.kNumLowLenSymbols)
199                         {
200                                 rangeEncoder.Encode(_choice, 0, 0);
201                                 _lowCoder[posState].Encode(rangeEncoder, symbol);
202                         }
203                         else
204                         {
205                                 symbol -= Base.kNumLowLenSymbols;
206                                 rangeEncoder.Encode(_choice, 0, 1);
207                                 if (symbol < Base.kNumMidLenSymbols)
208                                 {
209                                         rangeEncoder.Encode(_choice, 1, 0);
210                                         _midCoder[posState].Encode(rangeEncoder, symbol);
211                                 }
212                                 else
213                                 {
214                                         rangeEncoder.Encode(_choice, 1, 1);
215                                         _highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols);
216                                 }
217                         }
218                 }
219
220                 public void SetPrices(int posState, int numSymbols, int[] prices, int st)
221                 {
222                         int a0 = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_choice[0]);
223                         int a1 = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_choice[0]);
224                         int b0 = a1 + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_choice[1]);
225                         int b1 = a1 + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_choice[1]);
226                         int i = 0;
227                         for (i = 0; i < Base.kNumLowLenSymbols; i++)
228                         {
229                                 if (i >= numSymbols)
230                                         return;
231                                 prices[st + i] = a0 + _lowCoder[posState].GetPrice(i);
232                         }
233                         for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++)
234                         {
235                                 if (i >= numSymbols)
236                                         return;
237                                 prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols);
238                         }
239                         for (; i < numSymbols; i++)
240                                 prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols);
241                 }
242         };
243
244         public static final int kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;
245
246         class LenPriceTableEncoder extends LenEncoder
247         {
248                 int[] _prices = new int[Base.kNumLenSymbols<<Base.kNumPosStatesBitsEncodingMax];
249                 int _tableSize;
250                 int[] _counters = new int[Base.kNumPosStatesEncodingMax];
251
252                 public void SetTableSize(int tableSize) { _tableSize = tableSize; }
253
254                 public int GetPrice(int symbol, int posState)
255                 {
256                         return _prices[posState * Base.kNumLenSymbols + symbol];
257                 }
258
259                 void UpdateTable(int posState)
260                 {
261                         SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols);
262                         _counters[posState] = _tableSize;
263                 }
264
265                 public void UpdateTables(int numPosStates)
266                 {
267                         for (int posState = 0; posState < numPosStates; posState++)
268                                 UpdateTable(posState);
269                 }
270
271                 public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, int symbol, int posState) throws IOException
272                 {
273                         super.Encode(rangeEncoder, symbol, posState);
274                         if (--_counters[posState] == 0)
275                                 UpdateTable(posState);
276                 }
277         }
278
279         static final int kNumOpts = 1 << 12;
280         class Optimal
281         {
282                 public int State;
283
284                 public boolean Prev1IsChar;
285                 public boolean Prev2;
286
287                 public int PosPrev2;
288                 public int BackPrev2;
289
290                 public int Price;
291                 public int PosPrev;
292                 public int BackPrev;
293
294                 public int Backs0;
295                 public int Backs1;
296                 public int Backs2;
297                 public int Backs3;
298
299                 public void MakeAsChar() { BackPrev = -1; Prev1IsChar = false; }
300                 public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
301                 public boolean IsShortRep() { return (BackPrev == 0); }
302         };
303         Optimal[] _optimum = new Optimal[kNumOpts];
304         SevenZip.Compression.LZ.BinTree _matchFinder = null;
305         SevenZip.Compression.RangeCoder.Encoder _rangeEncoder = new SevenZip.Compression.RangeCoder.Encoder();
306
307         short[] _isMatch = new short[Base.kNumStates<<Base.kNumPosStatesBitsMax];
308         short[] _isRep = new short[Base.kNumStates];
309         short[] _isRepG0 = new short[Base.kNumStates];
310         short[] _isRepG1 = new short[Base.kNumStates];
311         short[] _isRepG2 = new short[Base.kNumStates];
312         short[] _isRep0Long = new short[Base.kNumStates<<Base.kNumPosStatesBitsMax];
313
314         BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[Base.kNumLenToPosStates]; // kNumPosSlotBits
315
316         short[] _posEncoders = new short[Base.kNumFullDistances-Base.kEndPosModelIndex];
317         BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.kNumAlignBits);
318
319         LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();
320         LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();
321
322         LiteralEncoder _literalEncoder = new LiteralEncoder();
323
324         int[] _matchDistances = new int[Base.kMatchMaxLen*2+2];
325
326         int _numFastBytes = kNumFastBytesDefault;
327         int _longestMatchLength;
328         int _numDistancePairs;
329
330         int _additionalOffset;
331
332         int _optimumEndIndex;
333         int _optimumCurrentIndex;
334
335         boolean _longestMatchWasFound;
336
337         int[] _posSlotPrices = new int[1<<(Base.kNumPosSlotBits+Base.kNumLenToPosStatesBits)];
338         int[] _distancesPrices = new int[Base.kNumFullDistances<<Base.kNumLenToPosStatesBits];
339         int[] _alignPrices = new int[Base.kAlignTableSize];
340         int _alignPriceCount;
341
342         int _distTableSize = (kDefaultDictionaryLogSize * 2);
343
344         int _posStateBits = 2;
345         int _posStateMask = (4 - 1);
346         int _numLiteralPosStateBits = 0;
347         int _numLiteralContextBits = 3;
348
349         int _dictionarySize = (1 << kDefaultDictionaryLogSize);
350         int _dictionarySizePrev = -1;
351         int _numFastBytesPrev = -1;
352
353         long nowPos64;
354         boolean _finished;
355         java.io.InputStream _inStream;
356
357         int _matchFinderType = EMatchFinderTypeBT4;
358         boolean _writeEndMark = false;
359
360         boolean _needReleaseMFStream = false;
361
362         void Create()
363         {
364                 if (_matchFinder == null)
365                 {
366                         SevenZip.Compression.LZ.BinTree bt = new SevenZip.Compression.LZ.BinTree();
367                         int numHashBytes = 4;
368                         if (_matchFinderType == EMatchFinderTypeBT2)
369                                 numHashBytes = 2;
370                         bt.SetType(numHashBytes);
371                         _matchFinder = bt;
372                 }
373                 _literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);
374
375                 if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
376                         return;
377                 _matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1);
378                 _dictionarySizePrev = _dictionarySize;
379                 _numFastBytesPrev = _numFastBytes;
380         }
381
382         public Encoder()
383         {
384                 for (int i = 0; i < kNumOpts; i++)
385                         _optimum[i] = new Optimal();
386                 for (int i = 0; i < Base.kNumLenToPosStates; i++)
387                         _posSlotEncoder[i] = new BitTreeEncoder(Base.kNumPosSlotBits);
388         }
389
390         void SetWriteEndMarkerMode(boolean writeEndMarker)
391         {
392                 _writeEndMark = writeEndMarker;
393         }
394
395         void Init()
396         {
397                 BaseInit();
398                 _rangeEncoder.Init();
399
400                 SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isMatch);
401                 SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRep0Long);
402                 SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRep);
403                 SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG0);
404                 SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG1);
405                 SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG2);
406                 SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_posEncoders);
407
408
409
410
411
412
413
414                 _literalEncoder.Init();
415                 for (int i = 0; i < Base.kNumLenToPosStates; i++)
416                         _posSlotEncoder[i].Init();
417
418
419
420                 _lenEncoder.Init(1 << _posStateBits);
421                 _repMatchLenEncoder.Init(1 << _posStateBits);
422
423                 _posAlignEncoder.Init();
424
425                 _longestMatchWasFound = false;
426                 _optimumEndIndex = 0;
427                 _optimumCurrentIndex = 0;
428                 _additionalOffset = 0;
429         }
430
431         int ReadMatchDistances() throws java.io.IOException
432         {
433                 int lenRes = 0;
434                 _numDistancePairs = _matchFinder.GetMatches(_matchDistances);
435                 if (_numDistancePairs > 0)
436                 {
437                         lenRes = _matchDistances[_numDistancePairs - 2];
438                         if (lenRes == _numFastBytes)
439                                 lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[_numDistancePairs - 1],
440                                         Base.kMatchMaxLen - lenRes);
441                 }
442                 _additionalOffset++;
443                 return lenRes;
444         }
445
446         void MovePos(int num) throws java.io.IOException
447         {
448                 if (num > 0)
449                 {
450                         _matchFinder.Skip(num);
451                         _additionalOffset += num;
452                 }
453         }
454
455         int GetRepLen1Price(int state, int posState)
456         {
457                 return SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG0[state]) +
458                                 SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);
459         }
460
461         int GetPureRepPrice(int repIndex, int state, int posState)
462         {
463                 int price;
464                 if (repIndex == 0)
465                 {
466                         price = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG0[state]);
467                         price += SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);
468                 }
469                 else
470                 {
471                         price = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRepG0[state]);
472                         if (repIndex == 1)
473                                 price += SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG1[state]);
474                         else
475                         {
476                                 price += SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRepG1[state]);
477                                 price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(_isRepG2[state], repIndex - 2);
478                         }
479                 }
480                 return price;
481         }
482
483         int GetRepPrice(int repIndex, int len, int state, int posState)
484         {
485                 int price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
486                 return price + GetPureRepPrice(repIndex, state, posState);
487         }
488
489         int GetPosLenPrice(int pos, int len, int posState)
490         {
491                 int price;
492                 int lenToPosState = Base.GetLenToPosState(len);
493                 if (pos < Base.kNumFullDistances)
494                         price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos];
495                 else
496                         price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] +
497                                 _alignPrices[pos & Base.kAlignMask];
498                 return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
499         }
500
501         int Backward(int cur)
502         {
503                 _optimumEndIndex = cur;
504                 int posMem = _optimum[cur].PosPrev;
505                 int backMem = _optimum[cur].BackPrev;
506                 do
507                 {
508                         if (_optimum[cur].Prev1IsChar)
509                         {
510                                 _optimum[posMem].MakeAsChar();
511                                 _optimum[posMem].PosPrev = posMem - 1;
512                                 if (_optimum[cur].Prev2)
513                                 {
514                                         _optimum[posMem - 1].Prev1IsChar = false;
515                                         _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
516                                         _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
517                                 }
518                         }
519                         int posPrev = posMem;
520                         int backCur = backMem;
521
522                         backMem = _optimum[posPrev].BackPrev;
523                         posMem = _optimum[posPrev].PosPrev;
524
525                         _optimum[posPrev].BackPrev = backCur;
526                         _optimum[posPrev].PosPrev = cur;
527                         cur = posPrev;
528                 }
529                 while (cur > 0);
530                 backRes = _optimum[0].BackPrev;
531                 _optimumCurrentIndex = _optimum[0].PosPrev;
532                 return _optimumCurrentIndex;
533         }
534
535         int[] reps = new int[Base.kNumRepDistances];
536         int[] repLens = new int[Base.kNumRepDistances];
537         int backRes;
538
539         int GetOptimum(int position) throws IOException
540         {
541                 if (_optimumEndIndex != _optimumCurrentIndex)
542                 {
543                         int lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;
544                         backRes = _optimum[_optimumCurrentIndex].BackPrev;
545                         _optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;
546                         return lenRes;
547                 }
548                 _optimumCurrentIndex = _optimumEndIndex = 0;
549
550                 int lenMain, numDistancePairs;
551                 if (!_longestMatchWasFound)
552                 {
553                         lenMain = ReadMatchDistances();
554                 }
555                 else
556                 {
557                         lenMain = _longestMatchLength;
558                         _longestMatchWasFound = false;
559                 }
560                 numDistancePairs = _numDistancePairs;
561
562                 int numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1;
563                 if (numAvailableBytes < 2)
564                 {
565                         backRes = -1;
566                         return 1;
567                 }
568                 if (numAvailableBytes > Base.kMatchMaxLen)
569                         numAvailableBytes = Base.kMatchMaxLen;
570
571                 int repMaxIndex = 0;
572                 int i;
573                 for (i = 0; i < Base.kNumRepDistances; i++)
574                 {
575                         reps[i] = _repDistances[i];
576                         repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen);
577                         if (repLens[i] > repLens[repMaxIndex])
578                                 repMaxIndex = i;
579                 }
580                 if (repLens[repMaxIndex] >= _numFastBytes)
581                 {
582                         backRes = repMaxIndex;
583                         int lenRes = repLens[repMaxIndex];
584                         MovePos(lenRes - 1);
585                         return lenRes;
586                 }
587
588                 if (lenMain >= _numFastBytes)
589                 {
590                         backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances;
591                         MovePos(lenMain - 1);
592                         return lenMain;
593                 }
594
595                 byte currentByte = _matchFinder.GetIndexByte(0 - 1);
596                 byte matchByte = _matchFinder.GetIndexByte(0 - _repDistances[0] - 1 - 1);
597
598                 if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
599                 {
600                         backRes = -1;
601                         return 1;
602                 }
603
604                 _optimum[0].State = _state;
605
606                 int posState = (position & _posStateMask);
607
608                 _optimum[1].Price = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]) +
609                                 _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!Base.StateIsCharState(_state), matchByte, currentByte);
610                 _optimum[1].MakeAsChar();
611
612                 int matchPrice = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]);
613                 int repMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[_state]);
614
615                 if (matchByte == currentByte)
616                 {
617                         int shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
618                         if (shortRepPrice < _optimum[1].Price)
619                         {
620                                 _optimum[1].Price = shortRepPrice;
621                                 _optimum[1].MakeAsShortRep();
622                         }
623                 }
624
625                 int lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
626
627                 if (lenEnd < 2)
628                 {
629                         backRes = _optimum[1].BackPrev;
630                         return 1;
631                 }
632
633                 _optimum[1].PosPrev = 0;
634
635                 _optimum[0].Backs0 = reps[0];
636                 _optimum[0].Backs1 = reps[1];
637                 _optimum[0].Backs2 = reps[2];
638                 _optimum[0].Backs3 = reps[3];
639
640                 int len = lenEnd;
641                 do
642                         _optimum[len--].Price = kIfinityPrice;
643                 while (len >= 2);
644
645                 for (i = 0; i < Base.kNumRepDistances; i++)
646                 {
647                         int repLen = repLens[i];
648                         if (repLen < 2)
649                                 continue;
650                         int price = repMatchPrice + GetPureRepPrice(i, _state, posState);
651                         do
652                         {
653                                 int curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
654                                 Optimal optimum = _optimum[repLen];
655                                 if (curAndLenPrice < optimum.Price)
656                                 {
657                                         optimum.Price = curAndLenPrice;
658                                         optimum.PosPrev = 0;
659                                         optimum.BackPrev = i;
660                                         optimum.Prev1IsChar = false;
661                                 }
662                         }
663                         while (--repLen >= 2);
664                 }
665
666                 int normalMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep[_state]);
667
668                 len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
669                 if (len <= lenMain)
670                 {
671                         int offs = 0;
672                         while (len > _matchDistances[offs])
673                                 offs += 2;
674                         for (; ; len++)
675                         {
676                                 int distance = _matchDistances[offs + 1];
677                                 int curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
678                                 Optimal optimum = _optimum[len];
679                                 if (curAndLenPrice < optimum.Price)
680                                 {
681                                         optimum.Price = curAndLenPrice;
682                                         optimum.PosPrev = 0;
683                                         optimum.BackPrev = distance + Base.kNumRepDistances;
684                                         optimum.Prev1IsChar = false;
685                                 }
686                                 if (len == _matchDistances[offs])
687                                 {
688                                         offs += 2;
689                                         if (offs == numDistancePairs)
690                                                 break;
691                                 }
692                         }
693                 }
694
695                 int cur = 0;
696
697                 while (true)
698                 {
699                         cur++;
700                         if (cur == lenEnd)
701                                 return Backward(cur);
702                         int newLen = ReadMatchDistances();
703                         numDistancePairs = _numDistancePairs;
704                         if (newLen >= _numFastBytes)
705                         {
706
707                                 _longestMatchLength = newLen;
708                                 _longestMatchWasFound = true;
709                                 return Backward(cur);
710                         }
711                         position++;
712                         int posPrev = _optimum[cur].PosPrev;
713                         int state;
714                         if (_optimum[cur].Prev1IsChar)
715                         {
716                                 posPrev--;
717                                 if (_optimum[cur].Prev2)
718                                 {
719                                         state = _optimum[_optimum[cur].PosPrev2].State;
720                                         if (_optimum[cur].BackPrev2 < Base.kNumRepDistances)
721                                                 state = Base.StateUpdateRep(state);
722                                         else
723                                                 state = Base.StateUpdateMatch(state);
724                                 }
725                                 else
726                                         state = _optimum[posPrev].State;
727                                 state = Base.StateUpdateChar(state);
728                         }
729                         else
730                                 state = _optimum[posPrev].State;
731                         if (posPrev == cur - 1)
732                         {
733                                 if (_optimum[cur].IsShortRep())
734                                         state = Base.StateUpdateShortRep(state);
735                                 else
736                                         state = Base.StateUpdateChar(state);
737                         }
738                         else
739                         {
740                                 int pos;
741                                 if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2)
742                                 {
743                                         posPrev = _optimum[cur].PosPrev2;
744                                         pos = _optimum[cur].BackPrev2;
745                                         state = Base.StateUpdateRep(state);
746                                 }
747                                 else
748                                 {
749                                         pos = _optimum[cur].BackPrev;
750                                         if (pos < Base.kNumRepDistances)
751                                                 state = Base.StateUpdateRep(state);
752                                         else
753                                                 state = Base.StateUpdateMatch(state);
754                                 }
755                                 Optimal opt = _optimum[posPrev];
756                                 if (pos < Base.kNumRepDistances)
757                                 {
758                                         if (pos == 0)
759                                         {
760                                                 reps[0] = opt.Backs0;
761                                                 reps[1] = opt.Backs1;
762                                                 reps[2] = opt.Backs2;
763                                                 reps[3] = opt.Backs3;
764                                         }
765                                         else if (pos == 1)
766                                         {
767                                                 reps[0] = opt.Backs1;
768                                                 reps[1] = opt.Backs0;
769                                                 reps[2] = opt.Backs2;
770                                                 reps[3] = opt.Backs3;
771                                         }
772                                         else if (pos == 2)
773                                         {
774                                                 reps[0] = opt.Backs2;
775                                                 reps[1] = opt.Backs0;
776                                                 reps[2] = opt.Backs1;
777                                                 reps[3] = opt.Backs3;
778                                         }
779                                         else
780                                         {
781                                                 reps[0] = opt.Backs3;
782                                                 reps[1] = opt.Backs0;
783                                                 reps[2] = opt.Backs1;
784                                                 reps[3] = opt.Backs2;
785                                         }
786                                 }
787                                 else
788                                 {
789                                         reps[0] = (pos - Base.kNumRepDistances);
790                                         reps[1] = opt.Backs0;
791                                         reps[2] = opt.Backs1;
792                                         reps[3] = opt.Backs2;
793                                 }
794                         }
795                         _optimum[cur].State = state;
796                         _optimum[cur].Backs0 = reps[0];
797                         _optimum[cur].Backs1 = reps[1];
798                         _optimum[cur].Backs2 = reps[2];
799                         _optimum[cur].Backs3 = reps[3];
800                         int curPrice = _optimum[cur].Price;
801
802                         currentByte = _matchFinder.GetIndexByte(0 - 1);
803                         matchByte = _matchFinder.GetIndexByte(0 - reps[0] - 1 - 1);
804
805                         posState = (position & _posStateMask);
806
807                         int curAnd1Price = curPrice +
808                                 SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]) +
809                                 _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)).
810                                 GetPrice(!Base.StateIsCharState(state), matchByte, currentByte);
811
812                         Optimal nextOptimum = _optimum[cur + 1];
813
814                         boolean nextIsChar = false;
815                         if (curAnd1Price < nextOptimum.Price)
816                         {
817                                 nextOptimum.Price = curAnd1Price;
818                                 nextOptimum.PosPrev = cur;
819                                 nextOptimum.MakeAsChar();
820                                 nextIsChar = true;
821                         }
822
823                         matchPrice = curPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]);
824                         repMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state]);
825
826                         if (matchByte == currentByte &&
827                                 !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
828                         {
829                                 int shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
830                                 if (shortRepPrice <= nextOptimum.Price)
831                                 {
832                                         nextOptimum.Price = shortRepPrice;
833                                         nextOptimum.PosPrev = cur;
834                                         nextOptimum.MakeAsShortRep();
835                                         nextIsChar = true;
836                                 }
837                         }
838
839                         int numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1;
840                         numAvailableBytesFull = Math.min(kNumOpts - 1 - cur, numAvailableBytesFull);
841                         numAvailableBytes = numAvailableBytesFull;
842
843                         if (numAvailableBytes < 2)
844                                 continue;
845                         if (numAvailableBytes > _numFastBytes)
846                                 numAvailableBytes = _numFastBytes;
847                         if (!nextIsChar && matchByte != currentByte)
848                         {
849                                 // try Literal + rep0
850                                 int t = Math.min(numAvailableBytesFull - 1, _numFastBytes);
851                                 int lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t);
852                                 if (lenTest2 >= 2)
853                                 {
854                                         int state2 = Base.StateUpdateChar(state);
855
856                                         int posStateNext = (position + 1) & _posStateMask;
857                                         int nextRepMatchPrice = curAnd1Price +
858                                                 SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
859                                                 SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
860                                         {
861                                                 int offset = cur + 1 + lenTest2;
862                                                 while (lenEnd < offset)
863                                                         _optimum[++lenEnd].Price = kIfinityPrice;
864                                                 int curAndLenPrice = nextRepMatchPrice + GetRepPrice(
865                                                                 0, lenTest2, state2, posStateNext);
866                                                 Optimal optimum = _optimum[offset];
867                                                 if (curAndLenPrice < optimum.Price)
868                                                 {
869                                                         optimum.Price = curAndLenPrice;
870                                                         optimum.PosPrev = cur + 1;
871                                                         optimum.BackPrev = 0;
872                                                         optimum.Prev1IsChar = true;
873                                                         optimum.Prev2 = false;
874                                                 }
875                                         }
876                                 }
877                         }
878
879                         int startLen = 2; // speed optimization 
880
881                         for (int repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++)
882                         {
883                                 int lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes);
884                                 if (lenTest < 2)
885                                         continue;
886                                 int lenTestTemp = lenTest;
887                                 do
888                                 {
889                                         while (lenEnd < cur + lenTest)
890                                                 _optimum[++lenEnd].Price = kIfinityPrice;
891                                         int curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);
892                                         Optimal optimum = _optimum[cur + lenTest];
893                                         if (curAndLenPrice < optimum.Price)
894                                         {
895                                                 optimum.Price = curAndLenPrice;
896                                                 optimum.PosPrev = cur;
897                                                 optimum.BackPrev = repIndex;
898                                                 optimum.Prev1IsChar = false;
899                                         }
900                                 }
901                                 while (--lenTest >= 2);
902                                 lenTest = lenTestTemp;
903
904                                 if (repIndex == 0)
905                                         startLen = lenTest + 1;
906
907                                 // if (_maxMode)
908                                 if (lenTest < numAvailableBytesFull)
909                                 {
910                                         int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
911                                         int lenTest2 = _matchFinder.GetMatchLen(lenTest, reps[repIndex], t);
912                                         if (lenTest2 >= 2)
913                                         {
914                                                 int state2 = Base.StateUpdateRep(state);
915
916                                                 int posStateNext = (position + lenTest) & _posStateMask;
917                                                 int curAndLenCharPrice =
918                                                                 repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) +
919                                                                 SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
920                                                                 _literalEncoder.GetSubCoder(position + lenTest,
921                                                                 _matchFinder.GetIndexByte(lenTest - 1 - 1)).GetPrice(true,
922                                                                 _matchFinder.GetIndexByte(lenTest - 1 - (reps[repIndex] + 1)),
923                                                                 _matchFinder.GetIndexByte(lenTest - 1));
924                                                 state2 = Base.StateUpdateChar(state2);
925                                                 posStateNext = (position + lenTest + 1) & _posStateMask;
926                                                 int nextMatchPrice = curAndLenCharPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);
927                                                 int nextRepMatchPrice = nextMatchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
928
929                                                 // for(; lenTest2 >= 2; lenTest2--)
930                                                 {
931                                                         int offset = lenTest + 1 + lenTest2;
932                                                         while (lenEnd < cur + offset)
933                                                                 _optimum[++lenEnd].Price = kIfinityPrice;
934                                                         int curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
935                                                         Optimal optimum = _optimum[cur + offset];
936                                                         if (curAndLenPrice < optimum.Price)
937                                                         {
938                                                                 optimum.Price = curAndLenPrice;
939                                                                 optimum.PosPrev = cur + lenTest + 1;
940                                                                 optimum.BackPrev = 0;
941                                                                 optimum.Prev1IsChar = true;
942                                                                 optimum.Prev2 = true;
943                                                                 optimum.PosPrev2 = cur;
944                                                                 optimum.BackPrev2 = repIndex;
945                                                         }
946                                                 }
947                                         }
948                                 }
949                         }
950
951                         if (newLen > numAvailableBytes)
952                         {
953                                 newLen = numAvailableBytes;
954                                 for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) ;
955                                 _matchDistances[numDistancePairs] = newLen;
956                                 numDistancePairs += 2;
957                         }
958                         if (newLen >= startLen)
959                         {
960                                 normalMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep[state]);
961                                 while (lenEnd < cur + newLen)
962                                         _optimum[++lenEnd].Price = kIfinityPrice;
963
964                                 int offs = 0;
965                                 while (startLen > _matchDistances[offs])
966                                         offs += 2;
967
968                                 for (int lenTest = startLen; ; lenTest++)
969                                 {
970                                         int curBack = _matchDistances[offs + 1];
971                                         int curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);
972                                         Optimal optimum = _optimum[cur + lenTest];
973                                         if (curAndLenPrice < optimum.Price)
974                                         {
975                                                 optimum.Price = curAndLenPrice;
976                                                 optimum.PosPrev = cur;
977                                                 optimum.BackPrev = curBack + Base.kNumRepDistances;
978                                                 optimum.Prev1IsChar = false;
979                                         }
980
981                                         if (lenTest == _matchDistances[offs])
982                                         {
983                                                 if (lenTest < numAvailableBytesFull)
984                                                 {
985                                                         int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
986                                                         int lenTest2 = _matchFinder.GetMatchLen(lenTest, curBack, t);
987                                                         if (lenTest2 >= 2)
988                                                         {
989                                                                 int state2 = Base.StateUpdateMatch(state);
990
991                                                                 int posStateNext = (position + lenTest) & _posStateMask;
992                                                                 int curAndLenCharPrice = curAndLenPrice +
993                                                                         SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
994                                                                         _literalEncoder.GetSubCoder(position + lenTest,
995                                                                         _matchFinder.GetIndexByte(lenTest - 1 - 1)).
996                                                                         GetPrice(true,
997                                                                         _matchFinder.GetIndexByte(lenTest - (curBack + 1) - 1),
998                                                                         _matchFinder.GetIndexByte(lenTest - 1));
999                                                                 state2 = Base.StateUpdateChar(state2);
1000                                                                 posStateNext = (position + lenTest + 1) & _posStateMask;
1001                                                                 int nextMatchPrice = curAndLenCharPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);
1002                                                                 int nextRepMatchPrice = nextMatchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
1003
1004                                                                 int offset = lenTest + 1 + lenTest2;
1005                                                                 while (lenEnd < cur + offset)
1006                                                                         _optimum[++lenEnd].Price = kIfinityPrice;
1007                                                                 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
1008                                                                 optimum = _optimum[cur + offset];
1009                                                                 if (curAndLenPrice < optimum.Price)
1010                                                                 {
1011                                                                         optimum.Price = curAndLenPrice;
1012                                                                         optimum.PosPrev = cur + lenTest + 1;
1013                                                                         optimum.BackPrev = 0;
1014                                                                         optimum.Prev1IsChar = true;
1015                                                                         optimum.Prev2 = true;
1016                                                                         optimum.PosPrev2 = cur;
1017                                                                         optimum.BackPrev2 = curBack + Base.kNumRepDistances;
1018                                                                 }
1019                                                         }
1020                                                 }
1021                                                 offs += 2;
1022                                                 if (offs == numDistancePairs)
1023                                                         break;
1024                                         }
1025                                 }
1026                         }
1027                 }
1028         }
1029
1030         boolean ChangePair(int smallDist, int bigDist)
1031         {
1032                 int kDif = 7;
1033                 return (smallDist < (1 << (32 - kDif)) && bigDist >= (smallDist << kDif));
1034         }
1035
1036         void WriteEndMarker(int posState) throws IOException
1037         {
1038                 if (!_writeEndMark)
1039                         return;
1040
1041                 _rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 1);
1042                 _rangeEncoder.Encode(_isRep, _state, 0);
1043                 _state = Base.StateUpdateMatch(_state);
1044                 int len = Base.kMatchMinLen;
1045                 _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
1046                 int posSlot = (1 << Base.kNumPosSlotBits) - 1;
1047                 int lenToPosState = Base.GetLenToPosState(len);
1048                 _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
1049                 int footerBits = 30;
1050                 int posReduced = (1 << footerBits) - 1;
1051                 _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
1052                 _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
1053         }
1054
1055         void Flush(int nowPos) throws IOException
1056         {
1057                 ReleaseMFStream();
1058                 WriteEndMarker(nowPos & _posStateMask);
1059                 _rangeEncoder.FlushData();
1060                 _rangeEncoder.FlushStream();
1061         }
1062
1063         public void CodeOneBlock(long[] inSize, long[] outSize, boolean[] finished) throws IOException
1064         {
1065                 inSize[0] = 0;
1066                 outSize[0] = 0;
1067                 finished[0] = true;
1068
1069                 if (_inStream != null)
1070                 {
1071                         _matchFinder.SetStream(_inStream);
1072                         _matchFinder.Init();
1073                         _needReleaseMFStream = true;
1074                         _inStream = null;
1075                 }
1076
1077                 if (_finished)
1078                         return;
1079                 _finished = true;
1080
1081
1082                 long progressPosValuePrev = nowPos64;
1083                 if (nowPos64 == 0)
1084                 {
1085                         if (_matchFinder.GetNumAvailableBytes() == 0)
1086                         {
1087                                 Flush((int)nowPos64);
1088                                 return;
1089                         }
1090
1091                         ReadMatchDistances();
1092                         int posState = (int)(nowPos64) & _posStateMask;
1093                         _rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 0);
1094                         _state = Base.StateUpdateChar(_state);
1095                         byte curByte = _matchFinder.GetIndexByte(0 - _additionalOffset);
1096                         _literalEncoder.GetSubCoder((int)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte);
1097                         _previousByte = curByte;
1098                         _additionalOffset--;
1099                         nowPos64++;
1100                 }
1101                 if (_matchFinder.GetNumAvailableBytes() == 0)
1102                 {
1103                         Flush((int)nowPos64);
1104                         return;
1105                 }
1106                 while (true)
1107                 {
1108
1109                         int len = GetOptimum((int)nowPos64);
1110                         int pos = backRes;
1111                         int posState = ((int)nowPos64) & _posStateMask;
1112                         int complexState = (_state << Base.kNumPosStatesBitsMax) + posState;
1113                         if (len == 1 && pos == -1)
1114                         {
1115                                 _rangeEncoder.Encode(_isMatch, complexState, 0);
1116                                 byte curByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset));
1117                                 LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((int)nowPos64, _previousByte);
1118                                 if (!Base.StateIsCharState(_state))
1119                                 {
1120                                         byte matchByte = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - _additionalOffset));
1121                                         subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte);
1122                                 }
1123                                 else
1124                                         subCoder.Encode(_rangeEncoder, curByte);
1125                                 _previousByte = curByte;
1126                                 _state = Base.StateUpdateChar(_state);
1127                         }
1128                         else
1129                         {
1130                                 _rangeEncoder.Encode(_isMatch, complexState, 1);
1131                                 if (pos < Base.kNumRepDistances)
1132                                 {
1133                                         _rangeEncoder.Encode(_isRep, _state, 1);
1134                                         if (pos == 0)
1135                                         {
1136                                                 _rangeEncoder.Encode(_isRepG0, _state, 0);
1137                                                 if (len == 1)
1138                                                         _rangeEncoder.Encode(_isRep0Long, complexState, 0);
1139                                                 else
1140                                                         _rangeEncoder.Encode(_isRep0Long, complexState, 1);
1141                                         }
1142                                         else
1143                                         {
1144                                                 _rangeEncoder.Encode(_isRepG0, _state, 1);
1145                                                 if (pos == 1)
1146                                                         _rangeEncoder.Encode(_isRepG1, _state, 0);
1147                                                 else
1148                                                 {
1149                                                         _rangeEncoder.Encode(_isRepG1, _state, 1);
1150                                                         _rangeEncoder.Encode(_isRepG2, _state, pos - 2);
1151                                                 }
1152                                         }
1153                                         if (len == 1)
1154                                                 _state = Base.StateUpdateShortRep(_state);
1155                                         else
1156                                         {
1157                                                 _repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
1158                                                 _state = Base.StateUpdateRep(_state);
1159                                         }
1160                                         int distance = _repDistances[pos];
1161                                         if (pos != 0)
1162                                         {
1163                                                 for (int i = pos; i >= 1; i--)
1164                                                         _repDistances[i] = _repDistances[i - 1];
1165                                                 _repDistances[0] = distance;
1166                                         }
1167                                 }
1168                                 else
1169                                 {
1170                                         _rangeEncoder.Encode(_isRep, _state, 0);
1171                                         _state = Base.StateUpdateMatch(_state);
1172                                         _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
1173                                         pos -= Base.kNumRepDistances;
1174                                         int posSlot = GetPosSlot(pos);
1175                                         int lenToPosState = Base.GetLenToPosState(len);
1176                                         _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
1177
1178                                         if (posSlot >= Base.kStartPosModelIndex)
1179                                         {
1180                                                 int footerBits = (int)((posSlot >> 1) - 1);
1181                                                 int baseVal = ((2 | (posSlot & 1)) << footerBits);
1182                                                 int posReduced = pos - baseVal;
1183
1184                                                 if (posSlot < Base.kEndPosModelIndex)
1185                                                         BitTreeEncoder.ReverseEncode(_posEncoders,
1186                                                                         baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced);
1187                                                 else
1188                                                 {
1189                                                         _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
1190                                                         _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
1191                                                         _alignPriceCount++;
1192                                                 }
1193                                         }
1194                                         int distance = pos;
1195                                         for (int i = Base.kNumRepDistances - 1; i >= 1; i--)
1196                                                 _repDistances[i] = _repDistances[i - 1];
1197                                         _repDistances[0] = distance;
1198                                         _matchPriceCount++;
1199                                 }
1200                                 _previousByte = _matchFinder.GetIndexByte(len - 1 - _additionalOffset);
1201                         }
1202                         _additionalOffset -= len;
1203                         nowPos64 += len;
1204                         if (_additionalOffset == 0)
1205                         {
1206                                 // if (!_fastMode)
1207                                 if (_matchPriceCount >= (1 << 7))
1208                                         FillDistancesPrices();
1209                                 if (_alignPriceCount >= Base.kAlignTableSize)
1210                                         FillAlignPrices();
1211                                 inSize[0] = nowPos64;
1212                                 outSize[0] = _rangeEncoder.GetProcessedSizeAdd();
1213                                 if (_matchFinder.GetNumAvailableBytes() == 0)
1214                                 {
1215                                         Flush((int)nowPos64);
1216                                         return;
1217                                 }
1218
1219                                 if (nowPos64 - progressPosValuePrev >= (1 << 12))
1220                                 {
1221                                         _finished = false;
1222                                         finished[0] = false;
1223                                         return;
1224                                 }
1225                         }
1226                 }
1227         }
1228
1229         void ReleaseMFStream()
1230         {
1231                 if (_matchFinder != null && _needReleaseMFStream)
1232                 {
1233                         _matchFinder.ReleaseStream();
1234                         _needReleaseMFStream = false;
1235                 }
1236         }
1237
1238         void SetOutStream(java.io.OutputStream outStream)
1239         { _rangeEncoder.SetStream(outStream); }
1240         void ReleaseOutStream()
1241         { _rangeEncoder.ReleaseStream(); }
1242
1243         void ReleaseStreams()
1244         {
1245                 ReleaseMFStream();
1246                 ReleaseOutStream();
1247         }
1248
1249         void SetStreams(java.io.InputStream inStream, java.io.OutputStream outStream,
1250                         long inSize, long outSize)
1251         {
1252                 _inStream = inStream;
1253                 _finished = false;
1254                 Create();
1255                 SetOutStream(outStream);
1256                 Init();
1257
1258                 // if (!_fastMode)
1259                 {
1260                         FillDistancesPrices();
1261                         FillAlignPrices();
1262                 }
1263
1264                 _lenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
1265                 _lenEncoder.UpdateTables(1 << _posStateBits);
1266                 _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
1267                 _repMatchLenEncoder.UpdateTables(1 << _posStateBits);
1268
1269                 nowPos64 = 0;
1270         }
1271
1272         long[] processedInSize = new long[1]; long[] processedOutSize = new long[1]; boolean[] finished = new boolean[1];
1273         public void Code(java.io.InputStream inStream, java.io.OutputStream outStream,
1274                         long inSize, long outSize, ICodeProgress progress) throws IOException
1275         {
1276                 _needReleaseMFStream = false;
1277                 try
1278                 {
1279                         SetStreams(inStream, outStream, inSize, outSize);
1280                         while (true)
1281                         {
1282
1283
1284
1285                                 CodeOneBlock(processedInSize, processedOutSize, finished);
1286                                 if (finished[0])
1287                                         return;
1288                                 if (progress != null)
1289                                 {
1290                                         progress.SetProgress(processedInSize[0], processedOutSize[0]);
1291                                 }
1292                         }
1293                 }
1294                 finally
1295                 {
1296                         ReleaseStreams();
1297                 }
1298         }
1299
1300         public static final int kPropSize = 5;
1301         byte[] properties = new byte[kPropSize];
1302
1303         public void WriteCoderProperties(java.io.OutputStream outStream) throws IOException
1304         {
1305                 properties[0] = (byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
1306                 for (int i = 0; i < 4; i++)
1307                         properties[1 + i] = (byte)(_dictionarySize >> (8 * i));
1308                 outStream.write(properties, 0, kPropSize);
1309         }
1310
1311         int[] tempPrices = new int[Base.kNumFullDistances];
1312         int _matchPriceCount;
1313
1314         void FillDistancesPrices()
1315         {
1316                 for (int i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++)
1317                 {
1318                         int posSlot = GetPosSlot(i);
1319                         int footerBits = (int)((posSlot >> 1) - 1);
1320                         int baseVal = ((2 | (posSlot & 1)) << footerBits);
1321                         tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders,
1322                                 baseVal - posSlot - 1, footerBits, i - baseVal);
1323                 }
1324
1325                 for (int lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++)
1326                 {
1327                         int posSlot;
1328                         BitTreeEncoder encoder = _posSlotEncoder[lenToPosState];
1329
1330                         int st = (lenToPosState << Base.kNumPosSlotBits);
1331                         for (posSlot = 0; posSlot < _distTableSize; posSlot++)
1332                                 _posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot);
1333                         for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
1334                                 _posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << SevenZip.Compression.RangeCoder.Encoder.kNumBitPriceShiftBits);
1335
1336                         int st2 = lenToPosState * Base.kNumFullDistances;
1337                         int i;
1338                         for (i = 0; i < Base.kStartPosModelIndex; i++)
1339                                 _distancesPrices[st2 + i] = _posSlotPrices[st + i];
1340                         for (; i < Base.kNumFullDistances; i++)
1341                                 _distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i];
1342                 }
1343                 _matchPriceCount = 0;
1344         }
1345
1346         void FillAlignPrices()
1347         {
1348                 for (int i = 0; i < Base.kAlignTableSize; i++)
1349                         _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
1350                 _alignPriceCount = 0;
1351         }
1352
1353
1354         public boolean SetAlgorithm(int algorithm)
1355         {
1356                 /*
1357                 _fastMode = (algorithm == 0);
1358                 _maxMode = (algorithm >= 2);
1359                 */
1360                 return true;
1361         }
1362
1363         public boolean SetDictionarySize(int dictionarySize)
1364         {
1365                 int kDicLogSizeMaxCompress = 29;
1366                 if (dictionarySize < (1 << Base.kDicLogSizeMin) || dictionarySize > (1 << kDicLogSizeMaxCompress))
1367                         return false;
1368                 _dictionarySize = dictionarySize;
1369                 int dicLogSize;
1370                 for (dicLogSize = 0; dictionarySize > (1 << dicLogSize); dicLogSize++) ;
1371                 _distTableSize = dicLogSize * 2;
1372                 return true;
1373         }
1374
1375         public boolean SeNumFastBytes(int numFastBytes)
1376         {
1377                 if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen)
1378                         return false;
1379                 _numFastBytes = numFastBytes;
1380                 return true;
1381         }
1382
1383         public boolean SetMatchFinder(int matchFinderIndex)
1384         {
1385                 if (matchFinderIndex < 0 || matchFinderIndex > 2)
1386                         return false;
1387                 int matchFinderIndexPrev = _matchFinderType;
1388                 _matchFinderType = matchFinderIndex;
1389                 if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType)
1390                 {
1391                         _dictionarySizePrev = -1;
1392                         _matchFinder = null;
1393                 }
1394                 return true;
1395         }
1396
1397         public boolean SetLcLpPb(int lc, int lp, int pb)
1398         {
1399                 if (
1400                                 lp < 0 || lp > Base.kNumLitPosStatesBitsEncodingMax ||
1401                                 lc < 0 || lc > Base.kNumLitContextBitsMax ||
1402                                 pb < 0 || pb > Base.kNumPosStatesBitsEncodingMax)
1403                         return false;
1404                 _numLiteralPosStateBits = lp;
1405                 _numLiteralContextBits = lc;
1406                 _posStateBits = pb;
1407                 _posStateMask = ((1) << _posStateBits) - 1;
1408                 return true;
1409         }
1410
1411         public void SetEndMarkerMode(boolean endMarkerMode)
1412         {
1413                 _writeEndMark = endMarkerMode;
1414         }
1415 }
1416