Upload 2.0.2
[physicsfs] / lzma / CPP / 7zip / Compress / LZMA / LZMADecoder.cpp
1 // LZMADecoder.cpp
2
3 #include "StdAfx.h"
4
5 #include "LZMADecoder.h"
6 #include "../../../Common/Defs.h"
7
8 namespace NCompress {
9 namespace NLZMA {
10
11 const int kLenIdFinished = -1;
12 const int kLenIdNeedInit = -2;
13
14 void CDecoder::Init()
15 {
16   { 
17     for(int i = 0; i < kNumStates; i++)
18     {
19       for (UInt32 j = 0; j <= _posStateMask; j++)
20       {
21         _isMatch[i][j].Init();
22         _isRep0Long[i][j].Init();
23       }
24       _isRep[i].Init();
25       _isRepG0[i].Init();
26       _isRepG1[i].Init();
27       _isRepG2[i].Init();
28     }
29   }
30   { 
31     for (UInt32 i = 0; i < kNumLenToPosStates; i++)
32     _posSlotDecoder[i].Init();
33   }
34   { 
35     for(UInt32 i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
36       _posDecoders[i].Init();
37   }
38   _posAlignDecoder.Init();
39   _lenDecoder.Init(_posStateMask + 1);
40   _repMatchLenDecoder.Init(_posStateMask + 1);
41   _literalDecoder.Init();
42
43   _state.Init();
44   _reps[0] = _reps[1] = _reps[2] = _reps[3] = 0;
45 }
46
47 HRESULT CDecoder::CodeSpec(UInt32 curSize)
48 {
49   if (_outSizeDefined)
50   {
51     const UInt64 rem = _outSize - _outWindowStream.GetProcessedSize();
52     if (curSize > rem)
53       curSize = (UInt32)rem;
54   }
55
56   if (_remainLen == kLenIdFinished)
57     return S_OK;
58   if (_remainLen == kLenIdNeedInit)
59   {
60     _rangeDecoder.Init();
61     Init();
62     _remainLen = 0;
63   }
64   if (curSize == 0)
65     return S_OK;
66
67   UInt32 rep0 = _reps[0];
68   UInt32 rep1 = _reps[1];
69   UInt32 rep2 = _reps[2];
70   UInt32 rep3 = _reps[3];
71   CState state = _state;
72   Byte previousByte;
73
74   while(_remainLen > 0 && curSize > 0)
75   {
76     previousByte = _outWindowStream.GetByte(rep0);
77     _outWindowStream.PutByte(previousByte);
78     _remainLen--;
79     curSize--;
80   }
81   UInt64 nowPos64 = _outWindowStream.GetProcessedSize();
82   if (nowPos64 == 0)
83     previousByte = 0;
84   else
85     previousByte = _outWindowStream.GetByte(0);
86
87   while(curSize > 0)
88   {
89     {
90       #ifdef _NO_EXCEPTIONS
91       if (_rangeDecoder.Stream.ErrorCode != S_OK)
92         return _rangeDecoder.Stream.ErrorCode;
93       #endif
94       if (_rangeDecoder.Stream.WasFinished())
95         return S_FALSE;
96       UInt32 posState = UInt32(nowPos64) & _posStateMask;
97       if (_isMatch[state.Index][posState].Decode(&_rangeDecoder) == 0)
98       {
99         if(!state.IsCharState())
100           previousByte = _literalDecoder.DecodeWithMatchByte(&_rangeDecoder, 
101               (UInt32)nowPos64, previousByte, _outWindowStream.GetByte(rep0));
102         else
103           previousByte = _literalDecoder.DecodeNormal(&_rangeDecoder, 
104               (UInt32)nowPos64, previousByte);
105         _outWindowStream.PutByte(previousByte);
106         state.UpdateChar();
107         curSize--;
108         nowPos64++;
109       }
110       else             
111       {
112         UInt32 len;
113         if(_isRep[state.Index].Decode(&_rangeDecoder) == 1)
114         {
115           len = 0;
116           if(_isRepG0[state.Index].Decode(&_rangeDecoder) == 0)
117           {
118             if(_isRep0Long[state.Index][posState].Decode(&_rangeDecoder) == 0)
119             {
120               state.UpdateShortRep();
121               len = 1;
122             }
123           }
124           else
125           {
126             UInt32 distance;
127             if(_isRepG1[state.Index].Decode(&_rangeDecoder) == 0)
128               distance = rep1;
129             else 
130             {
131               if (_isRepG2[state.Index].Decode(&_rangeDecoder) == 0)
132                 distance = rep2;
133               else
134               {
135                 distance = rep3;
136                 rep3 = rep2;
137               }
138               rep2 = rep1;
139             }
140             rep1 = rep0;
141             rep0 = distance;
142           }
143           if (len == 0)
144           {
145             len = _repMatchLenDecoder.Decode(&_rangeDecoder, posState) + kMatchMinLen;
146             state.UpdateRep();
147           }
148         }
149         else
150         {
151           rep3 = rep2;
152           rep2 = rep1;
153           rep1 = rep0;
154           len = kMatchMinLen + _lenDecoder.Decode(&_rangeDecoder, posState);
155           state.UpdateMatch();
156           UInt32 posSlot = _posSlotDecoder[GetLenToPosState(len)].Decode(&_rangeDecoder);
157           if (posSlot >= kStartPosModelIndex)
158           {
159             UInt32 numDirectBits = (posSlot >> 1) - 1;
160             rep0 = ((2 | (posSlot & 1)) << numDirectBits);
161
162             if (posSlot < kEndPosModelIndex)
163               rep0 += NRangeCoder::ReverseBitTreeDecode(_posDecoders + 
164                   rep0 - posSlot - 1, &_rangeDecoder, numDirectBits);
165             else
166             {
167               rep0 += (_rangeDecoder.DecodeDirectBits(
168                   numDirectBits - kNumAlignBits) << kNumAlignBits);
169               rep0 += _posAlignDecoder.ReverseDecode(&_rangeDecoder);
170               if (rep0 == 0xFFFFFFFF)
171               {
172                 _remainLen = kLenIdFinished;
173                 return S_OK;
174               }
175             }
176           }
177           else
178             rep0 = posSlot;
179         }
180         UInt32 locLen = len;
181         if (len > curSize)
182           locLen = (UInt32)curSize;
183         if (!_outWindowStream.CopyBlock(rep0, locLen))
184           return S_FALSE;
185         previousByte = _outWindowStream.GetByte(0);
186         curSize -= locLen;
187         nowPos64 += locLen;
188         len -= locLen;
189         if (len != 0)
190         {
191           _remainLen = (Int32)len;
192           break;
193         }
194
195         #ifdef _NO_EXCEPTIONS
196         if (_outWindowStream.ErrorCode != S_OK)
197           return _outWindowStream.ErrorCode;
198         #endif
199       }
200     }
201   }
202   if (_rangeDecoder.Stream.WasFinished())
203     return S_FALSE;
204   _reps[0] = rep0;
205   _reps[1] = rep1;
206   _reps[2] = rep2;
207   _reps[3] = rep3;
208   _state = state;
209
210   return S_OK;
211 }
212
213 STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream,
214     ISequentialOutStream *outStream, 
215     const UInt64 *, const UInt64 *outSize,
216     ICompressProgressInfo *progress)
217 {
218   SetInStream(inStream);
219   _outWindowStream.SetStream(outStream);
220   SetOutStreamSize(outSize);
221   CDecoderFlusher flusher(this);
222
223   for (;;)
224   {
225     UInt32 curSize = 1 << 18;
226     RINOK(CodeSpec(curSize));
227     if (_remainLen == kLenIdFinished)
228       break;
229     if (progress != NULL)
230     {
231       UInt64 inSize = _rangeDecoder.GetProcessedSize();
232       UInt64 nowPos64 = _outWindowStream.GetProcessedSize();
233       RINOK(progress->SetRatioInfo(&inSize, &nowPos64));
234     }
235     if (_outSizeDefined)
236       if (_outWindowStream.GetProcessedSize() >= _outSize)
237         break;
238   } 
239   flusher.NeedFlush = false;
240   return Flush();
241 }
242
243
244 #ifdef _NO_EXCEPTIONS
245
246 #define LZMA_TRY_BEGIN
247 #define LZMA_TRY_END
248
249 #else
250
251 #define LZMA_TRY_BEGIN try { 
252 #define LZMA_TRY_END } \
253   catch(const CInBufferException &e)  { return e.ErrorCode; } \
254   catch(const CLZOutWindowException &e)  { return e.ErrorCode; } \
255   catch(...) { return S_FALSE; }
256
257 #endif
258
259
260 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream,
261       ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
262       ICompressProgressInfo *progress)
263 {
264   LZMA_TRY_BEGIN
265   return CodeReal(inStream, outStream, inSize, outSize, progress); 
266   LZMA_TRY_END
267 }
268
269 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *properties, UInt32 size)
270 {
271   if (size < 5)
272     return E_INVALIDARG;
273   int lc = properties[0] % 9;
274   Byte remainder = (Byte)(properties[0] / 9);
275   int lp = remainder % 5;
276   int pb = remainder / 5;
277   if (pb > NLength::kNumPosStatesBitsMax)
278     return E_INVALIDARG;
279   _posStateMask = (1 << pb) - 1;
280   UInt32 dictionarySize = 0;
281   for (int i = 0; i < 4; i++)
282     dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
283   if (!_outWindowStream.Create(dictionarySize))
284     return E_OUTOFMEMORY;
285   if (!_literalDecoder.Create(lp, lc))
286     return E_OUTOFMEMORY;
287   if (!_rangeDecoder.Create(1 << 20))
288     return E_OUTOFMEMORY;
289   return S_OK;
290 }
291
292 STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
293 {
294   *value = _rangeDecoder.GetProcessedSize();
295   return S_OK;
296 }
297
298 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
299 {
300   _rangeDecoder.SetStream(inStream);
301   return S_OK;
302 }
303
304 STDMETHODIMP CDecoder::ReleaseInStream()
305 {
306   _rangeDecoder.ReleaseStream();
307   return S_OK;
308 }
309
310 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
311 {
312   _outSizeDefined = (outSize != NULL);
313   if (_outSizeDefined)
314     _outSize = *outSize;
315   _remainLen = kLenIdNeedInit;
316   _outWindowStream.Init();
317   return S_OK;
318 }
319
320 #ifndef NO_READ_FROM_CODER
321
322 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
323 {
324   LZMA_TRY_BEGIN
325   if (processedSize)
326     *processedSize = 0;
327   const UInt64 startPos = _outWindowStream.GetProcessedSize();
328   _outWindowStream.SetMemStream((Byte *)data);
329   RINOK(CodeSpec(size));
330   if (processedSize)
331     *processedSize = (UInt32)(_outWindowStream.GetProcessedSize() - startPos);
332   return Flush();
333   LZMA_TRY_END
334 }
335
336 #endif
337
338 }}