1 // LzxDecoder.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../Common/Defs.h"
6 
7 #include "LzxDecoder.h"
8 
9 namespace NCompress {
10 namespace NLzx {
11 
12 const int kLenIdNeedInit = -2;
13 
CDecoder(bool wimMode)14 CDecoder::CDecoder(bool wimMode):
15   _keepHistory(false),
16   _skipByte(false),
17   _wimMode(wimMode)
18 {
19   m_x86ConvertOutStreamSpec = new Cx86ConvertOutStream;
20   m_x86ConvertOutStream = m_x86ConvertOutStreamSpec;
21 }
22 
ReleaseStreams()23 void CDecoder::ReleaseStreams()
24 {
25   m_OutWindowStream.ReleaseStream();
26   m_InBitStream.ReleaseStream();
27   m_x86ConvertOutStreamSpec->ReleaseStream();
28 }
29 
Flush()30 STDMETHODIMP CDecoder::Flush()
31 {
32   RINOK(m_OutWindowStream.Flush());
33   return m_x86ConvertOutStreamSpec->Flush();
34 }
35 
ReadBits(int numBits)36 UInt32 CDecoder::ReadBits(int numBits) { return m_InBitStream.ReadBits(numBits); }
37 
38 #define RIF(x) { if (!(x)) return false; }
39 
ReadTable(Byte * lastLevels,Byte * newLevels,UInt32 numSymbols)40 bool CDecoder::ReadTable(Byte *lastLevels, Byte *newLevels, UInt32 numSymbols)
41 {
42   Byte levelLevels[kLevelTableSize];
43   UInt32 i;
44   for (i = 0; i < kLevelTableSize; i++)
45     levelLevels[i] = (Byte)ReadBits(kNumBitsForPreTreeLevel);
46   RIF(m_LevelDecoder.SetCodeLengths(levelLevels));
47   int num = 0;
48   Byte symbol = 0;
49   for (i = 0; i < numSymbols;)
50   {
51     if (num != 0)
52     {
53       lastLevels[i] = newLevels[i] = symbol;
54       i++;
55       num--;
56       continue;
57     }
58     UInt32 number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
59     if (number == kLevelSymbolZeros)
60     {
61       num = kLevelSymbolZerosStartValue + (int)ReadBits(kLevelSymbolZerosNumBits);
62       symbol = 0;
63     }
64     else if (number == kLevelSymbolZerosBig)
65     {
66       num = kLevelSymbolZerosBigStartValue + (int)ReadBits(kLevelSymbolZerosBigNumBits);
67       symbol = 0;
68     }
69     else if (number == kLevelSymbolSame || number <= kNumHuffmanBits)
70     {
71       if (number <= kNumHuffmanBits)
72         num = 1;
73       else
74       {
75         num = kLevelSymbolSameStartValue + (int)ReadBits(kLevelSymbolSameNumBits);
76         number = m_LevelDecoder.DecodeSymbol(&m_InBitStream);
77         if (number > kNumHuffmanBits)
78           return false;
79       }
80       symbol = Byte((17 + lastLevels[i] - number) % (kNumHuffmanBits + 1));
81     }
82     else
83       return false;
84   }
85   return true;
86 }
87 
ReadTables(void)88 bool CDecoder::ReadTables(void)
89 {
90   Byte newLevels[kMaxTableSize];
91   {
92     if (_skipByte)
93       m_InBitStream.DirectReadByte();
94     m_InBitStream.Normalize();
95 
96     int blockType = (int)ReadBits(kNumBlockTypeBits);
97     if (blockType > kBlockTypeUncompressed)
98       return false;
99     if (_wimMode)
100       if (ReadBits(1) == 1)
101         m_UnCompressedBlockSize = (1 << 15);
102       else
103         m_UnCompressedBlockSize = ReadBits(16);
104     else
105       m_UnCompressedBlockSize = m_InBitStream.ReadBitsBig(kUncompressedBlockSizeNumBits);
106 
107     m_IsUncompressedBlock = (blockType == kBlockTypeUncompressed);
108 
109     _skipByte = (m_IsUncompressedBlock && ((m_UnCompressedBlockSize & 1) != 0));
110 
111     if (m_IsUncompressedBlock)
112     {
113       ReadBits(16 - m_InBitStream.GetBitPosition());
114       if (!m_InBitStream.ReadUInt32(m_RepDistances[0]))
115         return false;
116       m_RepDistances[0]--;
117       for (int i = 1; i < kNumRepDistances; i++)
118       {
119         UInt32 rep = 0;
120         for (int j = 0; j < 4; j++)
121           rep |= (UInt32)m_InBitStream.DirectReadByte() << (8 * j);
122         m_RepDistances[i] = rep - 1;
123       }
124       return true;
125     }
126     m_AlignIsUsed = (blockType == kBlockTypeAligned);
127     if (m_AlignIsUsed)
128     {
129       for(int i = 0; i < kAlignTableSize; i++)
130         newLevels[i] = (Byte)ReadBits(kNumBitsForAlignLevel);
131       RIF(m_AlignDecoder.SetCodeLengths(newLevels));
132     }
133   }
134 
135   RIF(ReadTable(m_LastMainLevels, newLevels, 256));
136   RIF(ReadTable(m_LastMainLevels + 256, newLevels + 256, m_NumPosLenSlots));
137   for (UInt32 i = 256 + m_NumPosLenSlots; i < kMainTableSize; i++)
138     newLevels[i] = 0;
139   RIF(m_MainDecoder.SetCodeLengths(newLevels));
140 
141   RIF(ReadTable(m_LastLenLevels, newLevels, kNumLenSymbols));
142   return m_LenDecoder.SetCodeLengths(newLevels);
143 }
144 
145 class CDecoderFlusher
146 {
147   CDecoder *m_Decoder;
148 public:
149   bool NeedFlush;
CDecoderFlusher(CDecoder * decoder)150   CDecoderFlusher(CDecoder *decoder): m_Decoder(decoder), NeedFlush(true) {}
~CDecoderFlusher()151   ~CDecoderFlusher()
152   {
153     if (NeedFlush)
154       m_Decoder->Flush();
155     m_Decoder->ReleaseStreams();
156   }
157 };
158 
159 
ClearPrevLevels()160 void CDecoder::ClearPrevLevels()
161 {
162   int i;
163   for (i = 0; i < kMainTableSize; i++)
164     m_LastMainLevels[i] = 0;
165   for (i = 0; i < kNumLenSymbols; i++)
166     m_LastLenLevels[i] = 0;
167 };
168 
169 
CodeSpec(UInt32 curSize)170 HRESULT CDecoder::CodeSpec(UInt32 curSize)
171 {
172   if (_remainLen == kLenIdNeedInit)
173   {
174     _remainLen = 0;
175     m_InBitStream.Init();
176     if (!_keepHistory || !m_IsUncompressedBlock)
177       m_InBitStream.Normalize();
178     if (!_keepHistory)
179     {
180       _skipByte = false;
181       m_UnCompressedBlockSize = 0;
182       ClearPrevLevels();
183       UInt32 i86TranslationSize = 12000000;
184       bool translationMode = true;
185       if (!_wimMode)
186       {
187         translationMode = (ReadBits(1) != 0);
188         if (translationMode)
189         {
190           i86TranslationSize = ReadBits(16) << 16;
191           i86TranslationSize |= ReadBits(16);
192         }
193       }
194       m_x86ConvertOutStreamSpec->Init(translationMode, i86TranslationSize);
195 
196       for(int i = 0 ; i < kNumRepDistances; i++)
197         m_RepDistances[i] = 0;
198     }
199   }
200 
201   while(_remainLen > 0 && curSize > 0)
202   {
203     m_OutWindowStream.PutByte(m_OutWindowStream.GetByte(m_RepDistances[0]));
204     _remainLen--;
205     curSize--;
206   }
207 
208   while(curSize > 0)
209   {
210     if (m_UnCompressedBlockSize == 0)
211       if (!ReadTables())
212         return S_FALSE;
213     UInt32 next = (Int32)MyMin(m_UnCompressedBlockSize, curSize);
214     curSize -= next;
215     m_UnCompressedBlockSize -= next;
216     if (m_IsUncompressedBlock)
217     {
218       while(next > 0)
219       {
220         m_OutWindowStream.PutByte(m_InBitStream.DirectReadByte());
221         next--;
222       }
223     }
224     else while(next > 0)
225     {
226       UInt32 number = m_MainDecoder.DecodeSymbol(&m_InBitStream);
227       if (number < 256)
228       {
229         m_OutWindowStream.PutByte((Byte)number);
230         next--;
231       }
232       else
233       {
234         UInt32 posLenSlot = number - 256;
235         if (posLenSlot >= m_NumPosLenSlots)
236           return S_FALSE;
237         UInt32 posSlot = posLenSlot / kNumLenSlots;
238         UInt32 lenSlot = posLenSlot % kNumLenSlots;
239         UInt32 len = kMatchMinLen + lenSlot;
240         if (lenSlot == kNumLenSlots - 1)
241         {
242           UInt32 lenTemp = m_LenDecoder.DecodeSymbol(&m_InBitStream);
243           if (lenTemp >= kNumLenSymbols)
244             return S_FALSE;
245           len += lenTemp;
246         }
247 
248         if (posSlot < kNumRepDistances)
249         {
250           UInt32 distance = m_RepDistances[posSlot];
251           m_RepDistances[posSlot] = m_RepDistances[0];
252           m_RepDistances[0] = distance;
253         }
254         else
255         {
256           UInt32 distance;
257           int numDirectBits;
258           if (posSlot < kNumPowerPosSlots)
259           {
260             numDirectBits = (int)(posSlot >> 1) - 1;
261             distance = ((2 | (posSlot & 1)) << numDirectBits);
262           }
263           else
264           {
265             numDirectBits = kNumLinearPosSlotBits;
266             distance = ((posSlot - 0x22) << kNumLinearPosSlotBits);
267           }
268 
269           if (m_AlignIsUsed && numDirectBits >= kNumAlignBits)
270           {
271             distance += (m_InBitStream.ReadBits(numDirectBits - kNumAlignBits) << kNumAlignBits);
272             UInt32 alignTemp = m_AlignDecoder.DecodeSymbol(&m_InBitStream);
273             if (alignTemp >= kAlignTableSize)
274               return S_FALSE;
275             distance += alignTemp;
276           }
277           else
278             distance += m_InBitStream.ReadBits(numDirectBits);
279           m_RepDistances[2] = m_RepDistances[1];
280           m_RepDistances[1] = m_RepDistances[0];
281           m_RepDistances[0] = distance - kNumRepDistances;
282         }
283 
284         UInt32 locLen = len;
285         if (locLen > next)
286           locLen = next;
287 
288         if (!m_OutWindowStream.CopyBlock(m_RepDistances[0], locLen))
289           return S_FALSE;
290 
291         len -= locLen;
292         next -= locLen;
293         if (len != 0)
294         {
295           _remainLen = (int)len;
296           return S_OK;
297         }
298       }
299     }
300   }
301   return S_OK;
302 }
303 
CodeReal(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress)304 HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
305     const UInt64 *, const UInt64 *outSize, ICompressProgressInfo *progress)
306 {
307   if (outSize == NULL)
308     return E_INVALIDARG;
309   UInt64 size = *outSize;
310 
311   RINOK(SetInStream(inStream));
312   m_x86ConvertOutStreamSpec->SetStream(outStream);
313   m_OutWindowStream.SetStream(m_x86ConvertOutStream);
314   RINOK(SetOutStreamSize(outSize));
315 
316   CDecoderFlusher flusher(this);
317 
318   const UInt64 start = m_OutWindowStream.GetProcessedSize();
319   for (;;)
320   {
321     UInt32 curSize = 1 << 18;
322     UInt64 rem = size - (m_OutWindowStream.GetProcessedSize() - start);
323     if (curSize > rem)
324       curSize = (UInt32)rem;
325     if (curSize == 0)
326       break;
327     RINOK(CodeSpec(curSize));
328     if (progress != NULL)
329     {
330       UInt64 inSize = m_InBitStream.GetProcessedSize();
331       UInt64 nowPos64 = m_OutWindowStream.GetProcessedSize() - start;
332       RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
333     }
334   }
335   flusher.NeedFlush = false;
336   return Flush();
337 }
338 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)339 HRESULT CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
340     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
341 {
342   try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
343   catch(const CLzOutWindowException &e) { return e.ErrorCode; }
344   catch(...) { return S_FALSE; }
345 }
346 
SetInStream(ISequentialInStream * inStream)347 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
348 {
349   m_InBitStream.SetStream(inStream);
350   return S_OK;
351 }
352 
ReleaseInStream()353 STDMETHODIMP CDecoder::ReleaseInStream()
354 {
355   m_InBitStream.ReleaseStream();
356   return S_OK;
357 }
358 
SetOutStreamSize(const UInt64 * outSize)359 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
360 {
361   if (outSize == NULL)
362     return E_FAIL;
363   _remainLen = kLenIdNeedInit;
364   m_OutWindowStream.Init(_keepHistory);
365   return S_OK;
366 }
367 
SetParams(int numDictBits)368 HRESULT CDecoder::SetParams(int numDictBits)
369 {
370   if (numDictBits < kNumDictionaryBitsMin || numDictBits > kNumDictionaryBitsMax)
371     return E_INVALIDARG;
372   UInt32 numPosSlots;
373   if (numDictBits < 20)
374     numPosSlots = 30 + (numDictBits - 15) * 2;
375   else if (numDictBits == 20)
376     numPosSlots = 42;
377   else
378     numPosSlots = 50;
379   m_NumPosLenSlots = numPosSlots * kNumLenSlots;
380   if (!m_OutWindowStream.Create(kDictionarySizeMax))
381     return E_OUTOFMEMORY;
382   if (!m_InBitStream.Create(1 << 16))
383     return E_OUTOFMEMORY;
384   return S_OK;
385 }
386 
387 }}
388