xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/PpmdDecoder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // PpmdDecoder.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Alloc.h"
6*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/CpuArch.h"
7*f6dc9357SAndroid Build Coastguard Worker 
8*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
9*f6dc9357SAndroid Build Coastguard Worker 
10*f6dc9357SAndroid Build Coastguard Worker #include "PpmdDecoder.h"
11*f6dc9357SAndroid Build Coastguard Worker 
12*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
13*f6dc9357SAndroid Build Coastguard Worker namespace NPpmd {
14*f6dc9357SAndroid Build Coastguard Worker 
15*f6dc9357SAndroid Build Coastguard Worker static const UInt32 kBufSize = (1 << 16);
16*f6dc9357SAndroid Build Coastguard Worker 
17*f6dc9357SAndroid Build Coastguard Worker enum
18*f6dc9357SAndroid Build Coastguard Worker {
19*f6dc9357SAndroid Build Coastguard Worker   kStatus_NeedInit,
20*f6dc9357SAndroid Build Coastguard Worker   kStatus_Normal,
21*f6dc9357SAndroid Build Coastguard Worker   kStatus_Finished_With_Mark,
22*f6dc9357SAndroid Build Coastguard Worker   kStatus_Error
23*f6dc9357SAndroid Build Coastguard Worker };
24*f6dc9357SAndroid Build Coastguard Worker 
~CDecoder()25*f6dc9357SAndroid Build Coastguard Worker CDecoder::~CDecoder()
26*f6dc9357SAndroid Build Coastguard Worker {
27*f6dc9357SAndroid Build Coastguard Worker   ::MidFree(_outBuf);
28*f6dc9357SAndroid Build Coastguard Worker   Ppmd7_Free(&_ppmd, &g_BigAlloc);
29*f6dc9357SAndroid Build Coastguard Worker }
30*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2 (const Byte * props,UInt32 size))31*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size))
32*f6dc9357SAndroid Build Coastguard Worker {
33*f6dc9357SAndroid Build Coastguard Worker   if (size < 5)
34*f6dc9357SAndroid Build Coastguard Worker     return E_INVALIDARG;
35*f6dc9357SAndroid Build Coastguard Worker   _order = props[0];
36*f6dc9357SAndroid Build Coastguard Worker   const UInt32 memSize = GetUi32(props + 1);
37*f6dc9357SAndroid Build Coastguard Worker   if (_order < PPMD7_MIN_ORDER ||
38*f6dc9357SAndroid Build Coastguard Worker       _order > PPMD7_MAX_ORDER ||
39*f6dc9357SAndroid Build Coastguard Worker       memSize < PPMD7_MIN_MEM_SIZE ||
40*f6dc9357SAndroid Build Coastguard Worker       memSize > PPMD7_MAX_MEM_SIZE)
41*f6dc9357SAndroid Build Coastguard Worker     return E_NOTIMPL;
42*f6dc9357SAndroid Build Coastguard Worker   if (!_inStream.Alloc(1 << 20))
43*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
44*f6dc9357SAndroid Build Coastguard Worker   if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc))
45*f6dc9357SAndroid Build Coastguard Worker     return E_OUTOFMEMORY;
46*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
47*f6dc9357SAndroid Build Coastguard Worker }
48*f6dc9357SAndroid Build Coastguard Worker 
49*f6dc9357SAndroid Build Coastguard Worker #define MY_rangeDec  _ppmd.rc.dec
50*f6dc9357SAndroid Build Coastguard Worker 
51*f6dc9357SAndroid Build Coastguard Worker #define CHECK_EXTRA_ERROR \
52*f6dc9357SAndroid Build Coastguard Worker     if (_inStream.Extra) { \
53*f6dc9357SAndroid Build Coastguard Worker       _status = kStatus_Error; \
54*f6dc9357SAndroid Build Coastguard Worker       return (_res = (_inStream.Res != SZ_OK ? _inStream.Res: S_FALSE)); }
55*f6dc9357SAndroid Build Coastguard Worker 
56*f6dc9357SAndroid Build Coastguard Worker 
CodeSpec(Byte * memStream,UInt32 size)57*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
58*f6dc9357SAndroid Build Coastguard Worker {
59*f6dc9357SAndroid Build Coastguard Worker   if (_res != S_OK)
60*f6dc9357SAndroid Build Coastguard Worker     return _res;
61*f6dc9357SAndroid Build Coastguard Worker 
62*f6dc9357SAndroid Build Coastguard Worker   switch (_status)
63*f6dc9357SAndroid Build Coastguard Worker   {
64*f6dc9357SAndroid Build Coastguard Worker     case kStatus_Finished_With_Mark: return S_OK;
65*f6dc9357SAndroid Build Coastguard Worker     case kStatus_Error: return S_FALSE;
66*f6dc9357SAndroid Build Coastguard Worker     case kStatus_NeedInit:
67*f6dc9357SAndroid Build Coastguard Worker       _inStream.Init();
68*f6dc9357SAndroid Build Coastguard Worker       if (!Ppmd7z_RangeDec_Init(&MY_rangeDec))
69*f6dc9357SAndroid Build Coastguard Worker       {
70*f6dc9357SAndroid Build Coastguard Worker         _status = kStatus_Error;
71*f6dc9357SAndroid Build Coastguard Worker         return (_res = S_FALSE);
72*f6dc9357SAndroid Build Coastguard Worker       }
73*f6dc9357SAndroid Build Coastguard Worker       CHECK_EXTRA_ERROR
74*f6dc9357SAndroid Build Coastguard Worker       _status = kStatus_Normal;
75*f6dc9357SAndroid Build Coastguard Worker       Ppmd7_Init(&_ppmd, _order);
76*f6dc9357SAndroid Build Coastguard Worker       break;
77*f6dc9357SAndroid Build Coastguard Worker     default: break;
78*f6dc9357SAndroid Build Coastguard Worker   }
79*f6dc9357SAndroid Build Coastguard Worker 
80*f6dc9357SAndroid Build Coastguard Worker   if (_outSizeDefined)
81*f6dc9357SAndroid Build Coastguard Worker   {
82*f6dc9357SAndroid Build Coastguard Worker     const UInt64 rem = _outSize - _processedSize;
83*f6dc9357SAndroid Build Coastguard Worker     if (size > rem)
84*f6dc9357SAndroid Build Coastguard Worker       size = (UInt32)rem;
85*f6dc9357SAndroid Build Coastguard Worker   }
86*f6dc9357SAndroid Build Coastguard Worker 
87*f6dc9357SAndroid Build Coastguard Worker   int sym = 0;
88*f6dc9357SAndroid Build Coastguard Worker   {
89*f6dc9357SAndroid Build Coastguard Worker     Byte *buf = memStream;
90*f6dc9357SAndroid Build Coastguard Worker     const Byte *lim = buf + size;
91*f6dc9357SAndroid Build Coastguard Worker     for (; buf != lim; buf++)
92*f6dc9357SAndroid Build Coastguard Worker     {
93*f6dc9357SAndroid Build Coastguard Worker       sym = Ppmd7z_DecodeSymbol(&_ppmd);
94*f6dc9357SAndroid Build Coastguard Worker       if (_inStream.Extra || sym < 0)
95*f6dc9357SAndroid Build Coastguard Worker         break;
96*f6dc9357SAndroid Build Coastguard Worker       *buf = (Byte)sym;
97*f6dc9357SAndroid Build Coastguard Worker     }
98*f6dc9357SAndroid Build Coastguard Worker     /*
99*f6dc9357SAndroid Build Coastguard Worker     buf = Ppmd7z_DecodeSymbols(&_ppmd, buf, lim);
100*f6dc9357SAndroid Build Coastguard Worker     sym = _ppmd.LastSymbol;
101*f6dc9357SAndroid Build Coastguard Worker     */
102*f6dc9357SAndroid Build Coastguard Worker     _processedSize += (size_t)(buf - memStream);
103*f6dc9357SAndroid Build Coastguard Worker   }
104*f6dc9357SAndroid Build Coastguard Worker 
105*f6dc9357SAndroid Build Coastguard Worker   CHECK_EXTRA_ERROR
106*f6dc9357SAndroid Build Coastguard Worker 
107*f6dc9357SAndroid Build Coastguard Worker   if (sym >= 0)
108*f6dc9357SAndroid Build Coastguard Worker   {
109*f6dc9357SAndroid Build Coastguard Worker     if (!FinishStream
110*f6dc9357SAndroid Build Coastguard Worker         || !_outSizeDefined
111*f6dc9357SAndroid Build Coastguard Worker         || _outSize != _processedSize
112*f6dc9357SAndroid Build Coastguard Worker         || MY_rangeDec.Code == 0)
113*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
114*f6dc9357SAndroid Build Coastguard Worker     /*
115*f6dc9357SAndroid Build Coastguard Worker     // We can decode additional End Marker here:
116*f6dc9357SAndroid Build Coastguard Worker     sym = Ppmd7z_DecodeSymbol(&_ppmd);
117*f6dc9357SAndroid Build Coastguard Worker     CHECK_EXTRA_ERROR
118*f6dc9357SAndroid Build Coastguard Worker     */
119*f6dc9357SAndroid Build Coastguard Worker   }
120*f6dc9357SAndroid Build Coastguard Worker 
121*f6dc9357SAndroid Build Coastguard Worker   if (sym != PPMD7_SYM_END || MY_rangeDec.Code != 0)
122*f6dc9357SAndroid Build Coastguard Worker   {
123*f6dc9357SAndroid Build Coastguard Worker     _status = kStatus_Error;
124*f6dc9357SAndroid Build Coastguard Worker     return (_res = S_FALSE);
125*f6dc9357SAndroid Build Coastguard Worker   }
126*f6dc9357SAndroid Build Coastguard Worker 
127*f6dc9357SAndroid Build Coastguard Worker   _status = kStatus_Finished_With_Mark;
128*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
129*f6dc9357SAndroid Build Coastguard Worker }
130*f6dc9357SAndroid Build Coastguard Worker 
131*f6dc9357SAndroid Build Coastguard Worker 
132*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress))133*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
134*f6dc9357SAndroid Build Coastguard Worker     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
135*f6dc9357SAndroid Build Coastguard Worker {
136*f6dc9357SAndroid Build Coastguard Worker   if (!_outBuf)
137*f6dc9357SAndroid Build Coastguard Worker   {
138*f6dc9357SAndroid Build Coastguard Worker     _outBuf = (Byte *)::MidAlloc(kBufSize);
139*f6dc9357SAndroid Build Coastguard Worker     if (!_outBuf)
140*f6dc9357SAndroid Build Coastguard Worker       return E_OUTOFMEMORY;
141*f6dc9357SAndroid Build Coastguard Worker   }
142*f6dc9357SAndroid Build Coastguard Worker 
143*f6dc9357SAndroid Build Coastguard Worker   _inStream.Stream = inStream;
144*f6dc9357SAndroid Build Coastguard Worker   SetOutStreamSize(outSize);
145*f6dc9357SAndroid Build Coastguard Worker 
146*f6dc9357SAndroid Build Coastguard Worker   do
147*f6dc9357SAndroid Build Coastguard Worker   {
148*f6dc9357SAndroid Build Coastguard Worker     const UInt64 startPos = _processedSize;
149*f6dc9357SAndroid Build Coastguard Worker     const HRESULT res = CodeSpec(_outBuf, kBufSize);
150*f6dc9357SAndroid Build Coastguard Worker     const size_t processed = (size_t)(_processedSize - startPos);
151*f6dc9357SAndroid Build Coastguard Worker     RINOK(WriteStream(outStream, _outBuf, processed))
152*f6dc9357SAndroid Build Coastguard Worker     RINOK(res)
153*f6dc9357SAndroid Build Coastguard Worker     if (_status == kStatus_Finished_With_Mark)
154*f6dc9357SAndroid Build Coastguard Worker       break;
155*f6dc9357SAndroid Build Coastguard Worker     if (progress)
156*f6dc9357SAndroid Build Coastguard Worker     {
157*f6dc9357SAndroid Build Coastguard Worker       const UInt64 inProcessed = _inStream.GetProcessed();
158*f6dc9357SAndroid Build Coastguard Worker       RINOK(progress->SetRatioInfo(&inProcessed, &_processedSize))
159*f6dc9357SAndroid Build Coastguard Worker     }
160*f6dc9357SAndroid Build Coastguard Worker   }
161*f6dc9357SAndroid Build Coastguard Worker   while (!_outSizeDefined || _processedSize < _outSize);
162*f6dc9357SAndroid Build Coastguard Worker 
163*f6dc9357SAndroid Build Coastguard Worker   if (FinishStream && inSize && *inSize != _inStream.GetProcessed())
164*f6dc9357SAndroid Build Coastguard Worker     return S_FALSE;
165*f6dc9357SAndroid Build Coastguard Worker 
166*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
167*f6dc9357SAndroid Build Coastguard Worker }
168*f6dc9357SAndroid Build Coastguard Worker 
169*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::SetOutStreamSize (const UInt64 * outSize))170*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
171*f6dc9357SAndroid Build Coastguard Worker {
172*f6dc9357SAndroid Build Coastguard Worker   _outSizeDefined = (outSize != NULL);
173*f6dc9357SAndroid Build Coastguard Worker   if (_outSizeDefined)
174*f6dc9357SAndroid Build Coastguard Worker     _outSize = *outSize;
175*f6dc9357SAndroid Build Coastguard Worker   _processedSize = 0;
176*f6dc9357SAndroid Build Coastguard Worker   _status = kStatus_NeedInit;
177*f6dc9357SAndroid Build Coastguard Worker   _res = SZ_OK;
178*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
179*f6dc9357SAndroid Build Coastguard Worker }
180*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::SetFinishMode (UInt32 finishMode))181*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
182*f6dc9357SAndroid Build Coastguard Worker {
183*f6dc9357SAndroid Build Coastguard Worker   FinishStream = (finishMode != 0);
184*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
185*f6dc9357SAndroid Build Coastguard Worker }
186*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize (UInt64 * value))187*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
188*f6dc9357SAndroid Build Coastguard Worker {
189*f6dc9357SAndroid Build Coastguard Worker   *value = _inStream.GetProcessed();
190*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
191*f6dc9357SAndroid Build Coastguard Worker }
192*f6dc9357SAndroid Build Coastguard Worker 
193*f6dc9357SAndroid Build Coastguard Worker #ifndef Z7_NO_READ_FROM_CODER
194*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::SetInStream (ISequentialInStream * inStream))195*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream))
196*f6dc9357SAndroid Build Coastguard Worker {
197*f6dc9357SAndroid Build Coastguard Worker   InSeqStream = inStream;
198*f6dc9357SAndroid Build Coastguard Worker   _inStream.Stream = inStream;
199*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
200*f6dc9357SAndroid Build Coastguard Worker }
201*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::ReleaseInStream ())202*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::ReleaseInStream())
203*f6dc9357SAndroid Build Coastguard Worker {
204*f6dc9357SAndroid Build Coastguard Worker   InSeqStream.Release();
205*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
206*f6dc9357SAndroid Build Coastguard Worker }
207*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CDecoder::Read (void * data,UInt32 size,UInt32 * processedSize))208*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
209*f6dc9357SAndroid Build Coastguard Worker {
210*f6dc9357SAndroid Build Coastguard Worker   const UInt64 startPos = _processedSize;
211*f6dc9357SAndroid Build Coastguard Worker   const HRESULT res = CodeSpec((Byte *)data, size);
212*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
213*f6dc9357SAndroid Build Coastguard Worker     *processedSize = (UInt32)(_processedSize - startPos);
214*f6dc9357SAndroid Build Coastguard Worker   return res;
215*f6dc9357SAndroid Build Coastguard Worker }
216*f6dc9357SAndroid Build Coastguard Worker 
217*f6dc9357SAndroid Build Coastguard Worker #endif
218*f6dc9357SAndroid Build Coastguard Worker 
219*f6dc9357SAndroid Build Coastguard Worker }}
220