📄 lzmaencoder.cpp
字号:
UInt32 normalMatchPrice = matchPrice +
_isRep[state.Index].GetPrice0();
while(lenEnd < cur + newLen)
_optimum[++lenEnd].Price = kIfinityPrice;
for(UInt32 lenTest = newLen; lenTest >= 2; lenTest--)
{
UInt32 curBack = _matchDistances[lenTest];
UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, 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)
{
UInt32 backOffset = curBack + 1;
UInt32 temp;
for (temp = lenTest + 1; temp < numAvailableBytes; temp++)
if (data[temp] != data[(size_t)temp - backOffset])
break;
UInt32 lenTest2 = temp - (lenTest + 1);
if (lenTest2 >= 2)
{
CState state2 = state;
state2.UpdateMatch();
UInt32 posStateNext = (position + lenTest) & _posStateMask;
UInt32 curAndLenCharPrice = curAndLenPrice +
_isMatch[state2.Index][posStateNext].GetPrice0() +
_literalEncoder.GetPrice(position + lenTest, data[(size_t)lenTest - 1],
true, data[(size_t)lenTest - backOffset], data[lenTest]);
state2.UpdateChar();
posStateNext = (position + lenTest + 1) & _posStateMask;
UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[state2.Index][posStateNext].GetPrice1();
UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();
// for(; lenTest2 >= 2; lenTest2--)
{
UInt32 offset = lenTest + 1 + lenTest2;
while(lenEnd < cur + offset)
_optimum[++lenEnd].Price = kIfinityPrice;
UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
0, lenTest2, state2, posStateNext);
COptimal &optimum = _optimum[cur + 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;
}
}
}
}
}
}
}
}
static inline bool ChangePair(UInt32 smallDist, UInt32 bigDist)
{
const int kDif = 7;
return (smallDist < (UInt32(1) << (32-kDif)) && bigDist >= (smallDist << kDif));
}
HRESULT CEncoder::ReadMatchDistances(UInt32 &lenRes)
{
lenRes = _matchFinder->GetLongestMatch(_matchDistances);
if (lenRes == _numFastBytes)
lenRes += _matchFinder->GetMatchLen(lenRes, _matchDistances[lenRes],
kMatchMaxLen - lenRes);
_additionalOffset++;
return _matchFinder->MovePos();
}
HRESULT CEncoder::GetOptimumFast(UInt32 position, UInt32 &backRes, UInt32 &lenRes)
{
UInt32 lenMain;
if (!_longestMatchWasFound)
{
RINOK(ReadMatchDistances(lenMain));
}
else
{
lenMain = _longestMatchLength;
_longestMatchWasFound = false;
}
UInt32 repLens[kNumRepDistances];
UInt32 repMaxIndex = 0;
for(UInt32 i = 0; i < kNumRepDistances; i++)
{
repLens[i] = _matchFinder->GetMatchLen(0 - 1, _repDistances[i], kMatchMaxLen);
if (i == 0 || repLens[i] > repLens[repMaxIndex])
repMaxIndex = i;
}
if(repLens[repMaxIndex] >= _numFastBytes)
{
backRes = repMaxIndex;
lenRes = repLens[repMaxIndex];
return MovePos(lenRes - 1);
}
if(lenMain >= _numFastBytes)
{
backRes = _matchDistances[_numFastBytes] + kNumRepDistances;
lenRes = lenMain;
return MovePos(lenMain - 1);
}
while (lenMain > 2)
{
if (!ChangePair(_matchDistances[lenMain - 1], _matchDistances[lenMain]))
break;
lenMain--;
}
if (lenMain == 2 && _matchDistances[2] >= 0x80)
lenMain = 1;
UInt32 backMain = _matchDistances[lenMain];
if (repLens[repMaxIndex] >= 2)
{
if (repLens[repMaxIndex] + 1 >= lenMain ||
repLens[repMaxIndex] + 2 >= lenMain && (backMain > (1<<12)))
{
backRes = repMaxIndex;
lenRes = repLens[repMaxIndex];
return MovePos(lenRes - 1);
}
}
if (lenMain >= 2)
{
RINOK(ReadMatchDistances(_longestMatchLength));
if (_longestMatchLength >= 2 &&
(
(_longestMatchLength >= lenMain && _matchDistances[lenMain] < backMain) ||
_longestMatchLength == lenMain + 1 &&
!ChangePair(backMain, _matchDistances[_longestMatchLength]) ||
_longestMatchLength > lenMain + 1 ||
_longestMatchLength + 1 >= lenMain && lenMain >= 3 &&
ChangePair(_matchDistances[lenMain - 1], backMain)
)
)
{
_longestMatchWasFound = true;
backRes = UInt32(-1);
lenRes = 1;
return S_OK;
}
for(UInt32 i = 0; i < kNumRepDistances; i++)
{
UInt32 repLen = _matchFinder->GetMatchLen(0 - 1, _repDistances[i], kMatchMaxLen);
if (repLen >= 2 && repLen + 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;
}
STDMETHODIMP CEncoder::InitMatchFinder(IMatchFinder *matchFinder)
{
_matchFinder = matchFinder;
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);
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)
{
FillPosSlotPrices();
FillDistancesPrices();
FillAlignPrices();
}
_lenEncoder.SetTableSize(_numFastBytes);
_lenEncoder.UpdateTables(1 << _posStateBits);
_repMatchLenEncoder.SetTableSize(_numFastBytes);
_repMatchLenEncoder.UpdateTables(1 << _posStateBits);
lastPosSlotFillingPos = 0;
nowPos64 = 0;
return S_OK;
}
HRESULT CEncoder::CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished)
{
if (_inStream != 0)
{
RINOK(_matchFinder->Init(_inStream));
_needReleaseMFStream = true;
_inStream = 0;
}
*finished = 1;
if (_finished)
return S_OK;
_finished = true;
UInt64 progressPosValuePrev = nowPos64;
if (nowPos64 == 0)
{
if (_matchFinder->GetNumAvailableBytes() == 0)
return Flush(UInt32(nowPos64));
UInt32 len; // it's not used
RINOK(ReadMatchDistances(len));
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++;
}
if (_matchFinder->GetNumAvailableBytes() == 0)
return Flush(UInt32(nowPos64));
while(true)
{
#ifdef _NO_EXCEPTIONS
if (_rangeEncoder.Stream.ErrorCode != S_OK)
return _rangeEncoder.Stream.ErrorCode;
#endif
UInt32 pos;
UInt32 posState = UInt32(nowPos64) & _posStateMask;
UInt32 len;
HRESULT result;
if (_fastMode)
result = GetOptimumFast(UInt32(nowPos64), pos, len);
else
result = GetOptimum(UInt32(nowPos64), pos, len);
RINOK(result);
if(len == 1 && pos == 0xFFFFFFFF)
{
_isMatch[_state.Index][posState].Encode(&_rangeEncoder, 0);
Byte curByte = _matchFinder->GetIndexByte(0 - _additionalOffset);
CLiteralEncoder2 *subCoder = _literalEncoder.GetSubCoder(UInt32(nowPos64), _previousByte);
if(!_state.IsCharState())
{
Byte matchByte = _matchFinder->GetIndexByte(0 - _repDistances[0] - 1 - _additionalOffset);
subCoder->EncodeMatched(&_rangeEncoder, matchByte, curByte);
}
else
subCoder->Encode(&_rangeEncoder, 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);
if(len == 1)
_isRep0Long[_state.Index][posState].Encode(&_rangeEncoder, 0);
else
_isRep0Long[_state.Index][posState].Encode(&_rangeEncoder, 1);
}
else
{
_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 (len == 1)
_state.UpdateShortRep();
else
{
_repMatchLenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState);
_state.UpdateRep();
}
UInt32 distance = _repDistances[pos];
if (pos != 0)
{
for(UInt32 i = pos; i >= 1; i--)
_repDistances[i] = _repDistances[i - 1];
_repDistances[0] = distance;
}
}
else
{
_isRep[_state.Index].Encode(&_rangeEncoder, 0);
_state.UpdateMatch();
_lenEncoder.Encode(&_rangeEncoder, len - kMatchMinLen, posState);
pos -= kNumRepDistances;
UInt32 posSlot = GetPosSlot(pos);
UInt32 lenToPosState = GetLenToPosState(len);
_posSlotEncoder[lenToPosState].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);
if (!_fastMode)
if (--_alignPriceCount == 0)
FillAlignPrices();
}
}
UInt32 distance = pos;
for(UInt32 i = kNumRepDistances - 1; i >= 1; i--)
_repDistances[i] = _repDistances[i - 1];
_repDistances[0] = distance;
}
_previousByte = _matchFinder->GetIndexByte(len - 1 - _additionalOffset);
}
_additionalOffset -= len;
nowPos64 += len;
if (!_fastMode)
if (nowPos64 - lastPosSlotFillingPos >= (1 << 9))
{
FillPosSlotPrices();
FillDistancesPrices();
lastPosSlotFillingPos = nowPos64;
}
if (_additionalOffset == 0)
{
*inSize = nowPos64;
*outSize = _rangeEncoder.GetProcessedSize();
if (_matchFinder->GetNumAvailableBytes() == 0)
return Flush(UInt32(nowPos64));
if (nowPos64 - progressPosValuePrev >= (1 << 12))
{
_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::FillPosSlotPrices()
{
for (UInt32 lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
{
UInt32 posSlot;
for (posSlot = 0; posSlot < kEndPosModelIndex && posSlot < _distTableSize; posSlot++)
_posSlotPrices[lenToPosState][posSlot] = _posSlotEncoder[lenToPosState].GetPrice(posSlot);
for (; posSlot < _distTableSize; posSlot++)
_posSlotPrices[lenToPosState][posSlot] = _posSlotEncoder[lenToPosState].GetPrice(posSlot) +
((((posSlot >> 1) - 1) - kNumAlignBits) << NRangeCoder::kNumBitPriceShiftBits);
}
}
void CEncoder::FillDistancesPrices()
{
for (UInt32 lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
{
UInt32 i;
for (i = 0; i < kStartPosModelIndex; i++)
_distancesPrices[lenToPosState][i] = _posSlotPrices[lenToPosState][i];
for (; i < kNumFullDistances; i++)
{
UInt32 posSlot = GetPosSlot(i);
UInt32 footerBits = ((posSlot >> 1) - 1);
UInt32 base = ((2 | (posSlot & 1)) << footerBits);
_distancesPrices[lenToPosState][i] = _posSlotPrices[lenToPosState][posSlot] +
NRangeCoder::ReverseBitTreeGetPrice(_posEncoders +
base - posSlot - 1, footerBits, i - base);
}
}
}
void CEncoder::FillAlignPrices()
{
for (UInt32 i = 0; i < kAlignTableSize; i++)
_alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
_alignPriceCount = kAlignTableSize;
}
}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -