blob: b6a2f7d591bd31350790f3634254caa83b0490eb [file] [log] [blame]
// LZMA/Encoder.cpp
#include "StdAfx.h"
#include "../../../Common/Defs.h"
#include "../../Common/StreamUtils.h"
#include "LZMAEncoder.h"
// for minimal compressing code size define these:
// #define COMPRESS_MF_BT
// #define COMPRESS_MF_BT4
#if !defined(COMPRESS_MF_BT) && !defined(COMPRESS_MF_HC)
#define COMPRESS_MF_BT
#define COMPRESS_MF_HC
#endif
#ifdef COMPRESS_MF_BT
#if !defined(COMPRESS_MF_BT2) && !defined(COMPRESS_MF_BT3) && !defined(COMPRESS_MF_BT4)
#define COMPRESS_MF_BT2
#define COMPRESS_MF_BT3
#define COMPRESS_MF_BT4
#endif
#ifdef COMPRESS_MF_BT2
#include "../LZ/BinTree/BinTree2.h"
#endif
#ifdef COMPRESS_MF_BT3
#include "../LZ/BinTree/BinTree3.h"
#endif
#ifdef COMPRESS_MF_BT4
#include "../LZ/BinTree/BinTree4.h"
#endif
#endif
#ifdef COMPRESS_MF_HC
#include "../LZ/HashChain/HC4.h"
#endif
#ifdef COMPRESS_MF_MT
#include "../LZ/MT/MT.h"
#endif
namespace NCompress {
namespace NLZMA {
const int kDefaultDictionaryLogSize = 22;
const UInt32 kNumFastBytesDefault = 0x20;
enum
{
kBT2,
kBT3,
kBT4,
kHC4
};
static const wchar_t *kMatchFinderIDs[] =
{
L"BT2",
L"BT3",
L"BT4",
L"HC4"
};
Byte g_FastPos[1 << 11];
class CFastPosInit
{
public:
CFastPosInit() { Init(); }
void Init()
{
const Byte kFastSlots = 22;
int c = 2;
g_FastPos[0] = 0;
g_FastPos[1] = 1;
for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++)
{
UInt32 k = (1 << ((slotFast >> 1) - 1));
for (UInt32 j = 0; j < k; j++, c++)
g_FastPos[c] = slotFast;
}
}
} g_FastPosInit;
void CLiteralEncoder2::Encode(NRangeCoder::CEncoder *rangeEncoder, Byte symbol)
{
UInt32 context = 1;
int i = 8;
do
{
i--;
UInt32 bit = (symbol >> i) & 1;
_encoders[context].Encode(rangeEncoder, bit);
context = (context << 1) | bit;
}
while(i != 0);
}
void CLiteralEncoder2::EncodeMatched(NRangeCoder::CEncoder *rangeEncoder,
Byte matchByte, Byte symbol)
{
UInt32 context = 1;
int i = 8;
do
{
i--;
UInt32 bit = (symbol >> i) & 1;
UInt32 matchBit = (matchByte >> i) & 1;
_encoders[0x100 + (matchBit << 8) + context].Encode(rangeEncoder, bit);
context = (context << 1) | bit;
if (matchBit != bit)
{
while(i != 0)
{
i--;
UInt32 bit = (symbol >> i) & 1;
_encoders[context].Encode(rangeEncoder, bit);
context = (context << 1) | bit;
}
break;
}
}
while(i != 0);
}
UInt32 CLiteralEncoder2::GetPrice(bool matchMode, Byte matchByte, Byte symbol) const
{
UInt32 price = 0;
UInt32 context = 1;
int i = 8;
if (matchMode)
{
do
{
i--;
UInt32 matchBit = (matchByte >> i) & 1;
UInt32 bit = (symbol >> i) & 1;
price += _encoders[0x100 + (matchBit << 8) + context].GetPrice(bit);
context = (context << 1) | bit;
if (matchBit != bit)
break;
}
while (i != 0);
}
while(i != 0)
{
i--;
UInt32 bit = (symbol >> i) & 1;
price += _encoders[context].GetPrice(bit);
context = (context << 1) | bit;
}
return price;
};
namespace NLength {
void CEncoder::Init(UInt32 numPosStates)
{
_choice.Init();
_choice2.Init();
for (UInt32 posState = 0; posState < numPosStates; posState++)
{
_lowCoder[posState].Init();
_midCoder[posState].Init();
}
_highCoder.Init();
}
void CEncoder::Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState)
{
if(symbol < kNumLowSymbols)
{
_choice.Encode(rangeEncoder, 0);
_lowCoder[posState].Encode(rangeEncoder, symbol);
}
else
{
_choice.Encode(rangeEncoder, 1);
if(symbol < kNumLowSymbols + kNumMidSymbols)
{
_choice2.Encode(rangeEncoder, 0);
_midCoder[posState].Encode(rangeEncoder, symbol - kNumLowSymbols);
}
else
{
_choice2.Encode(rangeEncoder, 1);
_highCoder.Encode(rangeEncoder, symbol - kNumLowSymbols - kNumMidSymbols);
}
}
}
void CEncoder::SetPrices(UInt32 posState, UInt32 numSymbols, UInt32 *prices) const
{
UInt32 a0 = _choice.GetPrice0();
UInt32 a1 = _choice.GetPrice1();
UInt32 b0 = a1 + _choice2.GetPrice0();
UInt32 b1 = a1 + _choice2.GetPrice1();
UInt32 i = 0;
for (i = 0; i < kNumLowSymbols; i++)
{
if (i >= numSymbols)
return;
prices[i] = a0 + _lowCoder[posState].GetPrice(i);
}
for (; i < kNumLowSymbols + kNumMidSymbols; i++)
{
if (i >= numSymbols)
return;
prices[i] = b0 + _midCoder[posState].GetPrice(i - kNumLowSymbols);
}
for (; i < numSymbols; i++)
prices[i] = b1 + _highCoder.GetPrice(i - kNumLowSymbols - kNumMidSymbols);
}
}
CEncoder::CEncoder():
_numFastBytes(kNumFastBytesDefault),
_distTableSize(kDefaultDictionaryLogSize * 2),
_posStateBits(2),
_posStateMask(4 - 1),
_numLiteralPosStateBits(0),
_numLiteralContextBits(3),
_dictionarySize(1 << kDefaultDictionaryLogSize),
_dictionarySizePrev(UInt32(-1)),
_numFastBytesPrev(UInt32(-1)),
_matchFinderCycles(0),
_matchFinderIndex(kBT4),
#ifdef COMPRESS_MF_MT
_multiThread(false),
#endif
_writeEndMark(false),
setMfPasses(0)
{
// _maxMode = false;
_fastMode = false;
}
HRESULT CEncoder::Create()
{
if (!_rangeEncoder.Create(1 << 20))
return E_OUTOFMEMORY;
if (!_matchFinder)
{
switch(_matchFinderIndex)
{
#ifdef COMPRESS_MF_BT
#ifdef COMPRESS_MF_BT2
case kBT2:
{
NBT2::CMatchFinder *mfSpec = new NBT2::CMatchFinder;
setMfPasses = mfSpec;
_matchFinder = mfSpec;
break;
}
#endif
#ifdef COMPRESS_MF_BT3
case kBT3:
{
NBT3::CMatchFinder *mfSpec = new NBT3::CMatchFinder;
setMfPasses = mfSpec;
_matchFinder = mfSpec;
break;
}
#endif
#ifdef COMPRESS_MF_BT4
case kBT4:
{
NBT4::CMatchFinder *mfSpec = new NBT4::CMatchFinder;
setMfPasses = mfSpec;
_matchFinder = mfSpec;
break;
}
#endif
#endif
#ifdef COMPRESS_MF_HC
case kHC4:
{
NHC4::CMatchFinder *mfSpec = new NHC4::CMatchFinder;
setMfPasses = mfSpec;
_matchFinder = mfSpec;
break;
}
#endif
}
if (_matchFinder == 0)
return E_OUTOFMEMORY;
#ifdef COMPRESS_MF_MT
if (_multiThread && !(_fastMode && (_matchFinderIndex == kHC4)))
{
CMatchFinderMT *mfSpec = new CMatchFinderMT;
if (mfSpec == 0)
return E_OUTOFMEMORY;
CMyComPtr<IMatchFinder> mf = mfSpec;
RINOK(mfSpec->SetMatchFinder(_matchFinder));
_matchFinder.Release();
_matchFinder = mf;
}
#endif
}
if (!_literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits))
return E_OUTOFMEMORY;
if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
return S_OK;
RINOK(_matchFinder->Create(_dictionarySize, kNumOpts, _numFastBytes, kMatchMaxLen + 1)); // actually it's + _numFastBytes - _numFastBytes
if (_matchFinderCycles != 0 && setMfPasses != 0)
setMfPasses->SetNumPasses(_matchFinderCycles);
_dictionarySizePrev = _dictionarySize;
_numFastBytesPrev = _numFastBytes;
return S_OK;
}
static bool AreStringsEqual(const wchar_t *base, const wchar_t *testString)
{
while (true)
{
wchar_t c = *testString;
if (c >= 'a' && c <= 'z')
c -= 0x20;
if (*base != c)
return false;
if (c == 0)
return true;
base++;
testString++;
}
}
static int FindMatchFinder(const wchar_t *s)
{
for (int m = 0; m < (int)(sizeof(kMatchFinderIDs) / sizeof(kMatchFinderIDs[0])); m++)
if (AreStringsEqual(kMatchFinderIDs[m], s))
return m;
return -1;
}
STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
const PROPVARIANT *properties, UInt32 numProperties)
{
for (UInt32 i = 0; i < numProperties; i++)
{
const PROPVARIANT &prop = properties[i];
switch(propIDs[i])
{
case NCoderPropID::kNumFastBytes:
{
if (prop.vt != VT_UI4)
return E_INVALIDARG;
UInt32 numFastBytes = prop.ulVal;
if(numFastBytes < 5 || numFastBytes > kMatchMaxLen)
return E_INVALIDARG;
_numFastBytes = numFastBytes;
break;
}
case NCoderPropID::kMatchFinderCycles:
{
if (prop.vt != VT_UI4)
return E_INVALIDARG;
_matchFinderCycles = prop.ulVal;
break;
}
case NCoderPropID::kAlgorithm:
{
if (prop.vt != VT_UI4)
return E_INVALIDARG;
UInt32 maximize = prop.ulVal;
_fastMode = (maximize == 0);
// _maxMode = (maximize >= 2);
break;
}
case NCoderPropID::kMatchFinder:
{
if (prop.vt != VT_BSTR)
return E_INVALIDARG;
int matchFinderIndexPrev = _matchFinderIndex;
int m = FindMatchFinder(prop.bstrVal);
if (m < 0)
return E_INVALIDARG;
_matchFinderIndex = m;
if (_matchFinder && matchFinderIndexPrev != _matchFinderIndex)
{
_dictionarySizePrev = (UInt32)-1;
ReleaseMatchFinder();
}
break;
}
#ifdef COMPRESS_MF_MT
case NCoderPropID::kMultiThread:
{
if (prop.vt != VT_BOOL)
return E_INVALIDARG;
bool newMultiThread = (prop.boolVal == VARIANT_TRUE);
if (newMultiThread != _multiThread)
{
_dictionarySizePrev = (UInt32)-1;
ReleaseMatchFinder();
_multiThread = newMultiThread;
}
break;
}
case NCoderPropID::kNumThreads:
{
if (prop.vt != VT_UI4)
return E_INVALIDARG;
bool newMultiThread = (prop.ulVal > 1);
if (newMultiThread != _multiThread)
{
_dictionarySizePrev = (UInt32)-1;
ReleaseMatchFinder();
_multiThread = newMultiThread;
}
break;
}
#endif
case NCoderPropID::kDictionarySize:
{
const int kDicLogSizeMaxCompress = 30;
if (prop.vt != VT_UI4)
return E_INVALIDARG;
UInt32 dictionarySize = prop.ulVal;
if (dictionarySize < UInt32(1 << kDicLogSizeMin) ||
dictionarySize > UInt32(1 << kDicLogSizeMaxCompress))
return E_INVALIDARG;
_dictionarySize = dictionarySize;
UInt32 dicLogSize;
for(dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++)
if (dictionarySize <= (UInt32(1) << dicLogSize))
break;
_distTableSize = dicLogSize * 2;
break;
}
case NCoderPropID::kPosStateBits:
{
if (prop.vt != VT_UI4)
return E_INVALIDARG;
UInt32 value = prop.ulVal;
if (value > (UInt32)NLength::kNumPosStatesBitsEncodingMax)
return E_INVALIDARG;
_posStateBits = value;
_posStateMask = (1 << _posStateBits) - 1;
break;
}
case NCoderPropID::kLitPosBits:
{
if (prop.vt != VT_UI4)
return E_INVALIDARG;
UInt32 value = prop.ulVal;
if (value > (UInt32)kNumLitPosStatesBitsEncodingMax)
return E_INVALIDARG;
_numLiteralPosStateBits = value;
break;
}
case NCoderPropID::kLitContextBits:
{
if (prop.vt != VT_UI4)
return E_INVALIDARG;
UInt32 value = prop.ulVal;
if (value > (UInt32)kNumLitContextBitsMax)
return E_INVALIDARG;
_numLiteralContextBits = value;
break;
}
case NCoderPropID::kEndMarker:
{
if (prop.vt != VT_BOOL)
return E_INVALIDARG;
SetWriteEndMarkerMode(prop.boolVal == VARIANT_TRUE);
break;
}
default:
return E_INVALIDARG;
}
}
return S_OK;
}
STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
{
const UInt32 kPropSize = 5;
Byte properties[kPropSize];
properties[0] = (_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits;
for (int i = 0; i < 4; i++)
properties[1 + i] = Byte(_dictionarySize >> (8 * i));
return WriteStream(outStream, properties, kPropSize, NULL);
}
STDMETHODIMP CEncoder::SetOutStream(ISequentialOutStream *outStream)
{
_rangeEncoder.SetStream(outStream);
return S_OK;
}
STDMETHODIMP CEncoder::ReleaseOutStream()
{
_rangeEncoder.ReleaseStream();
return S_OK;
}
HRESULT CEncoder::Init()
{
CBaseState::Init();
// RINOK(_matchFinder->Init(inStream));
_rangeEncoder.Init();
for(int i = 0; i < kNumStates; i++)
{
for (UInt32 j = 0; j <= _posStateMask; j++)
{
_isMatch[i][j].Init();
_isRep0Long[i][j].Init();
}
_isRep[i].Init();
_isRepG0[i].Init();
_isRepG1[i].Init();
_isRepG2[i].Init();
}
_literalEncoder.Init();
{
for(UInt32 i = 0; i < kNumLenToPosStates; i++)
_posSlotEncoder[i].Init();
}
{
for(UInt32 i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
_posEncoders[i].Init();
}
_lenEncoder.Init(1 << _posStateBits);
_repMatchLenEncoder.Init(1 << _posStateBits);
_posAlignEncoder.Init();
_longestMatchWasFound = false;
_optimumEndIndex = 0;
_optimumCurrentIndex = 0;
_additionalOffset = 0;
return S_OK;
}
HRESULT CEncoder::MovePos(UInt32 num)
{
if (num == 0)
return S_OK;
_additionalOffset += num;
return _matchFinder->Skip(num);
}
UInt32 CEncoder::Backward(UInt32 &backRes, UInt32 cur)
{
_optimumEndIndex = cur;
UInt32 posMem = _optimum[cur].PosPrev;
UInt32 backMem = _optimum[cur].BackPrev;
do
{
if (_optimum[cur].Prev1IsChar)
{
_optimum[posMem].MakeAsChar();
_optimum[posMem].PosPrev = posMem - 1;
if (_optimum[cur].Prev2)
{
_optimum[posMem - 1].Prev1IsChar = false;
_optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
_optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
}
}
UInt32 posPrev = posMem;
UInt32 backCur = backMem;
backMem = _optimum[posPrev].BackPrev;
posMem = _optimum[posPrev].PosPrev;
_optimum[posPrev].BackPrev = backCur;
_optimum[posPrev].PosPrev = cur;
cur = posPrev;
}
while(cur != 0);
backRes = _optimum[0].BackPrev;
_optimumCurrentIndex = _optimum[0].PosPrev;
return _optimumCurrentIndex;
}
/*
Out:
(lenRes == 1) && (backRes == 0xFFFFFFFF) means Literal
*/
HRESULT CEncoder::GetOptimum(UInt32 position, UInt32 &backRes, UInt32 &lenRes)
{
if(_optimumEndIndex != _optimumCurrentIndex)
{
const COptimal &optimum = _optimum[_optimumCurrentIndex];
lenRes = optimum.PosPrev - _optimumCurrentIndex;
backRes = optimum.BackPrev;
_optimumCurrentIndex = optimum.PosPrev;
return S_OK;
}
_optimumCurrentIndex = _optimumEndIndex = 0;
UInt32 lenMain, numDistancePairs;
if (!_longestMatchWasFound)
{
RINOK(ReadMatchDistances(lenMain, numDistancePairs));
}
else
{
lenMain = _longestMatchLength;
numDistancePairs = _numDistancePairs;
_longestMatchWasFound = false;
}
const Byte *data = _matchFinder->GetPointerToCurrentPos() - 1;
UInt32 numAvailableBytes = _matchFinder->GetNumAvailableBytes() + 1;
if (numAvailableBytes < 2)
{
backRes = (UInt32)(-1);
lenRes = 1;
return S_OK;
}
if (numAvailableBytes > kMatchMaxLen)
numAvailableBytes = kMatchMaxLen;
UInt32 reps[kNumRepDistances];
UInt32 repLens[kNumRepDistances];
UInt32 repMaxIndex = 0;
UInt32 i;
for(i = 0; i < kNumRepDistances; i++)
{
reps[i] = _repDistances[i];
UInt32 backOffset = reps[i] + 1;
if (data[0] != data[(size_t)0 - backOffset] || data[1] != data[(size_t)1 - backOffset])
{
repLens[i] = 0;
continue;
}
UInt32 lenTest;
for (lenTest = 2; lenTest < numAvailableBytes &&
data[lenTest] == data[(size_t)lenTest - backOffset]; lenTest++);
repLens[i] = lenTest;
if (lenTest > repLens[repMaxIndex])
repMaxIndex = i;
}
if(repLens[repMaxIndex] >= _numFastBytes)
{
backRes = repMaxIndex;
lenRes = repLens[repMaxIndex];
return MovePos(lenRes - 1);
}
UInt32 *matchDistances = _matchDistances + 1;
if(lenMain >= _numFastBytes)
{
backRes = matchDistances[numDistancePairs - 1] + kNumRepDistances;
lenRes = lenMain;
return MovePos(lenMain - 1);
}
Byte currentByte = *data;
Byte matchByte = data[(size_t)0 - reps[0] - 1];
if(lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
{
backRes = (UInt32)-1;
lenRes = 1;
return S_OK;
}
_optimum[0].State = _state;
UInt32 posState = (position & _posStateMask);
_optimum[1].Price = _isMatch[_state.Index][posState].GetPrice0() +
_literalEncoder.GetSubCoder(position, _previousByte)->GetPrice(!_state.IsCharState(), matchByte, currentByte);
_optimum[1].MakeAsChar();
UInt32 matchPrice = _isMatch[_state.Index][posState].GetPrice1();
UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1();
if(matchByte == currentByte)
{
UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
if(shortRepPrice < _optimum[1].Price)
{
_optimum[1].Price = shortRepPrice;
_optimum[1].MakeAsShortRep();
}
}
UInt32 lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
if(lenEnd < 2)
{
backRes = _optimum[1].BackPrev;
lenRes = 1;
return S_OK;
}
_optimum[1].PosPrev = 0;
for (i = 0; i < kNumRepDistances; i++)
_optimum[0].Backs[i] = reps[i];
UInt32 len = lenEnd;
do
_optimum[len--].Price = kIfinityPrice;
while (len >= 2);
for(i = 0; i < kNumRepDistances; i++)
{
UInt32 repLen = repLens[i];
if (repLen < 2)
continue;
UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState);
do
{
UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
COptimal &optimum = _optimum[repLen];
if (curAndLenPrice < optimum.Price)
{
optimum.Price = curAndLenPrice;
optimum.PosPrev = 0;
optimum.BackPrev = i;
optimum.Prev1IsChar = false;
}
}
while(--repLen >= 2);
}
UInt32 normalMatchPrice = matchPrice + _isRep[_state.Index].GetPrice0();
len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
if (len <= lenMain)
{
UInt32 offs = 0;
while (len > matchDistances[offs])
offs += 2;
for(; ; len++)
{
UInt32 distance = matchDistances[offs + 1];
UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
COptimal &optimum = _optimum[len];
if (curAndLenPrice < optimum.Price)
{
optimum.Price = curAndLenPrice;
optimum.PosPrev = 0;
optimum.BackPrev = distance + kNumRepDistances;
optimum.Prev1IsChar = false;
}
if (len == matchDistances[offs])
{
offs += 2;
if (offs == numDistancePairs)
break;
}
}
}
UInt32 cur = 0;
while(true)
{
cur++;
if(cur == lenEnd)
{
lenRes = Backward(backRes, cur);
return S_OK;
}
UInt32 newLen, numDistancePairs;
RINOK(ReadMatchDistances(newLen, numDistancePairs));
if(newLen >= _numFastBytes)
{
_numDistancePairs = numDistancePairs;
_longestMatchLength = newLen;
_longestMatchWasFound = true;
lenRes = Backward(backRes, cur);
return S_OK;
}
position++;
COptimal &curOptimum = _optimum[cur];
UInt32 posPrev = curOptimum.PosPrev;
CState state;
if (curOptimum.Prev1IsChar)
{
posPrev--;
if (curOptimum.Prev2)
{
state = _optimum[curOptimum.PosPrev2].State;
if (curOptimum.BackPrev2 < kNumRepDistances)
state.UpdateRep();
else
state.UpdateMatch();
}
else
state = _optimum[posPrev].State;
state.UpdateChar();
}
else
state = _optimum[posPrev].State;
if (posPrev == cur - 1)
{
if (curOptimum.IsShortRep())
state.UpdateShortRep();
else
state.UpdateChar();
}
else
{
UInt32 pos;
if (curOptimum.Prev1IsChar && curOptimum.Prev2)
{
posPrev = curOptimum.PosPrev2;
pos = curOptimum.BackPrev2;
state.UpdateRep();
}
else
{
pos = curOptimum.BackPrev;
if (pos < kNumRepDistances)
state.UpdateRep();
else
state.UpdateMatch();
}
const COptimal &prevOptimum = _optimum[posPrev];
if (pos < kNumRepDistances)
{
reps[0] = prevOptimum.Backs[pos];
UInt32 i;
for(i = 1; i <= pos; i++)
reps[i] = prevOptimum.Backs[i - 1];
for(; i < kNumRepDistances; i++)
reps[i] = prevOptimum.Backs[i];
}
else
{
reps[0] = (pos - kNumRepDistances);
for(UInt32 i = 1; i < kNumRepDistances; i++)
reps[i] = prevOptimum.Backs[i - 1];
}
}
curOptimum.State = state;
for(UInt32 i = 0; i < kNumRepDistances; i++)
curOptimum.Backs[i] = reps[i];
UInt32 curPrice = curOptimum.Price;
const Byte *data = _matchFinder->GetPointerToCurrentPos() - 1;
const Byte currentByte = *data;
const Byte matchByte = data[(size_t)0 - reps[0] - 1];
UInt32 posState = (position & _posStateMask);
UInt32 curAnd1Price = curPrice +
_isMatch[state.Index][posState].GetPrice0() +
_literalEncoder.GetSubCoder(position, data[(size_t)0 - 1])->GetPrice(!state.IsCharState(), matchByte, currentByte);
COptimal &nextOptimum = _optimum[cur + 1];
bool nextIsChar = false;
if (curAnd1Price < nextOptimum.Price)
{
nextOptimum.Price = curAnd1Price;
nextOptimum.PosPrev = cur;
nextOptimum.MakeAsChar();
nextIsChar = true;
}
UInt32 matchPrice = curPrice + _isMatch[state.Index][posState].GetPrice1();
UInt32 repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1();
if(matchByte == currentByte &&
!(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
{
UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
if(shortRepPrice <= nextOptimum.Price)
{
nextOptimum.Price = shortRepPrice;
nextOptimum.PosPrev = cur;
nextOptimum.MakeAsShortRep();
nextIsChar = true;
}
}
/*
if(newLen == 2 && matchDistances[2] >= kDistLimit2) // test it maybe set 2000 ?
continue;
*/
UInt32 numAvailableBytesFull = _matchFinder->GetNumAvailableBytes() + 1;
numAvailableBytesFull = MyMin(kNumOpts - 1 - cur, numAvailableBytesFull);
UInt32 numAvailableBytes = numAvailableBytesFull;
if (numAvailableBytes < 2)
continue;
if (numAvailableBytes > _numFastBytes)
numAvailableBytes = _numFastBytes;
if (!nextIsChar && matchByte != currentByte) // speed optimization
{
// try Literal + rep0
UInt32 backOffset = reps[0] + 1;
UInt32 limit = MyMin(numAvailableBytesFull, _numFastBytes + 1);
UInt32 temp;
for (temp = 1; temp < limit &&
data[temp] == data[(size_t)temp - backOffset]; temp++);
UInt32 lenTest2 = temp - 1;
if (lenTest2 >= 2)
{
CState state2 = state;
state2.UpdateChar();
UInt32 posStateNext = (position + 1) & _posStateMask;
UInt32 nextRepMatchPrice = curAnd1Price +
_isMatch[state2.Index][posStateNext].GetPrice1() +
_isRep[state2.Index].GetPrice1();
// for (; lenTest2 >= 2; lenTest2--)
{
UInt32 offset = cur + 1 + lenTest2;
while(lenEnd < offset)
_optimum[++lenEnd].Price = kIfinityPrice;
UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
0, lenTest2, state2, posStateNext);
COptimal &optimum = _optimum[offset];
if (curAndLenPrice < optimum.Price)
{
optimum.Price = curAndLenPrice;
optimum.PosPrev = cur + 1;
optimum.BackPrev = 0;
optimum.Prev1IsChar = true;
optimum.Prev2 = false;
}
}
}
}
UInt32 startLen = 2; // speed optimization
for(UInt32 repIndex = 0; repIndex < kNumRepDistances; repIndex++)
{
// UInt32 repLen = _matchFinder->GetMatchLen(0 - 1, reps[repIndex], newLen); // test it;
UInt32 backOffset = reps[repIndex] + 1;
if (data[0] != data[(size_t)0 - backOffset] ||
data[1] != data[(size_t)1 - backOffset])
continue;
UInt32 lenTest;
for (lenTest = 2; lenTest < numAvailableBytes &&
data[lenTest] == data[(size_t)lenTest - backOffset]; lenTest++);
while(lenEnd < cur + lenTest)
_optimum[++lenEnd].Price = kIfinityPrice;
UInt32 lenTestTemp = lenTest;
UInt32 price = repMatchPrice + GetPureRepPrice(repIndex, state, posState);
do
{
UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(lenTest - 2, posState);
COptimal &optimum = _optimum[cur + lenTest];
if (curAndLenPrice < optimum.Price)
{
optimum.Price = curAndLenPrice;
optimum.PosPrev = cur;
optimum.BackPrev = repIndex;
optimum.Prev1IsChar = false;
}
}
while(--lenTest >= 2);
lenTest = lenTestTemp;
if (repIndex == 0)
startLen = lenTest + 1;
// if (_maxMode)
{
UInt32 lenTest2 = lenTest + 1;
UInt32 limit = MyMin(numAvailableBytesFull, lenTest2 + _numFastBytes);
for (; lenTest2 < limit &&
data[lenTest2] == data[(size_t)lenTest2 - backOffset]; lenTest2++);
lenTest2 -= lenTest + 1;
if (lenTest2 >= 2)
{
CState state2 = state;
state2.UpdateRep();
UInt32 posStateNext = (position + lenTest) & _posStateMask;
UInt32 curAndLenCharPrice =
price + _repMatchLenEncoder.GetPrice(lenTest - 2, posState) +
_isMatch[state2.Index][posStateNext].GetPrice0() +
_literalEncoder.GetSubCoder(position + lenTest, data[(size_t)lenTest - 1])->GetPrice(
true, data[(size_t)lenTest - backOffset], data[lenTest]);
state2.UpdateChar();
posStateNext = (position + lenTest + 1) & _posStateMask;
UInt32 nextRepMatchPrice = curAndLenCharPrice +
_isMatch[state2.Index][posStateNext].GetPrice1() +
_isRep[state2.Index].GetPrice1();
// for(; lenTest2 >= 2; lenTest2--)
{
UInt32 offset = cur + lenTest + 1 + lenTest2;
while(lenEnd < offset)
_optimum[++lenEnd].Price = kIfinityPrice;
UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
0, lenTest2, state2, posStateNext);
COptimal &optimum = _optimum[offset];
if (curAndLenPrice < optimum.Price)
{
optimum.Price = curAndLenPrice;
optimum.PosPrev = cur + lenTest + 1;
optimum.BackPrev = 0;
optimum.Prev1IsChar = true;
optimum.Prev2 = true;
optimum.PosPrev2 = cur;
optimum.BackPrev2 = repIndex;
}
}
}
}
}
// for(UInt32 lenTest = 2; lenTest <= newLen; lenTest++)
if (newLen > numAvailableBytes)
{
newLen = numAvailableBytes;
for (numDistancePairs = 0; newLen > matchDistances[numDistancePairs]; numDistancePairs += 2);
matchDistances[numDistancePairs] = newLen;
numDistancePairs += 2;
}
if (newLen >= startLen)
{
UInt32 normalMatchPrice = matchPrice + _isRep[state.Index].GetPrice0();
while(lenEnd < cur + newLen)
_optimum[++lenEnd].Price = kIfinityPrice;
UInt32 offs = 0;
while(startLen > matchDistances[offs])
offs += 2;
UInt32 curBack = matchDistances[offs + 1];
UInt32 posSlot = GetPosSlot2(curBack);
for(UInt32 lenTest = /*2*/ startLen; ; lenTest++)
{
UInt32 curAndLenPrice = normalMatchPrice;
UInt32 lenToPosState = GetLenToPosState(lenTest);
if (curBack < kNumFullDistances)
curAndLenPrice += _distancesPrices[lenToPosState][curBack];
else
curAndLenPrice += _posSlotPrices[lenToPosState][posSlot] + _alignPrices[curBack & kAlignMask];
curAndLenPrice += _lenEncoder.GetPrice(lenTest - kMatchMinLen, posState);
COptimal &optimum = _optimum[cur + lenTest];
if (curAndLenPrice < optimum.Price)
{
optimum.Price = curAndLenPrice;
optimum.PosPrev = cur;
optimum.BackPrev = curBack + kNumRepDistances;
optimum.Prev1IsChar = false;
}
if (/*_maxMode && */lenTest == matchDistances[offs])
{
// Try Match + Literal + Rep0
UInt32 backOffset = curBack + 1;
UInt32 lenTest2 = lenTest + 1;
UInt32 limit = MyMin(numAvailableBytesFull, lenTest2 + _numFastBytes);
for (; lenTest2 < limit &&
data[lenTest2] == data[(size_t)lenTest2 - backOffset]; lenTest2++);
lenTest2 -= lenTest + 1;
if (lenTest2 >= 2)
{
CState state2 = state;
state2.UpdateMatch();
UInt32 posStateNext = (position + lenTest) & _posStateMask;
UInt32 curAndLenCharPrice = curAndLenPrice +
_isMatch[state2.Index][posStateNext].GetPrice0() +
_literalEncoder.GetSubCoder(position + lenTest, data[(size_t)lenTest - 1])->GetPrice(
true, data[(size_t)lenTest - backOffset], data[lenTest]);
state2.UpdateChar();
posStateNext = (posStateNext + 1) & _posStateMask;
UInt32 nextRepMatchPrice = curAndLenCharPrice +
_isMatch[state2.Index][posStateNext].GetPrice1() +
_isRep[state2.Index].GetPrice1();
// for(; lenTest2 >= 2; lenTest2--)
{
UInt32 offset = cur + lenTest + 1 + lenTest2;
while(lenEnd < offset)
_optimum[++lenEnd].Price = kIfinityPrice;
UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
COptimal &optimum = _optimum[offset];
if (curAndLenPrice < optimum.Price)
{
optimum.Price = curAndLenPrice;
optimum.PosPrev = cur + lenTest + 1;
optimum.BackPrev = 0;
optimum.Prev1IsChar = true;
optimum.Prev2 = true;
optimum.PosPrev2 = cur;
optimum.BackPrev2 = curBack + kNumRepDistances;
}
}
}
offs += 2;
if (offs == numDistancePairs)
break;
curBack = matchDistances[offs + 1];
if (curBack >= kNumFullDistances)
posSlot = GetPosSlot2(curBack);
}
}
}
}
}
static inline bool ChangePair(UInt32 smallDist, UInt32 bigDist)
{
return ((bigDist >> 7) > smallDist);
}
HRESULT CEncoder::ReadMatchDistances(UInt32 &lenRes, UInt32 &numDistancePairs)
{
lenRes = 0;
RINOK(_matchFinder->GetMatches(_matchDistances));
numDistancePairs = _matchDistances[0];
if (numDistancePairs > 0)
{
lenRes = _matchDistances[1 + numDistancePairs - 2];
if (lenRes == _numFastBytes)
lenRes += _matchFinder->GetMatchLen(lenRes - 1, _matchDistances[1 + numDistancePairs - 1],
kMatchMaxLen - lenRes);
}
_additionalOffset++;
return S_OK;
}
HRESULT CEncoder::GetOptimumFast(UInt32 position, UInt32 &backRes, UInt32 &lenRes)
{
UInt32 lenMain, numDistancePairs;
if (!_longestMatchWasFound)
{
RINOK(ReadMatchDistances(lenMain, numDistancePairs));
}
else
{
lenMain = _longestMatchLength;
numDistancePairs = _numDistancePairs;
_longestMatchWasFound = false;
}
const Byte *data = _matchFinder->GetPointerToCurrentPos() - 1;
UInt32 numAvailableBytes = _matchFinder->GetNumAvailableBytes() + 1;
if (numAvailableBytes > kMatchMaxLen)
numAvailableBytes = kMatchMaxLen;
if (numAvailableBytes < 2)
{
backRes = (UInt32)(-1);
lenRes = 1;
return S_OK;
}
UInt32 repLens[kNumRepDistances];
UInt32 repMaxIndex = 0;
for(UInt32 i = 0; i < kNumRepDistances; i++)
{
UInt32 backOffset = _repDistances[i] + 1;
if (data[0] != data[(size_t)0 - backOffset] || data[1] != data[(size_t)1 - backOffset])
{
repLens[i] = 0;
continue;
}
UInt32 len;
for (len = 2; len < numAvailableBytes && data[len] == data[(size_t)len - backOffset]; len++);
if(len >= _numFastBytes)
{
backRes = i;
lenRes = len;
return MovePos(lenRes - 1);
}
repLens[i] = len;
if (len > repLens[repMaxIndex])
repMaxIndex = i;
}
UInt32 *matchDistances = _matchDistances + 1;
if(lenMain >= _numFastBytes)
{
backRes = matchDistances[numDistancePairs - 1] + kNumRepDistances;
lenRes = lenMain;
return MovePos(lenMain - 1);
}
UInt32 backMain = 0;
if (lenMain >= 2)
{
backMain = matchDistances[numDistancePairs - 1];
while (numDistancePairs > 2 && lenMain == matchDistances[numDistancePairs - 4] + 1)
{
if (!ChangePair(matchDistances[numDistancePairs - 3], backMain))
break;
numDistancePairs -= 2;
lenMain = matchDistances[numDistancePairs - 2];
backMain = matchDistances[numDistancePairs - 1];
}
if (lenMain == 2 && backMain >= 0x80)
lenMain = 1;
}
if (repLens[repMaxIndex] >= 2)
{
if (repLens[repMaxIndex] + 1 >= lenMain ||
repLens[repMaxIndex] + 2 >= lenMain && (backMain > (1 << 9)) ||
repLens[repMaxIndex] + 3 >= lenMain && (backMain > (1 << 15)))
{
backRes = repMaxIndex;
lenRes = repLens[repMaxIndex];
return MovePos(lenRes - 1);
}
}
if (lenMain >= 2 && numAvailableBytes > 2)
{
RINOK(ReadMatchDistances(_longestMatchLength, _numDistancePairs));
if (_longestMatchLength >= 2)
{
UInt32 newDistance = matchDistances[_numDistancePairs - 1];
if (_longestMatchLength >= lenMain && newDistance < backMain ||
_longestMatchLength == lenMain + 1 && !ChangePair(backMain, newDistance) ||
_longestMatchLength > lenMain + 1 ||
_longestMatchLength + 1 >= lenMain && lenMain >= 3 && ChangePair(newDistance, backMain))
{
_longestMatchWasFound = true;
backRes = UInt32(-1);
lenRes = 1;
return S_OK;
}
}
data++;
numAvailableBytes--;
for(UInt32 i = 0; i < kNumRepDistances; i++)
{
UInt32 backOffset = _repDistances[i] + 1;
if (data[1] != data[(size_t)1 - backOffset] || data[2] != data[(size_t)2 - backOffset])
{
repLens[i] = 0;
continue;
}
UInt32 len;
for (len = 2; len < numAvailableBytes && data[len] == data[(size_t)len - backOffset]; len++);
if (len + 1 >= lenMain)
{
_longestMatchWasFound = true;
backRes = UInt32(-1);
lenRes = 1;
return S_OK;
}
}
backRes = backMain + kNumRepDistances;
lenRes = lenMain;
return MovePos(lenMain - 2);
}
backRes = UInt32(-1);
lenRes = 1;
return S_OK;
}
HRESULT CEncoder::Flush(UInt32 nowPos)
{
ReleaseMFStream();
WriteEndMarker(nowPos & _posStateMask);
_rangeEncoder.FlushData();
return _rangeEncoder.FlushStream();
}
void CEncoder::WriteEndMarker(UInt32 posState)
{
// This function for writing End Mark for stream version of LZMA.
// In current version this feature is not used.
if (!_writeEndMark)
return;
_isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
_isRep[_state.Index].Encode(&_rangeEncoder, 0);
_state.UpdateMatch();
UInt32 len = kMatchMinLen; // kMatchMaxLen;
_lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
UInt32 posSlot = (1 << kNumPosSlotBits) - 1;
UInt32 lenToPosState = GetLenToPosState(len);
_posSlotEncoder[lenToPosState].Encode(&_rangeEncoder, posSlot);
UInt32 footerBits = 30;
UInt32 posReduced = (UInt32(1) << footerBits) - 1;
_rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
_posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
}
HRESULT CEncoder::CodeReal(ISequentialInStream *inStream,
ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize,
ICompressProgressInfo *progress)
{
_needReleaseMFStream = false;
CCoderReleaser coderReleaser(this);
RINOK(SetStreams(inStream, outStream, inSize, outSize));
while(true)
{
UInt64 processedInSize;
UInt64 processedOutSize;
Int32 finished;
RINOK(CodeOneBlock(&processedInSize, &processedOutSize, &finished));
if (finished != 0)
return S_OK;
if (progress != 0)
{
RINOK(progress->SetRatioInfo(&processedInSize, &processedOutSize));
}
}
}
HRESULT CEncoder::SetStreams(ISequentialInStream *inStream,
ISequentialOutStream *outStream,
const UInt64 *inSize, const UInt64 *outSize)
{
_inStream = inStream;
_finished = false;
RINOK(Create());
RINOK(SetOutStream(outStream));
RINOK(Init());
// CCoderReleaser releaser(this);
/*
if (_matchFinder->GetNumAvailableBytes() == 0)
return Flush();
*/
if (!_fastMode)
{
FillDistancesPrices();
FillAlignPrices();
}
_lenEncoder.SetTableSize(_numFastBytes + 1 - kMatchMinLen);
_lenEncoder.UpdateTables(1 << _posStateBits);
_repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - kMatchMinLen);
_repMatchLenEncoder.UpdateTables(1 << _posStateBits);
nowPos64 = 0;
return S_OK;
}
HRESULT CEncoder::CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished)
{
if (_inStream != 0)
{
RINOK(_matchFinder->SetStream(_inStream));
RINOK(_matchFinder->Init());
_needReleaseMFStream = true;
_inStream = 0;
}
*finished = 1;
if (_finished)
return S_OK;
_finished = true;
if (nowPos64 == 0)
{
if (_matchFinder->GetNumAvailableBytes() == 0)
return Flush(UInt32(nowPos64));
UInt32 len, numDistancePairs;
RINOK(ReadMatchDistances(len, numDistancePairs));
UInt32 posState = UInt32(nowPos64) & _posStateMask;
_isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
_state.UpdateChar();
Byte curByte = _matchFinder->GetIndexByte(0 - _additionalOffset);
_literalEncoder.GetSubCoder(UInt32(nowPos64), _previousByte)->Encode(&_rangeEncoder, curByte);
_previousByte = curByte;
_additionalOffset--;
nowPos64++;
}
UInt32 nowPos32 = (UInt32)nowPos64;
UInt32 progressPosValuePrev = nowPos32;
if (_matchFinder->GetNumAvailableBytes() == 0)
return Flush(nowPos32);
while(true)
{
#ifdef _NO_EXCEPTIONS
if (_rangeEncoder.Stream.ErrorCode != S_OK)
return _rangeEncoder.Stream.ErrorCode;
#endif
UInt32 pos, len;
HRESULT result;
if (_fastMode)
result = GetOptimumFast(nowPos32, pos, len);
else
result = GetOptimum(nowPos32, pos, len);
RINOK(result);
UInt32 posState = nowPos32 & _posStateMask;
if(len == 1 && pos == 0xFFFFFFFF)
{
_isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
Byte curByte = _matchFinder->GetIndexByte(0 - _additionalOffset);
CLiteralEncoder2 *subCoder = _literalEncoder.GetSubCoder(nowPos32, _previousByte);
if(_state.IsCharState())
subCoder->Encode(&_rangeEncoder, curByte);
else
{
Byte matchByte = _matchFinder->GetIndexByte(0 - _repDistances[0] - 1 - _additionalOffset);
subCoder->EncodeMatched(&_rangeEncoder, matchByte, curByte);
}
_state.UpdateChar();
_previousByte = curByte;
}
else
{
_isMatch[_state.Index][posState].Encode(&_rangeEncoder, 1);
if(pos < kNumRepDistances)
{
_isRep[_state.Index].Encode(&_rangeEncoder, 1);
if(pos == 0)
{
_isRepG0[_state.Index].Encode(&_rangeEncoder, 0);
_isRep0Long[_state.Index][posState].Encode(&_rangeEncoder, ((len == 1) ? 0 : 1));
}
else
{
UInt32 distance = _repDistances[pos];
_isRepG0[_state.Index].Encode(&_rangeEncoder, 1);
if (pos == 1)
_isRepG1[_state.Index].Encode(&_rangeEncoder, 0);
else
{
_isRepG1[_state.Index].Encode(&_rangeEncoder, 1);
_isRepG2[_state.Index].Encode(&_rangeEncoder, pos - 2);
if (pos == 3)
_repDistances[3] = _repDistances[2];
_repDistances[2] = _repDistances[1];
}
_repDistances[1] = _repDistances[0];
_repDistances[0] = distance;
}
if (len == 1)
_state.UpdateShortRep();
else
{
_repMatchLenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
_state.UpdateRep();
}
}
else
{
_isRep[_state.Index].Encode(&_rangeEncoder, 0);
_state.UpdateMatch();
_lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState, !_fastMode);
pos -= kNumRepDistances;
UInt32 posSlot = GetPosSlot(pos);
_posSlotEncoder[GetLenToPosState(len)].Encode(&_rangeEncoder, posSlot);
if (posSlot >= kStartPosModelIndex)
{
UInt32 footerBits = ((posSlot >> 1) - 1);
UInt32 base = ((2 | (posSlot & 1)) << footerBits);
UInt32 posReduced = pos - base;
if (posSlot < kEndPosModelIndex)
NRangeCoder::ReverseBitTreeEncode(_posEncoders + base - posSlot - 1,
&_rangeEncoder, footerBits, posReduced);
else
{
_rangeEncoder.EncodeDirectBits(posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
_posAlignEncoder.ReverseEncode(&_rangeEncoder, posReduced & kAlignMask);
_alignPriceCount++;
}
}
_repDistances[3] = _repDistances[2];
_repDistances[2] = _repDistances[1];
_repDistances[1] = _repDistances[0];
_repDistances[0] = pos;
_matchPriceCount++;
}
_previousByte = _matchFinder->GetIndexByte(len - 1 - _additionalOffset);
}
_additionalOffset -= len;
nowPos32 += len;
if (_additionalOffset == 0)
{
if (!_fastMode)
{
if (_matchPriceCount >= (1 << 7))
FillDistancesPrices();
if (_alignPriceCount >= kAlignTableSize)
FillAlignPrices();
}
if (_matchFinder->GetNumAvailableBytes() == 0)
return Flush(nowPos32);
if (nowPos32 - progressPosValuePrev >= (1 << 14))
{
nowPos64 += nowPos32 - progressPosValuePrev;
*inSize = nowPos64;
*outSize = _rangeEncoder.GetProcessedSize();
_finished = false;
*finished = 0;
return S_OK;
}
}
}
}
STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream,
ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
ICompressProgressInfo *progress)
{
#ifndef _NO_EXCEPTIONS
try
{
#endif
return CodeReal(inStream, outStream, inSize, outSize, progress);
#ifndef _NO_EXCEPTIONS
}
catch(const COutBufferException &e) { return e.ErrorCode; }
catch(...) { return E_FAIL; }
#endif
}
void CEncoder::FillDistancesPrices()
{
UInt32 tempPrices[kNumFullDistances];
for (UInt32 i = kStartPosModelIndex; i < kNumFullDistances; i++)
{
UInt32 posSlot = GetPosSlot(i);
UInt32 footerBits = ((posSlot >> 1) - 1);
UInt32 base = ((2 | (posSlot & 1)) << footerBits);
tempPrices[i] = NRangeCoder::ReverseBitTreeGetPrice(_posEncoders +
base - posSlot - 1, footerBits, i - base);
}
for (UInt32 lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
{
UInt32 posSlot;
NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumPosSlotBits> &encoder = _posSlotEncoder[lenToPosState];
UInt32 *posSlotPrices = _posSlotPrices[lenToPosState];
for (posSlot = 0; posSlot < _distTableSize; posSlot++)
posSlotPrices[posSlot] = encoder.GetPrice(posSlot);
for (posSlot = kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << NRangeCoder::kNumBitPriceShiftBits);
UInt32 *distancesPrices = _distancesPrices[lenToPosState];
UInt32 i;
for (i = 0; i < kStartPosModelIndex; i++)
distancesPrices[i] = posSlotPrices[i];
for (; i < kNumFullDistances; i++)
distancesPrices[i] = posSlotPrices[GetPosSlot(i)] + tempPrices[i];
}
_matchPriceCount = 0;
}
void CEncoder::FillAlignPrices()
{
for (UInt32 i = 0; i < kAlignTableSize; i++)
_alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
_alignPriceCount = 0;
}
}}