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