Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / Compress / DeflateDecoder.cpp
1 // DeflateDecoder.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "DeflateDecoder.h"\r
6 \r
7 namespace NCompress {\r
8 namespace NDeflate {\r
9 namespace NDecoder {\r
10 \r
11 static const int kLenIdFinished = -1;\r
12 static const int kLenIdNeedInit = -2;\r
13 \r
14 CCoder::CCoder(bool deflate64Mode, bool deflateNSIS):\r
15     _deflate64Mode(deflate64Mode),\r
16     _deflateNSIS(deflateNSIS),\r
17     _keepHistory(false),\r
18     _needInitInStream(true),\r
19     ZlibMode(false) {}\r
20 \r
21 UInt32 CCoder::ReadBits(int numBits)\r
22 {\r
23   return m_InBitStream.ReadBits(numBits);\r
24 }\r
25 \r
26 bool CCoder::DeCodeLevelTable(Byte *values, int numSymbols)\r
27 {\r
28   int i = 0;\r
29   do\r
30   {\r
31     UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);\r
32     if (number < kTableDirectLevels)\r
33       values[i++] = (Byte)number;\r
34     else if (number < kLevelTableSize)\r
35     {\r
36       if (number == kTableLevelRepNumber)\r
37       {\r
38         if (i == 0)\r
39           return false;\r
40         int num = ReadBits(2) + 3;\r
41         for (; num > 0 && i < numSymbols; num--, i++)\r
42           values[i] = values[i - 1];\r
43       }\r
44       else\r
45       {\r
46         int num;\r
47         if (number == kTableLevel0Number)\r
48           num = ReadBits(3) + 3;\r
49         else\r
50           num = ReadBits(7) + 11;\r
51         for (;num > 0 && i < numSymbols; num--)\r
52           values[i++] = 0;\r
53       }\r
54     }\r
55     else\r
56       return false;\r
57   }\r
58   while(i < numSymbols);\r
59   return true;\r
60 }\r
61 \r
62 #define RIF(x) { if (!(x)) return false; }\r
63 \r
64 bool CCoder::ReadTables(void)\r
65 {\r
66   m_FinalBlock = (ReadBits(kFinalBlockFieldSize) == NFinalBlockField::kFinalBlock);\r
67   UInt32 blockType = ReadBits(kBlockTypeFieldSize);\r
68   if (blockType > NBlockType::kDynamicHuffman)\r
69     return false;\r
70 \r
71   if (blockType == NBlockType::kStored)\r
72   {\r
73     m_StoredMode = true;\r
74     m_InBitStream.AlignToByte();\r
75     m_StoredBlockSize = ReadBits(kStoredBlockLengthFieldSize);\r
76     if (_deflateNSIS)\r
77       return true;\r
78     return (m_StoredBlockSize == (UInt16)~ReadBits(kStoredBlockLengthFieldSize));\r
79   }\r
80 \r
81   m_StoredMode = false;\r
82 \r
83   CLevels levels;\r
84   if (blockType == NBlockType::kFixedHuffman)\r
85   {\r
86     levels.SetFixedLevels();\r
87     _numDistLevels = _deflate64Mode ? kDistTableSize64 : kDistTableSize32;\r
88   }\r
89   else\r
90   {\r
91     int numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin;\r
92     _numDistLevels = ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin;\r
93     int numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin;\r
94 \r
95     if (!_deflate64Mode)\r
96       if (_numDistLevels > kDistTableSize32)\r
97         return false;\r
98     \r
99     Byte levelLevels[kLevelTableSize];\r
100     for (int i = 0; i < kLevelTableSize; i++)\r
101     {\r
102       int position = kCodeLengthAlphabetOrder[i];\r
103       if(i < numLevelCodes)\r
104         levelLevels[position] = (Byte)ReadBits(kLevelFieldSize);\r
105       else\r
106         levelLevels[position] = 0;\r
107     }\r
108     \r
109     RIF(m_LevelDecoder.SetCodeLengths(levelLevels));\r
110     \r
111     Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize];\r
112     if (!DeCodeLevelTable(tmpLevels, numLitLenLevels + _numDistLevels))\r
113       return false;\r
114 \r
115     levels.SubClear();\r
116     memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels);\r
117     memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels);\r
118   }\r
119   RIF(m_MainDecoder.SetCodeLengths(levels.litLenLevels));\r
120   return m_DistDecoder.SetCodeLengths(levels.distLevels);\r
121 }\r
122 \r
123 HRESULT CCoder::CodeSpec(UInt32 curSize)\r
124 {\r
125   if (_remainLen == kLenIdFinished)\r
126     return S_OK;\r
127   if (_remainLen == kLenIdNeedInit)\r
128   {\r
129     if (!_keepHistory)\r
130       if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32))\r
131         return E_OUTOFMEMORY;\r
132     RINOK(InitInStream(_needInitInStream));\r
133     m_OutWindowStream.Init(_keepHistory);\r
134     m_FinalBlock = false;\r
135     _remainLen = 0;\r
136     _needReadTable = true;\r
137   }\r
138 \r
139   if (curSize == 0)\r
140     return S_OK;\r
141 \r
142   while(_remainLen > 0 && curSize > 0)\r
143   {\r
144     _remainLen--;\r
145     Byte b = m_OutWindowStream.GetByte(_rep0);\r
146     m_OutWindowStream.PutByte(b);\r
147     curSize--;\r
148   }\r
149 \r
150   while(curSize > 0)\r
151   {\r
152     if (_needReadTable)\r
153     {\r
154       if (m_FinalBlock)\r
155       {\r
156         _remainLen = kLenIdFinished;\r
157         break;\r
158       }\r
159       if (!ReadTables())\r
160         return S_FALSE;\r
161       _needReadTable = false;\r
162     }\r
163 \r
164     if(m_StoredMode)\r
165     {\r
166       for (; m_StoredBlockSize > 0 && curSize > 0; m_StoredBlockSize--, curSize--)\r
167         m_OutWindowStream.PutByte(m_InBitStream.ReadByte());\r
168       _needReadTable = (m_StoredBlockSize == 0);\r
169       continue;\r
170     }\r
171     while(curSize > 0)\r
172     {\r
173       if (m_InBitStream.NumExtraBytes > 4)\r
174         return S_FALSE;\r
175 \r
176       UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);\r
177       if (number < 0x100)\r
178       {\r
179         m_OutWindowStream.PutByte((Byte)number);\r
180         curSize--;\r
181         continue;\r
182       }\r
183       else if (number == kSymbolEndOfBlock)\r
184       {\r
185         _needReadTable = true;\r
186         break;\r
187       }\r
188       else if (number < kMainTableSize)\r
189       {\r
190         number -= kSymbolMatch;\r
191         UInt32 len;\r
192         {\r
193           int numBits;\r
194           if (_deflate64Mode)\r
195           {\r
196             len = kLenStart64[number];\r
197             numBits = kLenDirectBits64[number];\r
198           }\r
199           else\r
200           {\r
201             len = kLenStart32[number];\r
202             numBits = kLenDirectBits32[number];\r
203           }\r
204           len += kMatchMinLen + m_InBitStream.ReadBits(numBits);\r
205         }\r
206         UInt32 locLen = len;\r
207         if (locLen > curSize)\r
208           locLen = (UInt32)curSize;\r
209         number = m_DistDecoder.DecodeSymbol(&m_InBitStream);\r
210         if (number >= _numDistLevels)\r
211           return S_FALSE;\r
212         UInt32 distance = kDistStart[number] + m_InBitStream.ReadBits(kDistDirectBits[number]);\r
213         if (!m_OutWindowStream.CopyBlock(distance, locLen))\r
214           return S_FALSE;\r
215         curSize -= locLen;\r
216         len -= locLen;\r
217         if (len != 0)\r
218         {\r
219           _remainLen = (Int32)len;\r
220           _rep0 = distance;\r
221           break;\r
222         }\r
223       }\r
224       else\r
225         return S_FALSE;\r
226     }\r
227   }\r
228   return S_OK;\r
229 }\r
230 \r
231 #ifdef _NO_EXCEPTIONS\r
232 \r
233 #define DEFLATE_TRY_BEGIN\r
234 #define DEFLATE_TRY_END\r
235 \r
236 #else\r
237 \r
238 #define DEFLATE_TRY_BEGIN try {\r
239 #define DEFLATE_TRY_END } \\r
240   catch(const CInBufferException &e)  { return e.ErrorCode; } \\r
241   catch(const CLzOutWindowException &e)  { return e.ErrorCode; } \\r
242   catch(...) { return S_FALSE; }\r
243 \r
244 #endif\r
245 \r
246 HRESULT CCoder::CodeReal(ISequentialOutStream *outStream,\r
247       const UInt64 *outSize, ICompressProgressInfo *progress)\r
248 {\r
249   DEFLATE_TRY_BEGIN\r
250   m_OutWindowStream.SetStream(outStream);\r
251   CCoderReleaser flusher(this);\r
252 \r
253   const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize();\r
254   const UInt64 start = m_OutWindowStream.GetProcessedSize();\r
255   for (;;)\r
256   {\r
257     UInt32 curSize = 1 << 18;\r
258     if (outSize != 0)\r
259     {\r
260       const UInt64 rem = *outSize - (m_OutWindowStream.GetProcessedSize() - start);\r
261       if (curSize > rem)\r
262         curSize = (UInt32)rem;\r
263     }\r
264     if (curSize == 0)\r
265       break;\r
266     RINOK(CodeSpec(curSize));\r
267     if (_remainLen == kLenIdFinished)\r
268       break;\r
269     if (progress != NULL)\r
270     {\r
271       const UInt64 inSize = m_InBitStream.GetProcessedSize() - inStart;\r
272       const UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;\r
273       RINOK(progress->SetRatioInfo(&inSize, &nowPos64));\r
274     }\r
275   }\r
276   if (_remainLen == kLenIdFinished && ZlibMode)\r
277   {\r
278     m_InBitStream.AlignToByte();\r
279     for (int i = 0; i < 4; i++)\r
280       ZlibFooter[i] = m_InBitStream.ReadByte();\r
281   }\r
282   flusher.NeedFlush = false;\r
283   HRESULT res = Flush();\r
284   if (res == S_OK && InputEofError())\r
285     return S_FALSE;\r
286   return res;\r
287   DEFLATE_TRY_END\r
288 }\r
289 \r
290 HRESULT CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,\r
291     const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)\r
292 {\r
293   SetInStream(inStream);\r
294   SetOutStreamSize(outSize);\r
295   HRESULT res = CodeReal(outStream, outSize, progress);\r
296   ReleaseInStream();\r
297   return res;\r
298 }\r
299 \r
300 STDMETHODIMP CCoder::GetInStreamProcessedSize(UInt64 *value)\r
301 {\r
302   if (value == NULL)\r
303     return E_INVALIDARG;\r
304   *value = m_InBitStream.GetProcessedSize();\r
305   return S_OK;\r
306 }\r
307 \r
308 STDMETHODIMP CCoder::SetInStream(ISequentialInStream *inStream)\r
309 {\r
310   m_InBitStream.SetStream(inStream);\r
311   return S_OK;\r
312 }\r
313 \r
314 STDMETHODIMP CCoder::ReleaseInStream()\r
315 {\r
316   m_InBitStream.ReleaseStream();\r
317   return S_OK;\r
318 }\r
319 \r
320 STDMETHODIMP CCoder::SetOutStreamSize(const UInt64 * /* outSize */)\r
321 {\r
322   _remainLen = kLenIdNeedInit;\r
323   _needInitInStream = true;\r
324   m_OutWindowStream.Init(_keepHistory);\r
325   return S_OK;\r
326 }\r
327 \r
328 #ifndef NO_READ_FROM_CODER\r
329 \r
330 STDMETHODIMP CCoder::Read(void *data, UInt32 size, UInt32 *processedSize)\r
331 {\r
332   DEFLATE_TRY_BEGIN\r
333   if (processedSize)\r
334     *processedSize = 0;\r
335   const UInt64 startPos = m_OutWindowStream.GetProcessedSize();\r
336   m_OutWindowStream.SetMemStream((Byte *)data);\r
337   RINOK(CodeSpec(size));\r
338   if (processedSize)\r
339     *processedSize = (UInt32)(m_OutWindowStream.GetProcessedSize() - startPos);\r
340   return Flush();\r
341   DEFLATE_TRY_END\r
342 }\r
343 \r
344 #endif\r
345 \r
346 STDMETHODIMP CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)\r
347 {\r
348   _remainLen = kLenIdNeedInit;\r
349   m_OutWindowStream.Init(_keepHistory);\r
350   return CodeReal(outStream, outSize, progress);\r
351 }\r
352 \r
353 }}}\r