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