1*f6dc9357SAndroid Build Coastguard Worker // ZstdDecoder.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 <stdio.h>
6*f6dc9357SAndroid Build Coastguard Worker
7*f6dc9357SAndroid Build Coastguard Worker #include "../../../C/Alloc.h"
8*f6dc9357SAndroid Build Coastguard Worker
9*f6dc9357SAndroid Build Coastguard Worker #include "../Common/CWrappers.h"
10*f6dc9357SAndroid Build Coastguard Worker #include "../Common/StreamUtils.h"
11*f6dc9357SAndroid Build Coastguard Worker
12*f6dc9357SAndroid Build Coastguard Worker #include "ZstdDecoder.h"
13*f6dc9357SAndroid Build Coastguard Worker
14*f6dc9357SAndroid Build Coastguard Worker namespace NCompress {
15*f6dc9357SAndroid Build Coastguard Worker namespace NZstd {
16*f6dc9357SAndroid Build Coastguard Worker
17*f6dc9357SAndroid Build Coastguard Worker static const size_t k_Zstd_BlockSizeMax = 1 << 17;
18*f6dc9357SAndroid Build Coastguard Worker /*
19*f6dc9357SAndroid Build Coastguard Worker we set _outStepMask as (k_Zstd_BlockSizeMax - 1), because:
20*f6dc9357SAndroid Build Coastguard Worker - cycSize in zstd decoder for isCyclicMode is aligned for (1 << 17) only.
21*f6dc9357SAndroid Build Coastguard Worker So some write sizes will be multiple of ((1 << 17) * n).
22*f6dc9357SAndroid Build Coastguard Worker - Also it can be optimal to flush data after each block decoding.
23*f6dc9357SAndroid Build Coastguard Worker */
24*f6dc9357SAndroid Build Coastguard Worker
CDecoder()25*f6dc9357SAndroid Build Coastguard Worker CDecoder::CDecoder():
26*f6dc9357SAndroid Build Coastguard Worker _outStepMask(k_Zstd_BlockSizeMax - 1) // must be = (1 << x) - 1
27*f6dc9357SAndroid Build Coastguard Worker , _dec(NULL)
28*f6dc9357SAndroid Build Coastguard Worker , _inProcessed(0)
29*f6dc9357SAndroid Build Coastguard Worker , _inBufSize(1u << 19) // larger value will reduce the number of memcpy() calls in CZstdDec code
30*f6dc9357SAndroid Build Coastguard Worker , _inBuf(NULL)
31*f6dc9357SAndroid Build Coastguard Worker , FinishMode(false)
32*f6dc9357SAndroid Build Coastguard Worker , DisableHash(False)
33*f6dc9357SAndroid Build Coastguard Worker // , DisableHash(True) // for debug : fast decoding without hash calculation
34*f6dc9357SAndroid Build Coastguard Worker {
35*f6dc9357SAndroid Build Coastguard Worker // ZstdDecInfo_Clear(&ResInfo);
36*f6dc9357SAndroid Build Coastguard Worker }
37*f6dc9357SAndroid Build Coastguard Worker
~CDecoder()38*f6dc9357SAndroid Build Coastguard Worker CDecoder::~CDecoder()
39*f6dc9357SAndroid Build Coastguard Worker {
40*f6dc9357SAndroid Build Coastguard Worker if (_dec)
41*f6dc9357SAndroid Build Coastguard Worker ZstdDec_Destroy(_dec);
42*f6dc9357SAndroid Build Coastguard Worker MidFree(_inBuf);
43*f6dc9357SAndroid Build Coastguard Worker }
44*f6dc9357SAndroid Build Coastguard Worker
45*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CDecoder::SetInBufSize (UInt32,UInt32 size))46*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size))
47*f6dc9357SAndroid Build Coastguard Worker { _inBufSize = size; return S_OK; }
Z7_COM7F_IMF(CDecoder::SetOutBufSize (UInt32,UInt32 size))48*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32 , UInt32 size))
49*f6dc9357SAndroid Build Coastguard Worker {
50*f6dc9357SAndroid Build Coastguard Worker // we round it down:
51*f6dc9357SAndroid Build Coastguard Worker size >>= 1;
52*f6dc9357SAndroid Build Coastguard Worker size |= size >> (1 << 0);
53*f6dc9357SAndroid Build Coastguard Worker size |= size >> (1 << 1);
54*f6dc9357SAndroid Build Coastguard Worker size |= size >> (1 << 2);
55*f6dc9357SAndroid Build Coastguard Worker size |= size >> (1 << 3);
56*f6dc9357SAndroid Build Coastguard Worker size |= size >> (1 << 4);
57*f6dc9357SAndroid Build Coastguard Worker _outStepMask = size; // it's (1 << x) - 1 now
58*f6dc9357SAndroid Build Coastguard Worker return S_OK;
59*f6dc9357SAndroid Build Coastguard Worker }
60*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CDecoder::SetDecoderProperties2 (const Byte *,UInt32))61*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte * /* prop */, UInt32 /* size */))
62*f6dc9357SAndroid Build Coastguard Worker {
63*f6dc9357SAndroid Build Coastguard Worker // if (size != 3 && size != 5) return E_NOTIMPL;
64*f6dc9357SAndroid Build Coastguard Worker return S_OK;
65*f6dc9357SAndroid Build Coastguard Worker }
66*f6dc9357SAndroid Build Coastguard Worker
67*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CDecoder::SetFinishMode (UInt32 finishMode))68*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
69*f6dc9357SAndroid Build Coastguard Worker {
70*f6dc9357SAndroid Build Coastguard Worker FinishMode = (finishMode != 0);
71*f6dc9357SAndroid Build Coastguard Worker // FinishMode = false; // for debug
72*f6dc9357SAndroid Build Coastguard Worker return S_OK;
73*f6dc9357SAndroid Build Coastguard Worker }
74*f6dc9357SAndroid Build Coastguard Worker
75*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CDecoder::ReadUnusedFromInBuf (void * data,UInt32 size,UInt32 * processedSize))76*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize))
77*f6dc9357SAndroid Build Coastguard Worker {
78*f6dc9357SAndroid Build Coastguard Worker size_t cur = ZstdDec_ReadUnusedFromInBuf(_dec, _afterDecoding_tempPos, data, size);
79*f6dc9357SAndroid Build Coastguard Worker _afterDecoding_tempPos += cur;
80*f6dc9357SAndroid Build Coastguard Worker size -= (UInt32)cur;
81*f6dc9357SAndroid Build Coastguard Worker if (size)
82*f6dc9357SAndroid Build Coastguard Worker {
83*f6dc9357SAndroid Build Coastguard Worker const size_t rem = _state.inLim - _state.inPos;
84*f6dc9357SAndroid Build Coastguard Worker if (size > rem)
85*f6dc9357SAndroid Build Coastguard Worker size = (UInt32)rem;
86*f6dc9357SAndroid Build Coastguard Worker if (size)
87*f6dc9357SAndroid Build Coastguard Worker {
88*f6dc9357SAndroid Build Coastguard Worker memcpy((Byte *)data + cur, _state.inBuf + _state.inPos, size);
89*f6dc9357SAndroid Build Coastguard Worker _state.inPos += size;
90*f6dc9357SAndroid Build Coastguard Worker cur += size;
91*f6dc9357SAndroid Build Coastguard Worker }
92*f6dc9357SAndroid Build Coastguard Worker }
93*f6dc9357SAndroid Build Coastguard Worker *processedSize = (UInt32)cur;
94*f6dc9357SAndroid Build Coastguard Worker return S_OK;
95*f6dc9357SAndroid Build Coastguard Worker }
96*f6dc9357SAndroid Build Coastguard Worker
97*f6dc9357SAndroid Build Coastguard Worker
98*f6dc9357SAndroid Build Coastguard Worker
Prepare(const UInt64 * outSize)99*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::Prepare(const UInt64 *outSize)
100*f6dc9357SAndroid Build Coastguard Worker {
101*f6dc9357SAndroid Build Coastguard Worker _inProcessed = 0;
102*f6dc9357SAndroid Build Coastguard Worker _afterDecoding_tempPos = 0;
103*f6dc9357SAndroid Build Coastguard Worker ZstdDecState_Clear(&_state);
104*f6dc9357SAndroid Build Coastguard Worker ZstdDecInfo_CLEAR(&ResInfo)
105*f6dc9357SAndroid Build Coastguard Worker // _state.outStep = _outStepMask + 1; // must be = (1 << x)
106*f6dc9357SAndroid Build Coastguard Worker _state.disableHash = DisableHash;
107*f6dc9357SAndroid Build Coastguard Worker if (outSize)
108*f6dc9357SAndroid Build Coastguard Worker {
109*f6dc9357SAndroid Build Coastguard Worker _state.outSize_Defined = True;
110*f6dc9357SAndroid Build Coastguard Worker _state.outSize = *outSize;
111*f6dc9357SAndroid Build Coastguard Worker // _state.outSize = 0; // for debug
112*f6dc9357SAndroid Build Coastguard Worker }
113*f6dc9357SAndroid Build Coastguard Worker if (!_dec)
114*f6dc9357SAndroid Build Coastguard Worker {
115*f6dc9357SAndroid Build Coastguard Worker _dec = ZstdDec_Create(&g_AlignedAlloc, &g_BigAlloc);
116*f6dc9357SAndroid Build Coastguard Worker if (!_dec)
117*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
118*f6dc9357SAndroid Build Coastguard Worker }
119*f6dc9357SAndroid Build Coastguard Worker if (!_inBuf || _inBufSize != _inBufSize_Allocated)
120*f6dc9357SAndroid Build Coastguard Worker {
121*f6dc9357SAndroid Build Coastguard Worker MidFree(_inBuf);
122*f6dc9357SAndroid Build Coastguard Worker _inBuf = NULL;
123*f6dc9357SAndroid Build Coastguard Worker _inBufSize_Allocated = 0;
124*f6dc9357SAndroid Build Coastguard Worker _inBuf = (Byte *)MidAlloc(_inBufSize);
125*f6dc9357SAndroid Build Coastguard Worker if (!_inBuf)
126*f6dc9357SAndroid Build Coastguard Worker return E_OUTOFMEMORY;
127*f6dc9357SAndroid Build Coastguard Worker _inBufSize_Allocated = _inBufSize;
128*f6dc9357SAndroid Build Coastguard Worker }
129*f6dc9357SAndroid Build Coastguard Worker _state.inBuf = _inBuf;
130*f6dc9357SAndroid Build Coastguard Worker ZstdDec_Init(_dec);
131*f6dc9357SAndroid Build Coastguard Worker return S_OK;
132*f6dc9357SAndroid Build Coastguard Worker }
133*f6dc9357SAndroid Build Coastguard Worker
134*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CDecoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress))135*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
136*f6dc9357SAndroid Build Coastguard Worker const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
137*f6dc9357SAndroid Build Coastguard Worker {
138*f6dc9357SAndroid Build Coastguard Worker RINOK(Prepare(outSize))
139*f6dc9357SAndroid Build Coastguard Worker
140*f6dc9357SAndroid Build Coastguard Worker UInt64 inPrev = 0;
141*f6dc9357SAndroid Build Coastguard Worker UInt64 outPrev = 0;
142*f6dc9357SAndroid Build Coastguard Worker UInt64 writtenSize = 0;
143*f6dc9357SAndroid Build Coastguard Worker bool readWasFinished = false;
144*f6dc9357SAndroid Build Coastguard Worker SRes sres = SZ_OK;
145*f6dc9357SAndroid Build Coastguard Worker HRESULT hres = S_OK;
146*f6dc9357SAndroid Build Coastguard Worker HRESULT hres_Read = S_OK;
147*f6dc9357SAndroid Build Coastguard Worker
148*f6dc9357SAndroid Build Coastguard Worker for (;;)
149*f6dc9357SAndroid Build Coastguard Worker {
150*f6dc9357SAndroid Build Coastguard Worker if (_state.inPos == _state.inLim && !readWasFinished)
151*f6dc9357SAndroid Build Coastguard Worker {
152*f6dc9357SAndroid Build Coastguard Worker _state.inPos = 0;
153*f6dc9357SAndroid Build Coastguard Worker _state.inLim = _inBufSize;
154*f6dc9357SAndroid Build Coastguard Worker hres_Read = ReadStream(inStream, _inBuf, &_state.inLim);
155*f6dc9357SAndroid Build Coastguard Worker // _state.inLim -= 5; readWasFinished = True; // for debug
156*f6dc9357SAndroid Build Coastguard Worker if (_state.inLim != _inBufSize || hres_Read != S_OK)
157*f6dc9357SAndroid Build Coastguard Worker {
158*f6dc9357SAndroid Build Coastguard Worker // hres_Read = 99; // for debug
159*f6dc9357SAndroid Build Coastguard Worker readWasFinished = True;
160*f6dc9357SAndroid Build Coastguard Worker }
161*f6dc9357SAndroid Build Coastguard Worker }
162*f6dc9357SAndroid Build Coastguard Worker {
163*f6dc9357SAndroid Build Coastguard Worker const size_t inPos_Start = _state.inPos;
164*f6dc9357SAndroid Build Coastguard Worker sres = ZstdDec_Decode(_dec, &_state);
165*f6dc9357SAndroid Build Coastguard Worker _inProcessed += _state.inPos - inPos_Start;
166*f6dc9357SAndroid Build Coastguard Worker }
167*f6dc9357SAndroid Build Coastguard Worker /*
168*f6dc9357SAndroid Build Coastguard Worker if (_state.status == ZSTD_STATUS_FINISHED_FRAME)
169*f6dc9357SAndroid Build Coastguard Worker printf("\nfinished frame pos=%8x, checksum=%08x\n", (unsigned)_state.outProcessed, (unsigned)_state.info.checksum);
170*f6dc9357SAndroid Build Coastguard Worker */
171*f6dc9357SAndroid Build Coastguard Worker const bool needStop = (sres != SZ_OK)
172*f6dc9357SAndroid Build Coastguard Worker || _state.status == ZSTD_STATUS_OUT_REACHED
173*f6dc9357SAndroid Build Coastguard Worker || (outSize && *outSize < _state.outProcessed)
174*f6dc9357SAndroid Build Coastguard Worker || (readWasFinished && _state.inPos == _state.inLim
175*f6dc9357SAndroid Build Coastguard Worker && ZstdDecState_DOES_NEED_MORE_INPUT_OR_FINISHED_FRAME(&_state));
176*f6dc9357SAndroid Build Coastguard Worker
177*f6dc9357SAndroid Build Coastguard Worker size_t size = _state.winPos - _state.wrPos; // full write size
178*f6dc9357SAndroid Build Coastguard Worker if (size)
179*f6dc9357SAndroid Build Coastguard Worker {
180*f6dc9357SAndroid Build Coastguard Worker if (!needStop)
181*f6dc9357SAndroid Build Coastguard Worker {
182*f6dc9357SAndroid Build Coastguard Worker // we try to flush on aligned positions, if possible
183*f6dc9357SAndroid Build Coastguard Worker size = _state.needWrite_Size; // minimal required write size
184*f6dc9357SAndroid Build Coastguard Worker const size_t alignedPos = _state.winPos & ~(size_t)_outStepMask;
185*f6dc9357SAndroid Build Coastguard Worker if (alignedPos > _state.wrPos)
186*f6dc9357SAndroid Build Coastguard Worker {
187*f6dc9357SAndroid Build Coastguard Worker const size_t size2 = alignedPos - _state.wrPos; // optimized aligned size
188*f6dc9357SAndroid Build Coastguard Worker if (size < size2)
189*f6dc9357SAndroid Build Coastguard Worker size = size2;
190*f6dc9357SAndroid Build Coastguard Worker }
191*f6dc9357SAndroid Build Coastguard Worker }
192*f6dc9357SAndroid Build Coastguard Worker if (size)
193*f6dc9357SAndroid Build Coastguard Worker {
194*f6dc9357SAndroid Build Coastguard Worker {
195*f6dc9357SAndroid Build Coastguard Worker size_t curSize = size;
196*f6dc9357SAndroid Build Coastguard Worker if (outSize)
197*f6dc9357SAndroid Build Coastguard Worker {
198*f6dc9357SAndroid Build Coastguard Worker const UInt64 rem = *outSize - writtenSize;
199*f6dc9357SAndroid Build Coastguard Worker if (curSize > rem)
200*f6dc9357SAndroid Build Coastguard Worker curSize = (size_t)rem;
201*f6dc9357SAndroid Build Coastguard Worker }
202*f6dc9357SAndroid Build Coastguard Worker if (curSize)
203*f6dc9357SAndroid Build Coastguard Worker {
204*f6dc9357SAndroid Build Coastguard Worker // printf("Write wrPos=%8x, size=%8x\n", (unsigned)_state.wrPos, (unsigned)size);
205*f6dc9357SAndroid Build Coastguard Worker hres = WriteStream(outStream, _state.win + _state.wrPos, curSize);
206*f6dc9357SAndroid Build Coastguard Worker if (hres != S_OK)
207*f6dc9357SAndroid Build Coastguard Worker break;
208*f6dc9357SAndroid Build Coastguard Worker writtenSize += curSize; // it's real size of data that was written to stream
209*f6dc9357SAndroid Build Coastguard Worker }
210*f6dc9357SAndroid Build Coastguard Worker }
211*f6dc9357SAndroid Build Coastguard Worker _state.wrPos += size; // virtual written size, that will be reported to CZstdDec
212*f6dc9357SAndroid Build Coastguard Worker // _state.needWrite_Size = 0; // optional
213*f6dc9357SAndroid Build Coastguard Worker }
214*f6dc9357SAndroid Build Coastguard Worker }
215*f6dc9357SAndroid Build Coastguard Worker
216*f6dc9357SAndroid Build Coastguard Worker if (needStop)
217*f6dc9357SAndroid Build Coastguard Worker break;
218*f6dc9357SAndroid Build Coastguard Worker if (progress)
219*f6dc9357SAndroid Build Coastguard Worker if (_inProcessed - inPrev >= (1 << 27)
220*f6dc9357SAndroid Build Coastguard Worker || _state.outProcessed - outPrev >= (1 << 28))
221*f6dc9357SAndroid Build Coastguard Worker {
222*f6dc9357SAndroid Build Coastguard Worker inPrev = _inProcessed;
223*f6dc9357SAndroid Build Coastguard Worker outPrev = _state.outProcessed;
224*f6dc9357SAndroid Build Coastguard Worker RINOK(progress->SetRatioInfo(&inPrev, &outPrev))
225*f6dc9357SAndroid Build Coastguard Worker }
226*f6dc9357SAndroid Build Coastguard Worker }
227*f6dc9357SAndroid Build Coastguard Worker
228*f6dc9357SAndroid Build Coastguard Worker if (hres == S_OK)
229*f6dc9357SAndroid Build Coastguard Worker {
230*f6dc9357SAndroid Build Coastguard Worker ZstdDec_GetResInfo(_dec, &_state, sres, &ResInfo);
231*f6dc9357SAndroid Build Coastguard Worker sres = ResInfo.decode_SRes;
232*f6dc9357SAndroid Build Coastguard Worker /* now (ResInfo.decode_SRes) can contain 2 extra error codes:
233*f6dc9357SAndroid Build Coastguard Worker - SZ_ERROR_NO_ARCHIVE : if no frames
234*f6dc9357SAndroid Build Coastguard Worker - SZ_ERROR_INPUT_EOF : if ZSTD_STATUS_NEEDS_MORE_INPUT
235*f6dc9357SAndroid Build Coastguard Worker */
236*f6dc9357SAndroid Build Coastguard Worker _inProcessed -= ResInfo.extraSize;
237*f6dc9357SAndroid Build Coastguard Worker if (hres_Read != S_OK && _state.inLim == _state.inPos && readWasFinished)
238*f6dc9357SAndroid Build Coastguard Worker {
239*f6dc9357SAndroid Build Coastguard Worker /* if (there is stream reading error,
240*f6dc9357SAndroid Build Coastguard Worker and decoding was stopped because of end of input stream),
241*f6dc9357SAndroid Build Coastguard Worker then we use reading error as main error code */
242*f6dc9357SAndroid Build Coastguard Worker if (sres == SZ_OK ||
243*f6dc9357SAndroid Build Coastguard Worker sres == SZ_ERROR_INPUT_EOF ||
244*f6dc9357SAndroid Build Coastguard Worker sres == SZ_ERROR_NO_ARCHIVE)
245*f6dc9357SAndroid Build Coastguard Worker hres = hres_Read;
246*f6dc9357SAndroid Build Coastguard Worker }
247*f6dc9357SAndroid Build Coastguard Worker if (sres == SZ_ERROR_INPUT_EOF && !FinishMode)
248*f6dc9357SAndroid Build Coastguard Worker {
249*f6dc9357SAndroid Build Coastguard Worker /* SZ_ERROR_INPUT_EOF case is allowed case for (!FinishMode) mode.
250*f6dc9357SAndroid Build Coastguard Worker So we restore SZ_OK result for that case: */
251*f6dc9357SAndroid Build Coastguard Worker ResInfo.decode_SRes = sres = SZ_OK;
252*f6dc9357SAndroid Build Coastguard Worker }
253*f6dc9357SAndroid Build Coastguard Worker if (hres == S_OK)
254*f6dc9357SAndroid Build Coastguard Worker {
255*f6dc9357SAndroid Build Coastguard Worker hres = SResToHRESULT(sres);
256*f6dc9357SAndroid Build Coastguard Worker if (hres == S_OK && FinishMode)
257*f6dc9357SAndroid Build Coastguard Worker {
258*f6dc9357SAndroid Build Coastguard Worker if ((inSize && *inSize != _inProcessed)
259*f6dc9357SAndroid Build Coastguard Worker || ResInfo.is_NonFinishedFrame
260*f6dc9357SAndroid Build Coastguard Worker || (outSize && (*outSize != writtenSize || writtenSize != _state.outProcessed)))
261*f6dc9357SAndroid Build Coastguard Worker hres = S_FALSE;
262*f6dc9357SAndroid Build Coastguard Worker }
263*f6dc9357SAndroid Build Coastguard Worker }
264*f6dc9357SAndroid Build Coastguard Worker }
265*f6dc9357SAndroid Build Coastguard Worker return hres;
266*f6dc9357SAndroid Build Coastguard Worker }
267*f6dc9357SAndroid Build Coastguard Worker
268*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize (UInt64 * value))269*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
270*f6dc9357SAndroid Build Coastguard Worker {
271*f6dc9357SAndroid Build Coastguard Worker *value = _inProcessed;
272*f6dc9357SAndroid Build Coastguard Worker return S_OK;
273*f6dc9357SAndroid Build Coastguard Worker }
274*f6dc9357SAndroid Build Coastguard Worker
275*f6dc9357SAndroid Build Coastguard Worker
276*f6dc9357SAndroid Build Coastguard Worker #ifndef Z7_NO_READ_FROM_CODER_ZSTD
277*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CDecoder::SetOutStreamSize (const UInt64 * outSize))278*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
279*f6dc9357SAndroid Build Coastguard Worker {
280*f6dc9357SAndroid Build Coastguard Worker _inProcessed = 0;
281*f6dc9357SAndroid Build Coastguard Worker _hres_Read = S_OK;
282*f6dc9357SAndroid Build Coastguard Worker _hres_Decode = S_OK;
283*f6dc9357SAndroid Build Coastguard Worker _writtenSize = 0;
284*f6dc9357SAndroid Build Coastguard Worker _readWasFinished = false;
285*f6dc9357SAndroid Build Coastguard Worker _wasFinished = false;
286*f6dc9357SAndroid Build Coastguard Worker return Prepare(outSize);
287*f6dc9357SAndroid Build Coastguard Worker }
288*f6dc9357SAndroid Build Coastguard Worker
289*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CDecoder::SetInStream (ISequentialInStream * inStream))290*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream))
291*f6dc9357SAndroid Build Coastguard Worker { _inStream = inStream; return S_OK; }
Z7_COM7F_IMF(CDecoder::ReleaseInStream ())292*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::ReleaseInStream())
293*f6dc9357SAndroid Build Coastguard Worker { _inStream.Release(); return S_OK; }
294*f6dc9357SAndroid Build Coastguard Worker
295*f6dc9357SAndroid Build Coastguard Worker
296*f6dc9357SAndroid Build Coastguard Worker // if SetInStream() mode: the caller must call GetFinishResult() after full decoding
297*f6dc9357SAndroid Build Coastguard Worker // to check that there decoding was finished correctly
298*f6dc9357SAndroid Build Coastguard Worker
GetFinishResult()299*f6dc9357SAndroid Build Coastguard Worker HRESULT CDecoder::GetFinishResult()
300*f6dc9357SAndroid Build Coastguard Worker {
301*f6dc9357SAndroid Build Coastguard Worker if (_state.winPos != _state.wrPos || !_wasFinished)
302*f6dc9357SAndroid Build Coastguard Worker return FinishMode ? S_FALSE : S_OK;
303*f6dc9357SAndroid Build Coastguard Worker // _state.winPos == _state.wrPos
304*f6dc9357SAndroid Build Coastguard Worker // _wasFinished == true
305*f6dc9357SAndroid Build Coastguard Worker if (FinishMode && _hres_Decode == S_OK && _state.outSize_Defined && _state.outSize != _writtenSize)
306*f6dc9357SAndroid Build Coastguard Worker _hres_Decode = S_FALSE;
307*f6dc9357SAndroid Build Coastguard Worker return _hres_Decode;
308*f6dc9357SAndroid Build Coastguard Worker }
309*f6dc9357SAndroid Build Coastguard Worker
310*f6dc9357SAndroid Build Coastguard Worker
Z7_COM7F_IMF(CDecoder::Read (void * data,UInt32 size,UInt32 * processedSize))311*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
312*f6dc9357SAndroid Build Coastguard Worker {
313*f6dc9357SAndroid Build Coastguard Worker if (processedSize)
314*f6dc9357SAndroid Build Coastguard Worker *processedSize = 0;
315*f6dc9357SAndroid Build Coastguard Worker
316*f6dc9357SAndroid Build Coastguard Worker for (;;)
317*f6dc9357SAndroid Build Coastguard Worker {
318*f6dc9357SAndroid Build Coastguard Worker if (_state.outSize_Defined)
319*f6dc9357SAndroid Build Coastguard Worker {
320*f6dc9357SAndroid Build Coastguard Worker // _writtenSize <= _state.outSize
321*f6dc9357SAndroid Build Coastguard Worker const UInt64 rem = _state.outSize - _writtenSize;
322*f6dc9357SAndroid Build Coastguard Worker if (size > rem)
323*f6dc9357SAndroid Build Coastguard Worker size = (UInt32)rem;
324*f6dc9357SAndroid Build Coastguard Worker }
325*f6dc9357SAndroid Build Coastguard Worker {
326*f6dc9357SAndroid Build Coastguard Worker size_t cur = _state.winPos - _state.wrPos;
327*f6dc9357SAndroid Build Coastguard Worker if (cur)
328*f6dc9357SAndroid Build Coastguard Worker {
329*f6dc9357SAndroid Build Coastguard Worker // _state.winPos != _state.wrPos;
330*f6dc9357SAndroid Build Coastguard Worker // so there is some decoded data that was not written still
331*f6dc9357SAndroid Build Coastguard Worker if (size == 0)
332*f6dc9357SAndroid Build Coastguard Worker {
333*f6dc9357SAndroid Build Coastguard Worker // if (FinishMode) and we are not allowed to write more, then it's data error
334*f6dc9357SAndroid Build Coastguard Worker if (FinishMode && _state.outSize_Defined && _state.outSize == _writtenSize)
335*f6dc9357SAndroid Build Coastguard Worker return S_FALSE;
336*f6dc9357SAndroid Build Coastguard Worker return S_OK;
337*f6dc9357SAndroid Build Coastguard Worker }
338*f6dc9357SAndroid Build Coastguard Worker if (cur > size)
339*f6dc9357SAndroid Build Coastguard Worker cur = (size_t)size;
340*f6dc9357SAndroid Build Coastguard Worker // cur != 0
341*f6dc9357SAndroid Build Coastguard Worker memcpy(data, _state.win + _state.wrPos, cur);
342*f6dc9357SAndroid Build Coastguard Worker _state.wrPos += cur;
343*f6dc9357SAndroid Build Coastguard Worker _writtenSize += cur;
344*f6dc9357SAndroid Build Coastguard Worker data = (void *)((Byte *)data + cur);
345*f6dc9357SAndroid Build Coastguard Worker if (processedSize)
346*f6dc9357SAndroid Build Coastguard Worker *processedSize += (UInt32)cur;
347*f6dc9357SAndroid Build Coastguard Worker size -= (UInt32)cur;
348*f6dc9357SAndroid Build Coastguard Worker continue;
349*f6dc9357SAndroid Build Coastguard Worker }
350*f6dc9357SAndroid Build Coastguard Worker }
351*f6dc9357SAndroid Build Coastguard Worker
352*f6dc9357SAndroid Build Coastguard Worker // _state.winPos == _state.wrPos
353*f6dc9357SAndroid Build Coastguard Worker if (_wasFinished)
354*f6dc9357SAndroid Build Coastguard Worker {
355*f6dc9357SAndroid Build Coastguard Worker if (_hres_Decode == S_OK && FinishMode
356*f6dc9357SAndroid Build Coastguard Worker && _state.outSize_Defined && _state.outSize != _writtenSize)
357*f6dc9357SAndroid Build Coastguard Worker _hres_Decode = S_FALSE;
358*f6dc9357SAndroid Build Coastguard Worker return _hres_Decode;
359*f6dc9357SAndroid Build Coastguard Worker }
360*f6dc9357SAndroid Build Coastguard Worker
361*f6dc9357SAndroid Build Coastguard Worker // _wasFinished == false
362*f6dc9357SAndroid Build Coastguard Worker if (size == 0 && _state.outSize_Defined && _state.outSize != _state.outProcessed)
363*f6dc9357SAndroid Build Coastguard Worker {
364*f6dc9357SAndroid Build Coastguard Worker /* size == 0 : so the caller don't need more data now.
365*f6dc9357SAndroid Build Coastguard Worker _state.outSize > _state.outProcessed : so more data will be requested
366*f6dc9357SAndroid Build Coastguard Worker later by caller for full processing.
367*f6dc9357SAndroid Build Coastguard Worker So we exit without ZstdDec_Decode() call, because we don't want
368*f6dc9357SAndroid Build Coastguard Worker ZstdDec_Decode() to start new block decoding
369*f6dc9357SAndroid Build Coastguard Worker */
370*f6dc9357SAndroid Build Coastguard Worker return S_OK;
371*f6dc9357SAndroid Build Coastguard Worker }
372*f6dc9357SAndroid Build Coastguard Worker // size != 0 || !_state.outSize_Defined || _state.outSize == _state.outProcessed)
373*f6dc9357SAndroid Build Coastguard Worker
374*f6dc9357SAndroid Build Coastguard Worker if (_state.inPos == _state.inLim && !_readWasFinished)
375*f6dc9357SAndroid Build Coastguard Worker {
376*f6dc9357SAndroid Build Coastguard Worker _state.inPos = 0;
377*f6dc9357SAndroid Build Coastguard Worker _state.inLim = _inBufSize;
378*f6dc9357SAndroid Build Coastguard Worker _hres_Read = ReadStream(_inStream, _inBuf, &_state.inLim);
379*f6dc9357SAndroid Build Coastguard Worker if (_state.inLim != _inBufSize || _hres_Read != S_OK)
380*f6dc9357SAndroid Build Coastguard Worker {
381*f6dc9357SAndroid Build Coastguard Worker // _hres_Read = 99; // for debug
382*f6dc9357SAndroid Build Coastguard Worker _readWasFinished = True;
383*f6dc9357SAndroid Build Coastguard Worker }
384*f6dc9357SAndroid Build Coastguard Worker }
385*f6dc9357SAndroid Build Coastguard Worker
386*f6dc9357SAndroid Build Coastguard Worker SRes sres;
387*f6dc9357SAndroid Build Coastguard Worker {
388*f6dc9357SAndroid Build Coastguard Worker const SizeT inPos_Start = _state.inPos;
389*f6dc9357SAndroid Build Coastguard Worker sres = ZstdDec_Decode(_dec, &_state);
390*f6dc9357SAndroid Build Coastguard Worker _inProcessed += _state.inPos - inPos_Start;
391*f6dc9357SAndroid Build Coastguard Worker }
392*f6dc9357SAndroid Build Coastguard Worker
393*f6dc9357SAndroid Build Coastguard Worker const bool inFinished = (_state.inPos == _state.inLim) && _readWasFinished;
394*f6dc9357SAndroid Build Coastguard Worker
395*f6dc9357SAndroid Build Coastguard Worker _wasFinished = (sres != SZ_OK)
396*f6dc9357SAndroid Build Coastguard Worker || _state.status == ZSTD_STATUS_OUT_REACHED
397*f6dc9357SAndroid Build Coastguard Worker || (_state.outSize_Defined && _state.outSize < _state.outProcessed)
398*f6dc9357SAndroid Build Coastguard Worker || (inFinished
399*f6dc9357SAndroid Build Coastguard Worker && ZstdDecState_DOES_NEED_MORE_INPUT_OR_FINISHED_FRAME(&_state));
400*f6dc9357SAndroid Build Coastguard Worker
401*f6dc9357SAndroid Build Coastguard Worker if (!_wasFinished)
402*f6dc9357SAndroid Build Coastguard Worker continue;
403*f6dc9357SAndroid Build Coastguard Worker
404*f6dc9357SAndroid Build Coastguard Worker // _wasFinished == true
405*f6dc9357SAndroid Build Coastguard Worker /* (_state.winPos != _state.wrPos) is possible here.
406*f6dc9357SAndroid Build Coastguard Worker So we still can have some data to flush,
407*f6dc9357SAndroid Build Coastguard Worker but we must all result variables .
408*f6dc9357SAndroid Build Coastguard Worker */
409*f6dc9357SAndroid Build Coastguard Worker HRESULT hres = S_OK;
410*f6dc9357SAndroid Build Coastguard Worker ZstdDec_GetResInfo(_dec, &_state, sres, &ResInfo);
411*f6dc9357SAndroid Build Coastguard Worker sres = ResInfo.decode_SRes;
412*f6dc9357SAndroid Build Coastguard Worker _inProcessed -= ResInfo.extraSize;
413*f6dc9357SAndroid Build Coastguard Worker if (_hres_Read != S_OK && inFinished)
414*f6dc9357SAndroid Build Coastguard Worker {
415*f6dc9357SAndroid Build Coastguard Worker if (sres == SZ_OK ||
416*f6dc9357SAndroid Build Coastguard Worker sres == SZ_ERROR_INPUT_EOF ||
417*f6dc9357SAndroid Build Coastguard Worker sres == SZ_ERROR_NO_ARCHIVE)
418*f6dc9357SAndroid Build Coastguard Worker hres = _hres_Read;
419*f6dc9357SAndroid Build Coastguard Worker }
420*f6dc9357SAndroid Build Coastguard Worker if (sres == SZ_ERROR_INPUT_EOF && !FinishMode)
421*f6dc9357SAndroid Build Coastguard Worker ResInfo.decode_SRes = sres = SZ_OK;
422*f6dc9357SAndroid Build Coastguard Worker if (hres == S_OK)
423*f6dc9357SAndroid Build Coastguard Worker {
424*f6dc9357SAndroid Build Coastguard Worker hres = SResToHRESULT(sres);
425*f6dc9357SAndroid Build Coastguard Worker if (hres == S_OK && FinishMode)
426*f6dc9357SAndroid Build Coastguard Worker if (!inFinished
427*f6dc9357SAndroid Build Coastguard Worker || ResInfo.is_NonFinishedFrame
428*f6dc9357SAndroid Build Coastguard Worker || (_state.outSize_Defined && _state.outSize != _state.outProcessed))
429*f6dc9357SAndroid Build Coastguard Worker hres = S_FALSE;
430*f6dc9357SAndroid Build Coastguard Worker }
431*f6dc9357SAndroid Build Coastguard Worker _hres_Decode = hres;
432*f6dc9357SAndroid Build Coastguard Worker }
433*f6dc9357SAndroid Build Coastguard Worker }
434*f6dc9357SAndroid Build Coastguard Worker
435*f6dc9357SAndroid Build Coastguard Worker #endif
436*f6dc9357SAndroid Build Coastguard Worker
437*f6dc9357SAndroid Build Coastguard Worker }}
438