1 // PpmdZip.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../C/CpuArch.h"
6
7 #include "../Common/RegisterCodec.h"
8 #include "../Common/StreamUtils.h"
9
10 #include "PpmdZip.h"
11
12 namespace NCompress {
13 namespace NPpmdZip {
14
CDecoder(bool fullFileMode)15 CDecoder::CDecoder(bool fullFileMode):
16 _fullFileMode(fullFileMode)
17 {
18 Ppmd8_Construct(&_ppmd);
19 _ppmd.Stream.In = &_inStream.vt;
20 }
21
~CDecoder()22 CDecoder::~CDecoder()
23 {
24 Ppmd8_Free(&_ppmd, &g_BigAlloc);
25 }
26
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)27 STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
28 const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
29 {
30 // try {
31
32 if (!_outStream.Alloc())
33 return E_OUTOFMEMORY;
34 if (!_inStream.Alloc(1 << 20))
35 return E_OUTOFMEMORY;
36
37 _inStream.Stream = inStream;
38 _inStream.Init();
39
40 {
41 Byte buf[2];
42 for (int i = 0; i < 2; i++)
43 buf[i] = _inStream.ReadByte();
44 if (_inStream.Extra)
45 return S_FALSE;
46
47 UInt32 val = GetUi16(buf);
48 unsigned order = (val & 0xF) + 1;
49 UInt32 mem = ((val >> 4) & 0xFF) + 1;
50 unsigned restor = (val >> 12);
51 if (order < 2 || restor > 2)
52 return S_FALSE;
53
54 #ifndef PPMD8_FREEZE_SUPPORT
55 if (restor == 2)
56 return E_NOTIMPL;
57 #endif
58
59 if (!Ppmd8_Alloc(&_ppmd, mem << 20, &g_BigAlloc))
60 return E_OUTOFMEMORY;
61
62 if (!Ppmd8_Init_RangeDec(&_ppmd))
63 return S_FALSE;
64 Ppmd8_Init(&_ppmd, order, restor);
65 }
66
67 bool wasFinished = false;
68 UInt64 processedSize = 0;
69
70 for (;;)
71 {
72 size_t size = kBufSize;
73 if (outSize)
74 {
75 const UInt64 rem = *outSize - processedSize;
76 if (size > rem)
77 {
78 size = (size_t)rem;
79 if (size == 0)
80 break;
81 }
82 }
83
84 int sym;
85 Byte *buf = _outStream.Buf;
86 const Byte *lim = buf + size;
87
88 do
89 {
90 sym = Ppmd8_DecodeSymbol(&_ppmd);
91 if (_inStream.Extra || sym < 0)
92 break;
93 *buf++ = (Byte)sym;
94 }
95 while (buf != lim);
96
97 size_t cur = (size_t)(buf - _outStream.Buf);
98 processedSize += cur;
99
100 RINOK(WriteStream(outStream, _outStream.Buf, cur));
101
102 RINOK(_inStream.Res);
103 if (_inStream.Extra)
104 return S_FALSE;
105
106 if (sym < 0)
107 {
108 if (sym != -1)
109 return S_FALSE;
110 wasFinished = true;
111 break;
112 }
113
114 if (progress)
115 {
116 const UInt64 inProccessed = _inStream.GetProcessed();
117 RINOK(progress->SetRatioInfo(&inProccessed, &processedSize));
118 }
119 }
120
121 RINOK(_inStream.Res);
122
123 if (_fullFileMode)
124 {
125 if (!wasFinished)
126 {
127 int res = Ppmd8_DecodeSymbol(&_ppmd);
128 RINOK(_inStream.Res);
129 if (_inStream.Extra || res != -1)
130 return S_FALSE;
131 }
132 if (!Ppmd8_RangeDec_IsFinishedOK(&_ppmd))
133 return S_FALSE;
134
135 if (inSize && *inSize != _inStream.GetProcessed())
136 return S_FALSE;
137 }
138
139 return S_OK;
140
141 // } catch (...) { return E_FAIL; }
142 }
143
144
SetFinishMode(UInt32 finishMode)145 STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
146 {
147 _fullFileMode = (finishMode != 0);
148 return S_OK;
149 }
150
GetInStreamProcessedSize(UInt64 * value)151 STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
152 {
153 *value = _inStream.GetProcessed();
154 return S_OK;
155 }
156
157
158
159 // ---------- Encoder ----------
160
Normalize(int level)161 void CEncProps::Normalize(int level)
162 {
163 if (level < 0) level = 5;
164 if (level == 0) level = 1;
165 if (level > 9) level = 9;
166 if (MemSizeMB == (UInt32)(Int32)-1)
167 MemSizeMB = 1 << (level - 1);
168 const unsigned kMult = 16;
169 for (UInt32 m = 1; m < MemSizeMB; m <<= 1)
170 if (ReduceSize <= (m << 20) / kMult)
171 {
172 MemSizeMB = m;
173 break;
174 }
175 if (Order == -1) Order = 3 + level;
176 if (Restor == -1)
177 Restor = level < 7 ?
178 PPMD8_RESTORE_METHOD_RESTART :
179 PPMD8_RESTORE_METHOD_CUT_OFF;
180 }
181
~CEncoder()182 CEncoder::~CEncoder()
183 {
184 Ppmd8_Free(&_ppmd, &g_BigAlloc);
185 }
186
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * coderProps,UInt32 numProps)187 STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)
188 {
189 int level = -1;
190 CEncProps props;
191 for (UInt32 i = 0; i < numProps; i++)
192 {
193 const PROPVARIANT &prop = coderProps[i];
194 PROPID propID = propIDs[i];
195 if (propID > NCoderPropID::kReduceSize)
196 continue;
197 if (propID == NCoderPropID::kReduceSize)
198 {
199 props.ReduceSize = (UInt32)(Int32)-1;
200 if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1)
201 props.ReduceSize = (UInt32)prop.uhVal.QuadPart;
202 continue;
203 }
204 if (prop.vt != VT_UI4)
205 return E_INVALIDARG;
206 UInt32 v = (UInt32)prop.ulVal;
207 switch (propID)
208 {
209 case NCoderPropID::kUsedMemorySize:
210 if (v < (1 << 20) || v > (1 << 28))
211 return E_INVALIDARG;
212 props.MemSizeMB = v >> 20;
213 break;
214 case NCoderPropID::kOrder:
215 if (v < PPMD8_MIN_ORDER || v > PPMD8_MAX_ORDER)
216 return E_INVALIDARG;
217 props.Order = (Byte)v;
218 break;
219 case NCoderPropID::kNumThreads: break;
220 case NCoderPropID::kLevel: level = (int)v; break;
221 case NCoderPropID::kAlgorithm:
222 if (v >= PPMD8_RESTORE_METHOD_UNSUPPPORTED)
223 return E_INVALIDARG;
224 props.Restor = (int)v;
225 break;
226 default: return E_INVALIDARG;
227 }
228 }
229 props.Normalize(level);
230 _props = props;
231 return S_OK;
232 }
233
CEncoder()234 CEncoder::CEncoder()
235 {
236 _props.Normalize(-1);
237 _ppmd.Stream.Out = &_outStream.vt;
238 Ppmd8_Construct(&_ppmd);
239 }
240
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 *,ICompressProgressInfo * progress)241 STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
242 const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
243 {
244 if (!_inStream.Alloc())
245 return E_OUTOFMEMORY;
246 if (!_outStream.Alloc(1 << 20))
247 return E_OUTOFMEMORY;
248 if (!Ppmd8_Alloc(&_ppmd, _props.MemSizeMB << 20, &g_BigAlloc))
249 return E_OUTOFMEMORY;
250
251 _outStream.Stream = outStream;
252 _outStream.Init();
253
254 Ppmd8_Init_RangeEnc(&_ppmd);
255 Ppmd8_Init(&_ppmd, (unsigned)_props.Order, (unsigned)_props.Restor);
256
257 {
258 UInt32 val = (UInt32)(((unsigned)_props.Order - 1) + ((_props.MemSizeMB - 1) << 4) + ((unsigned)_props.Restor << 12));
259 _outStream.WriteByte((Byte)(val & 0xFF));
260 _outStream.WriteByte((Byte)(val >> 8));
261 }
262 RINOK(_outStream.Res);
263
264 UInt64 processed = 0;
265 for (;;)
266 {
267 UInt32 size;
268 RINOK(inStream->Read(_inStream.Buf, kBufSize, &size));
269 if (size == 0)
270 {
271 Ppmd8_EncodeSymbol(&_ppmd, -1);
272 Ppmd8_Flush_RangeEnc(&_ppmd);
273 return _outStream.Flush();
274 }
275
276 processed += size;
277 const Byte *buf = _inStream.Buf;
278 const Byte *lim = buf + size;
279 do
280 {
281 Ppmd8_EncodeSymbol(&_ppmd, *buf);
282 if (_outStream.Res != S_OK)
283 break;
284 }
285 while (++buf != lim);
286
287 RINOK(_outStream.Res);
288
289 if (progress)
290 {
291 const UInt64 outProccessed = _outStream.GetProcessed();
292 RINOK(progress->SetRatioInfo(&processed, &outProccessed));
293 }
294 }
295 }
296
297
298
299
300 }}
301