2 // 2009-03-11 : Igor Pavlov : Public domain
\r
6 #include "../../../C/Alloc.h"
\r
7 #include "../../../C/CpuArch.h"
\r
9 #include "../Common/StreamUtils.h"
\r
11 #include "PpmdDecoder.h"
\r
13 namespace NCompress {
\r
16 static const UInt32 kBufSize = (1 << 20);
\r
26 static void *SzBigAlloc(void *, size_t size) { return BigAlloc(size); }
\r
27 static void SzBigFree(void *, void *address) { BigFree(address); }
\r
28 static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
\r
30 CDecoder::~CDecoder()
\r
33 Ppmd7_Free(&_ppmd, &g_BigAlloc);
\r
36 STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
\r
39 return E_INVALIDARG;
\r
41 UInt32 memSize = GetUi32(props + 1);
\r
42 if (_order < PPMD7_MIN_ORDER ||
\r
43 _order > PPMD7_MAX_ORDER ||
\r
44 memSize < PPMD7_MIN_MEM_SIZE ||
\r
45 memSize > PPMD7_MAX_MEM_SIZE)
\r
47 if (!_inStream.Alloc(1 << 20))
\r
48 return E_OUTOFMEMORY;
\r
49 if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc))
\r
50 return E_OUTOFMEMORY;
\r
54 HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
\r
58 case kStatus_Finished: return S_OK;
\r
59 case kStatus_Error: return S_FALSE;
\r
60 case kStatus_NeedInit:
\r
62 if (!Ppmd7z_RangeDec_Init(&_rangeDec))
\r
64 _status = kStatus_Error;
\r
67 _status = kStatus_Normal;
\r
68 Ppmd7_Init(&_ppmd, _order);
\r
71 if (_outSizeDefined)
\r
73 const UInt64 rem = _outSize - _processedSize;
\r
80 for (i = 0; i != size; i++)
\r
82 sym = Ppmd7_DecodeSymbol(&_ppmd, &_rangeDec.p);
\r
83 if (_inStream.Extra || sym < 0)
\r
85 memStream[i] = (Byte)sym;
\r
88 _processedSize += i;
\r
89 if (_inStream.Extra)
\r
91 _status = kStatus_Error;
\r
92 return _inStream.Res;
\r
95 _status = (sym < -1) ? kStatus_Error : kStatus_Finished;
\r
99 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
\r
100 const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
\r
104 _outBuf = (Byte *)::MidAlloc(kBufSize);
\r
106 return E_OUTOFMEMORY;
\r
109 _inStream.Stream = inStream;
\r
110 SetOutStreamSize(outSize);
\r
114 const UInt64 startPos = _processedSize;
\r
115 HRESULT res = CodeSpec(_outBuf, kBufSize);
\r
116 size_t processed = (size_t)(_processedSize - startPos);
\r
117 RINOK(WriteStream(outStream, _outBuf, processed));
\r
119 if (_status == kStatus_Finished)
\r
123 UInt64 inSize = _inStream.GetProcessed();
\r
124 RINOK(progress->SetRatioInfo(&inSize, &_processedSize));
\r
127 while (!_outSizeDefined || _processedSize < _outSize);
\r
131 STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
\r
133 _outSizeDefined = (outSize != NULL);
\r
134 if (_outSizeDefined)
\r
135 _outSize = *outSize;
\r
136 _processedSize = 0;
\r
137 _status = kStatus_NeedInit;
\r
141 #ifndef NO_READ_FROM_CODER
\r
143 STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
\r
145 InSeqStream = inStream;
\r
146 _inStream.Stream = inStream;
\r
150 STDMETHODIMP CDecoder::ReleaseInStream()
\r
152 InSeqStream.Release();
\r
156 STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
\r
158 const UInt64 startPos = _processedSize;
\r
159 HRESULT res = CodeSpec((Byte *)data, size);
\r
161 *processedSize = (UInt32)(_processedSize - startPos);
\r