1 // QuantumDecoder.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../Common/Defs.h"
6 
7 #include "QuantumDecoder.h"
8 
9 namespace NCompress {
10 namespace NQuantum {
11 
12 // const UInt32 kDictionarySizeMax = (1 << 21);
13 
14 const int kLenIdNeedInit = -2;
15 
Init()16 void CDecoder::Init()
17 {
18   m_Selector.Init(kNumSelectors);
19   for (unsigned int i = 0; i < kNumLitSelectors; i++)
20     m_Literals[i].Init(kNumLitSymbols);
21   unsigned int numItems = _numDictBits << 1;
22   m_PosSlot[0].Init(MyMin(numItems, kNumLen3PosSymbolsMax));
23   m_PosSlot[1].Init(MyMin(numItems, kNumLen4PosSymbolsMax));
24   m_PosSlot[2].Init(MyMin(numItems, kNumLen5PosSymbolsMax));
25   m_LenSlot.Init(kNumLenSymbols);
26 }
27 
CodeSpec(UInt32 curSize)28 HRESULT CDecoder::CodeSpec(UInt32 curSize)
29 {
30   if (_remainLen == kLenIdNeedInit)
31   {
32     if (!_keepHistory)
33     {
34       if (!_outWindowStream.Create(_dictionarySize))
35         return E_OUTOFMEMORY;
36       Init();
37     }
38     if (!_rangeDecoder.Create(1 << 20))
39       return E_OUTOFMEMORY;
40     _rangeDecoder.Init();
41     _remainLen = 0;
42   }
43   if (curSize == 0)
44     return S_OK;
45 
46   while(_remainLen > 0 && curSize > 0)
47   {
48     _remainLen--;
49     Byte b = _outWindowStream.GetByte(_rep0);
50     _outWindowStream.PutByte(b);
51     curSize--;
52   }
53 
54   while(curSize > 0)
55   {
56     if (_rangeDecoder.Stream.WasFinished())
57       return S_FALSE;
58 
59     unsigned int selector = m_Selector.Decode(&_rangeDecoder);
60     if (selector < kNumLitSelectors)
61     {
62       Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&_rangeDecoder));
63       _outWindowStream.PutByte(b);
64       curSize--;
65     }
66     else
67     {
68       selector -= kNumLitSelectors;
69       unsigned int len = selector + kMatchMinLen;
70       if (selector == 2)
71       {
72         unsigned int lenSlot = m_LenSlot.Decode(&_rangeDecoder);;
73         if (lenSlot >= kNumSimpleLenSlots)
74         {
75           lenSlot -= 2;
76           int numDirectBits = (int)(lenSlot >> 2);
77           len +=  ((4 | (lenSlot & 3)) << numDirectBits) - 2;
78           if (numDirectBits < 6)
79             len += _rangeDecoder.Stream.ReadBits(numDirectBits);
80         }
81         else
82           len += lenSlot;
83       }
84       UInt32 rep0 = m_PosSlot[selector].Decode(&_rangeDecoder);;
85       if (rep0 >= kNumSimplePosSlots)
86       {
87         int numDirectBits = (int)((rep0 >> 1) - 1);
88         rep0 = ((2 | (rep0 & 1)) << numDirectBits) + _rangeDecoder.Stream.ReadBits(numDirectBits);
89       }
90       unsigned int locLen = len;
91       if (len > curSize)
92         locLen = (unsigned int)curSize;
93       if (!_outWindowStream.CopyBlock(rep0, locLen))
94         return S_FALSE;
95       curSize -= locLen;
96       len -= locLen;
97       if (len != 0)
98       {
99         _remainLen = (int)len;
100         _rep0 = rep0;
101         break;
102       }
103     }
104   }
105   return _rangeDecoder.Stream.WasFinished() ? S_FALSE : S_OK;
106 }
107 
CodeReal(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress)108 HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
109     const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
110 {
111   if (outSize == NULL)
112     return E_INVALIDARG;
113   UInt64 size = *outSize;
114 
115   SetInStream(inStream);
116   _outWindowStream.SetStream(outStream);
117   SetOutStreamSize(outSize);
118   CDecoderFlusher flusher(this);
119 
120   const UInt64 start = _outWindowStream.GetProcessedSize();
121   for (;;)
122   {
123     UInt32 curSize = 1 << 18;
124     UInt64 rem = size - (_outWindowStream.GetProcessedSize() - start);
125     if (curSize > rem)
126       curSize = (UInt32)rem;
127     if (curSize == 0)
128       break;
129     RINOK(CodeSpec(curSize));
130     if (progress != NULL)
131     {
132       UInt64 inSize = _rangeDecoder.GetProcessedSize();
133       UInt64 nowPos64 = _outWindowStream.GetProcessedSize() - start;
134       RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
135     }
136   }
137   flusher.NeedFlush = false;
138   return Flush();
139 }
140 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)141 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
142     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
143 {
144   try  { return CodeReal(inStream, outStream, inSize, outSize, progress); }
145   catch(const CInBufferException &e)  { return e.ErrorCode; }
146   catch(const CLzOutWindowException &e)  { return e.ErrorCode; }
147   catch(...) { return S_FALSE; }
148 }
149 
SetInStream(ISequentialInStream * inStream)150 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
151 {
152   _rangeDecoder.SetStream(inStream);
153   return S_OK;
154 }
155 
ReleaseInStream()156 STDMETHODIMP CDecoder::ReleaseInStream()
157 {
158   _rangeDecoder.ReleaseStream();
159   return S_OK;
160 }
161 
SetOutStreamSize(const UInt64 * outSize)162 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
163 {
164   if (outSize == NULL)
165     return E_FAIL;
166   _remainLen = kLenIdNeedInit;
167   _outWindowStream.Init(_keepHistory);
168   return S_OK;
169 }
170 
171 }}
172