19 #include "../../../Common/Defs.h"
20 #include "../../Common/StreamUtils.h"
22 #include "LZMAEncoder.h"
24 // extern "C" { #include "../../../../C/7zCrc.h" }
32 // struct CCrcInit { CCrcInit() { InitCrcTable(); } } g_CrcInit;
34 const int kDefaultDictionaryLogSize = 22;
35 const UInt32 kNumFastBytesDefault = 0x20;
38 Byte g_FastPos[1 << kNumLogBits];
43 CFastPosInit() { Init(); }
46 const Byte kFastSlots = kNumLogBits * 2;
51 for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++)
53 UInt32 k = (1 << ((slotFast >> 1) - 1));
54 for (UInt32 j = 0; j < k; j++, c++)
55 g_FastPos[c] = slotFast;
61 void CLiteralEncoder2::Encode(NRangeCoder::CEncoder *rangeEncoder, Byte symbol)
68 UInt32 bit = (symbol >> i) & 1;
69 _encoders[context].Encode(rangeEncoder, bit);
70 context = (context << 1) | bit;
75 void CLiteralEncoder2::EncodeMatched(NRangeCoder::CEncoder *rangeEncoder,
76 Byte matchByte, Byte symbol)
83 UInt32 bit = (symbol >> i) & 1;
84 UInt32 matchBit = (matchByte >> i) & 1;
85 _encoders[0x100 + (matchBit << 8) + context].Encode(rangeEncoder, bit);
86 context = (context << 1) | bit;
92 UInt32 bit = (symbol >> i) & 1;
93 _encoders[context].Encode(rangeEncoder, bit);
94 context = (context << 1) | bit;
102 UInt32 CLiteralEncoder2::GetPrice(bool matchMode, Byte matchByte, Byte symbol) const
112 UInt32 matchBit = (matchByte >> i) & 1;
113 UInt32 bit = (symbol >> i) & 1;
114 price += _encoders[0x100 + (matchBit << 8) + context].GetPrice(bit);
115 context = (context << 1) | bit;
124 UInt32 bit = (symbol >> i) & 1;
125 price += _encoders[context].GetPrice(bit);
126 context = (context << 1) | bit;
134 void CEncoder::Init(UInt32 numPosStates)
138 for (UInt32 posState = 0; posState < numPosStates; posState++)
140 _lowCoder[posState].Init();
141 _midCoder[posState].Init();
146 void CEncoder::Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState)
148 if(symbol < kNumLowSymbols)
150 _choice.Encode(rangeEncoder, 0);
151 _lowCoder[posState].Encode(rangeEncoder, symbol);
155 _choice.Encode(rangeEncoder, 1);
156 if(symbol < kNumLowSymbols + kNumMidSymbols)
158 _choice2.Encode(rangeEncoder, 0);
159 _midCoder[posState].Encode(rangeEncoder, symbol - kNumLowSymbols);
163 _choice2.Encode(rangeEncoder, 1);
164 _highCoder.Encode(rangeEncoder, symbol - kNumLowSymbols - kNumMidSymbols);
169 void CEncoder::SetPrices(UInt32 posState, UInt32 numSymbols, UInt32 *prices) const
171 UInt32 a0 = _choice.GetPrice0();
172 UInt32 a1 = _choice.GetPrice1();
173 UInt32 b0 = a1 + _choice2.GetPrice0();
174 UInt32 b1 = a1 + _choice2.GetPrice1();
176 for (i = 0; i < kNumLowSymbols; i++)
180 prices[i] = a0 + _lowCoder[posState].GetPrice(i);
182 for (; i < kNumLowSymbols + kNumMidSymbols; i++)
186 prices[i] = b0 + _midCoder[posState].GetPrice(i - kNumLowSymbols);
188 for (; i < numSymbols; i++)
189 prices[i] = b1 + _highCoder.GetPrice(i - kNumLowSymbols - kNumMidSymbols);
194 CEncoder::CEncoder():
195 _numFastBytes(kNumFastBytesDefault),
196 _distTableSize(kDefaultDictionaryLogSize * 2),
198 _posStateMask(4 - 1),
199 _numLiteralPosStateBits(0),
200 _numLiteralContextBits(3),
201 _dictionarySize(1 << kDefaultDictionaryLogSize),
202 _matchFinderCycles(0),
203 #ifdef COMPRESS_MF_MT
208 MatchFinder_Construct(&_matchFinderBase);
211 #ifdef COMPRESS_MF_MT
212 MatchFinderMt_Construct(&_matchFinderMt);
213 _matchFinderMt.MatchFinder = &_matchFinderBase;
218 static void *SzAlloc(size_t size) { return BigAlloc(size); }
219 static void SzFree(void *address) { BigFree(address); }
220 ISzAlloc g_Alloc = { SzAlloc, SzFree };
222 CEncoder::~CEncoder()
224 #ifdef COMPRESS_MF_MT
225 MatchFinderMt_Destruct(&_matchFinderMt, &g_Alloc);
227 MatchFinder_Free(&_matchFinderBase, &g_Alloc);
230 static const UInt32 kBigHashDicLimit = (UInt32)1 << 24;
232 HRESULT CEncoder::Create()
234 if (!_rangeEncoder.Create(1 << 20))
235 return E_OUTOFMEMORY;
236 bool btMode = (_matchFinderBase.btMode != 0);
237 #ifdef COMPRESS_MF_MT
238 _mtMode = (_multiThread && !_fastMode && btMode);
241 if (!_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits))
242 return E_OUTOFMEMORY;
244 _matchFinderBase.bigHash = (_dictionarySize > kBigHashDicLimit);
246 UInt32 numCycles = 16 + (_numFastBytes >> 1);
249 if (_matchFinderCycles != 0)
250 numCycles = _matchFinderCycles;
251 _matchFinderBase.cutValue = numCycles;
252 #ifdef COMPRESS_MF_MT
255 RINOK(MatchFinderMt_Create(&_matchFinderMt, _dictionarySize, kNumOpts, _numFastBytes, kMatchMaxLen, &g_Alloc));
256 _matchFinderObj = &_matchFinderMt;
257 MatchFinderMt_CreateVTable(&_matchFinderMt, &_matchFinder);
262 if (!MatchFinder_Create(&_matchFinderBase, _dictionarySize, kNumOpts, _numFastBytes, kMatchMaxLen, &g_Alloc))
263 return E_OUTOFMEMORY;
264 _matchFinderObj = &_matchFinderBase;
265 MatchFinder_CreateVTable(&_matchFinderBase, &_matchFinder);
270 inline wchar_t GetUpperChar(wchar_t c)
272 if (c >= 'a' && c <= 'z')
277 static int ParseMatchFinder(const wchar_t *s, int *btMode, UInt32 *numHashBytes /* , int *skipModeBits */)
279 wchar_t c = GetUpperChar(*s++);
282 if (GetUpperChar(*s++) != L'C')
284 int numHashBytesLoc = (int)(*s++ - L'0');
285 if (numHashBytesLoc < 4 || numHashBytesLoc > 4)
290 *numHashBytes = numHashBytesLoc;
296 if (GetUpperChar(*s++) != L'T')
298 int numHashBytesLoc = (int)(*s++ - L'0');
299 if (numHashBytesLoc < 2 || numHashBytesLoc > 4)
301 c = GetUpperChar(*s++);
303 int skipModeBitsLoc = 0;
307 c = GetUpperChar(*s++);
313 *numHashBytes = numHashBytesLoc;
314 // *skipModeBits = skipModeBitsLoc;
318 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
319 const PROPVARIANT *properties, UInt32 numProperties)
321 for (UInt32 i = 0; i < numProperties; i++)
323 const PROPVARIANT &prop = properties[i];
326 case NCoderPropID::kNumFastBytes:
328 if (prop.vt != VT_UI4)
330 UInt32 numFastBytes = prop.ulVal;
331 if(numFastBytes < 5 || numFastBytes > kMatchMaxLen)
333 _numFastBytes = numFastBytes;
336 case NCoderPropID::kMatchFinderCycles:
338 if (prop.vt != VT_UI4)
340 _matchFinderCycles = prop.ulVal;
343 case NCoderPropID::kAlgorithm:
345 if (prop.vt != VT_UI4)
347 UInt32 maximize = prop.ulVal;
348 _fastMode = (maximize == 0);
349 // _maxMode = (maximize >= 2);
352 case NCoderPropID::kMatchFinder:
354 if (prop.vt != VT_BSTR)
356 if (!ParseMatchFinder(prop.bstrVal, &_matchFinderBase.btMode, &_matchFinderBase.numHashBytes /* , &_matchFinderBase.skipModeBits */))
360 case NCoderPropID::kMultiThread:
362 if (prop.vt != VT_BOOL)
364 #ifdef COMPRESS_MF_MT
365 Bool newMultiThread = (prop.boolVal == VARIANT_TRUE);
366 if (newMultiThread != _multiThread)
368 ReleaseMatchFinder();
369 _multiThread = newMultiThread;
374 case NCoderPropID::kNumThreads:
376 if (prop.vt != VT_UI4)
378 #ifdef COMPRESS_MF_MT
379 Bool newMultiThread = (prop.ulVal > 1) ? True : False;
380 if (newMultiThread != _multiThread)
382 ReleaseMatchFinder();
383 _multiThread = newMultiThread;
388 case NCoderPropID::kDictionarySize:
390 const int kDicLogSizeMaxCompress = 30; // must be <= ((kNumLogBits - 1) * 2) + 7 = 31;
391 if (prop.vt != VT_UI4)
393 UInt32 dictionarySize = prop.ulVal;
394 if (dictionarySize < UInt32(1 << kDicLogSizeMin) ||
395 dictionarySize > UInt32(1 << kDicLogSizeMaxCompress))
397 _dictionarySize = dictionarySize;
399 for(dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++)
400 if (dictionarySize <= (UInt32(1) << dicLogSize))
402 _distTableSize = dicLogSize * 2;
405 case NCoderPropID::kPosStateBits:
407 if (prop.vt != VT_UI4)
409 UInt32 value = prop.ulVal;
410 if (value > (UInt32)NLength::kNumPosStatesBitsEncodingMax)
412 _posStateBits = value;
413 _posStateMask = (1 << _posStateBits) - 1;
416 case NCoderPropID::kLitPosBits:
418 if (prop.vt != VT_UI4)
420 UInt32 value = prop.ulVal;
421 if (value > (UInt32)kNumLitPosStatesBitsEncodingMax)
423 _numLiteralPosStateBits = value;
426 case NCoderPropID::kLitContextBits:
428 if (prop.vt != VT_UI4)
430 UInt32 value = prop.ulVal;
431 if (value > (UInt32)kNumLitContextBitsMax)
433 _numLiteralContextBits = value;
436 case NCoderPropID::kEndMarker:
438 if (prop.vt != VT_BOOL)
440 SetWriteEndMarkerMode(prop.boolVal == VARIANT_TRUE);
450 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
452 const UInt32 kPropSize = 5;
453 Byte properties[kPropSize];
454 properties[0] = (Byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
455 for (int i = 0; i < 4; i++)
456 properties[1 + i] = Byte(_dictionarySize >> (8 * i));
457 return WriteStream(outStream, properties, kPropSize, NULL);
460 STDMETHODIMP CEncoder::SetOutStream(ISequentialOutStream *outStream)
462 _rangeEncoder.SetStream(outStream);
466 STDMETHODIMP CEncoder::ReleaseOutStream()
468 _rangeEncoder.ReleaseStream();
472 HRESULT CEncoder::Init()
476 _rangeEncoder.Init();
478 for(int i = 0; i < kNumStates; i++)
480 for (UInt32 j = 0; j <= _posStateMask; j++)
482 _isMatch[i][j].Init();
483 _isRep0Long[i][j].Init();
491 _literalEncoder.Init();
494 for(UInt32 i = 0; i < kNumLenToPosStates; i++)
495 _posSlotEncoder[i].Init();
498 for(UInt32 i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
499 _posEncoders[i].Init();
502 _lenEncoder.Init(1 << _posStateBits);
503 _repMatchLenEncoder.Init(1 << _posStateBits);
505 _posAlignEncoder.Init();
507 _longestMatchWasFound = false;
508 _optimumEndIndex = 0;
509 _optimumCurrentIndex = 0;
510 _additionalOffset = 0;
519 void CEncoder::MovePos(UInt32 num)
523 printf("\n MovePos %d", num);
527 _additionalOffset += num;
528 _matchFinder.Skip(_matchFinderObj, num);
532 UInt32 CEncoder::Backward(UInt32 &backRes, UInt32 cur)
534 _optimumEndIndex = cur;
535 UInt32 posMem = _optimum[cur].PosPrev;
536 UInt32 backMem = _optimum[cur].BackPrev;
539 if (_optimum[cur].Prev1IsChar)
541 _optimum[posMem].MakeAsChar();
542 _optimum[posMem].PosPrev = posMem - 1;
543 if (_optimum[cur].Prev2)
545 _optimum[posMem - 1].Prev1IsChar = false;
546 _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
547 _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
550 UInt32 posPrev = posMem;
551 UInt32 backCur = backMem;
553 backMem = _optimum[posPrev].BackPrev;
554 posMem = _optimum[posPrev].PosPrev;
556 _optimum[posPrev].BackPrev = backCur;
557 _optimum[posPrev].PosPrev = cur;
561 backRes = _optimum[0].BackPrev;
562 _optimumCurrentIndex = _optimum[0].PosPrev;
563 return _optimumCurrentIndex;
568 (lenRes == 1) && (backRes == 0xFFFFFFFF) means Literal
571 UInt32 CEncoder::GetOptimum(UInt32 position, UInt32 &backRes)
573 if(_optimumEndIndex != _optimumCurrentIndex)
575 const COptimal &optimum = _optimum[_optimumCurrentIndex];
576 UInt32 lenRes = optimum.PosPrev - _optimumCurrentIndex;
577 backRes = optimum.BackPrev;
578 _optimumCurrentIndex = optimum.PosPrev;
581 _optimumCurrentIndex = _optimumEndIndex = 0;
583 UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes(_matchFinderObj);
585 UInt32 lenMain, numDistancePairs;
586 if (!_longestMatchWasFound)
588 lenMain = ReadMatchDistances(numDistancePairs);
592 lenMain = _longestMatchLength;
593 numDistancePairs = _numDistancePairs;
594 _longestMatchWasFound = false;
597 const Byte *data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
598 if (numAvailableBytes < 2)
600 backRes = (UInt32)(-1);
603 if (numAvailableBytes > kMatchMaxLen)
604 numAvailableBytes = kMatchMaxLen;
606 UInt32 reps[kNumRepDistances];
607 UInt32 repLens[kNumRepDistances];
608 UInt32 repMaxIndex = 0;
610 for(i = 0; i < kNumRepDistances; i++)
612 reps[i] = _repDistances[i];
613 const Byte *data2 = data - (reps[i] + 1);
614 if (data[0] != data2[0] || data[1] != data2[1])
620 for (lenTest = 2; lenTest < numAvailableBytes && data[lenTest] == data2[lenTest]; lenTest++);
621 repLens[i] = lenTest;
622 if (lenTest > repLens[repMaxIndex])
625 if(repLens[repMaxIndex] >= _numFastBytes)
627 backRes = repMaxIndex;
628 UInt32 lenRes = repLens[repMaxIndex];
633 UInt32 *matchDistances = _matchDistances;
634 if(lenMain >= _numFastBytes)
636 backRes = matchDistances[numDistancePairs - 1] + kNumRepDistances;
637 MovePos(lenMain - 1);
640 Byte currentByte = *data;
641 Byte matchByte = *(data - (reps[0] + 1));
643 if(lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
645 backRes = (UInt32)-1;
649 _optimum[0].State = _state;
651 UInt32 posState = (position & _posStateMask);
653 _optimum[1].Price = _isMatch[_state.Index][posState].GetPrice0() +
654 _literalEncoder.GetSubCoder(position, _previousByte)->GetPrice(!_state.IsCharState(), matchByte, currentByte);
655 _optimum[1].MakeAsChar();
657 UInt32 matchPrice = _isMatch[_state.Index][posState].GetPrice1();
658 UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1();
660 if(matchByte == currentByte)
662 UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
663 if(shortRepPrice < _optimum[1].Price)
665 _optimum[1].Price = shortRepPrice;
666 _optimum[1].MakeAsShortRep();
669 UInt32 lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
673 backRes = _optimum[1].BackPrev;
677 _optimum[1].PosPrev = 0;
678 for (i = 0; i < kNumRepDistances; i++)
679 _optimum[0].Backs[i] = reps[i];
683 _optimum[len--].Price = kIfinityPrice;
686 for(i = 0; i < kNumRepDistances; i++)
688 UInt32 repLen = repLens[i];
691 UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState);
694 UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
695 COptimal &optimum = _optimum[repLen];
696 if (curAndLenPrice < optimum.Price)
698 optimum.Price = curAndLenPrice;
700 optimum.BackPrev = i;
701 optimum.Prev1IsChar = false;
704 while(--repLen >= 2);
707 UInt32 normalMatchPrice = matchPrice + _isRep[_state.Index].GetPrice0();
709 len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
713 while (len > matchDistances[offs])
717 UInt32 distance = matchDistances[offs + 1];
718 UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
719 COptimal &optimum = _optimum[len];
720 if (curAndLenPrice < optimum.Price)
722 optimum.Price = curAndLenPrice;
724 optimum.BackPrev = distance + kNumRepDistances;
725 optimum.Prev1IsChar = false;
727 if (len == matchDistances[offs])
730 if (offs == numDistancePairs)
743 return Backward(backRes, cur);
745 UInt32 numAvailableBytesFull = _matchFinder.GetNumAvailableBytes(_matchFinderObj);
746 UInt32 newLen, numDistancePairs;
747 newLen = ReadMatchDistances(numDistancePairs);
748 if(newLen >= _numFastBytes)
750 _numDistancePairs = numDistancePairs;
751 _longestMatchLength = newLen;
752 _longestMatchWasFound = true;
753 return Backward(backRes, cur);
756 COptimal &curOptimum = _optimum[cur];
757 UInt32 posPrev = curOptimum.PosPrev;
759 if (curOptimum.Prev1IsChar)
762 if (curOptimum.Prev2)
764 state = _optimum[curOptimum.PosPrev2].State;
765 if (curOptimum.BackPrev2 < kNumRepDistances)
771 state = _optimum[posPrev].State;
775 state = _optimum[posPrev].State;
776 if (posPrev == cur - 1)
778 if (curOptimum.IsShortRep())
779 state.UpdateShortRep();
786 if (curOptimum.Prev1IsChar && curOptimum.Prev2)
788 posPrev = curOptimum.PosPrev2;
789 pos = curOptimum.BackPrev2;
794 pos = curOptimum.BackPrev;
795 if (pos < kNumRepDistances)
800 const COptimal &prevOptimum = _optimum[posPrev];
801 if (pos < kNumRepDistances)
803 reps[0] = prevOptimum.Backs[pos];
805 for(i = 1; i <= pos; i++)
806 reps[i] = prevOptimum.Backs[i - 1];
807 for(; i < kNumRepDistances; i++)
808 reps[i] = prevOptimum.Backs[i];
812 reps[0] = (pos - kNumRepDistances);
813 for(UInt32 i = 1; i < kNumRepDistances; i++)
814 reps[i] = prevOptimum.Backs[i - 1];
817 curOptimum.State = state;
818 for(UInt32 i = 0; i < kNumRepDistances; i++)
819 curOptimum.Backs[i] = reps[i];
820 UInt32 curPrice = curOptimum.Price;
821 const Byte *data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
822 const Byte currentByte = *data;
823 const Byte matchByte = *(data - (reps[0] + 1));
825 UInt32 posState = (position & _posStateMask);
827 UInt32 curAnd1Price = curPrice +
828 _isMatch[state.Index][posState].GetPrice0() +
829 _literalEncoder.GetSubCoder(position, *(data - 1))->GetPrice(!state.IsCharState(), matchByte, currentByte);
831 COptimal &nextOptimum = _optimum[cur + 1];
833 bool nextIsChar = false;
834 if (curAnd1Price < nextOptimum.Price)
836 nextOptimum.Price = curAnd1Price;
837 nextOptimum.PosPrev = cur;
838 nextOptimum.MakeAsChar();
842 UInt32 matchPrice = curPrice + _isMatch[state.Index][posState].GetPrice1();
843 UInt32 repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1();
845 if(matchByte == currentByte &&
846 !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
848 UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
849 if(shortRepPrice <= nextOptimum.Price)
851 nextOptimum.Price = shortRepPrice;
852 nextOptimum.PosPrev = cur;
853 nextOptimum.MakeAsShortRep();
858 if(newLen == 2 && matchDistances[2] >= kDistLimit2) // test it maybe set 2000 ?
862 numAvailableBytesFull = MyMin(kNumOpts - 1 - cur, numAvailableBytesFull);
863 UInt32 numAvailableBytes = numAvailableBytesFull;
865 if (numAvailableBytes < 2)
867 if (numAvailableBytes > _numFastBytes)
868 numAvailableBytes = _numFastBytes;
869 if (!nextIsChar && matchByte != currentByte) // speed optimization
871 // try Literal + rep0
872 const Byte *data2 = data - (reps[0] + 1);
873 UInt32 limit = MyMin(numAvailableBytesFull, _numFastBytes + 1);
875 for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
876 UInt32 lenTest2 = temp - 1;
879 CState state2 = state;
881 UInt32 posStateNext = (position + 1) & _posStateMask;
882 UInt32 nextRepMatchPrice = curAnd1Price +
883 _isMatch[state2.Index][posStateNext].GetPrice1() +
884 _isRep[state2.Index].GetPrice1();
885 // for (; lenTest2 >= 2; lenTest2--)
887 UInt32 offset = cur + 1 + lenTest2;
888 while(lenEnd < offset)
889 _optimum[++lenEnd].Price = kIfinityPrice;
890 UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
891 0, lenTest2, state2, posStateNext);
892 COptimal &optimum = _optimum[offset];
893 if (curAndLenPrice < optimum.Price)
895 optimum.Price = curAndLenPrice;
896 optimum.PosPrev = cur + 1;
897 optimum.BackPrev = 0;
898 optimum.Prev1IsChar = true;
899 optimum.Prev2 = false;
905 UInt32 startLen = 2; // speed optimization
906 for(UInt32 repIndex = 0; repIndex < kNumRepDistances; repIndex++)
908 // UInt32 repLen = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], newLen); // test it;
909 const Byte *data2 = data - (reps[repIndex] + 1);
910 if (data[0] != data2[0] || data[1] != data2[1])
913 for (lenTest = 2; lenTest < numAvailableBytes && data[lenTest] == data2[lenTest]; lenTest++);
914 while(lenEnd < cur + lenTest)
915 _optimum[++lenEnd].Price = kIfinityPrice;
916 UInt32 lenTestTemp = lenTest;
917 UInt32 price = repMatchPrice + GetPureRepPrice(repIndex, state, posState);
920 UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(lenTest - 2, posState);
921 COptimal &optimum = _optimum[cur + lenTest];
922 if (curAndLenPrice < optimum.Price)
924 optimum.Price = curAndLenPrice;
925 optimum.PosPrev = cur;
926 optimum.BackPrev = repIndex;
927 optimum.Prev1IsChar = false;
930 while(--lenTest >= 2);
931 lenTest = lenTestTemp;
934 startLen = lenTest + 1;
938 UInt32 lenTest2 = lenTest + 1;
939 UInt32 limit = MyMin(numAvailableBytesFull, lenTest2 + _numFastBytes);
940 for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
941 lenTest2 -= lenTest + 1;
944 CState state2 = state;
946 UInt32 posStateNext = (position + lenTest) & _posStateMask;
947 UInt32 curAndLenCharPrice =
948 price + _repMatchLenEncoder.GetPrice(lenTest - 2, posState) +
949 _isMatch[state2.Index][posStateNext].GetPrice0() +
950 _literalEncoder.GetSubCoder(position + lenTest, data[lenTest - 1])->GetPrice(
951 true, data2[lenTest], data[lenTest]);
953 posStateNext = (position + lenTest + 1) & _posStateMask;
954 UInt32 nextRepMatchPrice = curAndLenCharPrice +
955 _isMatch[state2.Index][posStateNext].GetPrice1() +
956 _isRep[state2.Index].GetPrice1();
958 // for(; lenTest2 >= 2; lenTest2--)
960 UInt32 offset = cur + lenTest + 1 + lenTest2;
961 while(lenEnd < offset)
962 _optimum[++lenEnd].Price = kIfinityPrice;
963 UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
964 0, lenTest2, state2, posStateNext);
965 COptimal &optimum = _optimum[offset];
966 if (curAndLenPrice < optimum.Price)
968 optimum.Price = curAndLenPrice;
969 optimum.PosPrev = cur + lenTest + 1;
970 optimum.BackPrev = 0;
971 optimum.Prev1IsChar = true;
972 optimum.Prev2 = true;
973 optimum.PosPrev2 = cur;
974 optimum.BackPrev2 = repIndex;
981 // for(UInt32 lenTest = 2; lenTest <= newLen; lenTest++)
982 if (newLen > numAvailableBytes)
984 newLen = numAvailableBytes;
985 for (numDistancePairs = 0; newLen > matchDistances[numDistancePairs]; numDistancePairs += 2);
986 matchDistances[numDistancePairs] = newLen;
987 numDistancePairs += 2;
989 if (newLen >= startLen)
991 UInt32 normalMatchPrice = matchPrice + _isRep[state.Index].GetPrice0();
992 while(lenEnd < cur + newLen)
993 _optimum[++lenEnd].Price = kIfinityPrice;
996 while(startLen > matchDistances[offs])
998 UInt32 curBack = matchDistances[offs + 1];
999 UInt32 posSlot = GetPosSlot2(curBack);
1000 for(UInt32 lenTest = /*2*/ startLen; ; lenTest++)
1002 UInt32 curAndLenPrice = normalMatchPrice;
1003 UInt32 lenToPosState = GetLenToPosState(lenTest);
1004 if (curBack < kNumFullDistances)
1005 curAndLenPrice += _distancesPrices[lenToPosState][curBack];
1007 curAndLenPrice += _posSlotPrices[lenToPosState][posSlot] + _alignPrices[curBack & kAlignMask];
1009 curAndLenPrice += _lenEncoder.GetPrice(lenTest - kMatchMinLen, posState);
1011 COptimal &optimum = _optimum[cur + lenTest];
1012 if (curAndLenPrice < optimum.Price)
1014 optimum.Price = curAndLenPrice;
1015 optimum.PosPrev = cur;
1016 optimum.BackPrev = curBack + kNumRepDistances;
1017 optimum.Prev1IsChar = false;
1020 if (/*_maxMode && */lenTest == matchDistances[offs])
1022 // Try Match + Literal + Rep0
1023 const Byte *data2 = data - (curBack + 1);
1024 UInt32 lenTest2 = lenTest + 1;
1025 UInt32 limit = MyMin(numAvailableBytesFull, lenTest2 + _numFastBytes);
1026 for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
1027 lenTest2 -= lenTest + 1;
1030 CState state2 = state;
1031 state2.UpdateMatch();
1032 UInt32 posStateNext = (position + lenTest) & _posStateMask;
1033 UInt32 curAndLenCharPrice = curAndLenPrice +
1034 _isMatch[state2.Index][posStateNext].GetPrice0() +
1035 _literalEncoder.GetSubCoder(position + lenTest, data[lenTest - 1])->GetPrice(
1036 true, data2[lenTest], data[lenTest]);
1037 state2.UpdateChar();
1038 posStateNext = (posStateNext + 1) & _posStateMask;
1039 UInt32 nextRepMatchPrice = curAndLenCharPrice +
1040 _isMatch[state2.Index][posStateNext].GetPrice1() +
1041 _isRep[state2.Index].GetPrice1();
1043 // for(; lenTest2 >= 2; lenTest2--)
1045 UInt32 offset = cur + lenTest + 1 + lenTest2;
1046 while(lenEnd < offset)
1047 _optimum[++lenEnd].Price = kIfinityPrice;
1048 UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
1049 COptimal &optimum = _optimum[offset];
1050 if (curAndLenPrice < optimum.Price)
1052 optimum.Price = curAndLenPrice;
1053 optimum.PosPrev = cur + lenTest + 1;
1054 optimum.BackPrev = 0;
1055 optimum.Prev1IsChar = true;
1056 optimum.Prev2 = true;
1057 optimum.PosPrev2 = cur;
1058 optimum.BackPrev2 = curBack + kNumRepDistances;
1063 if (offs == numDistancePairs)
1065 curBack = matchDistances[offs + 1];
1066 if (curBack >= kNumFullDistances)
1067 posSlot = GetPosSlot2(curBack);
1074 static inline bool ChangePair(UInt32 smallDist, UInt32 bigDist)
1076 return ((bigDist >> 7) > smallDist);
1079 UInt32 CEncoder::ReadMatchDistances(UInt32 &numDistancePairs)
1082 numDistancePairs = _matchFinder.GetMatches(_matchFinderObj, _matchDistances);
1084 printf("\n i = %d numPairs = %d ", ttt, numDistancePairs / 2);
1089 for (UInt32 i = 0; i < numDistancePairs; i += 2)
1090 printf("%2d %6d | ", _matchDistances[i], _matchDistances[i + 1]);
1092 if (numDistancePairs > 0)
1094 lenRes = _matchDistances[numDistancePairs - 2];
1095 if (lenRes == _numFastBytes)
1097 UInt32 numAvail = _matchFinder.GetNumAvailableBytes(_matchFinderObj) + 1;
1098 const Byte *pby = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
1099 UInt32 distance = _matchDistances[numDistancePairs - 1] + 1;
1100 if (numAvail > kMatchMaxLen)
1101 numAvail = kMatchMaxLen;
1103 const Byte *pby2 = pby - distance;
1104 for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
1107 _additionalOffset++;
1111 UInt32 CEncoder::GetOptimumFast(UInt32 &backRes)
1113 UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes(_matchFinderObj);
1114 UInt32 lenMain, numDistancePairs;
1115 if (!_longestMatchWasFound)
1117 lenMain = ReadMatchDistances(numDistancePairs);
1121 lenMain = _longestMatchLength;
1122 numDistancePairs = _numDistancePairs;
1123 _longestMatchWasFound = false;
1126 const Byte *data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
1127 if (numAvailableBytes > kMatchMaxLen)
1128 numAvailableBytes = kMatchMaxLen;
1129 if (numAvailableBytes < 2)
1131 backRes = (UInt32)(-1);
1135 UInt32 repLens[kNumRepDistances];
1136 UInt32 repMaxIndex = 0;
1138 for(UInt32 i = 0; i < kNumRepDistances; i++)
1140 const Byte *data2 = data - (_repDistances[i] + 1);
1141 if (data[0] != data2[0] || data[1] != data2[1])
1147 for (len = 2; len < numAvailableBytes && data[len] == data2[len]; len++);
1148 if(len >= _numFastBytes)
1155 if (len > repLens[repMaxIndex])
1158 UInt32 *matchDistances = _matchDistances;
1159 if(lenMain >= _numFastBytes)
1161 backRes = matchDistances[numDistancePairs - 1] + kNumRepDistances;
1162 MovePos(lenMain - 1);
1166 UInt32 backMain = 0; // for GCC
1169 backMain = matchDistances[numDistancePairs - 1];
1170 while (numDistancePairs > 2 && lenMain == matchDistances[numDistancePairs - 4] + 1)
1172 if (!ChangePair(matchDistances[numDistancePairs - 3], backMain))
1174 numDistancePairs -= 2;
1175 lenMain = matchDistances[numDistancePairs - 2];
1176 backMain = matchDistances[numDistancePairs - 1];
1178 if (lenMain == 2 && backMain >= 0x80)
1182 if (repLens[repMaxIndex] >= 2)
1184 if (repLens[repMaxIndex] + 1 >= lenMain ||
1185 repLens[repMaxIndex] + 2 >= lenMain && (backMain > (1 << 9)) ||
1186 repLens[repMaxIndex] + 3 >= lenMain && (backMain > (1 << 15)))
1188 backRes = repMaxIndex;
1189 UInt32 lenRes = repLens[repMaxIndex];
1190 MovePos(lenRes - 1);
1195 if (lenMain >= 2 && numAvailableBytes > 2)
1197 numAvailableBytes = _matchFinder.GetNumAvailableBytes(_matchFinderObj);
1198 _longestMatchLength = ReadMatchDistances(_numDistancePairs);
1199 if (_longestMatchLength >= 2)
1201 UInt32 newDistance = matchDistances[_numDistancePairs - 1];
1202 if (_longestMatchLength >= lenMain && newDistance < backMain ||
1203 _longestMatchLength == lenMain + 1 && !ChangePair(backMain, newDistance) ||
1204 _longestMatchLength > lenMain + 1 ||
1205 _longestMatchLength + 1 >= lenMain && lenMain >= 3 && ChangePair(newDistance, backMain))
1207 _longestMatchWasFound = true;
1208 backRes = UInt32(-1);
1212 data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
1213 for(UInt32 i = 0; i < kNumRepDistances; i++)
1215 const Byte *data2 = data - (_repDistances[i] + 1);
1216 if (data[1] != data2[1] || data[2] != data2[2])
1222 for (len = 2; len < numAvailableBytes && data[len] == data2[len]; len++);
1223 if (len + 1 >= lenMain)
1225 _longestMatchWasFound = true;
1226 backRes = UInt32(-1);
1230 backRes = backMain + kNumRepDistances;
1231 MovePos(lenMain - 2);
1234 backRes = UInt32(-1);
1238 HRESULT CEncoder::Flush(UInt32 nowPos)
1240 // ReleaseMFStream();
1241 if (_matchFinderBase.result != SZ_OK)
1242 return _matchFinderBase.result;
1243 WriteEndMarker(nowPos & _posStateMask);
1244 _rangeEncoder.FlushData();
1245 return _rangeEncoder.FlushStream();
1248 void CEncoder::WriteEndMarker(UInt32 posState)
1250 // This function for writing End Mark for stream version of LZMA.
1251 // In current version this feature is not used.
1255 _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
1256 _isRep[_state.Index].Encode(&_rangeEncoder, 0);
1257 _state.UpdateMatch();
1258 UInt32 len = kMatchMinLen; // kMatchMaxLen;
1259 _lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
1260 UInt32 posSlot = (1 << kNumPosSlotBits) - 1;
1261 UInt32 lenToPosState = GetLenToPosState(len);
1262 _posSlotEncoder[lenToPosState].Encode(&_rangeEncoder, posSlot);
1263 UInt32 footerBits = 30;
1264 UInt32 posReduced = (UInt32(1) << footerBits) - 1;
1265 _rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
1266 _posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
1269 HRESULT CEncoder::CodeReal(ISequentialInStream *inStream,
1270 ISequentialOutStream *outStream,
1271 const UInt64 *inSize, const UInt64 *outSize,
1272 ICompressProgressInfo *progress)
1274 // _needReleaseMFStream = false;
1275 #ifdef COMPRESS_MF_MT
1280 CCoderReleaser coderReleaser(this);
1281 RINOK(SetStreams(inStream, outStream, inSize, outSize));
1284 UInt64 processedInSize;
1285 UInt64 processedOutSize;
1287 RINOK(CodeOneBlock(&processedInSize, &processedOutSize, &finished));
1292 RINOK(progress->SetRatioInfo(&processedInSize, &processedOutSize));
1298 HRESULT CEncoder::SetStreams(ISequentialInStream *inStream,
1299 ISequentialOutStream *outStream,
1300 const UInt64 * /* inSize */, const UInt64 * /* outSize */)
1302 _inStream = inStream;
1305 RINOK(SetOutStream(outStream));
1310 FillDistancesPrices();
1314 _lenEncoder.SetTableSize(_numFastBytes + 1 - kMatchMinLen);
1315 _lenEncoder.UpdateTables(1 << _posStateBits);
1316 _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - kMatchMinLen);
1317 _repMatchLenEncoder.UpdateTables(1 << _posStateBits);
1323 static HRes MyRead(void *object, void *data, UInt32 size, UInt32 *processedSize)
1325 return (HRes)((CSeqInStream *)object)->RealStream->Read(data, size, processedSize);
1328 HRESULT CEncoder::CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished)
1332 _seqInStream.RealStream = _inStream;
1333 _seqInStream.SeqInStream.Read = MyRead;
1334 _matchFinderBase.stream = &_seqInStream.SeqInStream;
1335 _matchFinder.Init(_matchFinderObj);
1336 _needReleaseMFStream = true;
1343 return _matchFinderBase.result;
1348 if (_matchFinder.GetNumAvailableBytes(_matchFinderObj) == 0)
1349 return Flush((UInt32)nowPos64);
1350 UInt32 len, numDistancePairs;
1351 len = ReadMatchDistances(numDistancePairs);
1352 UInt32 posState = UInt32(nowPos64) & _posStateMask;
1353 _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
1354 _state.UpdateChar();
1355 Byte curByte = _matchFinder.GetIndexByte(_matchFinderObj, 0 - _additionalOffset);
1356 _literalEncoder.GetSubCoder(UInt32(nowPos64), _previousByte)->Encode(&_rangeEncoder, curByte);
1357 _previousByte = curByte;
1358 _additionalOffset--;
1362 UInt32 nowPos32 = (UInt32)nowPos64;
1363 UInt32 progressPosValuePrev = nowPos32;
1365 if (_matchFinder.GetNumAvailableBytes(_matchFinderObj) == 0)
1366 return Flush(nowPos32);
1370 #ifdef _NO_EXCEPTIONS
1371 if (_rangeEncoder.Stream.ErrorCode != S_OK)
1372 return _rangeEncoder.Stream.ErrorCode;
1377 len = GetOptimumFast(pos);
1379 len = GetOptimum(nowPos32, pos);
1381 UInt32 posState = nowPos32 & _posStateMask;
1382 if(len == 1 && pos == 0xFFFFFFFF)
1384 _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
1385 Byte curByte = _matchFinder.GetIndexByte(_matchFinderObj, 0 - _additionalOffset);
1386 CLiteralEncoder2 *subCoder = _literalEncoder.GetSubCoder(nowPos32, _previousByte);
1387 if(_state.IsCharState())
1388 subCoder->Encode(&_rangeEncoder, curByte);
1391 Byte matchByte = _matchFinder.GetIndexByte(_matchFinderObj, 0 - _repDistances[0] - 1 - _additionalOffset);
1392 subCoder->EncodeMatched(&_rangeEncoder, matchByte, curByte);
1394 _state.UpdateChar();
1395 _previousByte = curByte;
1399 _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
1400 if(pos < kNumRepDistances)
1402 _isRep[_state.Index].Encode(&_rangeEncoder, 1);
1405 _isRepG0[_state.Index].Encode(&_rangeEncoder, 0);
1406 _isRep0Long[_state.Index][posState].Encode(&_rangeEncoder, ((len == 1) ? 0 : 1));
1410 UInt32 distance = _repDistances[pos];
1411 _isRepG0[_state.Index].Encode(&_rangeEncoder, 1);
1413 _isRepG1[_state.Index].Encode(&_rangeEncoder, 0);
1416 _isRepG1[_state.Index].Encode(&_rangeEncoder, 1);
1417 _isRepG2[_state.Index].Encode(&_rangeEncoder, pos - 2);
1419 _repDistances[3] = _repDistances[2];
1420 _repDistances[2] = _repDistances[1];
1422 _repDistances[1] = _repDistances[0];
1423 _repDistances[0] = distance;
1426 _state.UpdateShortRep();
1429 _repMatchLenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
1435 _isRep[_state.Index].Encode(&_rangeEncoder, 0);
1436 _state.UpdateMatch();
1437 _lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
1438 pos -= kNumRepDistances;
1439 UInt32 posSlot = GetPosSlot(pos);
1440 _posSlotEncoder[GetLenToPosState(len)].Encode(&_rangeEncoder, posSlot);
1442 if (posSlot >= kStartPosModelIndex)
1444 UInt32 footerBits = ((posSlot >> 1) - 1);
1445 UInt32 base = ((2 | (posSlot & 1)) << footerBits);
1446 UInt32 posReduced = pos - base;
1448 if (posSlot < kEndPosModelIndex)
1449 NRangeCoder::ReverseBitTreeEncode(_posEncoders + base - posSlot - 1,
1450 &_rangeEncoder, footerBits, posReduced);
1453 _rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
1454 _posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
1458 _repDistances[3] = _repDistances[2];
1459 _repDistances[2] = _repDistances[1];
1460 _repDistances[1] = _repDistances[0];
1461 _repDistances[0] = pos;
1464 _previousByte = _matchFinder.GetIndexByte(_matchFinderObj, len - 1 - _additionalOffset);
1466 _additionalOffset -= len;
1468 if (_additionalOffset == 0)
1472 if (_matchPriceCount >= (1 << 7))
1473 FillDistancesPrices();
1474 if (_alignPriceCount >= kAlignTableSize)
1477 if (_matchFinder.GetNumAvailableBytes(_matchFinderObj) == 0)
1478 return Flush(nowPos32);
1479 if (nowPos32 - progressPosValuePrev >= (1 << 14))
1481 nowPos64 += nowPos32 - progressPosValuePrev;
1483 *outSize = _rangeEncoder.GetProcessedSize();
1486 return _matchFinderBase.result;
1492 STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream,
1493 ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
1494 ICompressProgressInfo *progress)
1496 #ifndef _NO_EXCEPTIONS
1500 return CodeReal(inStream, outStream, inSize, outSize, progress);
1501 #ifndef _NO_EXCEPTIONS
1503 catch(const COutBufferException &e) { return e.ErrorCode; }
1504 catch(...) { return E_FAIL; }
1508 void CEncoder::FillDistancesPrices()
1510 UInt32 tempPrices[kNumFullDistances];
1511 for (UInt32 i = kStartPosModelIndex; i < kNumFullDistances; i++)
1513 UInt32 posSlot = GetPosSlot(i);
1514 UInt32 footerBits = ((posSlot >> 1) - 1);
1515 UInt32 base = ((2 | (posSlot & 1)) << footerBits);
1516 tempPrices[i] = NRangeCoder::ReverseBitTreeGetPrice(_posEncoders +
1517 base - posSlot - 1, footerBits, i - base);
1520 for (UInt32 lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
1523 NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumPosSlotBits> &encoder = _posSlotEncoder[lenToPosState];
1524 UInt32 *posSlotPrices = _posSlotPrices[lenToPosState];
1525 for (posSlot = 0; posSlot < _distTableSize; posSlot++)
1526 posSlotPrices[posSlot] = encoder.GetPrice(posSlot);
1527 for (posSlot = kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
1528 posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << NRangeCoder::kNumBitPriceShiftBits);
1530 UInt32 *distancesPrices = _distancesPrices[lenToPosState];
1532 for (i = 0; i < kStartPosModelIndex; i++)
1533 distancesPrices[i] = posSlotPrices[i];
1534 for (; i < kNumFullDistances; i++)
1535 distancesPrices[i] = posSlotPrices[GetPosSlot(i)] + tempPrices[i];
1537 _matchPriceCount = 0;
1540 void CEncoder::FillAlignPrices()
1542 for (UInt32 i = 0; i < kAlignTableSize; i++)
1543 _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
1544 _alignPriceCount = 0;