diff options
Diffstat (limited to 'CPP/7zip/Compress/LzhDecoder.cpp')
-rwxr-xr-x | CPP/7zip/Compress/LzhDecoder.cpp | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/CPP/7zip/Compress/LzhDecoder.cpp b/CPP/7zip/Compress/LzhDecoder.cpp new file mode 100755 index 00000000..6f9b5065 --- /dev/null +++ b/CPP/7zip/Compress/LzhDecoder.cpp @@ -0,0 +1,220 @@ +// LzhDecoder.cpp + +#include "StdAfx.h" + +#include "LzhDecoder.h" + +#include "Windows/Defs.h" + +namespace NCompress{ +namespace NLzh { +namespace NDecoder { + +static const UInt32 kHistorySize = (1 << 16); + +static const int kBlockSizeBits = 16; +static const int kNumCBits = 9; +static const int kNumLevelBits = 5; // smallest integer such that (1 << kNumLevelBits) > kNumLevelSymbols/ + +UInt32 CCoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); } + +HRESULT CCoder::ReadLevelTable() +{ + int n = ReadBits(kNumLevelBits); + if (n == 0) + { + m_LevelHuffman.Symbol = ReadBits(kNumLevelBits); + if (m_LevelHuffman.Symbol >= kNumLevelSymbols) + return S_FALSE; + } + else + { + if (n > kNumLevelSymbols) + return S_FALSE; + m_LevelHuffman.Symbol = -1; + Byte lens[kNumLevelSymbols]; + int i = 0; + while (i < n) + { + int c = m_InBitStream.ReadBits(3); + if (c == 7) + while (ReadBits(1)) + if (c++ > kMaxHuffmanLen) + return S_FALSE; + lens[i++] = (Byte)c; + if (i == kNumSpecLevelSymbols) + { + c = ReadBits(2); + while (--c >= 0) + lens[i++] = 0; + } + } + while (i < kNumLevelSymbols) + lens[i++] = 0; + m_LevelHuffman.SetCodeLengths(lens); + } + return S_OK; +} + +HRESULT CCoder::ReadPTable(int numBits) +{ + int n = ReadBits(numBits); + if (n == 0) + { + m_PHuffmanDecoder.Symbol = ReadBits(numBits); + if (m_PHuffmanDecoder.Symbol >= kNumDistanceSymbols) + return S_FALSE; + } + else + { + if (n > kNumDistanceSymbols) + return S_FALSE; + m_PHuffmanDecoder.Symbol = -1; + Byte lens[kNumDistanceSymbols]; + int i = 0; + while (i < n) + { + int c = m_InBitStream.ReadBits(3); + if (c == 7) + while (ReadBits(1)) + { + if (c > kMaxHuffmanLen) + return S_FALSE; + c++; + } + lens[i++] = (Byte)c; + } + while (i < kNumDistanceSymbols) + lens[i++] = 0; + m_PHuffmanDecoder.SetCodeLengths(lens); + } + return S_OK; +} + +HRESULT CCoder::ReadCTable() +{ + int n = ReadBits(kNumCBits); + if (n == 0) + { + m_CHuffmanDecoder.Symbol = ReadBits(kNumCBits); + if (m_CHuffmanDecoder.Symbol >= kNumCSymbols) + return S_FALSE; + } + else + { + if (n > kNumCSymbols) + return S_FALSE; + m_CHuffmanDecoder.Symbol = -1; + Byte lens[kNumCSymbols]; + int i = 0; + while (i < n) + { + int c = m_LevelHuffman.Decode(&m_InBitStream); + if (c < kNumSpecLevelSymbols) + { + if (c == 0) + c = 1; + else if (c == 1) + c = ReadBits(4) + 3; + else + c = ReadBits(kNumCBits) + 20; + while (--c >= 0) + { + if (i > kNumCSymbols) + return S_FALSE; + lens[i++] = 0; + } + } + else + lens[i++] = (Byte)(c - 2); + } + while (i < kNumCSymbols) + lens[i++] = 0; + m_CHuffmanDecoder.SetCodeLengths(lens); + } + return S_OK; +} + +STDMETHODIMP CCoder::CodeReal(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + if (outSize == NULL) + return E_INVALIDARG; + + if (!m_OutWindowStream.Create(kHistorySize)) + return E_OUTOFMEMORY; + if (!m_InBitStream.Create(1 << 20)) + return E_OUTOFMEMORY; + + UInt64 pos = 0; + m_OutWindowStream.SetStream(outStream); + m_OutWindowStream.Init(false); + m_InBitStream.SetStream(inStream); + m_InBitStream.Init(); + + CCoderReleaser coderReleaser(this); + + int pbit; + if (m_NumDictBits <= 13) + pbit = 4; + else + pbit = 5; + + UInt32 blockSize = 0; + + while(pos < *outSize) + { + // for (i = 0; i < dictSize; i++) dtext[i] = 0x20; + + if (blockSize == 0) + { + if (progress != NULL) + { + UInt64 packSize = m_InBitStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&packSize, &pos)); + } + blockSize = ReadBits(kBlockSizeBits); + ReadLevelTable(); + ReadCTable(); + RINOK(ReadPTable(pbit)); + } + blockSize--; + UInt32 c = m_CHuffmanDecoder.Decode(&m_InBitStream); + if (c < 256) + { + m_OutWindowStream.PutByte((Byte)c); + pos++; + } + else if (c >= kNumCSymbols) + return S_FALSE; + else + { + // offset = (interface->method == LARC_METHOD_NUM) ? 0x100 - 2 : 0x100 - 3; + UInt32 len = c - 256 + kMinMatch; + UInt32 distance = m_PHuffmanDecoder.Decode(&m_InBitStream); + if (distance != 0) + distance = (1 << (distance - 1)) + ReadBits(distance - 1); + if (distance >= pos) + return S_FALSE; + if (pos + len > *outSize) + len = (UInt32)(*outSize - pos); + pos += len; + m_OutWindowStream.CopyBlock(distance, len); + } + } + coderReleaser.NeedFlush = false; + return m_OutWindowStream.Flush(); +} + +STDMETHODIMP CCoder::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; } +} + +}}} |