summaryrefslogtreecommitdiffstats
path: root/src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.cpp')
-rw-r--r--src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.cpp387
1 files changed, 387 insertions, 0 deletions
diff --git a/src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.cpp b/src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.cpp
new file mode 100644
index 000000000..d1027f1f3
--- /dev/null
+++ b/src/libs/7zip/unix/CPP/7zip/Compress/LzxDecoder.cpp
@@ -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(unsigned 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));
+ unsigned 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 + (unsigned)ReadBits(kLevelSymbolZerosNumBits);
+ symbol = 0;
+ }
+ else if (number == kLevelSymbolZerosBig)
+ {
+ num = kLevelSymbolZerosBigStartValue + (unsigned)ReadBits(kLevelSymbolZerosBigNumBits);
+ symbol = 0;
+ }
+ else if (number == kLevelSymbolSame || number <= kNumHuffmanBits)
+ {
+ if (number <= kNumHuffmanBits)
+ num = 1;
+ else
+ {
+ num = kLevelSymbolSameStartValue + (unsigned)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();
+
+ unsigned blockType = (unsigned)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 (unsigned i = 1; i < kNumRepDistances; i++)
+ {
+ UInt32 rep = 0;
+ for (unsigned 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 (unsigned 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()
+{
+ unsigned 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 (unsigned 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;
+ unsigned numDirectBits;
+ if (posSlot < kNumPowerPosSlots)
+ {
+ numDirectBits = (unsigned)(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(unsigned 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;
+}
+
+}}