mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-13 08:11:33 -06:00
4.63
This commit is contained in:
committed by
Kornel Lesiński
parent
c1f1243a70
commit
3a524e5ba2
387
CPP/7zip/Compress/LzxDecoder.cpp
Executable file
387
CPP/7zip/Compress/LzxDecoder.cpp
Executable file
@@ -0,0 +1,387 @@
|
||||
// LzxDecoder.cpp
|
||||
|
||||
#include "StdAfx.h"
|
||||
|
||||
#include "../../Common/Defs.h"
|
||||
|
||||
#include "LzxDecoder.h"
|
||||
|
||||
namespace NCompress {
|
||||
namespace NLzx {
|
||||
|
||||
const int kLenIdNeedInit = -2;
|
||||
|
||||
CDecoder::CDecoder(bool wimMode):
|
||||
_keepHistory(false),
|
||||
_skipByte(false),
|
||||
_wimMode(wimMode)
|
||||
{
|
||||
m_x86ConvertOutStreamSpec = new Cx86ConvertOutStream;
|
||||
m_x86ConvertOutStream = m_x86ConvertOutStreamSpec;
|
||||
}
|
||||
|
||||
void CDecoder::ReleaseStreams()
|
||||
{
|
||||
m_OutWindowStream.ReleaseStream();
|
||||
m_InBitStream.ReleaseStream();
|
||||
m_x86ConvertOutStreamSpec->ReleaseStream();
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::Flush()
|
||||
{
|
||||
RINOK(m_OutWindowStream.Flush());
|
||||
return m_x86ConvertOutStreamSpec->Flush();
|
||||
}
|
||||
|
||||
UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
|
||||
|
||||
#define RIF(x) { if (!(x)) return false; }
|
||||
|
||||
bool CDecoder::ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols)
|
||||
{
|
||||
Byte levelLevels[kLevelTableSize];
|
||||
UInt32 i;
|
||||
for (i = 0; i < kLevelTableSize; i++)
|
||||
levelLevels[i] = (Byte)ReadBits(kNumBitsForPreTreeLevel);
|
||||
RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
|
||||
int num = 0;
|
||||
Byte symbol = 0;
|
||||
for (i = 0; i < numSymbols;)
|
||||
{
|
||||
if (num != 0)
|
||||
{
|
||||
lastLevels[i] = newLevels[i] = symbol;
|
||||
i++;
|
||||
num--;
|
||||
continue;
|
||||
}
|
||||
UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
|
||||
if (number == kLevelSymbolZeros)
|
||||
{
|
||||
num = kLevelSymbolZerosStartValue + (int)ReadBits(kLevelSymbolZerosNumBits);
|
||||
symbol = 0;
|
||||
}
|
||||
else if (number == kLevelSymbolZerosBig)
|
||||
{
|
||||
num = kLevelSymbolZerosBigStartValue + (int)ReadBits(kLevelSymbolZerosBigNumBits);
|
||||
symbol = 0;
|
||||
}
|
||||
else if (number == kLevelSymbolSame || number <= kNumHuffmanBits)
|
||||
{
|
||||
if (number <= kNumHuffmanBits)
|
||||
num = 1;
|
||||
else
|
||||
{
|
||||
num = kLevelSymbolSameStartValue + (int)ReadBits(kLevelSymbolSameNumBits);
|
||||
number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
|
||||
if (number > kNumHuffmanBits)
|
||||
return false;
|
||||
}
|
||||
symbol = Byte((17 + lastLevels[i] - number) % (kNumHuffmanBits + 1));
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDecoder::ReadTables(void)
|
||||
{
|
||||
Byte newLevels[kMaxTableSize];
|
||||
{
|
||||
if (_skipByte)
|
||||
m_InBitStream.DirectReadByte();
|
||||
m_InBitStream.Normalize();
|
||||
|
||||
int blockType = (int)ReadBits(kNumBlockTypeBits);
|
||||
if (blockType > kBlockTypeUncompressed)
|
||||
return false;
|
||||
if (_wimMode)
|
||||
if (ReadBits(1) == 1)
|
||||
m_UnCompressedBlockSize = (1 << 15);
|
||||
else
|
||||
m_UnCompressedBlockSize = ReadBits(16);
|
||||
else
|
||||
m_UnCompressedBlockSize = m_InBitStream.ReadBitsBig(kUncompressedBlockSizeNumBits);
|
||||
|
||||
m_IsUncompressedBlock = (blockType == kBlockTypeUncompressed);
|
||||
|
||||
_skipByte = (m_IsUncompressedBlock && ((m_UnCompressedBlockSize & 1) != 0));
|
||||
|
||||
if (m_IsUncompressedBlock)
|
||||
{
|
||||
ReadBits(16 - m_InBitStream.GetBitPosition());
|
||||
if (!m_InBitStream.ReadUInt32(m_RepDistances[0]))
|
||||
return false;
|
||||
m_RepDistances[0]--;
|
||||
for (int i = 1; i < kNumRepDistances; i++)
|
||||
{
|
||||
UInt32 rep = 0;
|
||||
for (int j = 0; j < 4; j++)
|
||||
rep |= (UInt32)m_InBitStream.DirectReadByte() << (8 * j);
|
||||
m_RepDistances[i] = rep - 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
m_AlignIsUsed = (blockType == kBlockTypeAligned);
|
||||
if (m_AlignIsUsed)
|
||||
{
|
||||
for(int i = 0; i < kAlignTableSize; i++)
|
||||
newLevels[i] = (Byte)ReadBits(kNumBitsForAlignLevel);
|
||||
RIF(m_AlignDecoder.SetCodeLengths(newLevels));
|
||||
}
|
||||
}
|
||||
|
||||
RIF(ReadTable(m_LastMainLevels, newLevels, 256));
|
||||
RIF(ReadTable(m_LastMainLevels + 256, newLevels + 256, m_NumPosLenSlots));
|
||||
for (UInt32 i = 256 + m_NumPosLenSlots; i < kMainTableSize; i++)
|
||||
newLevels[i] = 0;
|
||||
RIF(m_MainDecoder.SetCodeLengths(newLevels));
|
||||
|
||||
RIF(ReadTable(m_LastLenLevels, newLevels, kNumLenSymbols));
|
||||
return m_LenDecoder.SetCodeLengths(newLevels);
|
||||
}
|
||||
|
||||
class CDecoderFlusher
|
||||
{
|
||||
CDecoder *m_Decoder;
|
||||
public:
|
||||
bool NeedFlush;
|
||||
CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {}
|
||||
~CDecoderFlusher()
|
||||
{
|
||||
if (NeedFlush)
|
||||
m_Decoder->Flush();
|
||||
m_Decoder->ReleaseStreams();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void CDecoder::ClearPrevLevels()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < kMainTableSize; i++)
|
||||
m_LastMainLevels[i] = 0;
|
||||
for (i = 0; i < kNumLenSymbols; i++)
|
||||
m_LastLenLevels[i] = 0;
|
||||
};
|
||||
|
||||
|
||||
HRESULT CDecoder::CodeSpec(UInt32 curSize)
|
||||
{
|
||||
if (_remainLen == kLenIdNeedInit)
|
||||
{
|
||||
_remainLen = 0;
|
||||
m_InBitStream.Init();
|
||||
if (!_keepHistory || !m_IsUncompressedBlock)
|
||||
m_InBitStream.Normalize();
|
||||
if (!_keepHistory)
|
||||
{
|
||||
_skipByte = false;
|
||||
m_UnCompressedBlockSize = 0;
|
||||
ClearPrevLevels();
|
||||
UInt32 i86TranslationSize = 12000000;
|
||||
bool translationMode = true;
|
||||
if (!_wimMode)
|
||||
{
|
||||
translationMode = (ReadBits(1) != 0);
|
||||
if (translationMode)
|
||||
{
|
||||
i86TranslationSize = ReadBits(16) << 16;
|
||||
i86TranslationSize |= ReadBits(16);
|
||||
}
|
||||
}
|
||||
m_x86ConvertOutStreamSpec->Init(translationMode, i86TranslationSize);
|
||||
|
||||
for(int i = 0 ; i < kNumRepDistances; i++)
|
||||
m_RepDistances[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
while(_remainLen > 0 && curSize > 0)
|
||||
{
|
||||
m_OutWindowStream.PutByte(m_OutWindowStream.GetByte(m_RepDistances[0]));
|
||||
_remainLen--;
|
||||
curSize--;
|
||||
}
|
||||
|
||||
while(curSize > 0)
|
||||
{
|
||||
if (m_UnCompressedBlockSize == 0)
|
||||
if (!ReadTables())
|
||||
return S_FALSE;
|
||||
UInt32 next = (Int32)MyMin(m_UnCompressedBlockSize, curSize);
|
||||
curSize -= next;
|
||||
m_UnCompressedBlockSize -= next;
|
||||
if (m_IsUncompressedBlock)
|
||||
{
|
||||
while(next > 0)
|
||||
{
|
||||
m_OutWindowStream.PutByte(m_InBitStream.DirectReadByte());
|
||||
next--;
|
||||
}
|
||||
}
|
||||
else while(next > 0)
|
||||
{
|
||||
UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
|
||||
if (number < 256)
|
||||
{
|
||||
m_OutWindowStream.PutByte((Byte)number);
|
||||
next--;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 posLenSlot = number - 256;
|
||||
if (posLenSlot >= m_NumPosLenSlots)
|
||||
return S_FALSE;
|
||||
UInt32 posSlot = posLenSlot / kNumLenSlots;
|
||||
UInt32 lenSlot = posLenSlot % kNumLenSlots;
|
||||
UInt32 len = kMatchMinLen + lenSlot;
|
||||
if (lenSlot == kNumLenSlots - 1)
|
||||
{
|
||||
UInt32 lenTemp = m_LenDecoder.DecodeSymbol(&m_InBitStream);
|
||||
if (lenTemp >= kNumLenSymbols)
|
||||
return S_FALSE;
|
||||
len += lenTemp;
|
||||
}
|
||||
|
||||
if (posSlot < kNumRepDistances)
|
||||
{
|
||||
UInt32 distance = m_RepDistances[posSlot];
|
||||
m_RepDistances[posSlot] = m_RepDistances[0];
|
||||
m_RepDistances[0] = distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 distance;
|
||||
int numDirectBits;
|
||||
if (posSlot < kNumPowerPosSlots)
|
||||
{
|
||||
numDirectBits = (int)(posSlot >> 1) - 1;
|
||||
distance = ((2 | (posSlot & 1)) << numDirectBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
numDirectBits = kNumLinearPosSlotBits;
|
||||
distance = ((posSlot - 0x22) << kNumLinearPosSlotBits);
|
||||
}
|
||||
|
||||
if (m_AlignIsUsed && numDirectBits >= kNumAlignBits)
|
||||
{
|
||||
distance += (m_InBitStream.ReadBits(numDirectBits - kNumAlignBits) << kNumAlignBits);
|
||||
UInt32 alignTemp = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
|
||||
if (alignTemp >= kAlignTableSize)
|
||||
return S_FALSE;
|
||||
distance += alignTemp;
|
||||
}
|
||||
else
|
||||
distance += m_InBitStream.ReadBits(numDirectBits);
|
||||
m_RepDistances[2] = m_RepDistances[1];
|
||||
m_RepDistances[1] = m_RepDistances[0];
|
||||
m_RepDistances[0] = distance - kNumRepDistances;
|
||||
}
|
||||
|
||||
UInt32 locLen = len;
|
||||
if (locLen > next)
|
||||
locLen = next;
|
||||
|
||||
if (!m_OutWindowStream.CopyBlock(m_RepDistances[0], locLen))
|
||||
return S_FALSE;
|
||||
|
||||
len -= locLen;
|
||||
next -= locLen;
|
||||
if (len != 0)
|
||||
{
|
||||
_remainLen = (int)len;
|
||||
return S_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 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;
|
||||
|
||||
RINOK(SetInStream(inStream));
|
||||
m_x86ConvertOutStreamSpec->SetStream(outStream);
|
||||
m_OutWindowStream.SetStream(m_x86ConvertOutStream);
|
||||
RINOK(SetOutStreamSize(outSize));
|
||||
|
||||
CDecoderFlusher flusher(this);
|
||||
|
||||
const UInt64 start = m_OutWindowStream.GetProcessedSize();
|
||||
for (;;)
|
||||
{
|
||||
UInt32 curSize = 1 << 18;
|
||||
UInt64 rem = size - (m_OutWindowStream.GetProcessedSize() - start);
|
||||
if (curSize > rem)
|
||||
curSize = (UInt32)rem;
|
||||
if (curSize == 0)
|
||||
break;
|
||||
RINOK(CodeSpec(curSize));
|
||||
if (progress != NULL)
|
||||
{
|
||||
UInt64 inSize = m_InBitStream.GetProcessedSize();
|
||||
UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
|
||||
RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
|
||||
}
|
||||
}
|
||||
flusher.NeedFlush = false;
|
||||
return Flush();
|
||||
}
|
||||
|
||||
HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
|
||||
const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
|
||||
{
|
||||
try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
|
||||
catch(const CLzOutWindowException &e) { return e.ErrorCode; }
|
||||
catch(...) { return S_FALSE; }
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
|
||||
{
|
||||
m_InBitStream.SetStream(inStream);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::ReleaseInStream()
|
||||
{
|
||||
m_InBitStream.ReleaseStream();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
|
||||
{
|
||||
if (outSize == NULL)
|
||||
return E_FAIL;
|
||||
_remainLen = kLenIdNeedInit;
|
||||
m_OutWindowStream.Init(_keepHistory);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT CDecoder::SetParams(int numDictBits)
|
||||
{
|
||||
if (numDictBits < kNumDictionaryBitsMin || numDictBits > kNumDictionaryBitsMax)
|
||||
return E_INVALIDARG;
|
||||
UInt32 numPosSlots;
|
||||
if (numDictBits < 20)
|
||||
numPosSlots = 30 + (numDictBits - 15) * 2;
|
||||
else if (numDictBits == 20)
|
||||
numPosSlots = 42;
|
||||
else
|
||||
numPosSlots = 50;
|
||||
m_NumPosLenSlots = numPosSlots * kNumLenSlots;
|
||||
if (!m_OutWindowStream.Create(kDictionarySizeMax))
|
||||
return E_OUTOFMEMORY;
|
||||
if (!m_InBitStream.Create(1 << 16))
|
||||
return E_OUTOFMEMORY;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
}}
|
||||
Reference in New Issue
Block a user