// QuantumDecoder.cpp #include "StdAfx.h" #include "../../Common/Defs.h" #include "QuantumDecoder.h" namespace NCompress { namespace NQuantum { static const int kLenIdNeedInit = -2; static const unsigned kNumLenSymbols = 27; static const unsigned kMatchMinLen = 3; static const unsigned kNumSimplePosSlots = 4; static const unsigned kNumSimpleLenSlots = 6; void CDecoder::Init() { m_Selector.Init(kNumSelectors); unsigned i; for (i = 0; i < kNumLitSelectors; i++) m_Literals[i].Init(kNumLitSymbols); unsigned numItems = (_numDictBits == 0 ? 1 : (_numDictBits << 1)); const unsigned kNumPosSymbolsMax[kNumMatchSelectors] = { 24, 36, 42 }; for (i = 0; i < kNumMatchSelectors; i++) m_PosSlot[i].Init(MyMin(numItems, kNumPosSymbolsMax[i])); m_LenSlot.Init(kNumLenSymbols); } HRESULT CDecoder::CodeSpec(UInt32 curSize) { if (_remainLen == kLenIdNeedInit) { if (!_keepHistory) { if (!_outWindowStream.Create((UInt32)1 << _numDictBits)) return E_OUTOFMEMORY; Init(); } if (!_rangeDecoder.Create(1 << 20)) return E_OUTOFMEMORY; _rangeDecoder.Init(); _remainLen = 0; } if (curSize == 0) return S_OK; while (_remainLen > 0 && curSize > 0) { _remainLen--; Byte b = _outWindowStream.GetByte(_rep0); _outWindowStream.PutByte(b); curSize--; } while (curSize > 0) { if (_rangeDecoder.Stream.WasFinished()) return S_FALSE; unsigned selector = m_Selector.Decode(&_rangeDecoder); if (selector < kNumLitSelectors) { Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&_rangeDecoder)); _outWindowStream.PutByte(b); curSize--; } else { selector -= kNumLitSelectors; unsigned len = selector + kMatchMinLen; if (selector == 2) { unsigned lenSlot = m_LenSlot.Decode(&_rangeDecoder); if (lenSlot >= kNumSimpleLenSlots) { lenSlot -= 2; int numDirectBits = (int)(lenSlot >> 2); len += ((4 | (lenSlot & 3)) << numDirectBits) - 2; if (numDirectBits < 6) len += _rangeDecoder.Stream.ReadBits(numDirectBits); } else len += lenSlot; } UInt32 rep0 = m_PosSlot[selector].Decode(&_rangeDecoder); if (rep0 >= kNumSimplePosSlots) { int numDirectBits = (int)((rep0 >> 1) - 1); rep0 = ((2 | (rep0 & 1)) << numDirectBits) + _rangeDecoder.Stream.ReadBits(numDirectBits); } unsigned locLen = len; if (len > curSize) locLen = (unsigned)curSize; if (!_outWindowStream.CopyBlock(rep0, locLen)) return S_FALSE; curSize -= locLen; len -= locLen; if (len != 0) { _remainLen = (int)len; _rep0 = rep0; break; } } } return _rangeDecoder.Stream.WasFinished() ? S_FALSE : 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; SetInStream(inStream); _outWindowStream.SetStream(outStream); SetOutStreamSize(outSize); CDecoderFlusher flusher(this); const UInt64 start = _outWindowStream.GetProcessedSize(); for (;;) { UInt32 curSize = 1 << 18; UInt64 rem = size - (_outWindowStream.GetProcessedSize() - start); if (curSize > rem) curSize = (UInt32)rem; if (curSize == 0) break; RINOK(CodeSpec(curSize)); if (progress != NULL) { UInt64 inSize = _rangeDecoder.GetProcessedSize(); UInt64 nowPos64 = _outWindowStream.GetProcessedSize() - start; RINOK(progress->SetRatioInfo(&inSize, &nowPos64)); } } flusher.NeedFlush = false; return Flush(); } STDMETHODIMP CDecoder::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; } } STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _rangeDecoder.SetStream(inStream); return S_OK; } STDMETHODIMP CDecoder::ReleaseInStream() { _rangeDecoder.ReleaseStream(); return S_OK; } STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) { if (outSize == NULL) return E_FAIL; _remainLen = kLenIdNeedInit; _outWindowStream.Init(_keepHistory); return S_OK; } }}