5 #include "../../../Common/Defs.h"
\r
6 #include "../../Common/StreamUtils.h"
\r
8 #include "LZMAEncoder.h"
\r
10 // for minimal compressing code size define these:
\r
11 // #define COMPRESS_MF_BT
\r
12 // #define COMPRESS_MF_BT4
\r
14 #if !defined(COMPRESS_MF_BT) && !defined(COMPRESS_MF_HC)
\r
15 #define COMPRESS_MF_BT
\r
16 #define COMPRESS_MF_HC
\r
19 #ifdef COMPRESS_MF_BT
\r
20 #if !defined(COMPRESS_MF_BT2) && !defined(COMPRESS_MF_BT3) && !defined(COMPRESS_MF_BT4)
\r
21 #define COMPRESS_MF_BT2
\r
22 #define COMPRESS_MF_BT3
\r
23 #define COMPRESS_MF_BT4
\r
25 #ifdef COMPRESS_MF_BT2
\r
26 #include "../LZ/BinTree/BinTree2.h"
\r
28 #ifdef COMPRESS_MF_BT3
\r
29 #include "../LZ/BinTree/BinTree3.h"
\r
31 #ifdef COMPRESS_MF_BT4
\r
32 #include "../LZ/BinTree/BinTree4.h"
\r
36 #ifdef COMPRESS_MF_HC
\r
37 #include "../LZ/HashChain/HC4.h"
\r
40 #ifdef COMPRESS_MF_MT
\r
41 #include "../LZ/MT/MT.h"
\r
44 namespace NCompress {
\r
47 const int kDefaultDictionaryLogSize = 22;
\r
48 const UInt32 kNumFastBytesDefault = 0x20;
\r
58 static const wchar_t *kMatchFinderIDs[] =
\r
66 Byte g_FastPos[1 << 11];
\r
71 CFastPosInit() { Init(); }
\r
74 const Byte kFastSlots = 22;
\r
79 for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++)
\r
81 UInt32 k = (1 << ((slotFast >> 1) - 1));
\r
82 for (UInt32 j = 0; j < k; j++, c++)
\r
83 g_FastPos[c] = slotFast;
\r
89 void CLiteralEncoder2::Encode(NRangeCoder::CEncoder *rangeEncoder, Byte symbol)
\r
96 UInt32 bit = (symbol >> i) & 1;
\r
97 _encoders[context].Encode(rangeEncoder, bit);
\r
98 context = (context << 1) | bit;
\r
103 void CLiteralEncoder2::EncodeMatched(NRangeCoder::CEncoder *rangeEncoder,
\r
104 Byte matchByte, Byte symbol)
\r
106 UInt32 context = 1;
\r
111 UInt32 bit = (symbol >> i) & 1;
\r
112 UInt32 matchBit = (matchByte >> i) & 1;
\r
113 _encoders[0x100 + (matchBit << 8) + context].Encode(rangeEncoder, bit);
\r
114 context = (context << 1) | bit;
\r
115 if (matchBit != bit)
\r
120 UInt32 bit = (symbol >> i) & 1;
\r
121 _encoders[context].Encode(rangeEncoder, bit);
\r
122 context = (context << 1) | bit;
\r
130 UInt32 CLiteralEncoder2::GetPrice(bool matchMode, Byte matchByte, Byte symbol) const
\r
133 UInt32 context = 1;
\r
140 UInt32 matchBit = (matchByte >> i) & 1;
\r
141 UInt32 bit = (symbol >> i) & 1;
\r
142 price += _encoders[0x100 + (matchBit << 8) + context].GetPrice(bit);
\r
143 context = (context << 1) | bit;
\r
144 if (matchBit != bit)
\r
152 UInt32 bit = (symbol >> i) & 1;
\r
153 price += _encoders[context].GetPrice(bit);
\r
154 context = (context << 1) | bit;
\r
160 namespace NLength {
\r
162 void CEncoder::Init(UInt32 numPosStates)
\r
166 for (UInt32 posState = 0; posState < numPosStates; posState++)
\r
168 _lowCoder[posState].Init();
\r
169 _midCoder[posState].Init();
\r
174 void CEncoder::Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState)
\r
176 if(symbol < kNumLowSymbols)
\r
178 _choice.Encode(rangeEncoder, 0);
\r
179 _lowCoder[posState].Encode(rangeEncoder, symbol);
\r
183 _choice.Encode(rangeEncoder, 1);
\r
184 if(symbol < kNumLowSymbols + kNumMidSymbols)
\r
186 _choice2.Encode(rangeEncoder, 0);
\r
187 _midCoder[posState].Encode(rangeEncoder, symbol - kNumLowSymbols);
\r
191 _choice2.Encode(rangeEncoder, 1);
\r
192 _highCoder.Encode(rangeEncoder, symbol - kNumLowSymbols - kNumMidSymbols);
\r
197 void CEncoder::SetPrices(UInt32 posState, UInt32 numSymbols, UInt32 *prices) const
\r
199 UInt32 a0 = _choice.GetPrice0();
\r
200 UInt32 a1 = _choice.GetPrice1();
\r
201 UInt32 b0 = a1 + _choice2.GetPrice0();
\r
202 UInt32 b1 = a1 + _choice2.GetPrice1();
\r
204 for (i = 0; i < kNumLowSymbols; i++)
\r
206 if (i >= numSymbols)
\r
208 prices[i] = a0 + _lowCoder[posState].GetPrice(i);
\r
210 for (; i < kNumLowSymbols + kNumMidSymbols; i++)
\r
212 if (i >= numSymbols)
\r
214 prices[i] = b0 + _midCoder[posState].GetPrice(i - kNumLowSymbols);
\r
216 for (; i < numSymbols; i++)
\r
217 prices[i] = b1 + _highCoder.GetPrice(i - kNumLowSymbols - kNumMidSymbols);
\r
221 CEncoder::CEncoder():
\r
222 _numFastBytes(kNumFastBytesDefault),
\r
223 _distTableSize(kDefaultDictionaryLogSize * 2),
\r
225 _posStateMask(4 - 1),
\r
226 _numLiteralPosStateBits(0),
\r
227 _numLiteralContextBits(3),
\r
228 _dictionarySize(1 << kDefaultDictionaryLogSize),
\r
229 _dictionarySizePrev(UInt32(-1)),
\r
230 _numFastBytesPrev(UInt32(-1)),
\r
231 _matchFinderCycles(0),
\r
232 _matchFinderIndex(kBT4),
\r
233 #ifdef COMPRESS_MF_MT
\r
234 _multiThread(false),
\r
236 _writeEndMark(false),
\r
239 // _maxMode = false;
\r
243 HRESULT CEncoder::Create()
\r
245 if (!_rangeEncoder.Create(1 << 20))
\r
246 return E_OUTOFMEMORY;
\r
249 switch(_matchFinderIndex)
\r
251 #ifdef COMPRESS_MF_BT
\r
252 #ifdef COMPRESS_MF_BT2
\r
255 NBT2::CMatchFinder *mfSpec = new NBT2::CMatchFinder;
\r
256 setMfPasses = mfSpec;
\r
257 _matchFinder = mfSpec;
\r
261 #ifdef COMPRESS_MF_BT3
\r
264 NBT3::CMatchFinder *mfSpec = new NBT3::CMatchFinder;
\r
265 setMfPasses = mfSpec;
\r
266 _matchFinder = mfSpec;
\r
270 #ifdef COMPRESS_MF_BT4
\r
273 NBT4::CMatchFinder *mfSpec = new NBT4::CMatchFinder;
\r
274 setMfPasses = mfSpec;
\r
275 _matchFinder = mfSpec;
\r
281 #ifdef COMPRESS_MF_HC
\r
284 NHC4::CMatchFinder *mfSpec = new NHC4::CMatchFinder;
\r
285 setMfPasses = mfSpec;
\r
286 _matchFinder = mfSpec;
\r
291 if (_matchFinder == 0)
\r
292 return E_OUTOFMEMORY;
\r
294 #ifdef COMPRESS_MF_MT
\r
295 if (_multiThread && !(_fastMode && (_matchFinderIndex == kHC4)))
\r
297 CMatchFinderMT *mfSpec = new CMatchFinderMT;
\r
299 return E_OUTOFMEMORY;
\r
300 CMyComPtr<IMatchFinder> mf = mfSpec;
\r
301 RINOK(mfSpec->SetMatchFinder(_matchFinder));
\r
302 _matchFinder.Release();
\r
308 if (!_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits))
\r
309 return E_OUTOFMEMORY;
\r
311 if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
\r
313 RINOK(_matchFinder->Create(_dictionarySize, kNumOpts, _numFastBytes, kMatchMaxLen + 1)); // actually it's + _numFastBytes - _numFastBytes
\r
314 if (_matchFinderCycles != 0 && setMfPasses != 0)
\r
315 setMfPasses->SetNumPasses(_matchFinderCycles);
\r
316 _dictionarySizePrev = _dictionarySize;
\r
317 _numFastBytesPrev = _numFastBytes;
\r
321 static bool AreStringsEqual(const wchar_t *base, const wchar_t *testString)
\r
325 wchar_t c = *testString;
\r
326 if (c >= 'a' && c <= 'z')
\r
337 static int FindMatchFinder(const wchar_t *s)
\r
339 for (int m = 0; m < (int)(sizeof(kMatchFinderIDs) / sizeof(kMatchFinderIDs[0])); m++)
\r
340 if (AreStringsEqual(kMatchFinderIDs[m], s))
\r
345 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
\r
346 const PROPVARIANT *properties, UInt32 numProperties)
\r
348 for (UInt32 i = 0; i < numProperties; i++)
\r
350 const PROPVARIANT &prop = properties[i];
\r
353 case NCoderPropID::kNumFastBytes:
\r
355 if (prop.vt != VT_UI4)
\r
356 return E_INVALIDARG;
\r
357 UInt32 numFastBytes = prop.ulVal;
\r
358 if(numFastBytes < 5 || numFastBytes > kMatchMaxLen)
\r
359 return E_INVALIDARG;
\r
360 _numFastBytes = numFastBytes;
\r
363 case NCoderPropID::kMatchFinderCycles:
\r
365 if (prop.vt != VT_UI4)
\r
366 return E_INVALIDARG;
\r
367 _matchFinderCycles = prop.ulVal;
\r
370 case NCoderPropID::kAlgorithm:
\r
372 if (prop.vt != VT_UI4)
\r
373 return E_INVALIDARG;
\r
374 UInt32 maximize = prop.ulVal;
\r
375 _fastMode = (maximize == 0);
\r
376 // _maxMode = (maximize >= 2);
\r
379 case NCoderPropID::kMatchFinder:
\r
381 if (prop.vt != VT_BSTR)
\r
382 return E_INVALIDARG;
\r
383 int matchFinderIndexPrev = _matchFinderIndex;
\r
384 int m = FindMatchFinder(prop.bstrVal);
\r
386 return E_INVALIDARG;
\r
387 _matchFinderIndex = m;
\r
388 if (_matchFinder && matchFinderIndexPrev != _matchFinderIndex)
\r
390 _dictionarySizePrev = (UInt32)-1;
\r
391 ReleaseMatchFinder();
\r
395 #ifdef COMPRESS_MF_MT
\r
396 case NCoderPropID::kMultiThread:
\r
398 if (prop.vt != VT_BOOL)
\r
399 return E_INVALIDARG;
\r
400 bool newMultiThread = (prop.boolVal == VARIANT_TRUE);
\r
401 if (newMultiThread != _multiThread)
\r
403 _dictionarySizePrev = (UInt32)-1;
\r
404 ReleaseMatchFinder();
\r
405 _multiThread = newMultiThread;
\r
409 case NCoderPropID::kNumThreads:
\r
411 if (prop.vt != VT_UI4)
\r
412 return E_INVALIDARG;
\r
413 bool newMultiThread = (prop.ulVal > 1);
\r
414 if (newMultiThread != _multiThread)
\r
416 _dictionarySizePrev = (UInt32)-1;
\r
417 ReleaseMatchFinder();
\r
418 _multiThread = newMultiThread;
\r
423 case NCoderPropID::kDictionarySize:
\r
425 const int kDicLogSizeMaxCompress = 30;
\r
426 if (prop.vt != VT_UI4)
\r
427 return E_INVALIDARG;
\r
428 UInt32 dictionarySize = prop.ulVal;
\r
429 if (dictionarySize < UInt32(1 << kDicLogSizeMin) ||
\r
430 dictionarySize > UInt32(1 << kDicLogSizeMaxCompress))
\r
431 return E_INVALIDARG;
\r
432 _dictionarySize = dictionarySize;
\r
434 for(dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++)
\r
435 if (dictionarySize <= (UInt32(1) << dicLogSize))
\r
437 _distTableSize = dicLogSize * 2;
\r
440 case NCoderPropID::kPosStateBits:
\r
442 if (prop.vt != VT_UI4)
\r
443 return E_INVALIDARG;
\r
444 UInt32 value = prop.ulVal;
\r
445 if (value > (UInt32)NLength::kNumPosStatesBitsEncodingMax)
\r
446 return E_INVALIDARG;
\r
447 _posStateBits = value;
\r
448 _posStateMask = (1 << _posStateBits) - 1;
\r
451 case NCoderPropID::kLitPosBits:
\r
453 if (prop.vt != VT_UI4)
\r
454 return E_INVALIDARG;
\r
455 UInt32 value = prop.ulVal;
\r
456 if (value > (UInt32)kNumLitPosStatesBitsEncodingMax)
\r
457 return E_INVALIDARG;
\r
458 _numLiteralPosStateBits = value;
\r
461 case NCoderPropID::kLitContextBits:
\r
463 if (prop.vt != VT_UI4)
\r
464 return E_INVALIDARG;
\r
465 UInt32 value = prop.ulVal;
\r
466 if (value > (UInt32)kNumLitContextBitsMax)
\r
467 return E_INVALIDARG;
\r
468 _numLiteralContextBits = value;
\r
471 case NCoderPropID::kEndMarker:
\r
473 if (prop.vt != VT_BOOL)
\r
474 return E_INVALIDARG;
\r
475 SetWriteEndMarkerMode(prop.boolVal == VARIANT_TRUE);
\r
479 return E_INVALIDARG;
\r
485 STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
\r
487 const UInt32 kPropSize = 5;
\r
488 Byte properties[kPropSize];
\r
489 properties[0] = (_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits;
\r
490 for (int i = 0; i < 4; i++)
\r
491 properties[1 + i] = Byte(_dictionarySize >> (8 * i));
\r
492 return WriteStream(outStream, properties, kPropSize, NULL);
\r
495 STDMETHODIMP CEncoder::SetOutStream(ISequentialOutStream *outStream)
\r
497 _rangeEncoder.SetStream(outStream);
\r
501 STDMETHODIMP CEncoder::ReleaseOutStream()
\r
503 _rangeEncoder.ReleaseStream();
\r
507 HRESULT CEncoder::Init()
\r
509 CBaseState::Init();
\r
511 // RINOK(_matchFinder->Init(inStream));
\r
512 _rangeEncoder.Init();
\r
514 for(int i = 0; i < kNumStates; i++)
\r
516 for (UInt32 j = 0; j <= _posStateMask; j++)
\r
518 _isMatch[i][j].Init();
\r
519 _isRep0Long[i][j].Init();
\r
522 _isRepG0[i].Init();
\r
523 _isRepG1[i].Init();
\r
524 _isRepG2[i].Init();
\r
527 _literalEncoder.Init();
\r
530 for(UInt32 i = 0; i < kNumLenToPosStates; i++)
\r
531 _posSlotEncoder[i].Init();
\r
534 for(UInt32 i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
\r
535 _posEncoders[i].Init();
\r
538 _lenEncoder.Init(1 << _posStateBits);
\r
539 _repMatchLenEncoder.Init(1 << _posStateBits);
\r
541 _posAlignEncoder.Init();
\r
543 _longestMatchWasFound = false;
\r
544 _optimumEndIndex = 0;
\r
545 _optimumCurrentIndex = 0;
\r
546 _additionalOffset = 0;
\r
551 HRESULT CEncoder::MovePos(UInt32 num)
\r
555 _additionalOffset += num;
\r
556 return _matchFinder->Skip(num);
\r
559 UInt32 CEncoder::Backward(UInt32 &backRes, UInt32 cur)
\r
561 _optimumEndIndex = cur;
\r
562 UInt32 posMem = _optimum[cur].PosPrev;
\r
563 UInt32 backMem = _optimum[cur].BackPrev;
\r
566 if (_optimum[cur].Prev1IsChar)
\r
568 _optimum[posMem].MakeAsChar();
\r
569 _optimum[posMem].PosPrev = posMem - 1;
\r
570 if (_optimum[cur].Prev2)
\r
572 _optimum[posMem - 1].Prev1IsChar = false;
\r
573 _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
\r
574 _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
\r
577 UInt32 posPrev = posMem;
\r
578 UInt32 backCur = backMem;
\r
580 backMem = _optimum[posPrev].BackPrev;
\r
581 posMem = _optimum[posPrev].PosPrev;
\r
583 _optimum[posPrev].BackPrev = backCur;
\r
584 _optimum[posPrev].PosPrev = cur;
\r
588 backRes = _optimum[0].BackPrev;
\r
589 _optimumCurrentIndex = _optimum[0].PosPrev;
\r
590 return _optimumCurrentIndex;
\r
595 (lenRes == 1) && (backRes == 0xFFFFFFFF) means Literal
\r
598 HRESULT CEncoder::GetOptimum(UInt32 position, UInt32 &backRes, UInt32 &lenRes)
\r
600 if(_optimumEndIndex != _optimumCurrentIndex)
\r
602 const COptimal &optimum = _optimum[_optimumCurrentIndex];
\r
603 lenRes = optimum.PosPrev - _optimumCurrentIndex;
\r
604 backRes = optimum.BackPrev;
\r
605 _optimumCurrentIndex = optimum.PosPrev;
\r
608 _optimumCurrentIndex = _optimumEndIndex = 0;
\r
610 UInt32 lenMain, numDistancePairs;
\r
611 if (!_longestMatchWasFound)
\r
613 RINOK(ReadMatchDistances(lenMain, numDistancePairs));
\r
617 lenMain = _longestMatchLength;
\r
618 numDistancePairs = _numDistancePairs;
\r
619 _longestMatchWasFound = false;
\r
622 const Byte *data = _matchFinder->GetPointerToCurrentPos() - 1;
\r
623 UInt32 numAvailableBytes = _matchFinder->GetNumAvailableBytes() + 1;
\r
624 if (numAvailableBytes < 2)
\r
626 backRes = (UInt32)(-1);
\r
630 if (numAvailableBytes > kMatchMaxLen)
\r
631 numAvailableBytes = kMatchMaxLen;
\r
633 UInt32 reps[kNumRepDistances];
\r
634 UInt32 repLens[kNumRepDistances];
\r
635 UInt32 repMaxIndex = 0;
\r
637 for(i = 0; i < kNumRepDistances; i++)
\r
639 reps[i] = _repDistances[i];
\r
640 UInt32 backOffset = reps[i] + 1;
\r
641 if (data[0] != data[(size_t)0 - backOffset] || data[1] != data[(size_t)1 - backOffset])
\r
647 for (lenTest = 2; lenTest < numAvailableBytes &&
\r
648 data[lenTest] == data[(size_t)lenTest - backOffset]; lenTest++);
\r
649 repLens[i] = lenTest;
\r
650 if (lenTest > repLens[repMaxIndex])
\r
653 if(repLens[repMaxIndex] >= _numFastBytes)
\r
655 backRes = repMaxIndex;
\r
656 lenRes = repLens[repMaxIndex];
\r
657 return MovePos(lenRes - 1);
\r
660 UInt32 *matchDistances = _matchDistances + 1;
\r
661 if(lenMain >= _numFastBytes)
\r
663 backRes = matchDistances[numDistancePairs - 1] + kNumRepDistances;
\r
665 return MovePos(lenMain - 1);
\r
667 Byte currentByte = *data;
\r
668 Byte matchByte = data[(size_t)0 - reps[0] - 1];
\r
670 if(lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
\r
672 backRes = (UInt32)-1;
\r
677 _optimum[0].State = _state;
\r
679 UInt32 posState = (position & _posStateMask);
\r
681 _optimum[1].Price = _isMatch[_state.Index][posState].GetPrice0() +
\r
682 _literalEncoder.GetSubCoder(position, _previousByte)->GetPrice(!_state.IsCharState(), matchByte, currentByte);
\r
683 _optimum[1].MakeAsChar();
\r
685 UInt32 matchPrice = _isMatch[_state.Index][posState].GetPrice1();
\r
686 UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1();
\r
688 if(matchByte == currentByte)
\r
690 UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
\r
691 if(shortRepPrice < _optimum[1].Price)
\r
693 _optimum[1].Price = shortRepPrice;
\r
694 _optimum[1].MakeAsShortRep();
\r
697 UInt32 lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
\r
701 backRes = _optimum[1].BackPrev;
\r
706 _optimum[1].PosPrev = 0;
\r
707 for (i = 0; i < kNumRepDistances; i++)
\r
708 _optimum[0].Backs[i] = reps[i];
\r
710 UInt32 len = lenEnd;
\r
712 _optimum[len--].Price = kIfinityPrice;
\r
715 for(i = 0; i < kNumRepDistances; i++)
\r
717 UInt32 repLen = repLens[i];
\r
720 UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState);
\r
723 UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
\r
724 COptimal &optimum = _optimum[repLen];
\r
725 if (curAndLenPrice < optimum.Price)
\r
727 optimum.Price = curAndLenPrice;
\r
728 optimum.PosPrev = 0;
\r
729 optimum.BackPrev = i;
\r
730 optimum.Prev1IsChar = false;
\r
733 while(--repLen >= 2);
\r
736 UInt32 normalMatchPrice = matchPrice + _isRep[_state.Index].GetPrice0();
\r
738 len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
\r
739 if (len <= lenMain)
\r
742 while (len > matchDistances[offs])
\r
746 UInt32 distance = matchDistances[offs + 1];
\r
747 UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
\r
748 COptimal &optimum = _optimum[len];
\r
749 if (curAndLenPrice < optimum.Price)
\r
751 optimum.Price = curAndLenPrice;
\r
752 optimum.PosPrev = 0;
\r
753 optimum.BackPrev = distance + kNumRepDistances;
\r
754 optimum.Prev1IsChar = false;
\r
756 if (len == matchDistances[offs])
\r
759 if (offs == numDistancePairs)
\r
772 lenRes = Backward(backRes, cur);
\r
775 UInt32 newLen, numDistancePairs;
\r
776 RINOK(ReadMatchDistances(newLen, numDistancePairs));
\r
777 if(newLen >= _numFastBytes)
\r
779 _numDistancePairs = numDistancePairs;
\r
780 _longestMatchLength = newLen;
\r
781 _longestMatchWasFound = true;
\r
782 lenRes = Backward(backRes, cur);
\r
786 COptimal &curOptimum = _optimum[cur];
\r
787 UInt32 posPrev = curOptimum.PosPrev;
\r
789 if (curOptimum.Prev1IsChar)
\r
792 if (curOptimum.Prev2)
\r
794 state = _optimum[curOptimum.PosPrev2].State;
\r
795 if (curOptimum.BackPrev2 < kNumRepDistances)
\r
798 state.UpdateMatch();
\r
801 state = _optimum[posPrev].State;
\r
802 state.UpdateChar();
\r
805 state = _optimum[posPrev].State;
\r
806 if (posPrev == cur - 1)
\r
808 if (curOptimum.IsShortRep())
\r
809 state.UpdateShortRep();
\r
811 state.UpdateChar();
\r
816 if (curOptimum.Prev1IsChar && curOptimum.Prev2)
\r
818 posPrev = curOptimum.PosPrev2;
\r
819 pos = curOptimum.BackPrev2;
\r
824 pos = curOptimum.BackPrev;
\r
825 if (pos < kNumRepDistances)
\r
828 state.UpdateMatch();
\r
830 const COptimal &prevOptimum = _optimum[posPrev];
\r
831 if (pos < kNumRepDistances)
\r
833 reps[0] = prevOptimum.Backs[pos];
\r
835 for(i = 1; i <= pos; i++)
\r
836 reps[i] = prevOptimum.Backs[i - 1];
\r
837 for(; i < kNumRepDistances; i++)
\r
838 reps[i] = prevOptimum.Backs[i];
\r
842 reps[0] = (pos - kNumRepDistances);
\r
843 for(UInt32 i = 1; i < kNumRepDistances; i++)
\r
844 reps[i] = prevOptimum.Backs[i - 1];
\r
847 curOptimum.State = state;
\r
848 for(UInt32 i = 0; i < kNumRepDistances; i++)
\r
849 curOptimum.Backs[i] = reps[i];
\r
850 UInt32 curPrice = curOptimum.Price;
\r
851 const Byte *data = _matchFinder->GetPointerToCurrentPos() - 1;
\r
852 const Byte currentByte = *data;
\r
853 const Byte matchByte = data[(size_t)0 - reps[0] - 1];
\r
855 UInt32 posState = (position & _posStateMask);
\r
857 UInt32 curAnd1Price = curPrice +
\r
858 _isMatch[state.Index][posState].GetPrice0() +
\r
859 _literalEncoder.GetSubCoder(position, data[(size_t)0 - 1])->GetPrice(!state.IsCharState(), matchByte, currentByte);
\r
861 COptimal &nextOptimum = _optimum[cur + 1];
\r
863 bool nextIsChar = false;
\r
864 if (curAnd1Price < nextOptimum.Price)
\r
866 nextOptimum.Price = curAnd1Price;
\r
867 nextOptimum.PosPrev = cur;
\r
868 nextOptimum.MakeAsChar();
\r
872 UInt32 matchPrice = curPrice + _isMatch[state.Index][posState].GetPrice1();
\r
873 UInt32 repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1();
\r
875 if(matchByte == currentByte &&
\r
876 !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
\r
878 UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
\r
879 if(shortRepPrice <= nextOptimum.Price)
\r
881 nextOptimum.Price = shortRepPrice;
\r
882 nextOptimum.PosPrev = cur;
\r
883 nextOptimum.MakeAsShortRep();
\r
888 if(newLen == 2 && matchDistances[2] >= kDistLimit2) // test it maybe set 2000 ?
\r
892 UInt32 numAvailableBytesFull = _matchFinder->GetNumAvailableBytes() + 1;
\r
893 numAvailableBytesFull = MyMin(kNumOpts - 1 - cur, numAvailableBytesFull);
\r
894 UInt32 numAvailableBytes = numAvailableBytesFull;
\r
896 if (numAvailableBytes < 2)
\r
898 if (numAvailableBytes > _numFastBytes)
\r
899 numAvailableBytes = _numFastBytes;
\r
900 if (!nextIsChar && matchByte != currentByte) // speed optimization
\r
902 // try Literal + rep0
\r
903 UInt32 backOffset = reps[0] + 1;
\r
904 UInt32 limit = MyMin(numAvailableBytesFull, _numFastBytes + 1);
\r
906 for (temp = 1; temp < limit &&
\r
907 data[temp] == data[(size_t)temp - backOffset]; temp++);
\r
908 UInt32 lenTest2 = temp - 1;
\r
911 CState state2 = state;
\r
912 state2.UpdateChar();
\r
913 UInt32 posStateNext = (position + 1) & _posStateMask;
\r
914 UInt32 nextRepMatchPrice = curAnd1Price +
\r
915 _isMatch[state2.Index][posStateNext].GetPrice1() +
\r
916 _isRep[state2.Index].GetPrice1();
\r
917 // for (; lenTest2 >= 2; lenTest2--)
\r
919 UInt32 offset = cur + 1 + lenTest2;
\r
920 while(lenEnd < offset)
\r
921 _optimum[++lenEnd].Price = kIfinityPrice;
\r
922 UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
\r
923 0, lenTest2, state2, posStateNext);
\r
924 COptimal &optimum = _optimum[offset];
\r
925 if (curAndLenPrice < optimum.Price)
\r
927 optimum.Price = curAndLenPrice;
\r
928 optimum.PosPrev = cur + 1;
\r
929 optimum.BackPrev = 0;
\r
930 optimum.Prev1IsChar = true;
\r
931 optimum.Prev2 = false;
\r
937 UInt32 startLen = 2; // speed optimization
\r
938 for(UInt32 repIndex = 0; repIndex < kNumRepDistances; repIndex++)
\r
940 // UInt32 repLen = _matchFinder->GetMatchLen(0 - 1, reps[repIndex], newLen); // test it;
\r
941 UInt32 backOffset = reps[repIndex] + 1;
\r
942 if (data[0] != data[(size_t)0 - backOffset] ||
\r
943 data[1] != data[(size_t)1 - backOffset])
\r
946 for (lenTest = 2; lenTest < numAvailableBytes &&
\r
947 data[lenTest] == data[(size_t)lenTest - backOffset]; lenTest++);
\r
948 while(lenEnd < cur + lenTest)
\r
949 _optimum[++lenEnd].Price = kIfinityPrice;
\r
950 UInt32 lenTestTemp = lenTest;
\r
951 UInt32 price = repMatchPrice + GetPureRepPrice(repIndex, state, posState);
\r
954 UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(lenTest - 2, posState);
\r
955 COptimal &optimum = _optimum[cur + lenTest];
\r
956 if (curAndLenPrice < optimum.Price)
\r
958 optimum.Price = curAndLenPrice;
\r
959 optimum.PosPrev = cur;
\r
960 optimum.BackPrev = repIndex;
\r
961 optimum.Prev1IsChar = false;
\r
964 while(--lenTest >= 2);
\r
965 lenTest = lenTestTemp;
\r
968 startLen = lenTest + 1;
\r
972 UInt32 lenTest2 = lenTest + 1;
\r
973 UInt32 limit = MyMin(numAvailableBytesFull, lenTest2 + _numFastBytes);
\r
974 for (; lenTest2 < limit &&
\r
975 data[lenTest2] == data[(size_t)lenTest2 - backOffset]; lenTest2++);
\r
976 lenTest2 -= lenTest + 1;
\r
979 CState state2 = state;
\r
980 state2.UpdateRep();
\r
981 UInt32 posStateNext = (position + lenTest) & _posStateMask;
\r
982 UInt32 curAndLenCharPrice =
\r
983 price + _repMatchLenEncoder.GetPrice(lenTest - 2, posState) +
\r
984 _isMatch[state2.Index][posStateNext].GetPrice0() +
\r
985 _literalEncoder.GetSubCoder(position + lenTest, data[(size_t)lenTest - 1])->GetPrice(
\r
986 true, data[(size_t)lenTest - backOffset], data[lenTest]);
\r
987 state2.UpdateChar();
\r
988 posStateNext = (position + lenTest + 1) & _posStateMask;
\r
989 UInt32 nextRepMatchPrice = curAndLenCharPrice +
\r
990 _isMatch[state2.Index][posStateNext].GetPrice1() +
\r
991 _isRep[state2.Index].GetPrice1();
\r
993 // for(; lenTest2 >= 2; lenTest2--)
\r
995 UInt32 offset = cur + lenTest + 1 + lenTest2;
\r
996 while(lenEnd < offset)
\r
997 _optimum[++lenEnd].Price = kIfinityPrice;
\r
998 UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
\r
999 0, lenTest2, state2, posStateNext);
\r
1000 COptimal &optimum = _optimum[offset];
\r
1001 if (curAndLenPrice < optimum.Price)
\r
1003 optimum.Price = curAndLenPrice;
\r
1004 optimum.PosPrev = cur + lenTest + 1;
\r
1005 optimum.BackPrev = 0;
\r
1006 optimum.Prev1IsChar = true;
\r
1007 optimum.Prev2 = true;
\r
1008 optimum.PosPrev2 = cur;
\r
1009 optimum.BackPrev2 = repIndex;
\r
1016 // for(UInt32 lenTest = 2; lenTest <= newLen; lenTest++)
\r
1017 if (newLen > numAvailableBytes)
\r
1019 newLen = numAvailableBytes;
\r
1020 for (numDistancePairs = 0; newLen > matchDistances[numDistancePairs]; numDistancePairs += 2);
\r
1021 matchDistances[numDistancePairs] = newLen;
\r
1022 numDistancePairs += 2;
\r
1024 if (newLen >= startLen)
\r
1026 UInt32 normalMatchPrice = matchPrice + _isRep[state.Index].GetPrice0();
\r
1027 while(lenEnd < cur + newLen)
\r
1028 _optimum[++lenEnd].Price = kIfinityPrice;
\r
1031 while(startLen > matchDistances[offs])
\r
1033 UInt32 curBack = matchDistances[offs + 1];
\r
1034 UInt32 posSlot = GetPosSlot2(curBack);
\r
1035 for(UInt32 lenTest = /*2*/ startLen; ; lenTest++)
\r
1037 UInt32 curAndLenPrice = normalMatchPrice;
\r
1038 UInt32 lenToPosState = GetLenToPosState(lenTest);
\r
1039 if (curBack < kNumFullDistances)
\r
1040 curAndLenPrice += _distancesPrices[lenToPosState][curBack];
\r
1042 curAndLenPrice += _posSlotPrices[lenToPosState][posSlot] + _alignPrices[curBack & kAlignMask];
\r
1044 curAndLenPrice += _lenEncoder.GetPrice(lenTest - kMatchMinLen, posState);
\r
1046 COptimal &optimum = _optimum[cur + lenTest];
\r
1047 if (curAndLenPrice < optimum.Price)
\r
1049 optimum.Price = curAndLenPrice;
\r
1050 optimum.PosPrev = cur;
\r
1051 optimum.BackPrev = curBack + kNumRepDistances;
\r
1052 optimum.Prev1IsChar = false;
\r
1055 if (/*_maxMode && */lenTest == matchDistances[offs])
\r
1057 // Try Match + Literal + Rep0
\r
1058 UInt32 backOffset = curBack + 1;
\r
1059 UInt32 lenTest2 = lenTest + 1;
\r
1060 UInt32 limit = MyMin(numAvailableBytesFull, lenTest2 + _numFastBytes);
\r
1061 for (; lenTest2 < limit &&
\r
1062 data[lenTest2] == data[(size_t)lenTest2 - backOffset]; lenTest2++);
\r
1063 lenTest2 -= lenTest + 1;
\r
1064 if (lenTest2 >= 2)
\r
1066 CState state2 = state;
\r
1067 state2.UpdateMatch();
\r
1068 UInt32 posStateNext = (position + lenTest) & _posStateMask;
\r
1069 UInt32 curAndLenCharPrice = curAndLenPrice +
\r
1070 _isMatch[state2.Index][posStateNext].GetPrice0() +
\r
1071 _literalEncoder.GetSubCoder(position + lenTest, data[(size_t)lenTest - 1])->GetPrice(
\r
1072 true, data[(size_t)lenTest - backOffset], data[lenTest]);
\r
1073 state2.UpdateChar();
\r
1074 posStateNext = (posStateNext + 1) & _posStateMask;
\r
1075 UInt32 nextRepMatchPrice = curAndLenCharPrice +
\r
1076 _isMatch[state2.Index][posStateNext].GetPrice1() +
\r
1077 _isRep[state2.Index].GetPrice1();
\r
1079 // for(; lenTest2 >= 2; lenTest2--)
\r
1081 UInt32 offset = cur + lenTest + 1 + lenTest2;
\r
1082 while(lenEnd < offset)
\r
1083 _optimum[++lenEnd].Price = kIfinityPrice;
\r
1084 UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
\r
1085 COptimal &optimum = _optimum[offset];
\r
1086 if (curAndLenPrice < optimum.Price)
\r
1088 optimum.Price = curAndLenPrice;
\r
1089 optimum.PosPrev = cur + lenTest + 1;
\r
1090 optimum.BackPrev = 0;
\r
1091 optimum.Prev1IsChar = true;
\r
1092 optimum.Prev2 = true;
\r
1093 optimum.PosPrev2 = cur;
\r
1094 optimum.BackPrev2 = curBack + kNumRepDistances;
\r
1099 if (offs == numDistancePairs)
\r
1101 curBack = matchDistances[offs + 1];
\r
1102 if (curBack >= kNumFullDistances)
\r
1103 posSlot = GetPosSlot2(curBack);
\r
1110 static inline bool ChangePair(UInt32 smallDist, UInt32 bigDist)
\r
1112 return ((bigDist >> 7) > smallDist);
\r
1116 HRESULT CEncoder::ReadMatchDistances(UInt32 &lenRes, UInt32 &numDistancePairs)
\r
1119 RINOK(_matchFinder->GetMatches(_matchDistances));
\r
1120 numDistancePairs = _matchDistances[0];
\r
1121 if (numDistancePairs > 0)
\r
1123 lenRes = _matchDistances[1 + numDistancePairs - 2];
\r
1124 if (lenRes == _numFastBytes)
\r
1125 lenRes += _matchFinder->GetMatchLen(lenRes - 1, _matchDistances[1 + numDistancePairs - 1],
\r
1126 kMatchMaxLen - lenRes);
\r
1128 _additionalOffset++;
\r
1132 HRESULT CEncoder::GetOptimumFast(UInt32 position, UInt32 &backRes, UInt32 &lenRes)
\r
1134 UInt32 lenMain, numDistancePairs;
\r
1135 if (!_longestMatchWasFound)
\r
1137 RINOK(ReadMatchDistances(lenMain, numDistancePairs));
\r
1141 lenMain = _longestMatchLength;
\r
1142 numDistancePairs = _numDistancePairs;
\r
1143 _longestMatchWasFound = false;
\r
1146 const Byte *data = _matchFinder->GetPointerToCurrentPos() - 1;
\r
1147 UInt32 numAvailableBytes = _matchFinder->GetNumAvailableBytes() + 1;
\r
1148 if (numAvailableBytes > kMatchMaxLen)
\r
1149 numAvailableBytes = kMatchMaxLen;
\r
1150 if (numAvailableBytes < 2)
\r
1152 backRes = (UInt32)(-1);
\r
1157 UInt32 repLens[kNumRepDistances];
\r
1158 UInt32 repMaxIndex = 0;
\r
1160 for(UInt32 i = 0; i < kNumRepDistances; i++)
\r
1162 UInt32 backOffset = _repDistances[i] + 1;
\r
1163 if (data[0] != data[(size_t)0 - backOffset] || data[1] != data[(size_t)1 - backOffset])
\r
1169 for (len = 2; len < numAvailableBytes && data[len] == data[(size_t)len - backOffset]; len++);
\r
1170 if(len >= _numFastBytes)
\r
1174 return MovePos(lenRes - 1);
\r
1177 if (len > repLens[repMaxIndex])
\r
1180 UInt32 *matchDistances = _matchDistances + 1;
\r
1181 if(lenMain >= _numFastBytes)
\r
1183 backRes = matchDistances[numDistancePairs - 1] + kNumRepDistances;
\r
1185 return MovePos(lenMain - 1);
\r
1188 UInt32 backMain = 0;
\r
1191 backMain = matchDistances[numDistancePairs - 1];
\r
1192 while (numDistancePairs > 2 && lenMain == matchDistances[numDistancePairs - 4] + 1)
\r
1194 if (!ChangePair(matchDistances[numDistancePairs - 3], backMain))
\r
1196 numDistancePairs -= 2;
\r
1197 lenMain = matchDistances[numDistancePairs - 2];
\r
1198 backMain = matchDistances[numDistancePairs - 1];
\r
1200 if (lenMain == 2 && backMain >= 0x80)
\r
1204 if (repLens[repMaxIndex] >= 2)
\r
1206 if (repLens[repMaxIndex] + 1 >= lenMain ||
\r
1207 repLens[repMaxIndex] + 2 >= lenMain && (backMain > (1 << 9)) ||
\r
1208 repLens[repMaxIndex] + 3 >= lenMain && (backMain > (1 << 15)))
\r
1210 backRes = repMaxIndex;
\r
1211 lenRes = repLens[repMaxIndex];
\r
1212 return MovePos(lenRes - 1);
\r
1216 if (lenMain >= 2 && numAvailableBytes > 2)
\r
1218 RINOK(ReadMatchDistances(_longestMatchLength, _numDistancePairs));
\r
1219 if (_longestMatchLength >= 2)
\r
1221 UInt32 newDistance = matchDistances[_numDistancePairs - 1];
\r
1222 if (_longestMatchLength >= lenMain && newDistance < backMain ||
\r
1223 _longestMatchLength == lenMain + 1 && !ChangePair(backMain, newDistance) ||
\r
1224 _longestMatchLength > lenMain + 1 ||
\r
1225 _longestMatchLength + 1 >= lenMain && lenMain >= 3 && ChangePair(newDistance, backMain))
\r
1227 _longestMatchWasFound = true;
\r
1228 backRes = UInt32(-1);
\r
1234 numAvailableBytes--;
\r
1235 for(UInt32 i = 0; i < kNumRepDistances; i++)
\r
1237 UInt32 backOffset = _repDistances[i] + 1;
\r
1238 if (data[1] != data[(size_t)1 - backOffset] || data[2] != data[(size_t)2 - backOffset])
\r
1244 for (len = 2; len < numAvailableBytes && data[len] == data[(size_t)len - backOffset]; len++);
\r
1245 if (len + 1 >= lenMain)
\r
1247 _longestMatchWasFound = true;
\r
1248 backRes = UInt32(-1);
\r
1253 backRes = backMain + kNumRepDistances;
\r
1255 return MovePos(lenMain - 2);
\r
1257 backRes = UInt32(-1);
\r
1262 HRESULT CEncoder::Flush(UInt32 nowPos)
\r
1264 ReleaseMFStream();
\r
1265 WriteEndMarker(nowPos & _posStateMask);
\r
1266 _rangeEncoder.FlushData();
\r
1267 return _rangeEncoder.FlushStream();
\r
1270 void CEncoder::WriteEndMarker(UInt32 posState)
\r
1272 // This function for writing End Mark for stream version of LZMA.
\r
1273 // In current version this feature is not used.
\r
1274 if (!_writeEndMark)
\r
1277 _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
\r
1278 _isRep[_state.Index].Encode(&_rangeEncoder, 0);
\r
1279 _state.UpdateMatch();
\r
1280 UInt32 len = kMatchMinLen; // kMatchMaxLen;
\r
1281 _lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
\r
1282 UInt32 posSlot = (1 << kNumPosSlotBits) - 1;
\r
1283 UInt32 lenToPosState = GetLenToPosState(len);
\r
1284 _posSlotEncoder[lenToPosState].Encode(&_rangeEncoder, posSlot);
\r
1285 UInt32 footerBits = 30;
\r
1286 UInt32 posReduced = (UInt32(1) << footerBits) - 1;
\r
1287 _rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
\r
1288 _posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
\r
1291 HRESULT CEncoder::CodeReal(ISequentialInStream *inStream,
\r
1292 ISequentialOutStream *outStream,
\r
1293 const UInt64 *inSize, const UInt64 *outSize,
\r
1294 ICompressProgressInfo *progress)
\r
1296 _needReleaseMFStream = false;
\r
1297 CCoderReleaser coderReleaser(this);
\r
1298 RINOK(SetStreams(inStream, outStream, inSize, outSize));
\r
1301 UInt64 processedInSize;
\r
1302 UInt64 processedOutSize;
\r
1304 RINOK(CodeOneBlock(&processedInSize, &processedOutSize, &finished));
\r
1305 if (finished != 0)
\r
1307 if (progress != 0)
\r
1309 RINOK(progress->SetRatioInfo(&processedInSize, &processedOutSize));
\r
1314 HRESULT CEncoder::SetStreams(ISequentialInStream *inStream,
\r
1315 ISequentialOutStream *outStream,
\r
1316 const UInt64 *inSize, const UInt64 *outSize)
\r
1318 _inStream = inStream;
\r
1319 _finished = false;
\r
1321 RINOK(SetOutStream(outStream));
\r
1324 // CCoderReleaser releaser(this);
\r
1327 if (_matchFinder->GetNumAvailableBytes() == 0)
\r
1333 FillDistancesPrices();
\r
1334 FillAlignPrices();
\r
1337 _lenEncoder.SetTableSize(_numFastBytes + 1 - kMatchMinLen);
\r
1338 _lenEncoder.UpdateTables(1 << _posStateBits);
\r
1339 _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - kMatchMinLen);
\r
1340 _repMatchLenEncoder.UpdateTables(1 << _posStateBits);
\r
1346 HRESULT CEncoder::CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished)
\r
1348 if (_inStream != 0)
\r
1350 RINOK(_matchFinder->SetStream(_inStream));
\r
1351 RINOK(_matchFinder->Init());
\r
1352 _needReleaseMFStream = true;
\r
1362 if (nowPos64 == 0)
\r
1364 if (_matchFinder->GetNumAvailableBytes() == 0)
\r
1365 return Flush(UInt32(nowPos64));
\r
1366 UInt32 len, numDistancePairs;
\r
1367 RINOK(ReadMatchDistances(len, numDistancePairs));
\r
1368 UInt32 posState = UInt32(nowPos64) & _posStateMask;
\r
1369 _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
\r
1370 _state.UpdateChar();
\r
1371 Byte curByte = _matchFinder->GetIndexByte(0 - _additionalOffset);
\r
1372 _literalEncoder.GetSubCoder(UInt32(nowPos64), _previousByte)->Encode(&_rangeEncoder, curByte);
\r
1373 _previousByte = curByte;
\r
1374 _additionalOffset--;
\r
1378 UInt32 nowPos32 = (UInt32)nowPos64;
\r
1379 UInt32 progressPosValuePrev = nowPos32;
\r
1381 if (_matchFinder->GetNumAvailableBytes() == 0)
\r
1382 return Flush(nowPos32);
\r
1386 #ifdef _NO_EXCEPTIONS
\r
1387 if (_rangeEncoder.Stream.ErrorCode != S_OK)
\r
1388 return _rangeEncoder.Stream.ErrorCode;
\r
1393 result = GetOptimumFast(nowPos32, pos, len);
\r
1395 result = GetOptimum(nowPos32, pos, len);
\r
1398 UInt32 posState = nowPos32 & _posStateMask;
\r
1399 if(len == 1 && pos == 0xFFFFFFFF)
\r
1401 _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
\r
1402 Byte curByte = _matchFinder->GetIndexByte(0 - _additionalOffset);
\r
1403 CLiteralEncoder2 *subCoder = _literalEncoder.GetSubCoder(nowPos32, _previousByte);
\r
1404 if(_state.IsCharState())
\r
1405 subCoder->Encode(&_rangeEncoder, curByte);
\r
1408 Byte matchByte = _matchFinder->GetIndexByte(0 - _repDistances[0] - 1 - _additionalOffset);
\r
1409 subCoder->EncodeMatched(&_rangeEncoder, matchByte, curByte);
\r
1411 _state.UpdateChar();
\r
1412 _previousByte = curByte;
\r
1416 _isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
\r
1417 if(pos < kNumRepDistances)
\r
1419 _isRep[_state.Index].Encode(&_rangeEncoder, 1);
\r
1422 _isRepG0[_state.Index].Encode(&_rangeEncoder, 0);
\r
1423 _isRep0Long[_state.Index][posState].Encode(&_rangeEncoder, ((len == 1) ? 0 : 1));
\r
1427 UInt32 distance = _repDistances[pos];
\r
1428 _isRepG0[_state.Index].Encode(&_rangeEncoder, 1);
\r
1430 _isRepG1[_state.Index].Encode(&_rangeEncoder, 0);
\r
1433 _isRepG1[_state.Index].Encode(&_rangeEncoder, 1);
\r
1434 _isRepG2[_state.Index].Encode(&_rangeEncoder, pos - 2);
\r
1436 _repDistances[3] = _repDistances[2];
\r
1437 _repDistances[2] = _repDistances[1];
\r
1439 _repDistances[1] = _repDistances[0];
\r
1440 _repDistances[0] = distance;
\r
1443 _state.UpdateShortRep();
\r
1446 _repMatchLenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
\r
1447 _state.UpdateRep();
\r
1452 _isRep[_state.Index].Encode(&_rangeEncoder, 0);
\r
1453 _state.UpdateMatch();
\r
1454 _lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
\r
1455 pos -= kNumRepDistances;
\r
1456 UInt32 posSlot = GetPosSlot(pos);
\r
1457 _posSlotEncoder[GetLenToPosState(len)].Encode(&_rangeEncoder, posSlot);
\r
1459 if (posSlot >= kStartPosModelIndex)
\r
1461 UInt32 footerBits = ((posSlot >> 1) - 1);
\r
1462 UInt32 base = ((2 | (posSlot & 1)) << footerBits);
\r
1463 UInt32 posReduced = pos - base;
\r
1465 if (posSlot < kEndPosModelIndex)
\r
1466 NRangeCoder::ReverseBitTreeEncode(_posEncoders + base - posSlot - 1,
\r
1467 &_rangeEncoder, footerBits, posReduced);
\r
1470 _rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
\r
1471 _posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
\r
1472 _alignPriceCount++;
\r
1475 _repDistances[3] = _repDistances[2];
\r
1476 _repDistances[2] = _repDistances[1];
\r
1477 _repDistances[1] = _repDistances[0];
\r
1478 _repDistances[0] = pos;
\r
1479 _matchPriceCount++;
\r
1481 _previousByte = _matchFinder->GetIndexByte(len - 1 - _additionalOffset);
\r
1483 _additionalOffset -= len;
\r
1485 if (_additionalOffset == 0)
\r
1489 if (_matchPriceCount >= (1 << 7))
\r
1490 FillDistancesPrices();
\r
1491 if (_alignPriceCount >= kAlignTableSize)
\r
1492 FillAlignPrices();
\r
1494 if (_matchFinder->GetNumAvailableBytes() == 0)
\r
1495 return Flush(nowPos32);
\r
1496 if (nowPos32 - progressPosValuePrev >= (1 << 14))
\r
1498 nowPos64 += nowPos32 - progressPosValuePrev;
\r
1499 *inSize = nowPos64;
\r
1500 *outSize = _rangeEncoder.GetProcessedSize();
\r
1501 _finished = false;
\r
1509 STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream,
\r
1510 ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
\r
1511 ICompressProgressInfo *progress)
\r
1513 #ifndef _NO_EXCEPTIONS
\r
1517 return CodeReal(inStream, outStream, inSize, outSize, progress);
\r
1518 #ifndef _NO_EXCEPTIONS
\r
1520 catch(const COutBufferException &e) { return e.ErrorCode; }
\r
1521 catch(...) { return E_FAIL; }
\r
1525 void CEncoder::FillDistancesPrices()
\r
1527 UInt32 tempPrices[kNumFullDistances];
\r
1528 for (UInt32 i = kStartPosModelIndex; i < kNumFullDistances; i++)
\r
1530 UInt32 posSlot = GetPosSlot(i);
\r
1531 UInt32 footerBits = ((posSlot >> 1) - 1);
\r
1532 UInt32 base = ((2 | (posSlot & 1)) << footerBits);
\r
1533 tempPrices[i] = NRangeCoder::ReverseBitTreeGetPrice(_posEncoders +
\r
1534 base - posSlot - 1, footerBits, i - base);
\r
1537 for (UInt32 lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
\r
1540 NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumPosSlotBits> &encoder = _posSlotEncoder[lenToPosState];
\r
1541 UInt32 *posSlotPrices = _posSlotPrices[lenToPosState];
\r
1542 for (posSlot = 0; posSlot < _distTableSize; posSlot++)
\r
1543 posSlotPrices[posSlot] = encoder.GetPrice(posSlot);
\r
1544 for (posSlot = kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
\r
1545 posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << NRangeCoder::kNumBitPriceShiftBits);
\r
1547 UInt32 *distancesPrices = _distancesPrices[lenToPosState];
\r
1549 for (i = 0; i < kStartPosModelIndex; i++)
\r
1550 distancesPrices[i] = posSlotPrices[i];
\r
1551 for (; i < kNumFullDistances; i++)
\r
1552 distancesPrices[i] = posSlotPrices[GetPosSlot(i)] + tempPrices[i];
\r
1554 _matchPriceCount = 0;
\r
1557 void CEncoder::FillAlignPrices()
\r
1559 for (UInt32 i = 0; i < kAlignTableSize; i++)
\r
1560 _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
\r
1561 _alignPriceCount = 0;
\r