mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-12 07:09:54 -06:00
357 lines
9.5 KiB
C++
Executable File
357 lines
9.5 KiB
C++
Executable File
// LZMADecoder.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "LZMADecoder.h"
|
|
#include "../../../Common/Defs.h"
|
|
#include "../../../Common/ComTry.h"
|
|
|
|
/*
|
|
#include "fstream.h"
|
|
#include "iomanip.h"
|
|
|
|
ofstream ofs("res.dat");
|
|
|
|
const int kNumCounters = 3;
|
|
UINT32 g_Counter[kNumCounters];
|
|
class C1
|
|
{
|
|
public:
|
|
~C1()
|
|
{
|
|
for (int i = 0; i < kNumCounters; i++)
|
|
ofs << setw(10) << g_Counter[i] << endl;
|
|
}
|
|
} g_C1;
|
|
*/
|
|
|
|
/*
|
|
const UINT32 kLenTableMax = 20;
|
|
const UINT32 kNumDists = NCompress::NLZMA::kDistTableSizeMax / 2;
|
|
UINT32 g_Counts[kLenTableMax][kNumDists];
|
|
class C1
|
|
{
|
|
public:
|
|
~C1 ()
|
|
{
|
|
UINT32 sums[kLenTableMax];
|
|
for (int len = 2; len < kLenTableMax; len++)
|
|
{
|
|
sums[len] = 0;
|
|
for (int dist = 0; dist < kNumDists; dist++)
|
|
sums[len] += g_Counts[len][dist];
|
|
if (sums[len] == 0)
|
|
sums[len] = 1;
|
|
}
|
|
for (int dist = 0; dist < kNumDists; dist++)
|
|
{
|
|
ofs << setw(4) << dist << " ";
|
|
for (int len = 2; len < kLenTableMax; len++)
|
|
{
|
|
ofs << setw(4) << g_Counts[len][dist] * 1000 / sums[len];
|
|
}
|
|
ofs << endl;
|
|
}
|
|
}
|
|
} g_Class;
|
|
|
|
void UpdateStat(UINT32 len, UINT32 dist)
|
|
{
|
|
if (len >= kLenTableMax)
|
|
len = kLenTableMax - 1;
|
|
g_Counts[len][dist / 2]++;
|
|
}
|
|
*/
|
|
|
|
namespace NCompress {
|
|
namespace NLZMA {
|
|
|
|
HRESULT CDecoder::SetDictionarySize(UINT32 dictionarySize)
|
|
{
|
|
if (_dictionarySize != dictionarySize)
|
|
{
|
|
_dictionarySize = dictionarySize;
|
|
_dictionarySizeCheck = MyMax(_dictionarySize, UINT32(1));
|
|
UINT32 blockSize = MyMax(_dictionarySizeCheck, UINT32(1 << 12));
|
|
try
|
|
{
|
|
_outWindowStream.Create(blockSize /*, kMatchMaxLen */);
|
|
}
|
|
catch(...)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CDecoder::SetLiteralProperties(
|
|
UINT32 numLiteralPosStateBits, UINT32 numLiteralContextBits)
|
|
{
|
|
if (numLiteralPosStateBits > 8)
|
|
return E_INVALIDARG;
|
|
if (numLiteralContextBits > 8)
|
|
return E_INVALIDARG;
|
|
_literalDecoder.Create(numLiteralPosStateBits, numLiteralContextBits);
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT CDecoder::SetPosBitsProperties(UINT32 numPosStateBits)
|
|
{
|
|
if (numPosStateBits > NLength::kNumPosStatesBitsMax)
|
|
return E_INVALIDARG;
|
|
UINT32 numPosStates = 1 << numPosStateBits;
|
|
_lenDecoder.Create(numPosStates);
|
|
_repMatchLenDecoder.Create(numPosStates);
|
|
_posStateMask = numPosStates - 1;
|
|
return S_OK;
|
|
}
|
|
|
|
CDecoder::CDecoder():
|
|
_dictionarySize((UINT32)-1)
|
|
{
|
|
Create();
|
|
}
|
|
|
|
HRESULT CDecoder::Create()
|
|
{
|
|
COM_TRY_BEGIN
|
|
for(int i = 0; i < kNumPosModels; i++)
|
|
_posDecoders[i].Create(((kStartPosModelIndex + i) >> 1) - 1);
|
|
COM_TRY_END
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
HRESULT CDecoder::Init(ISequentialInStream *inStream,
|
|
ISequentialOutStream *outStream)
|
|
{
|
|
_rangeDecoder.Init(inStream);
|
|
|
|
_outWindowStream.Init(outStream);
|
|
|
|
int i;
|
|
for(i = 0; i < kNumStates; i++)
|
|
{
|
|
for (UINT32 j = 0; j <= _posStateMask; j++)
|
|
{
|
|
_mainChoiceDecoders[i][j].Init();
|
|
_matchRepShortChoiceDecoders[i][j].Init();
|
|
}
|
|
_matchChoiceDecoders[i].Init();
|
|
_matchRepChoiceDecoders[i].Init();
|
|
_matchRep1ChoiceDecoders[i].Init();
|
|
_matchRep2ChoiceDecoders[i].Init();
|
|
}
|
|
|
|
_literalDecoder.Init();
|
|
|
|
// _repMatchLenDecoder.Init();
|
|
|
|
for (i = 0; i < kNumLenToPosStates; i++)
|
|
_posSlotDecoder[i].Init();
|
|
|
|
for(i = 0; i < kNumPosModels; i++)
|
|
_posDecoders[i].Init();
|
|
|
|
_lenDecoder.Init();
|
|
_repMatchLenDecoder.Init();
|
|
|
|
_posAlignDecoder.Init();
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream,
|
|
ISequentialOutStream *outStream,
|
|
const UINT64 *inSize, const UINT64 *outSize,
|
|
ICompressProgressInfo *progress)
|
|
{
|
|
/*
|
|
if (outSize == NULL)
|
|
return E_INVALIDARG;
|
|
*/
|
|
|
|
Init(inStream, outStream);
|
|
CDecoderFlusher flusher(this);
|
|
|
|
CState state;
|
|
state.Init();
|
|
bool peviousIsMatch = false;
|
|
BYTE previousByte = 0;
|
|
UINT32 repDistances[kNumRepDistances];
|
|
for(int i = 0 ; i < kNumRepDistances; i++)
|
|
repDistances[i] = 0;
|
|
|
|
UINT64 nowPos64 = 0;
|
|
UINT64 size = (outSize == NULL) ? (UINT64)(INT64)(-1) : *outSize;
|
|
while(nowPos64 < size)
|
|
{
|
|
UINT64 nextPos = MyMin(nowPos64 + (1 << 18), size);
|
|
while(nowPos64 < nextPos)
|
|
{
|
|
UINT32 posState = UINT32(nowPos64) & _posStateMask;
|
|
if (_mainChoiceDecoders[state.Index][posState].Decode(&_rangeDecoder) == kMainChoiceLiteralIndex)
|
|
{
|
|
state.UpdateChar();
|
|
if(peviousIsMatch)
|
|
{
|
|
BYTE matchByte = _outWindowStream.GetOneByte(0 - repDistances[0] - 1);
|
|
previousByte = _literalDecoder.DecodeWithMatchByte(&_rangeDecoder,
|
|
UINT32(nowPos64), previousByte, matchByte);
|
|
peviousIsMatch = false;
|
|
}
|
|
else
|
|
previousByte = _literalDecoder.DecodeNormal(&_rangeDecoder,
|
|
UINT32(nowPos64), previousByte);
|
|
_outWindowStream.PutOneByte(previousByte);
|
|
nowPos64++;
|
|
}
|
|
else
|
|
{
|
|
peviousIsMatch = true;
|
|
UINT32 distance, len;
|
|
if(_matchChoiceDecoders[state.Index].Decode(&_rangeDecoder) ==
|
|
kMatchChoiceRepetitionIndex)
|
|
{
|
|
if(_matchRepChoiceDecoders[state.Index].Decode(&_rangeDecoder) == 0)
|
|
{
|
|
if(_matchRepShortChoiceDecoders[state.Index][posState].Decode(&_rangeDecoder) == 0)
|
|
{
|
|
state.UpdateShortRep();
|
|
previousByte = _outWindowStream.GetOneByte(0 - repDistances[0] - 1);
|
|
_outWindowStream.PutOneByte(previousByte);
|
|
nowPos64++;
|
|
continue;
|
|
}
|
|
distance = repDistances[0];
|
|
}
|
|
else
|
|
{
|
|
if(_matchRep1ChoiceDecoders[state.Index].Decode(&_rangeDecoder) == 0)
|
|
distance = repDistances[1];
|
|
else
|
|
{
|
|
if (_matchRep2ChoiceDecoders[state.Index].Decode(&_rangeDecoder) == 0)
|
|
distance = repDistances[2];
|
|
else
|
|
{
|
|
distance = repDistances[3];
|
|
repDistances[3] = repDistances[2];
|
|
}
|
|
repDistances[2] = repDistances[1];
|
|
}
|
|
repDistances[1] = repDistances[0];
|
|
repDistances[0] = distance;
|
|
}
|
|
len = _repMatchLenDecoder.Decode(&_rangeDecoder, posState) + kMatchMinLen;
|
|
state.UpdateRep();
|
|
}
|
|
else
|
|
{
|
|
len = kMatchMinLen + _lenDecoder.Decode(&_rangeDecoder, posState);
|
|
state.UpdateMatch();
|
|
UINT32 posSlot = _posSlotDecoder[GetLenToPosState(len)].Decode(&_rangeDecoder);
|
|
if (posSlot >= kStartPosModelIndex)
|
|
{
|
|
UINT32 numDirectBits = (posSlot >> 1) - 1;
|
|
distance = ((2 | (posSlot & 1)) << numDirectBits);
|
|
|
|
if (posSlot < kEndPosModelIndex)
|
|
distance += _posDecoders[posSlot - kStartPosModelIndex].Decode(&_rangeDecoder);
|
|
else
|
|
{
|
|
distance += (_rangeDecoder.DecodeDirectBits(
|
|
numDirectBits - kNumAlignBits) << kNumAlignBits);
|
|
distance += _posAlignDecoder.Decode(&_rangeDecoder);
|
|
}
|
|
}
|
|
else
|
|
distance = posSlot;
|
|
|
|
repDistances[3] = repDistances[2];
|
|
repDistances[2] = repDistances[1];
|
|
repDistances[1] = repDistances[0];
|
|
repDistances[0] = distance;
|
|
// UpdateStat(len, posSlot);
|
|
}
|
|
if (distance >= nowPos64 || distance >= _dictionarySizeCheck)
|
|
{
|
|
if (distance == (UINT32)(-1) && size == (UINT64)(INT64)(-1))
|
|
{
|
|
flusher.NeedFlush = false;
|
|
return Flush();
|
|
}
|
|
throw "data error";
|
|
}
|
|
_outWindowStream.CopyBackBlock(distance, len);
|
|
nowPos64 += len;
|
|
previousByte = _outWindowStream.GetOneByte(0 - 1);
|
|
}
|
|
}
|
|
if (progress != NULL)
|
|
{
|
|
UINT64 inSize = _rangeDecoder.GetProcessedSize();
|
|
RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
|
|
}
|
|
}
|
|
flusher.NeedFlush = false;
|
|
return Flush();
|
|
}
|
|
|
|
STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
|
|
ISequentialOutStream *outStream, const UINT64 *inSize, const UINT64 *outSize,
|
|
ICompressProgressInfo *progress)
|
|
{
|
|
try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
|
|
catch(const CInBufferException &e) { return e.ErrorCode; }
|
|
catch(const CLZOutWindowException &e) { return e.ErrorCode; }
|
|
catch(...) { return S_FALSE; }
|
|
}
|
|
|
|
|
|
static HRESULT DecodeProperties(ISequentialInStream *inStream,
|
|
UINT32 &numPosStateBits,
|
|
UINT32 &numLiteralPosStateBits,
|
|
UINT32 &numLiteralContextBits,
|
|
UINT32 &dictionarySize)
|
|
{
|
|
UINT32 processesedSize;
|
|
|
|
BYTE firstByte;
|
|
RINOK(inStream->Read(&firstByte, sizeof(firstByte), &processesedSize));
|
|
if (processesedSize != sizeof(firstByte))
|
|
return E_INVALIDARG;
|
|
|
|
numLiteralContextBits = firstByte % 9;
|
|
BYTE remainder = firstByte / 9;
|
|
numLiteralPosStateBits = remainder % 5;
|
|
numPosStateBits = remainder / 5;
|
|
|
|
RINOK(inStream->Read(&dictionarySize, sizeof(dictionarySize), &processesedSize));
|
|
if (processesedSize != sizeof(dictionarySize))
|
|
return E_INVALIDARG;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CDecoder::SetDecoderProperties(ISequentialInStream *inStream)
|
|
{
|
|
UINT32 numPosStateBits;
|
|
UINT32 numLiteralPosStateBits;
|
|
UINT32 numLiteralContextBits;
|
|
UINT32 dictionarySize;
|
|
RINOK(DecodeProperties(inStream,
|
|
numPosStateBits,
|
|
numLiteralPosStateBits,
|
|
numLiteralContextBits,
|
|
dictionarySize));
|
|
RINOK(SetDictionarySize(dictionarySize));
|
|
RINOK(SetLiteralProperties(numLiteralPosStateBits, numLiteralContextBits));
|
|
RINOK(SetPosBitsProperties(numPosStateBits));
|
|
return S_OK;
|
|
}
|
|
|
|
}}
|