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
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 }
78
79 if (_outSizeDefined)
80 {
81 const UInt64 rem = _outSize - _processedSize;
82 if (size > rem)
83 size = (UInt32)rem;
84 }
85
86 int sym = 0;
87 {
88 Byte *buf = memStream;
89 const Byte *lim = buf + size;
90 for (; buf != lim; buf++)
91 {
92 sym = Ppmd7z_DecodeSymbol(&_ppmd);
93 if (_inStream.Extra || sym < 0)
94 break;
95 *buf = (Byte)sym;
96 }
97 /*
98 buf = Ppmd7z_DecodeSymbols(&_ppmd, buf, lim);
99 sym = _ppmd.LastSymbol;
100 */
101 _processedSize += (size_t)(buf - memStream);
102 }
103
104 CHECK_EXTRA_ERROR
105
106 if (sym >= 0)
107 {
108 if (!FinishStream
109 || !_outSizeDefined
110 || _outSize != _processedSize
111 || MY_rangeDec.Code == 0)
112 return S_OK;
113 /*
114 // We can decode additional End Marker here:
115 sym = Ppmd7z_DecodeSymbol(&_ppmd);
116 CHECK_EXTRA_ERROR
117 */
118 }
119
120 if (sym != PPMD7_SYM_END || MY_rangeDec.Code != 0)
121 {
122 _status = kStatus_Error;
123 return (_res = S_FALSE);
124 }
125
126 _status = kStatus_Finished_With_Mark;
127 return S_OK;
128 }
129
130
131
Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)132 Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
133 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
134 {
135 if (!_outBuf)
136 {
137 _outBuf = (Byte *)::MidAlloc(kBufSize);
138 if (!_outBuf)
139 return E_OUTOFMEMORY;
140 }
141
142 _inStream.Stream = inStream;
143 SetOutStreamSize(outSize);
144
145 do
146 {
147 const UInt64 startPos = _processedSize;
148 const HRESULT res = CodeSpec(_outBuf, kBufSize);
149 const size_t processed = (size_t)(_processedSize - startPos);
150 RINOK(WriteStream(outStream, _outBuf, processed))
151 RINOK(res)
152 if (_status == kStatus_Finished_With_Mark)
153 break;
154 if (progress)
155 {
156 const UInt64 inProcessed = _inStream.GetProcessed();
157 RINOK(progress->SetRatioInfo(&inProcessed, &_processedSize))
158 }
159 }
160 while (!_outSizeDefined || _processedSize < _outSize);
161
162 if (FinishStream && inSize && *inSize != _inStream.GetProcessed())
163 return S_FALSE;
164
165 return S_OK;
166 }
167
168
SetOutStreamSize(const UInt64 *outSize)169 Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
170 {
171 _outSizeDefined = (outSize != NULL);
172 if (_outSizeDefined)
173 _outSize = *outSize;
174 _processedSize = 0;
175 _status = kStatus_NeedInit;
176 _res = SZ_OK;
177 return S_OK;
178 }
179
SetFinishMode(UInt32 finishMode)180 Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
181 {
182 FinishStream = (finishMode != 0);
183 return S_OK;
184 }
185
GetInStreamProcessedSize(UInt64 *value)186 Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
187 {
188 *value = _inStream.GetProcessed();
189 return S_OK;
190 }
191
192 #ifndef Z7_NO_READ_FROM_CODER
193
SetInStream(ISequentialInStream *inStream)194 Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream))
195 {
196 InSeqStream = inStream;
197 _inStream.Stream = inStream;
198 return S_OK;
199 }
200
ReleaseInStream()201 Z7_COM7F_IMF(CDecoder::ReleaseInStream())
202 {
203 InSeqStream.Release();
204 return S_OK;
205 }
206
Read(void *data, UInt32 size, UInt32 *processedSize)207 Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
208 {
209 const UInt64 startPos = _processedSize;
210 const HRESULT res = CodeSpec((Byte *)data, size);
211 if (processedSize)
212 *processedSize = (UInt32)(_processedSize - startPos);
213 return res;
214 }
215
216 #endif
217
218 }}
219