xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/PpmdZip.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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