1// LZMADecoder.cpp
2
3#include "StdAfx.h"
4
5#include "LZMADecoder.h"
6#include "../../../Common/Defs.h"
7
8namespace NCompress {
9namespace NLZMA {
10
11const int kLenIdFinished = -1;
12const int kLenIdNeedInit = -2;
13
14void 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
47HRESULT 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
213STDMETHODIMP 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
260STDMETHODIMP 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
269STDMETHODIMP 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  _posStateMask = (1 << pb) - 1;
278  UInt32 dictionarySize = 0;
279  for (int i = 0; i < 4; i++)
280    dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
281  return SetDecoderPropertiesRaw(lc, lp, pb, dictionarySize);
282}
283
284STDMETHODIMP CDecoder::SetDecoderPropertiesRaw(int lc, int lp, int pb, UInt32 dictionarySize)
285{
286  if (pb > NLength::kNumPosStatesBitsMax)
287    return E_INVALIDARG;
288  if (!_outWindowStream.Create(dictionarySize))
289    return E_OUTOFMEMORY;
290  if (!_literalDecoder.Create(lp, lc))
291    return E_OUTOFMEMORY;
292  if (!_rangeDecoder.Create(1 << 20))
293    return E_OUTOFMEMORY;
294  return S_OK;
295}
296
297STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
298{
299  *value = _rangeDecoder.GetProcessedSize();
300  return S_OK;
301}
302
303STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
304{
305  _rangeDecoder.SetStream(inStream);
306  return S_OK;
307}
308
309STDMETHODIMP CDecoder::ReleaseInStream()
310{
311  _rangeDecoder.ReleaseStream();
312  return S_OK;
313}
314
315STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
316{
317  _outSizeDefined = (outSize != NULL);
318  if (_outSizeDefined)
319    _outSize = *outSize;
320  _remainLen = kLenIdNeedInit;
321  _outWindowStream.Init();
322  return S_OK;
323}
324
325#ifndef NO_READ_FROM_CODER
326
327STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
328{
329  LZMA_TRY_BEGIN
330  if (processedSize)
331    *processedSize = 0;
332  const UInt64 startPos = _outWindowStream.GetProcessedSize();
333  _outWindowStream.SetMemStream((Byte *)data);
334  RINOK(CodeSpec(size));
335  if (processedSize)
336    *processedSize = (UInt32)(_outWindowStream.GetProcessedSize() - startPos);
337  return Flush();
338  LZMA_TRY_END
339}
340
341#endif
342
343}}
344