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