1 // PpmdDecoder.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../C/Alloc.h"
6 #include "../../../C/CpuArch.h"
7
8 #include "../Common/StreamUtils.h"
9
10 #include "PpmdDecoder.h"
11
12 namespace NCompress {
13 namespace NPpmd {
14
15 static const UInt32 kBufSize = (1 << 16);
16
17 enum
18 {
19 kStatus_NeedInit,
20 kStatus_Normal,
21 kStatus_Finished_With_Mark,
22 kStatus_Error
23 };
24
~CDecoder()25 CDecoder::~CDecoder()
26 {
27 ::MidFree(_outBuf);
28 Ppmd7_Free(&_ppmd, &g_BigAlloc);
29 }
30
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2 (const Byte * props,UInt32 size))31 Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size))
32 {
33 if (size < 5)
34 return E_INVALIDARG;
35 _order = props[0];
36 const UInt32 memSize = GetUi32(props + 1);
37 if (_order < PPMD7_MIN_ORDER ||
38 _order > PPMD7_MAX_ORDER ||
39 memSize < PPMD7_MIN_MEM_SIZE ||
40 memSize > PPMD7_MAX_MEM_SIZE)
41 return E_NOTIMPL;
42 if (!_inStream.Alloc(1 << 20))
43 return E_OUTOFMEMORY;
44 if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc))
45 return E_OUTOFMEMORY;
46 return S_OK;
47 }
48
49 #define MY_rangeDec _ppmd.rc.dec
50
51 #define CHECK_EXTRA_ERROR \
52 if (_inStream.Extra) { \
53 _status = kStatus_Error; \
54 return (_res = (_inStream.Res != SZ_OK ? _inStream.Res: S_FALSE)); }
55
56
CodeSpec(Byte * memStream,UInt32 size)57 HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
58 {
59 if (_res != S_OK)
60 return _res;
61
62 switch (_status)
63 {
64 case kStatus_Finished_With_Mark: return S_OK;
65 case kStatus_Error: return S_FALSE;
66 case kStatus_NeedInit:
67 _inStream.Init();
68 if (!Ppmd7z_RangeDec_Init(&MY_rangeDec))
69 {
70 _status = kStatus_Error;
71 return (_res = S_FALSE);
72 }
73 CHECK_EXTRA_ERROR
74 _status = kStatus_Normal;
75 Ppmd7_Init(&_ppmd, _order);
76 break;
77 default: break;
78 }
79
80 if (_outSizeDefined)
81 {
82 const UInt64 rem = _outSize - _processedSize;
83 if (size > rem)
84 size = (UInt32)rem;
85 }
86
87 int sym = 0;
88 {
89 Byte *buf = memStream;
90 const Byte *lim = buf + size;
91 for (; buf != lim; buf++)
92 {
93 sym = Ppmd7z_DecodeSymbol(&_ppmd);
94 if (_inStream.Extra || sym < 0)
95 break;
96 *buf = (Byte)sym;
97 }
98 /*
99 buf = Ppmd7z_DecodeSymbols(&_ppmd, buf, lim);
100 sym = _ppmd.LastSymbol;
101 */
102 _processedSize += (size_t)(buf - memStream);
103 }
104
105 CHECK_EXTRA_ERROR
106
107 if (sym >= 0)
108 {
109 if (!FinishStream
110 || !_outSizeDefined
111 || _outSize != _processedSize
112 || MY_rangeDec.Code == 0)
113 return S_OK;
114 /*
115 // We can decode additional End Marker here:
116 sym = Ppmd7z_DecodeSymbol(&_ppmd);
117 CHECK_EXTRA_ERROR
118 */
119 }
120
121 if (sym != PPMD7_SYM_END || MY_rangeDec.Code != 0)
122 {
123 _status = kStatus_Error;
124 return (_res = S_FALSE);
125 }
126
127 _status = kStatus_Finished_With_Mark;
128 return S_OK;
129 }
130
131
132
Z7_COM7F_IMF(CDecoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress))133 Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
134 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
135 {
136 if (!_outBuf)
137 {
138 _outBuf = (Byte *)::MidAlloc(kBufSize);
139 if (!_outBuf)
140 return E_OUTOFMEMORY;
141 }
142
143 _inStream.Stream = inStream;
144 SetOutStreamSize(outSize);
145
146 do
147 {
148 const UInt64 startPos = _processedSize;
149 const HRESULT res = CodeSpec(_outBuf, kBufSize);
150 const size_t processed = (size_t)(_processedSize - startPos);
151 RINOK(WriteStream(outStream, _outBuf, processed))
152 RINOK(res)
153 if (_status == kStatus_Finished_With_Mark)
154 break;
155 if (progress)
156 {
157 const UInt64 inProcessed = _inStream.GetProcessed();
158 RINOK(progress->SetRatioInfo(&inProcessed, &_processedSize))
159 }
160 }
161 while (!_outSizeDefined || _processedSize < _outSize);
162
163 if (FinishStream && inSize && *inSize != _inStream.GetProcessed())
164 return S_FALSE;
165
166 return S_OK;
167 }
168
169
Z7_COM7F_IMF(CDecoder::SetOutStreamSize (const UInt64 * outSize))170 Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
171 {
172 _outSizeDefined = (outSize != NULL);
173 if (_outSizeDefined)
174 _outSize = *outSize;
175 _processedSize = 0;
176 _status = kStatus_NeedInit;
177 _res = SZ_OK;
178 return S_OK;
179 }
180
Z7_COM7F_IMF(CDecoder::SetFinishMode (UInt32 finishMode))181 Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
182 {
183 FinishStream = (finishMode != 0);
184 return S_OK;
185 }
186
Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize (UInt64 * value))187 Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
188 {
189 *value = _inStream.GetProcessed();
190 return S_OK;
191 }
192
193 #ifndef Z7_NO_READ_FROM_CODER
194
Z7_COM7F_IMF(CDecoder::SetInStream (ISequentialInStream * inStream))195 Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream))
196 {
197 InSeqStream = inStream;
198 _inStream.Stream = inStream;
199 return S_OK;
200 }
201
Z7_COM7F_IMF(CDecoder::ReleaseInStream ())202 Z7_COM7F_IMF(CDecoder::ReleaseInStream())
203 {
204 InSeqStream.Release();
205 return S_OK;
206 }
207
Z7_COM7F_IMF(CDecoder::Read (void * data,UInt32 size,UInt32 * processedSize))208 Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
209 {
210 const UInt64 startPos = _processedSize;
211 const HRESULT res = CodeSpec((Byte *)data, size);
212 if (processedSize)
213 *processedSize = (UInt32)(_processedSize - startPos);
214 return res;
215 }
216
217 #endif
218
219 }}
220