// LzhDecoder.cpp #include "StdAfx.h" #include "LzhDecoder.h" namespace NCompress{ namespace NLzh { namespace NDecoder { static const UInt32 kWindowSizeMin = 1 << 16; static bool CheckCodeLens(const Byte *lens, unsigned num) { UInt32 sum = 0; for (unsigned i = 0; i < num; i++) { unsigned len = lens[i]; if (len != 0) sum += ((UInt32)1 << (NUM_CODE_BITS - len)); } return sum == ((UInt32)1 << NUM_CODE_BITS); } bool CCoder::ReadTP(unsigned num, unsigned numBits, int spec) { _symbolT = -1; UInt32 n = _inBitStream.ReadBits(numBits); if (n == 0) { _symbolT = _inBitStream.ReadBits(numBits); return ((unsigned)_symbolT < num); } if (n > num) return false; { Byte lens[NPT]; unsigned i; for (i = 0; i < NPT; i++) lens[i] = 0; i = 0; do { UInt32 val = _inBitStream.GetValue(16); unsigned c = val >> 13; if (c == 7) { UInt32 mask = 1 << 12; while (mask & val) { mask >>= 1; c++; } if (c > 16) return false; } _inBitStream.MovePos(c < 7 ? 3 : c - 3); lens[i++] = (Byte)c; if (i == (unsigned)spec) i += _inBitStream.ReadBits(2); } while (i < n); if (!CheckCodeLens(lens, NPT)) return false; return _decoderT.Build(lens); } } static const unsigned NUM_C_BITS = 9; bool CCoder::ReadC() { _symbolC = -1; unsigned n = _inBitStream.ReadBits(NUM_C_BITS); if (n == 0) { _symbolC = _inBitStream.ReadBits(NUM_C_BITS); return ((unsigned)_symbolC < NC); } if (n > NC) return false; { Byte lens[NC]; unsigned i = 0; do { UInt32 c = (unsigned)_symbolT; if (_symbolT < 0) c = _decoderT.Decode(&_inBitStream); if (c <= 2) { if (c == 0) c = 1; else if (c == 1) c = _inBitStream.ReadBits(4) + 3; else c = _inBitStream.ReadBits(NUM_C_BITS) + 20; if (i + c > n) return false; do lens[i++] = 0; while (--c); } else lens[i++] = (Byte)(c - 2); } while (i < n); while (i < NC) lens[i++] = 0; if (!CheckCodeLens(lens, NC)) return false; return _decoderC.Build(lens); } } HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress) { unsigned pbit = (DictSize <= (1 << 14) ? 4 : 5); UInt32 blockSize = 0; while (rem != 0) { if (blockSize == 0) { if (_inBitStream.ExtraBitsWereRead()) return S_FALSE; if (progress) { UInt64 packSize = _inBitStream.GetProcessedSize(); UInt64 pos = _outWindow.GetProcessedSize(); RINOK(progress->SetRatioInfo(&packSize, &pos)); } blockSize = _inBitStream.ReadBits(16); if (blockSize == 0) return S_FALSE; if (!ReadTP(NT, 5, 3)) return S_FALSE; if (!ReadC()) return S_FALSE; if (!ReadTP(NP, pbit, -1)) return S_FALSE; } blockSize--; UInt32 number = (unsigned)_symbolC; if (_symbolC < 0) number = _decoderC.Decode(&_inBitStream); if (number < 256) { _outWindow.PutByte((Byte)number); rem--; } else { UInt32 len = number - 256 + kMatchMinLen; UInt32 dist = (unsigned)_symbolT; if (_symbolT < 0) dist = _decoderT.Decode(&_inBitStream); if (dist > 1) { dist--; dist = ((UInt32)1 << dist) + _inBitStream.ReadBits((unsigned)dist); } if (dist >= DictSize) return S_FALSE; if (len > rem) len = (UInt32)rem; if (!_outWindow.CopyBlock(dist, len)) return S_FALSE; rem -= len; } } if (FinishMode) { if (blockSize != 0) return S_FALSE; if (_inBitStream.ReadAlignBits() != 0) return S_FALSE; } if (_inBitStream.ExtraBitsWereRead()) return S_FALSE; return S_OK; } STDMETHODIMP CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress) { try { if (!outSize) return E_INVALIDARG; if (!_outWindow.Create(DictSize > kWindowSizeMin ? DictSize : kWindowSizeMin)) return E_OUTOFMEMORY; if (!_inBitStream.Create(1 << 17)) return E_OUTOFMEMORY; _outWindow.SetStream(outStream); _outWindow.Init(false); _inBitStream.SetStream(inStream); _inBitStream.Init(); CCoderReleaser coderReleaser(this); RINOK(CodeReal(*outSize, progress)); coderReleaser.Disable(); return _outWindow.Flush(); } catch(const CInBufferException &e) { return e.ErrorCode; } catch(const CLzOutWindowException &e) { return e.ErrorCode; } catch(...) { return S_FALSE; } } }}}