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