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