1// PpmdDecoder.cpp
2// 2009-03-11 : Igor Pavlov : Public domain
3
4#include "StdAfx.h"
5
6#include "../../../C/Alloc.h"
7#include "../../../C/CpuArch.h"
8
9#include "../Common/StreamUtils.h"
10
11#include "PpmdDecoder.h"
12
13namespace NCompress {
14namespace NPpmd {
15
16static const UInt32 kBufSize = (1 << 20);
17
18enum
19{
20  kStatus_NeedInit,
21  kStatus_Normal,
22  kStatus_Finished,
23  kStatus_Error
24};
25
26static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
27static void SzBigFree(void *, void *address) { BigFree(address); }
28static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
29
30CDecoder::~CDecoder()
31{
32  ::MidFree(_outBuf);
33  Ppmd7_Free(&_ppmd, &g_BigAlloc);
34}
35
36STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
37{
38  if (size < 5)
39    return E_INVALIDARG;
40  _order = props[0];
41  UInt32 memSize = GetUi32(props + 1);
42  if (_order < PPMD7_MIN_ORDER ||
43      _order > PPMD7_MAX_ORDER ||
44      memSize < PPMD7_MIN_MEM_SIZE ||
45      memSize > PPMD7_MAX_MEM_SIZE)
46    return E_NOTIMPL;
47  if (!_inStream.Alloc(1 << 20))
48    return E_OUTOFMEMORY;
49  if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc))
50    return E_OUTOFMEMORY;
51  return S_OK;
52}
53
54HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
55{
56  switch(_status)
57  {
58    case kStatus_Finished: return S_OK;
59    case kStatus_Error: return S_FALSE;
60    case kStatus_NeedInit:
61      _inStream.Init();
62      if (!Ppmd7z_RangeDec_Init(&_rangeDec))
63      {
64        _status = kStatus_Error;
65        return S_FALSE;
66      }
67      _status = kStatus_Normal;
68      Ppmd7_Init(&_ppmd, _order);
69      break;
70  }
71  if (_outSizeDefined)
72  {
73    const UInt64 rem = _outSize - _processedSize;
74    if (size > rem)
75      size = (UInt32)rem;
76  }
77
78  UInt32 i;
79  int sym = 0;
80  for (i = 0; i != size; i++)
81  {
82    sym = Ppmd7_DecodeSymbol(&_ppmd, &_rangeDec.p);
83    if (_inStream.Extra || sym < 0)
84      break;
85    memStream[i] = (Byte)sym;
86  }
87
88  _processedSize += i;
89  if (_inStream.Extra)
90  {
91    _status = kStatus_Error;
92    return _inStream.Res;
93  }
94  if (sym < 0)
95    _status = (sym < -1) ? kStatus_Error : kStatus_Finished;
96  return S_OK;
97}
98
99STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
100    const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
101{
102  if (!_outBuf)
103  {
104    _outBuf = (Byte *)::MidAlloc(kBufSize);
105    if (!_outBuf)
106      return E_OUTOFMEMORY;
107  }
108
109  _inStream.Stream = inStream;
110  SetOutStreamSize(outSize);
111
112  do
113  {
114    const UInt64 startPos = _processedSize;
115    HRESULT res = CodeSpec(_outBuf, kBufSize);
116    size_t processed = (size_t)(_processedSize - startPos);
117    RINOK(WriteStream(outStream, _outBuf, processed));
118    RINOK(res);
119    if (_status == kStatus_Finished)
120      break;
121    if (progress)
122    {
123      UInt64 inSize = _inStream.GetProcessed();
124      RINOK(progress->SetRatioInfo(&inSize, &_processedSize));
125    }
126  }
127  while (!_outSizeDefined || _processedSize < _outSize);
128  return S_OK;
129}
130
131STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
132{
133  _outSizeDefined = (outSize != NULL);
134  if (_outSizeDefined)
135    _outSize = *outSize;
136  _processedSize = 0;
137  _status = kStatus_NeedInit;
138  return S_OK;
139}
140
141#ifndef NO_READ_FROM_CODER
142
143STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
144{
145  InSeqStream = inStream;
146  _inStream.Stream = inStream;
147  return S_OK;
148}
149
150STDMETHODIMP CDecoder::ReleaseInStream()
151{
152  InSeqStream.Release();
153  return S_OK;
154}
155
156STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
157{
158  const UInt64 startPos = _processedSize;
159  HRESULT res = CodeSpec((Byte *)data, size);
160  if (processedSize)
161    *processedSize = (UInt32)(_processedSize - startPos);
162  return res;
163}
164
165#endif
166
167}}
168