mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-06 13:14:59 -06:00
176 lines
4.6 KiB
C++
Executable File
176 lines
4.6 KiB
C++
Executable File
// QuantumDecoder.cpp
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include "../../Common/Defs.h"
|
|
|
|
#include "QuantumDecoder.h"
|
|
|
|
namespace NCompress {
|
|
namespace NQuantum {
|
|
|
|
static const int kLenIdNeedInit = -2;
|
|
|
|
static const unsigned kNumLenSymbols = 27;
|
|
static const unsigned kMatchMinLen = 3;
|
|
static const unsigned kNumSimplePosSlots = 4;
|
|
static const unsigned kNumSimpleLenSlots = 6;
|
|
|
|
void CDecoder::Init()
|
|
{
|
|
m_Selector.Init(kNumSelectors);
|
|
unsigned i;
|
|
for (i = 0; i < kNumLitSelectors; i++)
|
|
m_Literals[i].Init(kNumLitSymbols);
|
|
unsigned numItems = (_numDictBits == 0 ? 1 : (_numDictBits << 1));
|
|
const unsigned kNumPosSymbolsMax[kNumMatchSelectors] = { 24, 36, 42 };
|
|
for (i = 0; i < kNumMatchSelectors; i++)
|
|
m_PosSlot[i].Init(MyMin(numItems, kNumPosSymbolsMax[i]));
|
|
m_LenSlot.Init(kNumLenSymbols);
|
|
}
|
|
|
|
HRESULT CDecoder::CodeSpec(UInt32 curSize)
|
|
{
|
|
if (_remainLen == kLenIdNeedInit)
|
|
{
|
|
if (!_keepHistory)
|
|
{
|
|
if (!_outWindowStream.Create((UInt32)1 << _numDictBits))
|
|
return E_OUTOFMEMORY;
|
|
Init();
|
|
}
|
|
if (!_rangeDecoder.Create(1 << 20))
|
|
return E_OUTOFMEMORY;
|
|
_rangeDecoder.Init();
|
|
_remainLen = 0;
|
|
}
|
|
if (curSize == 0)
|
|
return S_OK;
|
|
|
|
while (_remainLen > 0 && curSize > 0)
|
|
{
|
|
_remainLen--;
|
|
Byte b = _outWindowStream.GetByte(_rep0);
|
|
_outWindowStream.PutByte(b);
|
|
curSize--;
|
|
}
|
|
|
|
while (curSize > 0)
|
|
{
|
|
if (_rangeDecoder.Stream.WasFinished())
|
|
return S_FALSE;
|
|
|
|
unsigned selector = m_Selector.Decode(&_rangeDecoder);
|
|
if (selector < kNumLitSelectors)
|
|
{
|
|
Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&_rangeDecoder));
|
|
_outWindowStream.PutByte(b);
|
|
curSize--;
|
|
}
|
|
else
|
|
{
|
|
selector -= kNumLitSelectors;
|
|
unsigned len = selector + kMatchMinLen;
|
|
if (selector == 2)
|
|
{
|
|
unsigned lenSlot = m_LenSlot.Decode(&_rangeDecoder);
|
|
if (lenSlot >= kNumSimpleLenSlots)
|
|
{
|
|
lenSlot -= 2;
|
|
int numDirectBits = (int)(lenSlot >> 2);
|
|
len += ((4 | (lenSlot & 3)) << numDirectBits) - 2;
|
|
if (numDirectBits < 6)
|
|
len += _rangeDecoder.Stream.ReadBits(numDirectBits);
|
|
}
|
|
else
|
|
len += lenSlot;
|
|
}
|
|
UInt32 rep0 = m_PosSlot[selector].Decode(&_rangeDecoder);
|
|
if (rep0 >= kNumSimplePosSlots)
|
|
{
|
|
int numDirectBits = (int)((rep0 >> 1) - 1);
|
|
rep0 = ((2 | (rep0 & 1)) << numDirectBits) + _rangeDecoder.Stream.ReadBits(numDirectBits);
|
|
}
|
|
unsigned locLen = len;
|
|
if (len > curSize)
|
|
locLen = (unsigned)curSize;
|
|
if (!_outWindowStream.CopyBlock(rep0, locLen))
|
|
return S_FALSE;
|
|
curSize -= locLen;
|
|
len -= locLen;
|
|
if (len != 0)
|
|
{
|
|
_remainLen = (int)len;
|
|
_rep0 = rep0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return _rangeDecoder.Stream.WasFinished() ? S_FALSE : S_OK;
|
|
}
|
|
|
|
HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
|
const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
|
|
{
|
|
if (outSize == NULL)
|
|
return E_INVALIDARG;
|
|
UInt64 size = *outSize;
|
|
|
|
SetInStream(inStream);
|
|
_outWindowStream.SetStream(outStream);
|
|
SetOutStreamSize(outSize);
|
|
CDecoderFlusher flusher(this);
|
|
|
|
const UInt64 start = _outWindowStream.GetProcessedSize();
|
|
for (;;)
|
|
{
|
|
UInt32 curSize = 1 << 18;
|
|
UInt64 rem = size - (_outWindowStream.GetProcessedSize() - start);
|
|
if (curSize > rem)
|
|
curSize = (UInt32)rem;
|
|
if (curSize == 0)
|
|
break;
|
|
RINOK(CodeSpec(curSize));
|
|
if (progress != NULL)
|
|
{
|
|
UInt64 inSize = _rangeDecoder.GetProcessedSize();
|
|
UInt64 nowPos64 = _outWindowStream.GetProcessedSize() - start;
|
|
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; }
|
|
}
|
|
|
|
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
|
|
{
|
|
_rangeDecoder.SetStream(inStream);
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CDecoder::ReleaseInStream()
|
|
{
|
|
_rangeDecoder.ReleaseStream();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
|
|
{
|
|
if (outSize == NULL)
|
|
return E_FAIL;
|
|
_remainLen = kLenIdNeedInit;
|
|
_outWindowStream.Init(_keepHistory);
|
|
return S_OK;
|
|
}
|
|
|
|
}}
|