• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
13 namespace NCompress {
14 namespace NPpmd {
15 
16 static const UInt32 kBufSize = (1 << 20);
17 
18 enum
19 {
20   kStatus_NeedInit,
21   kStatus_Normal,
22   kStatus_Finished,
23   kStatus_Error
24 };
25 
SzBigAlloc(void *,size_t size)26 static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
SzBigFree(void *,void * address)27 static void SzBigFree(void *, void *address) { BigFree(address); }
28 static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
29 
~CDecoder()30 CDecoder::~CDecoder()
31 {
32   ::MidFree(_outBuf);
33   Ppmd7_Free(&_ppmd, &g_BigAlloc);
34 }
35 
SetDecoderProperties2(const Byte * props,UInt32 size)36 STDMETHODIMP 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 
CodeSpec(Byte * memStream,UInt32 size)54 HRESULT 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 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 * outSize,ICompressProgressInfo * progress)99 STDMETHODIMP 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 
SetOutStreamSize(const UInt64 * outSize)131 STDMETHODIMP 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 
SetInStream(ISequentialInStream * inStream)143 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
144 {
145   InSeqStream = inStream;
146   _inStream.Stream = inStream;
147   return S_OK;
148 }
149 
ReleaseInStream()150 STDMETHODIMP CDecoder::ReleaseInStream()
151 {
152   InSeqStream.Release();
153   return S_OK;
154 }
155 
Read(void * data,UInt32 size,UInt32 * processedSize)156 STDMETHODIMP 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