// QuantumDecoder.h #ifndef __COMPRESS_QUANTUM_DECODER_H #define __COMPRESS_QUANTUM_DECODER_H #include "../../Common/MyCom.h" #include "LzOutWindow.h" namespace NCompress { namespace NQuantum { class CBitDecoder { UInt32 Value; bool _extra; const Byte *_buf; const Byte *_bufLim; public: void SetStreamAndInit(const Byte *inData, size_t inSize) { _buf = inData; _bufLim = inData + inSize; Value = 0x10000; _extra = false; } bool WasExtraRead() const { return _extra; } bool WasFinishedOK() const { return !_extra && _buf == _bufLim; } UInt32 ReadBit() { if (Value >= 0x10000) { Byte b; if (_buf >= _bufLim) { b = 0xFF; _extra = true; } else b = *_buf++; Value = 0x100 | b; } UInt32 res = (Value >> 7) & 1; Value <<= 1; return res; } UInt32 ReadStart16Bits() { // we use check for extra read in another code. UInt32 val = ((UInt32)*_buf << 8) | _buf[1]; _buf += 2; return val; } UInt32 ReadBits(unsigned numBits) // numBits > 0 { UInt32 res = 0; do res = (res << 1) | ReadBit(); while (--numBits); return res; } }; class CRangeDecoder { UInt32 Low; UInt32 Range; UInt32 Code; public: CBitDecoder Stream; void Init() { Low = 0; Range = 0x10000; Code = Stream.ReadStart16Bits(); } bool Finish() { // do all streams use these two bits at end? if (Stream.ReadBit() != 0) return false; if (Stream.ReadBit() != 0) return false; return Stream.WasFinishedOK(); } UInt32 GetThreshold(UInt32 total) const { return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required; } void Decode(UInt32 start, UInt32 end, UInt32 total) { UInt32 high = Low + end * Range / total - 1; UInt32 offset = start * Range / total; Code -= offset; Low += offset; for (;;) { if ((Low & 0x8000) != (high & 0x8000)) { if ((Low & 0x4000) == 0 || (high & 0x4000) != 0) break; Low &= 0x3FFF; high |= 0x4000; } Low = (Low << 1) & 0xFFFF; high = ((high << 1) | 1) & 0xFFFF; Code = ((Code << 1) | Stream.ReadBit()); } Range = high - Low + 1; } }; const unsigned kNumLitSelectorBits = 2; const unsigned kNumLitSelectors = (1 << kNumLitSelectorBits); const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits); const unsigned kNumMatchSelectors = 3; const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors; const unsigned kNumSymbolsMax = kNumLitSymbols; // 64 class CModelDecoder { unsigned NumItems; unsigned ReorderCount; UInt16 Freqs[kNumSymbolsMax + 1]; Byte Vals[kNumSymbolsMax]; public: void Init(unsigned numItems); unsigned Decode(CRangeDecoder *rc); }; class CDecoder: public IUnknown, public CMyUnknownImp { CLzOutWindow _outWindow; unsigned _numDictBits; CModelDecoder m_Selector; CModelDecoder m_Literals[kNumLitSelectors]; CModelDecoder m_PosSlot[kNumMatchSelectors]; CModelDecoder m_LenSlot; void Init(); HRESULT CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize); public: MY_UNKNOWN_IMP HRESULT Code(const Byte *inData, size_t inSize, ISequentialOutStream *outStream, UInt32 outSize, bool keepHistory); HRESULT SetParams(unsigned numDictBits); CDecoder(): _numDictBits(0) {} virtual ~CDecoder() {} }; }} #endif