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