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