1*a28cd43dSSascha Wildner /*
2*a28cd43dSSascha Wildner  * Copyright (c) 2016-2020, Yann Collet, Facebook, Inc.
3*a28cd43dSSascha Wildner  * All rights reserved.
4*a28cd43dSSascha Wildner  *
5*a28cd43dSSascha Wildner  * This source code is licensed under both the BSD-style license (found in the
6*a28cd43dSSascha Wildner  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7*a28cd43dSSascha Wildner  * in the COPYING file in the root directory of this source tree).
8*a28cd43dSSascha Wildner  * You may select, at your option, one of the above-listed licenses.
9*a28cd43dSSascha Wildner  */
10*a28cd43dSSascha Wildner 
11*a28cd43dSSascha Wildner 
12*a28cd43dSSascha Wildner /* ***************************************************************
13*a28cd43dSSascha Wildner *  Tuning parameters
14*a28cd43dSSascha Wildner *****************************************************************/
15*a28cd43dSSascha Wildner /*!
16*a28cd43dSSascha Wildner  * HEAPMODE :
17*a28cd43dSSascha Wildner  * Select how default decompression function ZSTD_decompress() allocates its context,
18*a28cd43dSSascha Wildner  * on stack (0), or into heap (1, default; requires malloc()).
19*a28cd43dSSascha Wildner  * Note that functions with explicit context such as ZSTD_decompressDCtx() are unaffected.
20*a28cd43dSSascha Wildner  */
21*a28cd43dSSascha Wildner #ifndef ZSTD_HEAPMODE
22*a28cd43dSSascha Wildner #  define ZSTD_HEAPMODE 1
23*a28cd43dSSascha Wildner #endif
24*a28cd43dSSascha Wildner 
25*a28cd43dSSascha Wildner /*!
26*a28cd43dSSascha Wildner *  LEGACY_SUPPORT :
27*a28cd43dSSascha Wildner *  if set to 1+, ZSTD_decompress() can decode older formats (v0.1+)
28*a28cd43dSSascha Wildner */
29*a28cd43dSSascha Wildner #ifndef ZSTD_LEGACY_SUPPORT
30*a28cd43dSSascha Wildner #  define ZSTD_LEGACY_SUPPORT 0
31*a28cd43dSSascha Wildner #endif
32*a28cd43dSSascha Wildner 
33*a28cd43dSSascha Wildner /*!
34*a28cd43dSSascha Wildner  *  MAXWINDOWSIZE_DEFAULT :
35*a28cd43dSSascha Wildner  *  maximum window size accepted by DStream __by default__.
36*a28cd43dSSascha Wildner  *  Frames requiring more memory will be rejected.
37*a28cd43dSSascha Wildner  *  It's possible to set a different limit using ZSTD_DCtx_setMaxWindowSize().
38*a28cd43dSSascha Wildner  */
39*a28cd43dSSascha Wildner #ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
40*a28cd43dSSascha Wildner #  define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1)
41*a28cd43dSSascha Wildner #endif
42*a28cd43dSSascha Wildner 
43*a28cd43dSSascha Wildner /*!
44*a28cd43dSSascha Wildner  *  NO_FORWARD_PROGRESS_MAX :
45*a28cd43dSSascha Wildner  *  maximum allowed nb of calls to ZSTD_decompressStream()
46*a28cd43dSSascha Wildner  *  without any forward progress
47*a28cd43dSSascha Wildner  *  (defined as: no byte read from input, and no byte flushed to output)
48*a28cd43dSSascha Wildner  *  before triggering an error.
49*a28cd43dSSascha Wildner  */
50*a28cd43dSSascha Wildner #ifndef ZSTD_NO_FORWARD_PROGRESS_MAX
51*a28cd43dSSascha Wildner #  define ZSTD_NO_FORWARD_PROGRESS_MAX 16
52*a28cd43dSSascha Wildner #endif
53*a28cd43dSSascha Wildner 
54*a28cd43dSSascha Wildner 
55*a28cd43dSSascha Wildner /*-*******************************************************
56*a28cd43dSSascha Wildner *  Dependencies
57*a28cd43dSSascha Wildner *********************************************************/
58*a28cd43dSSascha Wildner #include "../common/zstd_deps.h"   /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */
59*a28cd43dSSascha Wildner #include "../common/cpu.h"         /* bmi2 */
60*a28cd43dSSascha Wildner #include "../common/mem.h"         /* low level memory routines */
61*a28cd43dSSascha Wildner #define FSE_STATIC_LINKING_ONLY
62*a28cd43dSSascha Wildner #include "../common/fse.h"
63*a28cd43dSSascha Wildner #define HUF_STATIC_LINKING_ONLY
64*a28cd43dSSascha Wildner #include "../common/huf.h"
65*a28cd43dSSascha Wildner #include "../common/zstd_internal.h"  /* blockProperties_t */
66*a28cd43dSSascha Wildner #include "zstd_decompress_internal.h"   /* ZSTD_DCtx */
67*a28cd43dSSascha Wildner #include "zstd_ddict.h"  /* ZSTD_DDictDictContent */
68*a28cd43dSSascha Wildner #include "zstd_decompress_block.h"   /* ZSTD_decompressBlock_internal */
69*a28cd43dSSascha Wildner 
70*a28cd43dSSascha Wildner #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
71*a28cd43dSSascha Wildner #  include "../legacy/zstd_legacy.h"
72*a28cd43dSSascha Wildner #endif
73*a28cd43dSSascha Wildner 
74*a28cd43dSSascha Wildner 
75*a28cd43dSSascha Wildner /*-*************************************************************
76*a28cd43dSSascha Wildner *   Context management
77*a28cd43dSSascha Wildner ***************************************************************/
ZSTD_sizeof_DCtx(const ZSTD_DCtx * dctx)78*a28cd43dSSascha Wildner size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx)
79*a28cd43dSSascha Wildner {
80*a28cd43dSSascha Wildner     if (dctx==NULL) return 0;   /* support sizeof NULL */
81*a28cd43dSSascha Wildner     return sizeof(*dctx)
82*a28cd43dSSascha Wildner            + ZSTD_sizeof_DDict(dctx->ddictLocal)
83*a28cd43dSSascha Wildner            + dctx->inBuffSize + dctx->outBuffSize;
84*a28cd43dSSascha Wildner }
85*a28cd43dSSascha Wildner 
ZSTD_estimateDCtxSize(void)86*a28cd43dSSascha Wildner size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }
87*a28cd43dSSascha Wildner 
88*a28cd43dSSascha Wildner 
ZSTD_startingInputLength(ZSTD_format_e format)89*a28cd43dSSascha Wildner static size_t ZSTD_startingInputLength(ZSTD_format_e format)
90*a28cd43dSSascha Wildner {
91*a28cd43dSSascha Wildner     size_t const startingInputLength = ZSTD_FRAMEHEADERSIZE_PREFIX(format);
92*a28cd43dSSascha Wildner     /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
93*a28cd43dSSascha Wildner     assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) );
94*a28cd43dSSascha Wildner     return startingInputLength;
95*a28cd43dSSascha Wildner }
96*a28cd43dSSascha Wildner 
ZSTD_DCtx_resetParameters(ZSTD_DCtx * dctx)97*a28cd43dSSascha Wildner static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx)
98*a28cd43dSSascha Wildner {
99*a28cd43dSSascha Wildner     assert(dctx->streamStage == zdss_init);
100*a28cd43dSSascha Wildner     dctx->format = ZSTD_f_zstd1;
101*a28cd43dSSascha Wildner     dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
102*a28cd43dSSascha Wildner     dctx->outBufferMode = ZSTD_bm_buffered;
103*a28cd43dSSascha Wildner     dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum;
104*a28cd43dSSascha Wildner }
105*a28cd43dSSascha Wildner 
ZSTD_initDCtx_internal(ZSTD_DCtx * dctx)106*a28cd43dSSascha Wildner static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
107*a28cd43dSSascha Wildner {
108*a28cd43dSSascha Wildner     dctx->staticSize  = 0;
109*a28cd43dSSascha Wildner     dctx->ddict       = NULL;
110*a28cd43dSSascha Wildner     dctx->ddictLocal  = NULL;
111*a28cd43dSSascha Wildner     dctx->dictEnd     = NULL;
112*a28cd43dSSascha Wildner     dctx->ddictIsCold = 0;
113*a28cd43dSSascha Wildner     dctx->dictUses = ZSTD_dont_use;
114*a28cd43dSSascha Wildner     dctx->inBuff      = NULL;
115*a28cd43dSSascha Wildner     dctx->inBuffSize  = 0;
116*a28cd43dSSascha Wildner     dctx->outBuffSize = 0;
117*a28cd43dSSascha Wildner     dctx->streamStage = zdss_init;
118*a28cd43dSSascha Wildner     dctx->legacyContext = NULL;
119*a28cd43dSSascha Wildner     dctx->previousLegacyVersion = 0;
120*a28cd43dSSascha Wildner     dctx->noForwardProgress = 0;
121*a28cd43dSSascha Wildner     dctx->oversizedDuration = 0;
122*a28cd43dSSascha Wildner     dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
123*a28cd43dSSascha Wildner     ZSTD_DCtx_resetParameters(dctx);
124*a28cd43dSSascha Wildner     dctx->validateChecksum = 1;
125*a28cd43dSSascha Wildner #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
126*a28cd43dSSascha Wildner     dctx->dictContentEndForFuzzing = NULL;
127*a28cd43dSSascha Wildner #endif
128*a28cd43dSSascha Wildner }
129*a28cd43dSSascha Wildner 
ZSTD_initStaticDCtx(void * workspace,size_t workspaceSize)130*a28cd43dSSascha Wildner ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
131*a28cd43dSSascha Wildner {
132*a28cd43dSSascha Wildner     ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace;
133*a28cd43dSSascha Wildner 
134*a28cd43dSSascha Wildner     if ((size_t)workspace & 7) return NULL;  /* 8-aligned */
135*a28cd43dSSascha Wildner     if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL;  /* minimum size */
136*a28cd43dSSascha Wildner 
137*a28cd43dSSascha Wildner     ZSTD_initDCtx_internal(dctx);
138*a28cd43dSSascha Wildner     dctx->staticSize = workspaceSize;
139*a28cd43dSSascha Wildner     dctx->inBuff = (char*)(dctx+1);
140*a28cd43dSSascha Wildner     return dctx;
141*a28cd43dSSascha Wildner }
142*a28cd43dSSascha Wildner 
ZSTD_createDCtx_advanced(ZSTD_customMem customMem)143*a28cd43dSSascha Wildner ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
144*a28cd43dSSascha Wildner {
145*a28cd43dSSascha Wildner     if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
146*a28cd43dSSascha Wildner 
147*a28cd43dSSascha Wildner     {   ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem);
148*a28cd43dSSascha Wildner         if (!dctx) return NULL;
149*a28cd43dSSascha Wildner         dctx->customMem = customMem;
150*a28cd43dSSascha Wildner         ZSTD_initDCtx_internal(dctx);
151*a28cd43dSSascha Wildner         return dctx;
152*a28cd43dSSascha Wildner     }
153*a28cd43dSSascha Wildner }
154*a28cd43dSSascha Wildner 
ZSTD_createDCtx(void)155*a28cd43dSSascha Wildner ZSTD_DCtx* ZSTD_createDCtx(void)
156*a28cd43dSSascha Wildner {
157*a28cd43dSSascha Wildner     DEBUGLOG(3, "ZSTD_createDCtx");
158*a28cd43dSSascha Wildner     return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
159*a28cd43dSSascha Wildner }
160*a28cd43dSSascha Wildner 
ZSTD_clearDict(ZSTD_DCtx * dctx)161*a28cd43dSSascha Wildner static void ZSTD_clearDict(ZSTD_DCtx* dctx)
162*a28cd43dSSascha Wildner {
163*a28cd43dSSascha Wildner     ZSTD_freeDDict(dctx->ddictLocal);
164*a28cd43dSSascha Wildner     dctx->ddictLocal = NULL;
165*a28cd43dSSascha Wildner     dctx->ddict = NULL;
166*a28cd43dSSascha Wildner     dctx->dictUses = ZSTD_dont_use;
167*a28cd43dSSascha Wildner }
168*a28cd43dSSascha Wildner 
ZSTD_freeDCtx(ZSTD_DCtx * dctx)169*a28cd43dSSascha Wildner size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
170*a28cd43dSSascha Wildner {
171*a28cd43dSSascha Wildner     if (dctx==NULL) return 0;   /* support free on NULL */
172*a28cd43dSSascha Wildner     RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx");
173*a28cd43dSSascha Wildner     {   ZSTD_customMem const cMem = dctx->customMem;
174*a28cd43dSSascha Wildner         ZSTD_clearDict(dctx);
175*a28cd43dSSascha Wildner         ZSTD_customFree(dctx->inBuff, cMem);
176*a28cd43dSSascha Wildner         dctx->inBuff = NULL;
177*a28cd43dSSascha Wildner #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
178*a28cd43dSSascha Wildner         if (dctx->legacyContext)
179*a28cd43dSSascha Wildner             ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);
180*a28cd43dSSascha Wildner #endif
181*a28cd43dSSascha Wildner         ZSTD_customFree(dctx, cMem);
182*a28cd43dSSascha Wildner         return 0;
183*a28cd43dSSascha Wildner     }
184*a28cd43dSSascha Wildner }
185*a28cd43dSSascha Wildner 
186*a28cd43dSSascha Wildner /* no longer useful */
ZSTD_copyDCtx(ZSTD_DCtx * dstDCtx,const ZSTD_DCtx * srcDCtx)187*a28cd43dSSascha Wildner void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
188*a28cd43dSSascha Wildner {
189*a28cd43dSSascha Wildner     size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx);
190*a28cd43dSSascha Wildner     ZSTD_memcpy(dstDCtx, srcDCtx, toCopy);  /* no need to copy workspace */
191*a28cd43dSSascha Wildner }
192*a28cd43dSSascha Wildner 
193*a28cd43dSSascha Wildner 
194*a28cd43dSSascha Wildner /*-*************************************************************
195*a28cd43dSSascha Wildner  *   Frame header decoding
196*a28cd43dSSascha Wildner  ***************************************************************/
197*a28cd43dSSascha Wildner 
198*a28cd43dSSascha Wildner /*! ZSTD_isFrame() :
199*a28cd43dSSascha Wildner  *  Tells if the content of `buffer` starts with a valid Frame Identifier.
200*a28cd43dSSascha Wildner  *  Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
201*a28cd43dSSascha Wildner  *  Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.
202*a28cd43dSSascha Wildner  *  Note 3 : Skippable Frame Identifiers are considered valid. */
ZSTD_isFrame(const void * buffer,size_t size)203*a28cd43dSSascha Wildner unsigned ZSTD_isFrame(const void* buffer, size_t size)
204*a28cd43dSSascha Wildner {
205*a28cd43dSSascha Wildner     if (size < ZSTD_FRAMEIDSIZE) return 0;
206*a28cd43dSSascha Wildner     {   U32 const magic = MEM_readLE32(buffer);
207*a28cd43dSSascha Wildner         if (magic == ZSTD_MAGICNUMBER) return 1;
208*a28cd43dSSascha Wildner         if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;
209*a28cd43dSSascha Wildner     }
210*a28cd43dSSascha Wildner #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
211*a28cd43dSSascha Wildner     if (ZSTD_isLegacy(buffer, size)) return 1;
212*a28cd43dSSascha Wildner #endif
213*a28cd43dSSascha Wildner     return 0;
214*a28cd43dSSascha Wildner }
215*a28cd43dSSascha Wildner 
216*a28cd43dSSascha Wildner /** ZSTD_frameHeaderSize_internal() :
217*a28cd43dSSascha Wildner  *  srcSize must be large enough to reach header size fields.
218*a28cd43dSSascha Wildner  *  note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless.
219*a28cd43dSSascha Wildner  * @return : size of the Frame Header
220*a28cd43dSSascha Wildner  *           or an error code, which can be tested with ZSTD_isError() */
ZSTD_frameHeaderSize_internal(const void * src,size_t srcSize,ZSTD_format_e format)221*a28cd43dSSascha Wildner static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
222*a28cd43dSSascha Wildner {
223*a28cd43dSSascha Wildner     size_t const minInputSize = ZSTD_startingInputLength(format);
224*a28cd43dSSascha Wildner     RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong, "");
225*a28cd43dSSascha Wildner 
226*a28cd43dSSascha Wildner     {   BYTE const fhd = ((const BYTE*)src)[minInputSize-1];
227*a28cd43dSSascha Wildner         U32 const dictID= fhd & 3;
228*a28cd43dSSascha Wildner         U32 const singleSegment = (fhd >> 5) & 1;
229*a28cd43dSSascha Wildner         U32 const fcsId = fhd >> 6;
230*a28cd43dSSascha Wildner         return minInputSize + !singleSegment
231*a28cd43dSSascha Wildner              + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
232*a28cd43dSSascha Wildner              + (singleSegment && !fcsId);
233*a28cd43dSSascha Wildner     }
234*a28cd43dSSascha Wildner }
235*a28cd43dSSascha Wildner 
236*a28cd43dSSascha Wildner /** ZSTD_frameHeaderSize() :
237*a28cd43dSSascha Wildner  *  srcSize must be >= ZSTD_frameHeaderSize_prefix.
238*a28cd43dSSascha Wildner  * @return : size of the Frame Header,
239*a28cd43dSSascha Wildner  *           or an error code (if srcSize is too small) */
ZSTD_frameHeaderSize(const void * src,size_t srcSize)240*a28cd43dSSascha Wildner size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
241*a28cd43dSSascha Wildner {
242*a28cd43dSSascha Wildner     return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);
243*a28cd43dSSascha Wildner }
244*a28cd43dSSascha Wildner 
245*a28cd43dSSascha Wildner 
246*a28cd43dSSascha Wildner /** ZSTD_getFrameHeader_advanced() :
247*a28cd43dSSascha Wildner  *  decode Frame Header, or require larger `srcSize`.
248*a28cd43dSSascha Wildner  *  note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
249*a28cd43dSSascha Wildner  * @return : 0, `zfhPtr` is correctly filled,
250*a28cd43dSSascha Wildner  *          >0, `srcSize` is too small, value is wanted `srcSize` amount,
251*a28cd43dSSascha Wildner  *           or an error code, which can be tested using ZSTD_isError() */
ZSTD_getFrameHeader_advanced(ZSTD_frameHeader * zfhPtr,const void * src,size_t srcSize,ZSTD_format_e format)252*a28cd43dSSascha Wildner size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
253*a28cd43dSSascha Wildner {
254*a28cd43dSSascha Wildner     const BYTE* ip = (const BYTE*)src;
255*a28cd43dSSascha Wildner     size_t const minInputSize = ZSTD_startingInputLength(format);
256*a28cd43dSSascha Wildner 
257*a28cd43dSSascha Wildner     ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr));   /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */
258*a28cd43dSSascha Wildner     if (srcSize < minInputSize) return minInputSize;
259*a28cd43dSSascha Wildner     RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter");
260*a28cd43dSSascha Wildner 
261*a28cd43dSSascha Wildner     if ( (format != ZSTD_f_zstd1_magicless)
262*a28cd43dSSascha Wildner       && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {
263*a28cd43dSSascha Wildner         if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
264*a28cd43dSSascha Wildner             /* skippable frame */
265*a28cd43dSSascha Wildner             if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
266*a28cd43dSSascha Wildner                 return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */
267*a28cd43dSSascha Wildner             ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr));
268*a28cd43dSSascha Wildner             zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);
269*a28cd43dSSascha Wildner             zfhPtr->frameType = ZSTD_skippableFrame;
270*a28cd43dSSascha Wildner             return 0;
271*a28cd43dSSascha Wildner         }
272*a28cd43dSSascha Wildner         RETURN_ERROR(prefix_unknown, "");
273*a28cd43dSSascha Wildner     }
274*a28cd43dSSascha Wildner 
275*a28cd43dSSascha Wildner     /* ensure there is enough `srcSize` to fully read/decode frame header */
276*a28cd43dSSascha Wildner     {   size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format);
277*a28cd43dSSascha Wildner         if (srcSize < fhsize) return fhsize;
278*a28cd43dSSascha Wildner         zfhPtr->headerSize = (U32)fhsize;
279*a28cd43dSSascha Wildner     }
280*a28cd43dSSascha Wildner 
281*a28cd43dSSascha Wildner     {   BYTE const fhdByte = ip[minInputSize-1];
282*a28cd43dSSascha Wildner         size_t pos = minInputSize;
283*a28cd43dSSascha Wildner         U32 const dictIDSizeCode = fhdByte&3;
284*a28cd43dSSascha Wildner         U32 const checksumFlag = (fhdByte>>2)&1;
285*a28cd43dSSascha Wildner         U32 const singleSegment = (fhdByte>>5)&1;
286*a28cd43dSSascha Wildner         U32 const fcsID = fhdByte>>6;
287*a28cd43dSSascha Wildner         U64 windowSize = 0;
288*a28cd43dSSascha Wildner         U32 dictID = 0;
289*a28cd43dSSascha Wildner         U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN;
290*a28cd43dSSascha Wildner         RETURN_ERROR_IF((fhdByte & 0x08) != 0, frameParameter_unsupported,
291*a28cd43dSSascha Wildner                         "reserved bits, must be zero");
292*a28cd43dSSascha Wildner 
293*a28cd43dSSascha Wildner         if (!singleSegment) {
294*a28cd43dSSascha Wildner             BYTE const wlByte = ip[pos++];
295*a28cd43dSSascha Wildner             U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
296*a28cd43dSSascha Wildner             RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge, "");
297*a28cd43dSSascha Wildner             windowSize = (1ULL << windowLog);
298*a28cd43dSSascha Wildner             windowSize += (windowSize >> 3) * (wlByte&7);
299*a28cd43dSSascha Wildner         }
300*a28cd43dSSascha Wildner         switch(dictIDSizeCode)
301*a28cd43dSSascha Wildner         {
302*a28cd43dSSascha Wildner             default: assert(0);  /* impossible */
303*a28cd43dSSascha Wildner             case 0 : break;
304*a28cd43dSSascha Wildner             case 1 : dictID = ip[pos]; pos++; break;
305*a28cd43dSSascha Wildner             case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break;
306*a28cd43dSSascha Wildner             case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break;
307*a28cd43dSSascha Wildner         }
308*a28cd43dSSascha Wildner         switch(fcsID)
309*a28cd43dSSascha Wildner         {
310*a28cd43dSSascha Wildner             default: assert(0);  /* impossible */
311*a28cd43dSSascha Wildner             case 0 : if (singleSegment) frameContentSize = ip[pos]; break;
312*a28cd43dSSascha Wildner             case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;
313*a28cd43dSSascha Wildner             case 2 : frameContentSize = MEM_readLE32(ip+pos); break;
314*a28cd43dSSascha Wildner             case 3 : frameContentSize = MEM_readLE64(ip+pos); break;
315*a28cd43dSSascha Wildner         }
316*a28cd43dSSascha Wildner         if (singleSegment) windowSize = frameContentSize;
317*a28cd43dSSascha Wildner 
318*a28cd43dSSascha Wildner         zfhPtr->frameType = ZSTD_frame;
319*a28cd43dSSascha Wildner         zfhPtr->frameContentSize = frameContentSize;
320*a28cd43dSSascha Wildner         zfhPtr->windowSize = windowSize;
321*a28cd43dSSascha Wildner         zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
322*a28cd43dSSascha Wildner         zfhPtr->dictID = dictID;
323*a28cd43dSSascha Wildner         zfhPtr->checksumFlag = checksumFlag;
324*a28cd43dSSascha Wildner     }
325*a28cd43dSSascha Wildner     return 0;
326*a28cd43dSSascha Wildner }
327*a28cd43dSSascha Wildner 
328*a28cd43dSSascha Wildner /** ZSTD_getFrameHeader() :
329*a28cd43dSSascha Wildner  *  decode Frame Header, or require larger `srcSize`.
330*a28cd43dSSascha Wildner  *  note : this function does not consume input, it only reads it.
331*a28cd43dSSascha Wildner  * @return : 0, `zfhPtr` is correctly filled,
332*a28cd43dSSascha Wildner  *          >0, `srcSize` is too small, value is wanted `srcSize` amount,
333*a28cd43dSSascha Wildner  *           or an error code, which can be tested using ZSTD_isError() */
ZSTD_getFrameHeader(ZSTD_frameHeader * zfhPtr,const void * src,size_t srcSize)334*a28cd43dSSascha Wildner size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
335*a28cd43dSSascha Wildner {
336*a28cd43dSSascha Wildner     return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);
337*a28cd43dSSascha Wildner }
338*a28cd43dSSascha Wildner 
339*a28cd43dSSascha Wildner 
340*a28cd43dSSascha Wildner /** ZSTD_getFrameContentSize() :
341*a28cd43dSSascha Wildner  *  compatible with legacy mode
342*a28cd43dSSascha Wildner  * @return : decompressed size of the single frame pointed to be `src` if known, otherwise
343*a28cd43dSSascha Wildner  *         - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
344*a28cd43dSSascha Wildner  *         - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */
ZSTD_getFrameContentSize(const void * src,size_t srcSize)345*a28cd43dSSascha Wildner unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
346*a28cd43dSSascha Wildner {
347*a28cd43dSSascha Wildner #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
348*a28cd43dSSascha Wildner     if (ZSTD_isLegacy(src, srcSize)) {
349*a28cd43dSSascha Wildner         unsigned long long const ret = ZSTD_getDecompressedSize_legacy(src, srcSize);
350*a28cd43dSSascha Wildner         return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret;
351*a28cd43dSSascha Wildner     }
352*a28cd43dSSascha Wildner #endif
353*a28cd43dSSascha Wildner     {   ZSTD_frameHeader zfh;
354*a28cd43dSSascha Wildner         if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0)
355*a28cd43dSSascha Wildner             return ZSTD_CONTENTSIZE_ERROR;
356*a28cd43dSSascha Wildner         if (zfh.frameType == ZSTD_skippableFrame) {
357*a28cd43dSSascha Wildner             return 0;
358*a28cd43dSSascha Wildner         } else {
359*a28cd43dSSascha Wildner             return zfh.frameContentSize;
360*a28cd43dSSascha Wildner     }   }
361*a28cd43dSSascha Wildner }
362*a28cd43dSSascha Wildner 
readSkippableFrameSize(void const * src,size_t srcSize)363*a28cd43dSSascha Wildner static size_t readSkippableFrameSize(void const* src, size_t srcSize)
364*a28cd43dSSascha Wildner {
365*a28cd43dSSascha Wildner     size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE;
366*a28cd43dSSascha Wildner     U32 sizeU32;
367*a28cd43dSSascha Wildner 
368*a28cd43dSSascha Wildner     RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, "");
369*a28cd43dSSascha Wildner 
370*a28cd43dSSascha Wildner     sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);
371*a28cd43dSSascha Wildner     RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32,
372*a28cd43dSSascha Wildner                     frameParameter_unsupported, "");
373*a28cd43dSSascha Wildner     {
374*a28cd43dSSascha Wildner         size_t const skippableSize = skippableHeaderSize + sizeU32;
375*a28cd43dSSascha Wildner         RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, "");
376*a28cd43dSSascha Wildner         return skippableSize;
377*a28cd43dSSascha Wildner     }
378*a28cd43dSSascha Wildner }
379*a28cd43dSSascha Wildner 
380*a28cd43dSSascha Wildner /** ZSTD_findDecompressedSize() :
381*a28cd43dSSascha Wildner  *  compatible with legacy mode
382*a28cd43dSSascha Wildner  *  `srcSize` must be the exact length of some number of ZSTD compressed and/or
383*a28cd43dSSascha Wildner  *      skippable frames
384*a28cd43dSSascha Wildner  *  @return : decompressed size of the frames contained */
ZSTD_findDecompressedSize(const void * src,size_t srcSize)385*a28cd43dSSascha Wildner unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
386*a28cd43dSSascha Wildner {
387*a28cd43dSSascha Wildner     unsigned long long totalDstSize = 0;
388*a28cd43dSSascha Wildner 
389*a28cd43dSSascha Wildner     while (srcSize >= ZSTD_startingInputLength(ZSTD_f_zstd1)) {
390*a28cd43dSSascha Wildner         U32 const magicNumber = MEM_readLE32(src);
391*a28cd43dSSascha Wildner 
392*a28cd43dSSascha Wildner         if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
393*a28cd43dSSascha Wildner             size_t const skippableSize = readSkippableFrameSize(src, srcSize);
394*a28cd43dSSascha Wildner             if (ZSTD_isError(skippableSize)) {
395*a28cd43dSSascha Wildner                 return ZSTD_CONTENTSIZE_ERROR;
396*a28cd43dSSascha Wildner             }
397*a28cd43dSSascha Wildner             assert(skippableSize <= srcSize);
398*a28cd43dSSascha Wildner 
399*a28cd43dSSascha Wildner             src = (const BYTE *)src + skippableSize;
400*a28cd43dSSascha Wildner             srcSize -= skippableSize;
401*a28cd43dSSascha Wildner             continue;
402*a28cd43dSSascha Wildner         }
403*a28cd43dSSascha Wildner 
404*a28cd43dSSascha Wildner         {   unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
405*a28cd43dSSascha Wildner             if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret;
406*a28cd43dSSascha Wildner 
407*a28cd43dSSascha Wildner             /* check for overflow */
408*a28cd43dSSascha Wildner             if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR;
409*a28cd43dSSascha Wildner             totalDstSize += ret;
410*a28cd43dSSascha Wildner         }
411*a28cd43dSSascha Wildner         {   size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);
412*a28cd43dSSascha Wildner             if (ZSTD_isError(frameSrcSize)) {
413*a28cd43dSSascha Wildner                 return ZSTD_CONTENTSIZE_ERROR;
414*a28cd43dSSascha Wildner             }
415*a28cd43dSSascha Wildner 
416*a28cd43dSSascha Wildner             src = (const BYTE *)src + frameSrcSize;
417*a28cd43dSSascha Wildner             srcSize -= frameSrcSize;
418*a28cd43dSSascha Wildner         }
419*a28cd43dSSascha Wildner     }  /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
420*a28cd43dSSascha Wildner 
421*a28cd43dSSascha Wildner     if (srcSize) return ZSTD_CONTENTSIZE_ERROR;
422*a28cd43dSSascha Wildner 
423*a28cd43dSSascha Wildner     return totalDstSize;
424*a28cd43dSSascha Wildner }
425*a28cd43dSSascha Wildner 
426*a28cd43dSSascha Wildner /** ZSTD_getDecompressedSize() :
427*a28cd43dSSascha Wildner  *  compatible with legacy mode
428*a28cd43dSSascha Wildner  * @return : decompressed size if known, 0 otherwise
429*a28cd43dSSascha Wildner              note : 0 can mean any of the following :
430*a28cd43dSSascha Wildner                    - frame content is empty
431*a28cd43dSSascha Wildner                    - decompressed size field is not present in frame header
432*a28cd43dSSascha Wildner                    - frame header unknown / not supported
433*a28cd43dSSascha Wildner                    - frame header not complete (`srcSize` too small) */
ZSTD_getDecompressedSize(const void * src,size_t srcSize)434*a28cd43dSSascha Wildner unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
435*a28cd43dSSascha Wildner {
436*a28cd43dSSascha Wildner     unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
437*a28cd43dSSascha Wildner     ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN);
438*a28cd43dSSascha Wildner     return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret;
439*a28cd43dSSascha Wildner }
440*a28cd43dSSascha Wildner 
441*a28cd43dSSascha Wildner 
442*a28cd43dSSascha Wildner /** ZSTD_decodeFrameHeader() :
443*a28cd43dSSascha Wildner  * `headerSize` must be the size provided by ZSTD_frameHeaderSize().
444*a28cd43dSSascha Wildner  * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
ZSTD_decodeFrameHeader(ZSTD_DCtx * dctx,const void * src,size_t headerSize)445*a28cd43dSSascha Wildner static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
446*a28cd43dSSascha Wildner {
447*a28cd43dSSascha Wildner     size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);
448*a28cd43dSSascha Wildner     if (ZSTD_isError(result)) return result;    /* invalid header */
449*a28cd43dSSascha Wildner     RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small");
450*a28cd43dSSascha Wildner #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
451*a28cd43dSSascha Wildner     /* Skip the dictID check in fuzzing mode, because it makes the search
452*a28cd43dSSascha Wildner      * harder.
453*a28cd43dSSascha Wildner      */
454*a28cd43dSSascha Wildner     RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID),
455*a28cd43dSSascha Wildner                     dictionary_wrong, "");
456*a28cd43dSSascha Wildner #endif
457*a28cd43dSSascha Wildner     dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0;
458*a28cd43dSSascha Wildner     if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0);
459*a28cd43dSSascha Wildner     return 0;
460*a28cd43dSSascha Wildner }
461*a28cd43dSSascha Wildner 
ZSTD_errorFrameSizeInfo(size_t ret)462*a28cd43dSSascha Wildner static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret)
463*a28cd43dSSascha Wildner {
464*a28cd43dSSascha Wildner     ZSTD_frameSizeInfo frameSizeInfo;
465*a28cd43dSSascha Wildner     frameSizeInfo.compressedSize = ret;
466*a28cd43dSSascha Wildner     frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR;
467*a28cd43dSSascha Wildner     return frameSizeInfo;
468*a28cd43dSSascha Wildner }
469*a28cd43dSSascha Wildner 
ZSTD_findFrameSizeInfo(const void * src,size_t srcSize)470*a28cd43dSSascha Wildner static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize)
471*a28cd43dSSascha Wildner {
472*a28cd43dSSascha Wildner     ZSTD_frameSizeInfo frameSizeInfo;
473*a28cd43dSSascha Wildner     ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));
474*a28cd43dSSascha Wildner 
475*a28cd43dSSascha Wildner #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
476*a28cd43dSSascha Wildner     if (ZSTD_isLegacy(src, srcSize))
477*a28cd43dSSascha Wildner         return ZSTD_findFrameSizeInfoLegacy(src, srcSize);
478*a28cd43dSSascha Wildner #endif
479*a28cd43dSSascha Wildner 
480*a28cd43dSSascha Wildner     if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE)
481*a28cd43dSSascha Wildner         && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
482*a28cd43dSSascha Wildner         frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize);
483*a28cd43dSSascha Wildner         assert(ZSTD_isError(frameSizeInfo.compressedSize) ||
484*a28cd43dSSascha Wildner                frameSizeInfo.compressedSize <= srcSize);
485*a28cd43dSSascha Wildner         return frameSizeInfo;
486*a28cd43dSSascha Wildner     } else {
487*a28cd43dSSascha Wildner         const BYTE* ip = (const BYTE*)src;
488*a28cd43dSSascha Wildner         const BYTE* const ipstart = ip;
489*a28cd43dSSascha Wildner         size_t remainingSize = srcSize;
490*a28cd43dSSascha Wildner         size_t nbBlocks = 0;
491*a28cd43dSSascha Wildner         ZSTD_frameHeader zfh;
492*a28cd43dSSascha Wildner 
493*a28cd43dSSascha Wildner         /* Extract Frame Header */
494*a28cd43dSSascha Wildner         {   size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize);
495*a28cd43dSSascha Wildner             if (ZSTD_isError(ret))
496*a28cd43dSSascha Wildner                 return ZSTD_errorFrameSizeInfo(ret);
497*a28cd43dSSascha Wildner             if (ret > 0)
498*a28cd43dSSascha Wildner                 return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));
499*a28cd43dSSascha Wildner         }
500*a28cd43dSSascha Wildner 
501*a28cd43dSSascha Wildner         ip += zfh.headerSize;
502*a28cd43dSSascha Wildner         remainingSize -= zfh.headerSize;
503*a28cd43dSSascha Wildner 
504*a28cd43dSSascha Wildner         /* Iterate over each block */
505*a28cd43dSSascha Wildner         while (1) {
506*a28cd43dSSascha Wildner             blockProperties_t blockProperties;
507*a28cd43dSSascha Wildner             size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
508*a28cd43dSSascha Wildner             if (ZSTD_isError(cBlockSize))
509*a28cd43dSSascha Wildner                 return ZSTD_errorFrameSizeInfo(cBlockSize);
510*a28cd43dSSascha Wildner 
511*a28cd43dSSascha Wildner             if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)
512*a28cd43dSSascha Wildner                 return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));
513*a28cd43dSSascha Wildner 
514*a28cd43dSSascha Wildner             ip += ZSTD_blockHeaderSize + cBlockSize;
515*a28cd43dSSascha Wildner             remainingSize -= ZSTD_blockHeaderSize + cBlockSize;
516*a28cd43dSSascha Wildner             nbBlocks++;
517*a28cd43dSSascha Wildner 
518*a28cd43dSSascha Wildner             if (blockProperties.lastBlock) break;
519*a28cd43dSSascha Wildner         }
520*a28cd43dSSascha Wildner 
521*a28cd43dSSascha Wildner         /* Final frame content checksum */
522*a28cd43dSSascha Wildner         if (zfh.checksumFlag) {
523*a28cd43dSSascha Wildner             if (remainingSize < 4)
524*a28cd43dSSascha Wildner                 return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));
525*a28cd43dSSascha Wildner             ip += 4;
526*a28cd43dSSascha Wildner         }
527*a28cd43dSSascha Wildner 
528*a28cd43dSSascha Wildner         frameSizeInfo.compressedSize = (size_t)(ip - ipstart);
529*a28cd43dSSascha Wildner         frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN)
530*a28cd43dSSascha Wildner                                         ? zfh.frameContentSize
531*a28cd43dSSascha Wildner                                         : nbBlocks * zfh.blockSizeMax;
532*a28cd43dSSascha Wildner         return frameSizeInfo;
533*a28cd43dSSascha Wildner     }
534*a28cd43dSSascha Wildner }
535*a28cd43dSSascha Wildner 
536*a28cd43dSSascha Wildner /** ZSTD_findFrameCompressedSize() :
537*a28cd43dSSascha Wildner  *  compatible with legacy mode
538*a28cd43dSSascha Wildner  *  `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame
539*a28cd43dSSascha Wildner  *  `srcSize` must be at least as large as the frame contained
540*a28cd43dSSascha Wildner  *  @return : the compressed size of the frame starting at `src` */
ZSTD_findFrameCompressedSize(const void * src,size_t srcSize)541*a28cd43dSSascha Wildner size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
542*a28cd43dSSascha Wildner {
543*a28cd43dSSascha Wildner     ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
544*a28cd43dSSascha Wildner     return frameSizeInfo.compressedSize;
545*a28cd43dSSascha Wildner }
546*a28cd43dSSascha Wildner 
547*a28cd43dSSascha Wildner /** ZSTD_decompressBound() :
548*a28cd43dSSascha Wildner  *  compatible with legacy mode
549*a28cd43dSSascha Wildner  *  `src` must point to the start of a ZSTD frame or a skippeable frame
550*a28cd43dSSascha Wildner  *  `srcSize` must be at least as large as the frame contained
551*a28cd43dSSascha Wildner  *  @return : the maximum decompressed size of the compressed source
552*a28cd43dSSascha Wildner  */
ZSTD_decompressBound(const void * src,size_t srcSize)553*a28cd43dSSascha Wildner unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
554*a28cd43dSSascha Wildner {
555*a28cd43dSSascha Wildner     unsigned long long bound = 0;
556*a28cd43dSSascha Wildner     /* Iterate over each frame */
557*a28cd43dSSascha Wildner     while (srcSize > 0) {
558*a28cd43dSSascha Wildner         ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
559*a28cd43dSSascha Wildner         size_t const compressedSize = frameSizeInfo.compressedSize;
560*a28cd43dSSascha Wildner         unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;
561*a28cd43dSSascha Wildner         if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)
562*a28cd43dSSascha Wildner             return ZSTD_CONTENTSIZE_ERROR;
563*a28cd43dSSascha Wildner         assert(srcSize >= compressedSize);
564*a28cd43dSSascha Wildner         src = (const BYTE*)src + compressedSize;
565*a28cd43dSSascha Wildner         srcSize -= compressedSize;
566*a28cd43dSSascha Wildner         bound += decompressedBound;
567*a28cd43dSSascha Wildner     }
568*a28cd43dSSascha Wildner     return bound;
569*a28cd43dSSascha Wildner }
570*a28cd43dSSascha Wildner 
571*a28cd43dSSascha Wildner 
572*a28cd43dSSascha Wildner /*-*************************************************************
573*a28cd43dSSascha Wildner  *   Frame decoding
574*a28cd43dSSascha Wildner  ***************************************************************/
575*a28cd43dSSascha Wildner 
576*a28cd43dSSascha Wildner /** ZSTD_insertBlock() :
577*a28cd43dSSascha Wildner  *  insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
ZSTD_insertBlock(ZSTD_DCtx * dctx,const void * blockStart,size_t blockSize)578*a28cd43dSSascha Wildner size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
579*a28cd43dSSascha Wildner {
580*a28cd43dSSascha Wildner     DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize);
581*a28cd43dSSascha Wildner     ZSTD_checkContinuity(dctx, blockStart);
582*a28cd43dSSascha Wildner     dctx->previousDstEnd = (const char*)blockStart + blockSize;
583*a28cd43dSSascha Wildner     return blockSize;
584*a28cd43dSSascha Wildner }
585*a28cd43dSSascha Wildner 
586*a28cd43dSSascha Wildner 
ZSTD_copyRawBlock(void * dst,size_t dstCapacity,const void * src,size_t srcSize)587*a28cd43dSSascha Wildner static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity,
588*a28cd43dSSascha Wildner                           const void* src, size_t srcSize)
589*a28cd43dSSascha Wildner {
590*a28cd43dSSascha Wildner     DEBUGLOG(5, "ZSTD_copyRawBlock");
591*a28cd43dSSascha Wildner     RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, "");
592*a28cd43dSSascha Wildner     if (dst == NULL) {
593*a28cd43dSSascha Wildner         if (srcSize == 0) return 0;
594*a28cd43dSSascha Wildner         RETURN_ERROR(dstBuffer_null, "");
595*a28cd43dSSascha Wildner     }
596*a28cd43dSSascha Wildner     ZSTD_memcpy(dst, src, srcSize);
597*a28cd43dSSascha Wildner     return srcSize;
598*a28cd43dSSascha Wildner }
599*a28cd43dSSascha Wildner 
ZSTD_setRleBlock(void * dst,size_t dstCapacity,BYTE b,size_t regenSize)600*a28cd43dSSascha Wildner static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
601*a28cd43dSSascha Wildner                                BYTE b,
602*a28cd43dSSascha Wildner                                size_t regenSize)
603*a28cd43dSSascha Wildner {
604*a28cd43dSSascha Wildner     RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, "");
605*a28cd43dSSascha Wildner     if (dst == NULL) {
606*a28cd43dSSascha Wildner         if (regenSize == 0) return 0;
607*a28cd43dSSascha Wildner         RETURN_ERROR(dstBuffer_null, "");
608*a28cd43dSSascha Wildner     }
609*a28cd43dSSascha Wildner     ZSTD_memset(dst, b, regenSize);
610*a28cd43dSSascha Wildner     return regenSize;
611*a28cd43dSSascha Wildner }
612*a28cd43dSSascha Wildner 
613*a28cd43dSSascha Wildner 
614*a28cd43dSSascha Wildner /*! ZSTD_decompressFrame() :
615*a28cd43dSSascha Wildner  * @dctx must be properly initialized
616*a28cd43dSSascha Wildner  *  will update *srcPtr and *srcSizePtr,
617*a28cd43dSSascha Wildner  *  to make *srcPtr progress by one frame. */
ZSTD_decompressFrame(ZSTD_DCtx * dctx,void * dst,size_t dstCapacity,const void ** srcPtr,size_t * srcSizePtr)618*a28cd43dSSascha Wildner static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
619*a28cd43dSSascha Wildner                                    void* dst, size_t dstCapacity,
620*a28cd43dSSascha Wildner                              const void** srcPtr, size_t *srcSizePtr)
621*a28cd43dSSascha Wildner {
622*a28cd43dSSascha Wildner     const BYTE* ip = (const BYTE*)(*srcPtr);
623*a28cd43dSSascha Wildner     BYTE* const ostart = (BYTE* const)dst;
624*a28cd43dSSascha Wildner     BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart;
625*a28cd43dSSascha Wildner     BYTE* op = ostart;
626*a28cd43dSSascha Wildner     size_t remainingSrcSize = *srcSizePtr;
627*a28cd43dSSascha Wildner 
628*a28cd43dSSascha Wildner     DEBUGLOG(4, "ZSTD_decompressFrame (srcSize:%i)", (int)*srcSizePtr);
629*a28cd43dSSascha Wildner 
630*a28cd43dSSascha Wildner     /* check */
631*a28cd43dSSascha Wildner     RETURN_ERROR_IF(
632*a28cd43dSSascha Wildner         remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize,
633*a28cd43dSSascha Wildner         srcSize_wrong, "");
634*a28cd43dSSascha Wildner 
635*a28cd43dSSascha Wildner     /* Frame Header */
636*a28cd43dSSascha Wildner     {   size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal(
637*a28cd43dSSascha Wildner                 ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format);
638*a28cd43dSSascha Wildner         if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
639*a28cd43dSSascha Wildner         RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize,
640*a28cd43dSSascha Wildner                         srcSize_wrong, "");
641*a28cd43dSSascha Wildner         FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , "");
642*a28cd43dSSascha Wildner         ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;
643*a28cd43dSSascha Wildner     }
644*a28cd43dSSascha Wildner 
645*a28cd43dSSascha Wildner     /* Loop on each block */
646*a28cd43dSSascha Wildner     while (1) {
647*a28cd43dSSascha Wildner         size_t decodedSize;
648*a28cd43dSSascha Wildner         blockProperties_t blockProperties;
649*a28cd43dSSascha Wildner         size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties);
650*a28cd43dSSascha Wildner         if (ZSTD_isError(cBlockSize)) return cBlockSize;
651*a28cd43dSSascha Wildner 
652*a28cd43dSSascha Wildner         ip += ZSTD_blockHeaderSize;
653*a28cd43dSSascha Wildner         remainingSrcSize -= ZSTD_blockHeaderSize;
654*a28cd43dSSascha Wildner         RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, "");
655*a28cd43dSSascha Wildner 
656*a28cd43dSSascha Wildner         switch(blockProperties.blockType)
657*a28cd43dSSascha Wildner         {
658*a28cd43dSSascha Wildner         case bt_compressed:
659*a28cd43dSSascha Wildner             decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oend-op), ip, cBlockSize, /* frame */ 1);
660*a28cd43dSSascha Wildner             break;
661*a28cd43dSSascha Wildner         case bt_raw :
662*a28cd43dSSascha Wildner             decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize);
663*a28cd43dSSascha Wildner             break;
664*a28cd43dSSascha Wildner         case bt_rle :
665*a28cd43dSSascha Wildner             decodedSize = ZSTD_setRleBlock(op, (size_t)(oend-op), *ip, blockProperties.origSize);
666*a28cd43dSSascha Wildner             break;
667*a28cd43dSSascha Wildner         case bt_reserved :
668*a28cd43dSSascha Wildner         default:
669*a28cd43dSSascha Wildner             RETURN_ERROR(corruption_detected, "invalid block type");
670*a28cd43dSSascha Wildner         }
671*a28cd43dSSascha Wildner 
672*a28cd43dSSascha Wildner         if (ZSTD_isError(decodedSize)) return decodedSize;
673*a28cd43dSSascha Wildner         if (dctx->validateChecksum)
674*a28cd43dSSascha Wildner             XXH64_update(&dctx->xxhState, op, decodedSize);
675*a28cd43dSSascha Wildner         if (decodedSize != 0)
676*a28cd43dSSascha Wildner             op += decodedSize;
677*a28cd43dSSascha Wildner         assert(ip != NULL);
678*a28cd43dSSascha Wildner         ip += cBlockSize;
679*a28cd43dSSascha Wildner         remainingSrcSize -= cBlockSize;
680*a28cd43dSSascha Wildner         if (blockProperties.lastBlock) break;
681*a28cd43dSSascha Wildner     }
682*a28cd43dSSascha Wildner 
683*a28cd43dSSascha Wildner     if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {
684*a28cd43dSSascha Wildner         RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize,
685*a28cd43dSSascha Wildner                         corruption_detected, "");
686*a28cd43dSSascha Wildner     }
687*a28cd43dSSascha Wildner     if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
688*a28cd43dSSascha Wildner         RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, "");
689*a28cd43dSSascha Wildner         if (!dctx->forceIgnoreChecksum) {
690*a28cd43dSSascha Wildner             U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);
691*a28cd43dSSascha Wildner             U32 checkRead;
692*a28cd43dSSascha Wildner             checkRead = MEM_readLE32(ip);
693*a28cd43dSSascha Wildner             RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, "");
694*a28cd43dSSascha Wildner         }
695*a28cd43dSSascha Wildner         ip += 4;
696*a28cd43dSSascha Wildner         remainingSrcSize -= 4;
697*a28cd43dSSascha Wildner     }
698*a28cd43dSSascha Wildner 
699*a28cd43dSSascha Wildner     /* Allow caller to get size read */
700*a28cd43dSSascha Wildner     *srcPtr = ip;
701*a28cd43dSSascha Wildner     *srcSizePtr = remainingSrcSize;
702*a28cd43dSSascha Wildner     return (size_t)(op-ostart);
703*a28cd43dSSascha Wildner }
704*a28cd43dSSascha Wildner 
ZSTD_decompressMultiFrame(ZSTD_DCtx * dctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const void * dict,size_t dictSize,const ZSTD_DDict * ddict)705*a28cd43dSSascha Wildner static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
706*a28cd43dSSascha Wildner                                         void* dst, size_t dstCapacity,
707*a28cd43dSSascha Wildner                                   const void* src, size_t srcSize,
708*a28cd43dSSascha Wildner                                   const void* dict, size_t dictSize,
709*a28cd43dSSascha Wildner                                   const ZSTD_DDict* ddict)
710*a28cd43dSSascha Wildner {
711*a28cd43dSSascha Wildner     void* const dststart = dst;
712*a28cd43dSSascha Wildner     int moreThan1Frame = 0;
713*a28cd43dSSascha Wildner 
714*a28cd43dSSascha Wildner     DEBUGLOG(5, "ZSTD_decompressMultiFrame");
715*a28cd43dSSascha Wildner     assert(dict==NULL || ddict==NULL);  /* either dict or ddict set, not both */
716*a28cd43dSSascha Wildner 
717*a28cd43dSSascha Wildner     if (ddict) {
718*a28cd43dSSascha Wildner         dict = ZSTD_DDict_dictContent(ddict);
719*a28cd43dSSascha Wildner         dictSize = ZSTD_DDict_dictSize(ddict);
720*a28cd43dSSascha Wildner     }
721*a28cd43dSSascha Wildner 
722*a28cd43dSSascha Wildner     while (srcSize >= ZSTD_startingInputLength(dctx->format)) {
723*a28cd43dSSascha Wildner 
724*a28cd43dSSascha Wildner #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
725*a28cd43dSSascha Wildner         if (ZSTD_isLegacy(src, srcSize)) {
726*a28cd43dSSascha Wildner             size_t decodedSize;
727*a28cd43dSSascha Wildner             size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize);
728*a28cd43dSSascha Wildner             if (ZSTD_isError(frameSize)) return frameSize;
729*a28cd43dSSascha Wildner             RETURN_ERROR_IF(dctx->staticSize, memory_allocation,
730*a28cd43dSSascha Wildner                 "legacy support is not compatible with static dctx");
731*a28cd43dSSascha Wildner 
732*a28cd43dSSascha Wildner             decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);
733*a28cd43dSSascha Wildner             if (ZSTD_isError(decodedSize)) return decodedSize;
734*a28cd43dSSascha Wildner 
735*a28cd43dSSascha Wildner             assert(decodedSize <= dstCapacity);
736*a28cd43dSSascha Wildner             dst = (BYTE*)dst + decodedSize;
737*a28cd43dSSascha Wildner             dstCapacity -= decodedSize;
738*a28cd43dSSascha Wildner 
739*a28cd43dSSascha Wildner             src = (const BYTE*)src + frameSize;
740*a28cd43dSSascha Wildner             srcSize -= frameSize;
741*a28cd43dSSascha Wildner 
742*a28cd43dSSascha Wildner             continue;
743*a28cd43dSSascha Wildner         }
744*a28cd43dSSascha Wildner #endif
745*a28cd43dSSascha Wildner 
746*a28cd43dSSascha Wildner         {   U32 const magicNumber = MEM_readLE32(src);
747*a28cd43dSSascha Wildner             DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
748*a28cd43dSSascha Wildner                         (unsigned)magicNumber, ZSTD_MAGICNUMBER);
749*a28cd43dSSascha Wildner             if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
750*a28cd43dSSascha Wildner                 size_t const skippableSize = readSkippableFrameSize(src, srcSize);
751*a28cd43dSSascha Wildner                 FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed");
752*a28cd43dSSascha Wildner                 assert(skippableSize <= srcSize);
753*a28cd43dSSascha Wildner 
754*a28cd43dSSascha Wildner                 src = (const BYTE *)src + skippableSize;
755*a28cd43dSSascha Wildner                 srcSize -= skippableSize;
756*a28cd43dSSascha Wildner                 continue;
757*a28cd43dSSascha Wildner         }   }
758*a28cd43dSSascha Wildner 
759*a28cd43dSSascha Wildner         if (ddict) {
760*a28cd43dSSascha Wildner             /* we were called from ZSTD_decompress_usingDDict */
761*a28cd43dSSascha Wildner             FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict), "");
762*a28cd43dSSascha Wildner         } else {
763*a28cd43dSSascha Wildner             /* this will initialize correctly with no dict if dict == NULL, so
764*a28cd43dSSascha Wildner              * use this in all cases but ddict */
765*a28cd43dSSascha Wildner             FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), "");
766*a28cd43dSSascha Wildner         }
767*a28cd43dSSascha Wildner         ZSTD_checkContinuity(dctx, dst);
768*a28cd43dSSascha Wildner 
769*a28cd43dSSascha Wildner         {   const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,
770*a28cd43dSSascha Wildner                                                     &src, &srcSize);
771*a28cd43dSSascha Wildner             RETURN_ERROR_IF(
772*a28cd43dSSascha Wildner                 (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown)
773*a28cd43dSSascha Wildner              && (moreThan1Frame==1),
774*a28cd43dSSascha Wildner                 srcSize_wrong,
775*a28cd43dSSascha Wildner                 "At least one frame successfully completed, "
776*a28cd43dSSascha Wildner                 "but following bytes are garbage: "
777*a28cd43dSSascha Wildner                 "it's more likely to be a srcSize error, "
778*a28cd43dSSascha Wildner                 "specifying more input bytes than size of frame(s). "
779*a28cd43dSSascha Wildner                 "Note: one could be unlucky, it might be a corruption error instead, "
780*a28cd43dSSascha Wildner                 "happening right at the place where we expect zstd magic bytes. "
781*a28cd43dSSascha Wildner                 "But this is _much_ less likely than a srcSize field error.");
782*a28cd43dSSascha Wildner             if (ZSTD_isError(res)) return res;
783*a28cd43dSSascha Wildner             assert(res <= dstCapacity);
784*a28cd43dSSascha Wildner             if (res != 0)
785*a28cd43dSSascha Wildner                 dst = (BYTE*)dst + res;
786*a28cd43dSSascha Wildner             dstCapacity -= res;
787*a28cd43dSSascha Wildner         }
788*a28cd43dSSascha Wildner         moreThan1Frame = 1;
789*a28cd43dSSascha Wildner     }  /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
790*a28cd43dSSascha Wildner 
791*a28cd43dSSascha Wildner     RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed");
792*a28cd43dSSascha Wildner 
793*a28cd43dSSascha Wildner     return (size_t)((BYTE*)dst - (BYTE*)dststart);
794*a28cd43dSSascha Wildner }
795*a28cd43dSSascha Wildner 
ZSTD_decompress_usingDict(ZSTD_DCtx * dctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const void * dict,size_t dictSize)796*a28cd43dSSascha Wildner size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,
797*a28cd43dSSascha Wildner                                  void* dst, size_t dstCapacity,
798*a28cd43dSSascha Wildner                            const void* src, size_t srcSize,
799*a28cd43dSSascha Wildner                            const void* dict, size_t dictSize)
800*a28cd43dSSascha Wildner {
801*a28cd43dSSascha Wildner     return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL);
802*a28cd43dSSascha Wildner }
803*a28cd43dSSascha Wildner 
804*a28cd43dSSascha Wildner 
ZSTD_getDDict(ZSTD_DCtx * dctx)805*a28cd43dSSascha Wildner static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx)
806*a28cd43dSSascha Wildner {
807*a28cd43dSSascha Wildner     switch (dctx->dictUses) {
808*a28cd43dSSascha Wildner     default:
809*a28cd43dSSascha Wildner         assert(0 /* Impossible */);
810*a28cd43dSSascha Wildner         /* fall-through */
811*a28cd43dSSascha Wildner     case ZSTD_dont_use:
812*a28cd43dSSascha Wildner         ZSTD_clearDict(dctx);
813*a28cd43dSSascha Wildner         return NULL;
814*a28cd43dSSascha Wildner     case ZSTD_use_indefinitely:
815*a28cd43dSSascha Wildner         return dctx->ddict;
816*a28cd43dSSascha Wildner     case ZSTD_use_once:
817*a28cd43dSSascha Wildner         dctx->dictUses = ZSTD_dont_use;
818*a28cd43dSSascha Wildner         return dctx->ddict;
819*a28cd43dSSascha Wildner     }
820*a28cd43dSSascha Wildner }
821*a28cd43dSSascha Wildner 
ZSTD_decompressDCtx(ZSTD_DCtx * dctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)822*a28cd43dSSascha Wildner size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
823*a28cd43dSSascha Wildner {
824*a28cd43dSSascha Wildner     return ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ZSTD_getDDict(dctx));
825*a28cd43dSSascha Wildner }
826*a28cd43dSSascha Wildner 
827*a28cd43dSSascha Wildner 
ZSTD_decompress(void * dst,size_t dstCapacity,const void * src,size_t srcSize)828*a28cd43dSSascha Wildner size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
829*a28cd43dSSascha Wildner {
830*a28cd43dSSascha Wildner #if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1)
831*a28cd43dSSascha Wildner     size_t regenSize;
832*a28cd43dSSascha Wildner     ZSTD_DCtx* const dctx = ZSTD_createDCtx();
833*a28cd43dSSascha Wildner     RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!");
834*a28cd43dSSascha Wildner     regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);
835*a28cd43dSSascha Wildner     ZSTD_freeDCtx(dctx);
836*a28cd43dSSascha Wildner     return regenSize;
837*a28cd43dSSascha Wildner #else   /* stack mode */
838*a28cd43dSSascha Wildner     ZSTD_DCtx dctx;
839*a28cd43dSSascha Wildner     ZSTD_initDCtx_internal(&dctx);
840*a28cd43dSSascha Wildner     return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize);
841*a28cd43dSSascha Wildner #endif
842*a28cd43dSSascha Wildner }
843*a28cd43dSSascha Wildner 
844*a28cd43dSSascha Wildner 
845*a28cd43dSSascha Wildner /*-**************************************
846*a28cd43dSSascha Wildner *   Advanced Streaming Decompression API
847*a28cd43dSSascha Wildner *   Bufferless and synchronous
848*a28cd43dSSascha Wildner ****************************************/
ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx * dctx)849*a28cd43dSSascha Wildner size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }
850*a28cd43dSSascha Wildner 
851*a28cd43dSSascha Wildner /**
852*a28cd43dSSascha Wildner  * Similar to ZSTD_nextSrcSizeToDecompress(), but when when a block input can be streamed,
853*a28cd43dSSascha Wildner  * we allow taking a partial block as the input. Currently only raw uncompressed blocks can
854*a28cd43dSSascha Wildner  * be streamed.
855*a28cd43dSSascha Wildner  *
856*a28cd43dSSascha Wildner  * For blocks that can be streamed, this allows us to reduce the latency until we produce
857*a28cd43dSSascha Wildner  * output, and avoid copying the input.
858*a28cd43dSSascha Wildner  *
859*a28cd43dSSascha Wildner  * @param inputSize - The total amount of input that the caller currently has.
860*a28cd43dSSascha Wildner  */
ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx * dctx,size_t inputSize)861*a28cd43dSSascha Wildner static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t inputSize) {
862*a28cd43dSSascha Wildner     if (!(dctx->stage == ZSTDds_decompressBlock || dctx->stage == ZSTDds_decompressLastBlock))
863*a28cd43dSSascha Wildner         return dctx->expected;
864*a28cd43dSSascha Wildner     if (dctx->bType != bt_raw)
865*a28cd43dSSascha Wildner         return dctx->expected;
866*a28cd43dSSascha Wildner     return MIN(MAX(inputSize, 1), dctx->expected);
867*a28cd43dSSascha Wildner }
868*a28cd43dSSascha Wildner 
ZSTD_nextInputType(ZSTD_DCtx * dctx)869*a28cd43dSSascha Wildner ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {
870*a28cd43dSSascha Wildner     switch(dctx->stage)
871*a28cd43dSSascha Wildner     {
872*a28cd43dSSascha Wildner     default:   /* should not happen */
873*a28cd43dSSascha Wildner         assert(0);
874*a28cd43dSSascha Wildner     case ZSTDds_getFrameHeaderSize:
875*a28cd43dSSascha Wildner     case ZSTDds_decodeFrameHeader:
876*a28cd43dSSascha Wildner         return ZSTDnit_frameHeader;
877*a28cd43dSSascha Wildner     case ZSTDds_decodeBlockHeader:
878*a28cd43dSSascha Wildner         return ZSTDnit_blockHeader;
879*a28cd43dSSascha Wildner     case ZSTDds_decompressBlock:
880*a28cd43dSSascha Wildner         return ZSTDnit_block;
881*a28cd43dSSascha Wildner     case ZSTDds_decompressLastBlock:
882*a28cd43dSSascha Wildner         return ZSTDnit_lastBlock;
883*a28cd43dSSascha Wildner     case ZSTDds_checkChecksum:
884*a28cd43dSSascha Wildner         return ZSTDnit_checksum;
885*a28cd43dSSascha Wildner     case ZSTDds_decodeSkippableHeader:
886*a28cd43dSSascha Wildner     case ZSTDds_skipFrame:
887*a28cd43dSSascha Wildner         return ZSTDnit_skippableFrame;
888*a28cd43dSSascha Wildner     }
889*a28cd43dSSascha Wildner }
890*a28cd43dSSascha Wildner 
ZSTD_isSkipFrame(ZSTD_DCtx * dctx)891*a28cd43dSSascha Wildner static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; }
892*a28cd43dSSascha Wildner 
893*a28cd43dSSascha Wildner /** ZSTD_decompressContinue() :
894*a28cd43dSSascha Wildner  *  srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress())
895*a28cd43dSSascha Wildner  *  @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)
896*a28cd43dSSascha Wildner  *            or an error code, which can be tested using ZSTD_isError() */
ZSTD_decompressContinue(ZSTD_DCtx * dctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)897*a28cd43dSSascha Wildner size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
898*a28cd43dSSascha Wildner {
899*a28cd43dSSascha Wildner     DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);
900*a28cd43dSSascha Wildner     /* Sanity check */
901*a28cd43dSSascha Wildner     RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed");
902*a28cd43dSSascha Wildner     if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
903*a28cd43dSSascha Wildner 
904*a28cd43dSSascha Wildner     switch (dctx->stage)
905*a28cd43dSSascha Wildner     {
906*a28cd43dSSascha Wildner     case ZSTDds_getFrameHeaderSize :
907*a28cd43dSSascha Wildner         assert(src != NULL);
908*a28cd43dSSascha Wildner         if (dctx->format == ZSTD_f_zstd1) {  /* allows header */
909*a28cd43dSSascha Wildner             assert(srcSize >= ZSTD_FRAMEIDSIZE);  /* to read skippable magic number */
910*a28cd43dSSascha Wildner             if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {        /* skippable frame */
911*a28cd43dSSascha Wildner                 ZSTD_memcpy(dctx->headerBuffer, src, srcSize);
912*a28cd43dSSascha Wildner                 dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize;  /* remaining to load to get full skippable frame header */
913*a28cd43dSSascha Wildner                 dctx->stage = ZSTDds_decodeSkippableHeader;
914*a28cd43dSSascha Wildner                 return 0;
915*a28cd43dSSascha Wildner         }   }
916*a28cd43dSSascha Wildner         dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);
917*a28cd43dSSascha Wildner         if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
918*a28cd43dSSascha Wildner         ZSTD_memcpy(dctx->headerBuffer, src, srcSize);
919*a28cd43dSSascha Wildner         dctx->expected = dctx->headerSize - srcSize;
920*a28cd43dSSascha Wildner         dctx->stage = ZSTDds_decodeFrameHeader;
921*a28cd43dSSascha Wildner         return 0;
922*a28cd43dSSascha Wildner 
923*a28cd43dSSascha Wildner     case ZSTDds_decodeFrameHeader:
924*a28cd43dSSascha Wildner         assert(src != NULL);
925*a28cd43dSSascha Wildner         ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
926*a28cd43dSSascha Wildner         FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), "");
927*a28cd43dSSascha Wildner         dctx->expected = ZSTD_blockHeaderSize;
928*a28cd43dSSascha Wildner         dctx->stage = ZSTDds_decodeBlockHeader;
929*a28cd43dSSascha Wildner         return 0;
930*a28cd43dSSascha Wildner 
931*a28cd43dSSascha Wildner     case ZSTDds_decodeBlockHeader:
932*a28cd43dSSascha Wildner         {   blockProperties_t bp;
933*a28cd43dSSascha Wildner             size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
934*a28cd43dSSascha Wildner             if (ZSTD_isError(cBlockSize)) return cBlockSize;
935*a28cd43dSSascha Wildner             RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum");
936*a28cd43dSSascha Wildner             dctx->expected = cBlockSize;
937*a28cd43dSSascha Wildner             dctx->bType = bp.blockType;
938*a28cd43dSSascha Wildner             dctx->rleSize = bp.origSize;
939*a28cd43dSSascha Wildner             if (cBlockSize) {
940*a28cd43dSSascha Wildner                 dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;
941*a28cd43dSSascha Wildner                 return 0;
942*a28cd43dSSascha Wildner             }
943*a28cd43dSSascha Wildner             /* empty block */
944*a28cd43dSSascha Wildner             if (bp.lastBlock) {
945*a28cd43dSSascha Wildner                 if (dctx->fParams.checksumFlag) {
946*a28cd43dSSascha Wildner                     dctx->expected = 4;
947*a28cd43dSSascha Wildner                     dctx->stage = ZSTDds_checkChecksum;
948*a28cd43dSSascha Wildner                 } else {
949*a28cd43dSSascha Wildner                     dctx->expected = 0; /* end of frame */
950*a28cd43dSSascha Wildner                     dctx->stage = ZSTDds_getFrameHeaderSize;
951*a28cd43dSSascha Wildner                 }
952*a28cd43dSSascha Wildner             } else {
953*a28cd43dSSascha Wildner                 dctx->expected = ZSTD_blockHeaderSize;  /* jump to next header */
954*a28cd43dSSascha Wildner                 dctx->stage = ZSTDds_decodeBlockHeader;
955*a28cd43dSSascha Wildner             }
956*a28cd43dSSascha Wildner             return 0;
957*a28cd43dSSascha Wildner         }
958*a28cd43dSSascha Wildner 
959*a28cd43dSSascha Wildner     case ZSTDds_decompressLastBlock:
960*a28cd43dSSascha Wildner     case ZSTDds_decompressBlock:
961*a28cd43dSSascha Wildner         DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock");
962*a28cd43dSSascha Wildner         {   size_t rSize;
963*a28cd43dSSascha Wildner             switch(dctx->bType)
964*a28cd43dSSascha Wildner             {
965*a28cd43dSSascha Wildner             case bt_compressed:
966*a28cd43dSSascha Wildner                 DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");
967*a28cd43dSSascha Wildner                 rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1);
968*a28cd43dSSascha Wildner                 dctx->expected = 0;  /* Streaming not supported */
969*a28cd43dSSascha Wildner                 break;
970*a28cd43dSSascha Wildner             case bt_raw :
971*a28cd43dSSascha Wildner                 assert(srcSize <= dctx->expected);
972*a28cd43dSSascha Wildner                 rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);
973*a28cd43dSSascha Wildner                 FORWARD_IF_ERROR(rSize, "ZSTD_copyRawBlock failed");
974*a28cd43dSSascha Wildner                 assert(rSize == srcSize);
975*a28cd43dSSascha Wildner                 dctx->expected -= rSize;
976*a28cd43dSSascha Wildner                 break;
977*a28cd43dSSascha Wildner             case bt_rle :
978*a28cd43dSSascha Wildner                 rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize);
979*a28cd43dSSascha Wildner                 dctx->expected = 0;  /* Streaming not supported */
980*a28cd43dSSascha Wildner                 break;
981*a28cd43dSSascha Wildner             case bt_reserved :   /* should never happen */
982*a28cd43dSSascha Wildner             default:
983*a28cd43dSSascha Wildner                 RETURN_ERROR(corruption_detected, "invalid block type");
984*a28cd43dSSascha Wildner             }
985*a28cd43dSSascha Wildner             FORWARD_IF_ERROR(rSize, "");
986*a28cd43dSSascha Wildner             RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum");
987*a28cd43dSSascha Wildner             DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);
988*a28cd43dSSascha Wildner             dctx->decodedSize += rSize;
989*a28cd43dSSascha Wildner             if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize);
990*a28cd43dSSascha Wildner             dctx->previousDstEnd = (char*)dst + rSize;
991*a28cd43dSSascha Wildner 
992*a28cd43dSSascha Wildner             /* Stay on the same stage until we are finished streaming the block. */
993*a28cd43dSSascha Wildner             if (dctx->expected > 0) {
994*a28cd43dSSascha Wildner                 return rSize;
995*a28cd43dSSascha Wildner             }
996*a28cd43dSSascha Wildner 
997*a28cd43dSSascha Wildner             if (dctx->stage == ZSTDds_decompressLastBlock) {   /* end of frame */
998*a28cd43dSSascha Wildner                 DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize);
999*a28cd43dSSascha Wildner                 RETURN_ERROR_IF(
1000*a28cd43dSSascha Wildner                     dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
1001*a28cd43dSSascha Wildner                  && dctx->decodedSize != dctx->fParams.frameContentSize,
1002*a28cd43dSSascha Wildner                     corruption_detected, "");
1003*a28cd43dSSascha Wildner                 if (dctx->fParams.checksumFlag) {  /* another round for frame checksum */
1004*a28cd43dSSascha Wildner                     dctx->expected = 4;
1005*a28cd43dSSascha Wildner                     dctx->stage = ZSTDds_checkChecksum;
1006*a28cd43dSSascha Wildner                 } else {
1007*a28cd43dSSascha Wildner                     dctx->expected = 0;   /* ends here */
1008*a28cd43dSSascha Wildner                     dctx->stage = ZSTDds_getFrameHeaderSize;
1009*a28cd43dSSascha Wildner                 }
1010*a28cd43dSSascha Wildner             } else {
1011*a28cd43dSSascha Wildner                 dctx->stage = ZSTDds_decodeBlockHeader;
1012*a28cd43dSSascha Wildner                 dctx->expected = ZSTD_blockHeaderSize;
1013*a28cd43dSSascha Wildner             }
1014*a28cd43dSSascha Wildner             return rSize;
1015*a28cd43dSSascha Wildner         }
1016*a28cd43dSSascha Wildner 
1017*a28cd43dSSascha Wildner     case ZSTDds_checkChecksum:
1018*a28cd43dSSascha Wildner         assert(srcSize == 4);  /* guaranteed by dctx->expected */
1019*a28cd43dSSascha Wildner         {
1020*a28cd43dSSascha Wildner             if (dctx->validateChecksum) {
1021*a28cd43dSSascha Wildner                 U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
1022*a28cd43dSSascha Wildner                 U32 const check32 = MEM_readLE32(src);
1023*a28cd43dSSascha Wildner                 DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);
1024*a28cd43dSSascha Wildner                 RETURN_ERROR_IF(check32 != h32, checksum_wrong, "");
1025*a28cd43dSSascha Wildner             }
1026*a28cd43dSSascha Wildner             dctx->expected = 0;
1027*a28cd43dSSascha Wildner             dctx->stage = ZSTDds_getFrameHeaderSize;
1028*a28cd43dSSascha Wildner             return 0;
1029*a28cd43dSSascha Wildner         }
1030*a28cd43dSSascha Wildner 
1031*a28cd43dSSascha Wildner     case ZSTDds_decodeSkippableHeader:
1032*a28cd43dSSascha Wildner         assert(src != NULL);
1033*a28cd43dSSascha Wildner         assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);
1034*a28cd43dSSascha Wildner         ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize);   /* complete skippable header */
1035*a28cd43dSSascha Wildner         dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE);   /* note : dctx->expected can grow seriously large, beyond local buffer size */
1036*a28cd43dSSascha Wildner         dctx->stage = ZSTDds_skipFrame;
1037*a28cd43dSSascha Wildner         return 0;
1038*a28cd43dSSascha Wildner 
1039*a28cd43dSSascha Wildner     case ZSTDds_skipFrame:
1040*a28cd43dSSascha Wildner         dctx->expected = 0;
1041*a28cd43dSSascha Wildner         dctx->stage = ZSTDds_getFrameHeaderSize;
1042*a28cd43dSSascha Wildner         return 0;
1043*a28cd43dSSascha Wildner 
1044*a28cd43dSSascha Wildner     default:
1045*a28cd43dSSascha Wildner         assert(0);   /* impossible */
1046*a28cd43dSSascha Wildner         RETURN_ERROR(GENERIC, "impossible to reach");   /* some compiler require default to do something */
1047*a28cd43dSSascha Wildner     }
1048*a28cd43dSSascha Wildner }
1049*a28cd43dSSascha Wildner 
1050*a28cd43dSSascha Wildner 
ZSTD_refDictContent(ZSTD_DCtx * dctx,const void * dict,size_t dictSize)1051*a28cd43dSSascha Wildner static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
1052*a28cd43dSSascha Wildner {
1053*a28cd43dSSascha Wildner     dctx->dictEnd = dctx->previousDstEnd;
1054*a28cd43dSSascha Wildner     dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
1055*a28cd43dSSascha Wildner     dctx->prefixStart = dict;
1056*a28cd43dSSascha Wildner     dctx->previousDstEnd = (const char*)dict + dictSize;
1057*a28cd43dSSascha Wildner #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1058*a28cd43dSSascha Wildner     dctx->dictContentBeginForFuzzing = dctx->prefixStart;
1059*a28cd43dSSascha Wildner     dctx->dictContentEndForFuzzing = dctx->previousDstEnd;
1060*a28cd43dSSascha Wildner #endif
1061*a28cd43dSSascha Wildner     return 0;
1062*a28cd43dSSascha Wildner }
1063*a28cd43dSSascha Wildner 
1064*a28cd43dSSascha Wildner /*! ZSTD_loadDEntropy() :
1065*a28cd43dSSascha Wildner  *  dict : must point at beginning of a valid zstd dictionary.
1066*a28cd43dSSascha Wildner  * @return : size of entropy tables read */
1067*a28cd43dSSascha Wildner size_t
ZSTD_loadDEntropy(ZSTD_entropyDTables_t * entropy,const void * const dict,size_t const dictSize)1068*a28cd43dSSascha Wildner ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
1069*a28cd43dSSascha Wildner                   const void* const dict, size_t const dictSize)
1070*a28cd43dSSascha Wildner {
1071*a28cd43dSSascha Wildner     const BYTE* dictPtr = (const BYTE*)dict;
1072*a28cd43dSSascha Wildner     const BYTE* const dictEnd = dictPtr + dictSize;
1073*a28cd43dSSascha Wildner 
1074*a28cd43dSSascha Wildner     RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted, "dict is too small");
1075*a28cd43dSSascha Wildner     assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY);   /* dict must be valid */
1076*a28cd43dSSascha Wildner     dictPtr += 8;   /* skip header = magic + dictID */
1077*a28cd43dSSascha Wildner 
1078*a28cd43dSSascha Wildner     ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, OFTable) == offsetof(ZSTD_entropyDTables_t, LLTable) + sizeof(entropy->LLTable));
1079*a28cd43dSSascha Wildner     ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, MLTable) == offsetof(ZSTD_entropyDTables_t, OFTable) + sizeof(entropy->OFTable));
1080*a28cd43dSSascha Wildner     ZSTD_STATIC_ASSERT(sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable) >= HUF_DECOMPRESS_WORKSPACE_SIZE);
1081*a28cd43dSSascha Wildner     {   void* const workspace = &entropy->LLTable;   /* use fse tables as temporary workspace; implies fse tables are grouped together */
1082*a28cd43dSSascha Wildner         size_t const workspaceSize = sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable);
1083*a28cd43dSSascha Wildner #ifdef HUF_FORCE_DECOMPRESS_X1
1084*a28cd43dSSascha Wildner         /* in minimal huffman, we always use X1 variants */
1085*a28cd43dSSascha Wildner         size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable,
1086*a28cd43dSSascha Wildner                                                 dictPtr, dictEnd - dictPtr,
1087*a28cd43dSSascha Wildner                                                 workspace, workspaceSize);
1088*a28cd43dSSascha Wildner #else
1089*a28cd43dSSascha Wildner         size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,
1090*a28cd43dSSascha Wildner                                                 dictPtr, (size_t)(dictEnd - dictPtr),
1091*a28cd43dSSascha Wildner                                                 workspace, workspaceSize);
1092*a28cd43dSSascha Wildner #endif
1093*a28cd43dSSascha Wildner         RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, "");
1094*a28cd43dSSascha Wildner         dictPtr += hSize;
1095*a28cd43dSSascha Wildner     }
1096*a28cd43dSSascha Wildner 
1097*a28cd43dSSascha Wildner     {   short offcodeNCount[MaxOff+1];
1098*a28cd43dSSascha Wildner         unsigned offcodeMaxValue = MaxOff, offcodeLog;
1099*a28cd43dSSascha Wildner         size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr));
1100*a28cd43dSSascha Wildner         RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
1101*a28cd43dSSascha Wildner         RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, "");
1102*a28cd43dSSascha Wildner         RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
1103*a28cd43dSSascha Wildner         ZSTD_buildFSETable( entropy->OFTable,
1104*a28cd43dSSascha Wildner                             offcodeNCount, offcodeMaxValue,
1105*a28cd43dSSascha Wildner                             OF_base, OF_bits,
1106*a28cd43dSSascha Wildner                             offcodeLog,
1107*a28cd43dSSascha Wildner                             entropy->workspace, sizeof(entropy->workspace),
1108*a28cd43dSSascha Wildner                             /* bmi2 */0);
1109*a28cd43dSSascha Wildner         dictPtr += offcodeHeaderSize;
1110*a28cd43dSSascha Wildner     }
1111*a28cd43dSSascha Wildner 
1112*a28cd43dSSascha Wildner     {   short matchlengthNCount[MaxML+1];
1113*a28cd43dSSascha Wildner         unsigned matchlengthMaxValue = MaxML, matchlengthLog;
1114*a28cd43dSSascha Wildner         size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr));
1115*a28cd43dSSascha Wildner         RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
1116*a28cd43dSSascha Wildner         RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, "");
1117*a28cd43dSSascha Wildner         RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");
1118*a28cd43dSSascha Wildner         ZSTD_buildFSETable( entropy->MLTable,
1119*a28cd43dSSascha Wildner                             matchlengthNCount, matchlengthMaxValue,
1120*a28cd43dSSascha Wildner                             ML_base, ML_bits,
1121*a28cd43dSSascha Wildner                             matchlengthLog,
1122*a28cd43dSSascha Wildner                             entropy->workspace, sizeof(entropy->workspace),
1123*a28cd43dSSascha Wildner                             /* bmi2 */ 0);
1124*a28cd43dSSascha Wildner         dictPtr += matchlengthHeaderSize;
1125*a28cd43dSSascha Wildner     }
1126*a28cd43dSSascha Wildner 
1127*a28cd43dSSascha Wildner     {   short litlengthNCount[MaxLL+1];
1128*a28cd43dSSascha Wildner         unsigned litlengthMaxValue = MaxLL, litlengthLog;
1129*a28cd43dSSascha Wildner         size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr));
1130*a28cd43dSSascha Wildner         RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
1131*a28cd43dSSascha Wildner         RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, "");
1132*a28cd43dSSascha Wildner         RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");
1133*a28cd43dSSascha Wildner         ZSTD_buildFSETable( entropy->LLTable,
1134*a28cd43dSSascha Wildner                             litlengthNCount, litlengthMaxValue,
1135*a28cd43dSSascha Wildner                             LL_base, LL_bits,
1136*a28cd43dSSascha Wildner                             litlengthLog,
1137*a28cd43dSSascha Wildner                             entropy->workspace, sizeof(entropy->workspace),
1138*a28cd43dSSascha Wildner                             /* bmi2 */ 0);
1139*a28cd43dSSascha Wildner         dictPtr += litlengthHeaderSize;
1140*a28cd43dSSascha Wildner     }
1141*a28cd43dSSascha Wildner 
1142*a28cd43dSSascha Wildner     RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, "");
1143*a28cd43dSSascha Wildner     {   int i;
1144*a28cd43dSSascha Wildner         size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12));
1145*a28cd43dSSascha Wildner         for (i=0; i<3; i++) {
1146*a28cd43dSSascha Wildner             U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4;
1147*a28cd43dSSascha Wildner             RETURN_ERROR_IF(rep==0 || rep > dictContentSize,
1148*a28cd43dSSascha Wildner                             dictionary_corrupted, "");
1149*a28cd43dSSascha Wildner             entropy->rep[i] = rep;
1150*a28cd43dSSascha Wildner     }   }
1151*a28cd43dSSascha Wildner 
1152*a28cd43dSSascha Wildner     return (size_t)(dictPtr - (const BYTE*)dict);
1153*a28cd43dSSascha Wildner }
1154*a28cd43dSSascha Wildner 
ZSTD_decompress_insertDictionary(ZSTD_DCtx * dctx,const void * dict,size_t dictSize)1155*a28cd43dSSascha Wildner static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
1156*a28cd43dSSascha Wildner {
1157*a28cd43dSSascha Wildner     if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize);
1158*a28cd43dSSascha Wildner     {   U32 const magic = MEM_readLE32(dict);
1159*a28cd43dSSascha Wildner         if (magic != ZSTD_MAGIC_DICTIONARY) {
1160*a28cd43dSSascha Wildner             return ZSTD_refDictContent(dctx, dict, dictSize);   /* pure content mode */
1161*a28cd43dSSascha Wildner     }   }
1162*a28cd43dSSascha Wildner     dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);
1163*a28cd43dSSascha Wildner 
1164*a28cd43dSSascha Wildner     /* load entropy tables */
1165*a28cd43dSSascha Wildner     {   size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize);
1166*a28cd43dSSascha Wildner         RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted, "");
1167*a28cd43dSSascha Wildner         dict = (const char*)dict + eSize;
1168*a28cd43dSSascha Wildner         dictSize -= eSize;
1169*a28cd43dSSascha Wildner     }
1170*a28cd43dSSascha Wildner     dctx->litEntropy = dctx->fseEntropy = 1;
1171*a28cd43dSSascha Wildner 
1172*a28cd43dSSascha Wildner     /* reference dictionary content */
1173*a28cd43dSSascha Wildner     return ZSTD_refDictContent(dctx, dict, dictSize);
1174*a28cd43dSSascha Wildner }
1175*a28cd43dSSascha Wildner 
ZSTD_decompressBegin(ZSTD_DCtx * dctx)1176*a28cd43dSSascha Wildner size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
1177*a28cd43dSSascha Wildner {
1178*a28cd43dSSascha Wildner     assert(dctx != NULL);
1179*a28cd43dSSascha Wildner     dctx->expected = ZSTD_startingInputLength(dctx->format);  /* dctx->format must be properly set */
1180*a28cd43dSSascha Wildner     dctx->stage = ZSTDds_getFrameHeaderSize;
1181*a28cd43dSSascha Wildner     dctx->decodedSize = 0;
1182*a28cd43dSSascha Wildner     dctx->previousDstEnd = NULL;
1183*a28cd43dSSascha Wildner     dctx->prefixStart = NULL;
1184*a28cd43dSSascha Wildner     dctx->virtualStart = NULL;
1185*a28cd43dSSascha Wildner     dctx->dictEnd = NULL;
1186*a28cd43dSSascha Wildner     dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001);  /* cover both little and big endian */
1187*a28cd43dSSascha Wildner     dctx->litEntropy = dctx->fseEntropy = 0;
1188*a28cd43dSSascha Wildner     dctx->dictID = 0;
1189*a28cd43dSSascha Wildner     dctx->bType = bt_reserved;
1190*a28cd43dSSascha Wildner     ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
1191*a28cd43dSSascha Wildner     ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue));  /* initial repcodes */
1192*a28cd43dSSascha Wildner     dctx->LLTptr = dctx->entropy.LLTable;
1193*a28cd43dSSascha Wildner     dctx->MLTptr = dctx->entropy.MLTable;
1194*a28cd43dSSascha Wildner     dctx->OFTptr = dctx->entropy.OFTable;
1195*a28cd43dSSascha Wildner     dctx->HUFptr = dctx->entropy.hufTable;
1196*a28cd43dSSascha Wildner     return 0;
1197*a28cd43dSSascha Wildner }
1198*a28cd43dSSascha Wildner 
ZSTD_decompressBegin_usingDict(ZSTD_DCtx * dctx,const void * dict,size_t dictSize)1199*a28cd43dSSascha Wildner size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
1200*a28cd43dSSascha Wildner {
1201*a28cd43dSSascha Wildner     FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");
1202*a28cd43dSSascha Wildner     if (dict && dictSize)
1203*a28cd43dSSascha Wildner         RETURN_ERROR_IF(
1204*a28cd43dSSascha Wildner             ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)),
1205*a28cd43dSSascha Wildner             dictionary_corrupted, "");
1206*a28cd43dSSascha Wildner     return 0;
1207*a28cd43dSSascha Wildner }
1208*a28cd43dSSascha Wildner 
1209*a28cd43dSSascha Wildner 
1210*a28cd43dSSascha Wildner /* ======   ZSTD_DDict   ====== */
1211*a28cd43dSSascha Wildner 
ZSTD_decompressBegin_usingDDict(ZSTD_DCtx * dctx,const ZSTD_DDict * ddict)1212*a28cd43dSSascha Wildner size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
1213*a28cd43dSSascha Wildner {
1214*a28cd43dSSascha Wildner     DEBUGLOG(4, "ZSTD_decompressBegin_usingDDict");
1215*a28cd43dSSascha Wildner     assert(dctx != NULL);
1216*a28cd43dSSascha Wildner     if (ddict) {
1217*a28cd43dSSascha Wildner         const char* const dictStart = (const char*)ZSTD_DDict_dictContent(ddict);
1218*a28cd43dSSascha Wildner         size_t const dictSize = ZSTD_DDict_dictSize(ddict);
1219*a28cd43dSSascha Wildner         const void* const dictEnd = dictStart + dictSize;
1220*a28cd43dSSascha Wildner         dctx->ddictIsCold = (dctx->dictEnd != dictEnd);
1221*a28cd43dSSascha Wildner         DEBUGLOG(4, "DDict is %s",
1222*a28cd43dSSascha Wildner                     dctx->ddictIsCold ? "~cold~" : "hot!");
1223*a28cd43dSSascha Wildner     }
1224*a28cd43dSSascha Wildner     FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");
1225*a28cd43dSSascha Wildner     if (ddict) {   /* NULL ddict is equivalent to no dictionary */
1226*a28cd43dSSascha Wildner         ZSTD_copyDDictParameters(dctx, ddict);
1227*a28cd43dSSascha Wildner     }
1228*a28cd43dSSascha Wildner     return 0;
1229*a28cd43dSSascha Wildner }
1230*a28cd43dSSascha Wildner 
1231*a28cd43dSSascha Wildner /*! ZSTD_getDictID_fromDict() :
1232*a28cd43dSSascha Wildner  *  Provides the dictID stored within dictionary.
1233*a28cd43dSSascha Wildner  *  if @return == 0, the dictionary is not conformant with Zstandard specification.
1234*a28cd43dSSascha Wildner  *  It can still be loaded, but as a content-only dictionary. */
ZSTD_getDictID_fromDict(const void * dict,size_t dictSize)1235*a28cd43dSSascha Wildner unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
1236*a28cd43dSSascha Wildner {
1237*a28cd43dSSascha Wildner     if (dictSize < 8) return 0;
1238*a28cd43dSSascha Wildner     if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0;
1239*a28cd43dSSascha Wildner     return MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);
1240*a28cd43dSSascha Wildner }
1241*a28cd43dSSascha Wildner 
1242*a28cd43dSSascha Wildner /*! ZSTD_getDictID_fromFrame() :
1243*a28cd43dSSascha Wildner  *  Provides the dictID required to decompress frame stored within `src`.
1244*a28cd43dSSascha Wildner  *  If @return == 0, the dictID could not be decoded.
1245*a28cd43dSSascha Wildner  *  This could for one of the following reasons :
1246*a28cd43dSSascha Wildner  *  - The frame does not require a dictionary (most common case).
1247*a28cd43dSSascha Wildner  *  - The frame was built with dictID intentionally removed.
1248*a28cd43dSSascha Wildner  *    Needed dictionary is a hidden information.
1249*a28cd43dSSascha Wildner  *    Note : this use case also happens when using a non-conformant dictionary.
1250*a28cd43dSSascha Wildner  *  - `srcSize` is too small, and as a result, frame header could not be decoded.
1251*a28cd43dSSascha Wildner  *    Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`.
1252*a28cd43dSSascha Wildner  *  - This is not a Zstandard frame.
1253*a28cd43dSSascha Wildner  *  When identifying the exact failure cause, it's possible to use
1254*a28cd43dSSascha Wildner  *  ZSTD_getFrameHeader(), which will provide a more precise error code. */
ZSTD_getDictID_fromFrame(const void * src,size_t srcSize)1255*a28cd43dSSascha Wildner unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)
1256*a28cd43dSSascha Wildner {
1257*a28cd43dSSascha Wildner     ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 };
1258*a28cd43dSSascha Wildner     size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);
1259*a28cd43dSSascha Wildner     if (ZSTD_isError(hError)) return 0;
1260*a28cd43dSSascha Wildner     return zfp.dictID;
1261*a28cd43dSSascha Wildner }
1262*a28cd43dSSascha Wildner 
1263*a28cd43dSSascha Wildner 
1264*a28cd43dSSascha Wildner /*! ZSTD_decompress_usingDDict() :
1265*a28cd43dSSascha Wildner *   Decompression using a pre-digested Dictionary
1266*a28cd43dSSascha Wildner *   Use dictionary without significant overhead. */
ZSTD_decompress_usingDDict(ZSTD_DCtx * dctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const ZSTD_DDict * ddict)1267*a28cd43dSSascha Wildner size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
1268*a28cd43dSSascha Wildner                                   void* dst, size_t dstCapacity,
1269*a28cd43dSSascha Wildner                             const void* src, size_t srcSize,
1270*a28cd43dSSascha Wildner                             const ZSTD_DDict* ddict)
1271*a28cd43dSSascha Wildner {
1272*a28cd43dSSascha Wildner     /* pass content and size in case legacy frames are encountered */
1273*a28cd43dSSascha Wildner     return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize,
1274*a28cd43dSSascha Wildner                                      NULL, 0,
1275*a28cd43dSSascha Wildner                                      ddict);
1276*a28cd43dSSascha Wildner }
1277*a28cd43dSSascha Wildner 
1278*a28cd43dSSascha Wildner 
1279*a28cd43dSSascha Wildner /*=====================================
1280*a28cd43dSSascha Wildner *   Streaming decompression
1281*a28cd43dSSascha Wildner *====================================*/
1282*a28cd43dSSascha Wildner 
ZSTD_createDStream(void)1283*a28cd43dSSascha Wildner ZSTD_DStream* ZSTD_createDStream(void)
1284*a28cd43dSSascha Wildner {
1285*a28cd43dSSascha Wildner     DEBUGLOG(3, "ZSTD_createDStream");
1286*a28cd43dSSascha Wildner     return ZSTD_createDStream_advanced(ZSTD_defaultCMem);
1287*a28cd43dSSascha Wildner }
1288*a28cd43dSSascha Wildner 
ZSTD_initStaticDStream(void * workspace,size_t workspaceSize)1289*a28cd43dSSascha Wildner ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize)
1290*a28cd43dSSascha Wildner {
1291*a28cd43dSSascha Wildner     return ZSTD_initStaticDCtx(workspace, workspaceSize);
1292*a28cd43dSSascha Wildner }
1293*a28cd43dSSascha Wildner 
ZSTD_createDStream_advanced(ZSTD_customMem customMem)1294*a28cd43dSSascha Wildner ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem)
1295*a28cd43dSSascha Wildner {
1296*a28cd43dSSascha Wildner     return ZSTD_createDCtx_advanced(customMem);
1297*a28cd43dSSascha Wildner }
1298*a28cd43dSSascha Wildner 
ZSTD_freeDStream(ZSTD_DStream * zds)1299*a28cd43dSSascha Wildner size_t ZSTD_freeDStream(ZSTD_DStream* zds)
1300*a28cd43dSSascha Wildner {
1301*a28cd43dSSascha Wildner     return ZSTD_freeDCtx(zds);
1302*a28cd43dSSascha Wildner }
1303*a28cd43dSSascha Wildner 
1304*a28cd43dSSascha Wildner 
1305*a28cd43dSSascha Wildner /* ***  Initialization  *** */
1306*a28cd43dSSascha Wildner 
ZSTD_DStreamInSize(void)1307*a28cd43dSSascha Wildner size_t ZSTD_DStreamInSize(void)  { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; }
ZSTD_DStreamOutSize(void)1308*a28cd43dSSascha Wildner size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }
1309*a28cd43dSSascha Wildner 
ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx * dctx,const void * dict,size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_dictContentType_e dictContentType)1310*a28cd43dSSascha Wildner size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx,
1311*a28cd43dSSascha Wildner                                    const void* dict, size_t dictSize,
1312*a28cd43dSSascha Wildner                                          ZSTD_dictLoadMethod_e dictLoadMethod,
1313*a28cd43dSSascha Wildner                                          ZSTD_dictContentType_e dictContentType)
1314*a28cd43dSSascha Wildner {
1315*a28cd43dSSascha Wildner     RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
1316*a28cd43dSSascha Wildner     ZSTD_clearDict(dctx);
1317*a28cd43dSSascha Wildner     if (dict && dictSize != 0) {
1318*a28cd43dSSascha Wildner         dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem);
1319*a28cd43dSSascha Wildner         RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation, "NULL pointer!");
1320*a28cd43dSSascha Wildner         dctx->ddict = dctx->ddictLocal;
1321*a28cd43dSSascha Wildner         dctx->dictUses = ZSTD_use_indefinitely;
1322*a28cd43dSSascha Wildner     }
1323*a28cd43dSSascha Wildner     return 0;
1324*a28cd43dSSascha Wildner }
1325*a28cd43dSSascha Wildner 
ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx * dctx,const void * dict,size_t dictSize)1326*a28cd43dSSascha Wildner size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
1327*a28cd43dSSascha Wildner {
1328*a28cd43dSSascha Wildner     return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
1329*a28cd43dSSascha Wildner }
1330*a28cd43dSSascha Wildner 
ZSTD_DCtx_loadDictionary(ZSTD_DCtx * dctx,const void * dict,size_t dictSize)1331*a28cd43dSSascha Wildner size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
1332*a28cd43dSSascha Wildner {
1333*a28cd43dSSascha Wildner     return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
1334*a28cd43dSSascha Wildner }
1335*a28cd43dSSascha Wildner 
ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx * dctx,const void * prefix,size_t prefixSize,ZSTD_dictContentType_e dictContentType)1336*a28cd43dSSascha Wildner size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
1337*a28cd43dSSascha Wildner {
1338*a28cd43dSSascha Wildner     FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType), "");
1339*a28cd43dSSascha Wildner     dctx->dictUses = ZSTD_use_once;
1340*a28cd43dSSascha Wildner     return 0;
1341*a28cd43dSSascha Wildner }
1342*a28cd43dSSascha Wildner 
ZSTD_DCtx_refPrefix(ZSTD_DCtx * dctx,const void * prefix,size_t prefixSize)1343*a28cd43dSSascha Wildner size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize)
1344*a28cd43dSSascha Wildner {
1345*a28cd43dSSascha Wildner     return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent);
1346*a28cd43dSSascha Wildner }
1347*a28cd43dSSascha Wildner 
1348*a28cd43dSSascha Wildner 
1349*a28cd43dSSascha Wildner /* ZSTD_initDStream_usingDict() :
1350*a28cd43dSSascha Wildner  * return : expected size, aka ZSTD_startingInputLength().
1351*a28cd43dSSascha Wildner  * this function cannot fail */
ZSTD_initDStream_usingDict(ZSTD_DStream * zds,const void * dict,size_t dictSize)1352*a28cd43dSSascha Wildner size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)
1353*a28cd43dSSascha Wildner {
1354*a28cd43dSSascha Wildner     DEBUGLOG(4, "ZSTD_initDStream_usingDict");
1355*a28cd43dSSascha Wildner     FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) , "");
1356*a28cd43dSSascha Wildner     FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) , "");
1357*a28cd43dSSascha Wildner     return ZSTD_startingInputLength(zds->format);
1358*a28cd43dSSascha Wildner }
1359*a28cd43dSSascha Wildner 
1360*a28cd43dSSascha Wildner /* note : this variant can't fail */
ZSTD_initDStream(ZSTD_DStream * zds)1361*a28cd43dSSascha Wildner size_t ZSTD_initDStream(ZSTD_DStream* zds)
1362*a28cd43dSSascha Wildner {
1363*a28cd43dSSascha Wildner     DEBUGLOG(4, "ZSTD_initDStream");
1364*a28cd43dSSascha Wildner     return ZSTD_initDStream_usingDDict(zds, NULL);
1365*a28cd43dSSascha Wildner }
1366*a28cd43dSSascha Wildner 
1367*a28cd43dSSascha Wildner /* ZSTD_initDStream_usingDDict() :
1368*a28cd43dSSascha Wildner  * ddict will just be referenced, and must outlive decompression session
1369*a28cd43dSSascha Wildner  * this function cannot fail */
ZSTD_initDStream_usingDDict(ZSTD_DStream * dctx,const ZSTD_DDict * ddict)1370*a28cd43dSSascha Wildner size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
1371*a28cd43dSSascha Wildner {
1372*a28cd43dSSascha Wildner     FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , "");
1373*a28cd43dSSascha Wildner     FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , "");
1374*a28cd43dSSascha Wildner     return ZSTD_startingInputLength(dctx->format);
1375*a28cd43dSSascha Wildner }
1376*a28cd43dSSascha Wildner 
1377*a28cd43dSSascha Wildner /* ZSTD_resetDStream() :
1378*a28cd43dSSascha Wildner  * return : expected size, aka ZSTD_startingInputLength().
1379*a28cd43dSSascha Wildner  * this function cannot fail */
ZSTD_resetDStream(ZSTD_DStream * dctx)1380*a28cd43dSSascha Wildner size_t ZSTD_resetDStream(ZSTD_DStream* dctx)
1381*a28cd43dSSascha Wildner {
1382*a28cd43dSSascha Wildner     FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), "");
1383*a28cd43dSSascha Wildner     return ZSTD_startingInputLength(dctx->format);
1384*a28cd43dSSascha Wildner }
1385*a28cd43dSSascha Wildner 
1386*a28cd43dSSascha Wildner 
ZSTD_DCtx_refDDict(ZSTD_DCtx * dctx,const ZSTD_DDict * ddict)1387*a28cd43dSSascha Wildner size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
1388*a28cd43dSSascha Wildner {
1389*a28cd43dSSascha Wildner     RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
1390*a28cd43dSSascha Wildner     ZSTD_clearDict(dctx);
1391*a28cd43dSSascha Wildner     if (ddict) {
1392*a28cd43dSSascha Wildner         dctx->ddict = ddict;
1393*a28cd43dSSascha Wildner         dctx->dictUses = ZSTD_use_indefinitely;
1394*a28cd43dSSascha Wildner     }
1395*a28cd43dSSascha Wildner     return 0;
1396*a28cd43dSSascha Wildner }
1397*a28cd43dSSascha Wildner 
1398*a28cd43dSSascha Wildner /* ZSTD_DCtx_setMaxWindowSize() :
1399*a28cd43dSSascha Wildner  * note : no direct equivalence in ZSTD_DCtx_setParameter,
1400*a28cd43dSSascha Wildner  * since this version sets windowSize, and the other sets windowLog */
ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx * dctx,size_t maxWindowSize)1401*a28cd43dSSascha Wildner size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
1402*a28cd43dSSascha Wildner {
1403*a28cd43dSSascha Wildner     ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax);
1404*a28cd43dSSascha Wildner     size_t const min = (size_t)1 << bounds.lowerBound;
1405*a28cd43dSSascha Wildner     size_t const max = (size_t)1 << bounds.upperBound;
1406*a28cd43dSSascha Wildner     RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
1407*a28cd43dSSascha Wildner     RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound, "");
1408*a28cd43dSSascha Wildner     RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound, "");
1409*a28cd43dSSascha Wildner     dctx->maxWindowSize = maxWindowSize;
1410*a28cd43dSSascha Wildner     return 0;
1411*a28cd43dSSascha Wildner }
1412*a28cd43dSSascha Wildner 
ZSTD_DCtx_setFormat(ZSTD_DCtx * dctx,ZSTD_format_e format)1413*a28cd43dSSascha Wildner size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
1414*a28cd43dSSascha Wildner {
1415*a28cd43dSSascha Wildner     return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format);
1416*a28cd43dSSascha Wildner }
1417*a28cd43dSSascha Wildner 
ZSTD_dParam_getBounds(ZSTD_dParameter dParam)1418*a28cd43dSSascha Wildner ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
1419*a28cd43dSSascha Wildner {
1420*a28cd43dSSascha Wildner     ZSTD_bounds bounds = { 0, 0, 0 };
1421*a28cd43dSSascha Wildner     switch(dParam) {
1422*a28cd43dSSascha Wildner         case ZSTD_d_windowLogMax:
1423*a28cd43dSSascha Wildner             bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN;
1424*a28cd43dSSascha Wildner             bounds.upperBound = ZSTD_WINDOWLOG_MAX;
1425*a28cd43dSSascha Wildner             return bounds;
1426*a28cd43dSSascha Wildner         case ZSTD_d_format:
1427*a28cd43dSSascha Wildner             bounds.lowerBound = (int)ZSTD_f_zstd1;
1428*a28cd43dSSascha Wildner             bounds.upperBound = (int)ZSTD_f_zstd1_magicless;
1429*a28cd43dSSascha Wildner             ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
1430*a28cd43dSSascha Wildner             return bounds;
1431*a28cd43dSSascha Wildner         case ZSTD_d_stableOutBuffer:
1432*a28cd43dSSascha Wildner             bounds.lowerBound = (int)ZSTD_bm_buffered;
1433*a28cd43dSSascha Wildner             bounds.upperBound = (int)ZSTD_bm_stable;
1434*a28cd43dSSascha Wildner             return bounds;
1435*a28cd43dSSascha Wildner         case ZSTD_d_forceIgnoreChecksum:
1436*a28cd43dSSascha Wildner             bounds.lowerBound = (int)ZSTD_d_validateChecksum;
1437*a28cd43dSSascha Wildner             bounds.upperBound = (int)ZSTD_d_ignoreChecksum;
1438*a28cd43dSSascha Wildner             return bounds;
1439*a28cd43dSSascha Wildner         default:;
1440*a28cd43dSSascha Wildner     }
1441*a28cd43dSSascha Wildner     bounds.error = ERROR(parameter_unsupported);
1442*a28cd43dSSascha Wildner     return bounds;
1443*a28cd43dSSascha Wildner }
1444*a28cd43dSSascha Wildner 
1445*a28cd43dSSascha Wildner /* ZSTD_dParam_withinBounds:
1446*a28cd43dSSascha Wildner  * @return 1 if value is within dParam bounds,
1447*a28cd43dSSascha Wildner  * 0 otherwise */
ZSTD_dParam_withinBounds(ZSTD_dParameter dParam,int value)1448*a28cd43dSSascha Wildner static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value)
1449*a28cd43dSSascha Wildner {
1450*a28cd43dSSascha Wildner     ZSTD_bounds const bounds = ZSTD_dParam_getBounds(dParam);
1451*a28cd43dSSascha Wildner     if (ZSTD_isError(bounds.error)) return 0;
1452*a28cd43dSSascha Wildner     if (value < bounds.lowerBound) return 0;
1453*a28cd43dSSascha Wildner     if (value > bounds.upperBound) return 0;
1454*a28cd43dSSascha Wildner     return 1;
1455*a28cd43dSSascha Wildner }
1456*a28cd43dSSascha Wildner 
1457*a28cd43dSSascha Wildner #define CHECK_DBOUNDS(p,v) {                \
1458*a28cd43dSSascha Wildner     RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \
1459*a28cd43dSSascha Wildner }
1460*a28cd43dSSascha Wildner 
ZSTD_DCtx_getParameter(ZSTD_DCtx * dctx,ZSTD_dParameter param,int * value)1461*a28cd43dSSascha Wildner size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value)
1462*a28cd43dSSascha Wildner {
1463*a28cd43dSSascha Wildner     switch (param) {
1464*a28cd43dSSascha Wildner         case ZSTD_d_windowLogMax:
1465*a28cd43dSSascha Wildner             *value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize);
1466*a28cd43dSSascha Wildner             return 0;
1467*a28cd43dSSascha Wildner         case ZSTD_d_format:
1468*a28cd43dSSascha Wildner             *value = (int)dctx->format;
1469*a28cd43dSSascha Wildner             return 0;
1470*a28cd43dSSascha Wildner         case ZSTD_d_stableOutBuffer:
1471*a28cd43dSSascha Wildner             *value = (int)dctx->outBufferMode;
1472*a28cd43dSSascha Wildner             return 0;
1473*a28cd43dSSascha Wildner         case ZSTD_d_forceIgnoreChecksum:
1474*a28cd43dSSascha Wildner             *value = (int)dctx->forceIgnoreChecksum;
1475*a28cd43dSSascha Wildner             return 0;
1476*a28cd43dSSascha Wildner         default:;
1477*a28cd43dSSascha Wildner     }
1478*a28cd43dSSascha Wildner     RETURN_ERROR(parameter_unsupported, "");
1479*a28cd43dSSascha Wildner }
1480*a28cd43dSSascha Wildner 
ZSTD_DCtx_setParameter(ZSTD_DCtx * dctx,ZSTD_dParameter dParam,int value)1481*a28cd43dSSascha Wildner size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value)
1482*a28cd43dSSascha Wildner {
1483*a28cd43dSSascha Wildner     RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
1484*a28cd43dSSascha Wildner     switch(dParam) {
1485*a28cd43dSSascha Wildner         case ZSTD_d_windowLogMax:
1486*a28cd43dSSascha Wildner             if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT;
1487*a28cd43dSSascha Wildner             CHECK_DBOUNDS(ZSTD_d_windowLogMax, value);
1488*a28cd43dSSascha Wildner             dctx->maxWindowSize = ((size_t)1) << value;
1489*a28cd43dSSascha Wildner             return 0;
1490*a28cd43dSSascha Wildner         case ZSTD_d_format:
1491*a28cd43dSSascha Wildner             CHECK_DBOUNDS(ZSTD_d_format, value);
1492*a28cd43dSSascha Wildner             dctx->format = (ZSTD_format_e)value;
1493*a28cd43dSSascha Wildner             return 0;
1494*a28cd43dSSascha Wildner         case ZSTD_d_stableOutBuffer:
1495*a28cd43dSSascha Wildner             CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value);
1496*a28cd43dSSascha Wildner             dctx->outBufferMode = (ZSTD_bufferMode_e)value;
1497*a28cd43dSSascha Wildner             return 0;
1498*a28cd43dSSascha Wildner         case ZSTD_d_forceIgnoreChecksum:
1499*a28cd43dSSascha Wildner             CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value);
1500*a28cd43dSSascha Wildner             dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value;
1501*a28cd43dSSascha Wildner             return 0;
1502*a28cd43dSSascha Wildner         default:;
1503*a28cd43dSSascha Wildner     }
1504*a28cd43dSSascha Wildner     RETURN_ERROR(parameter_unsupported, "");
1505*a28cd43dSSascha Wildner }
1506*a28cd43dSSascha Wildner 
ZSTD_DCtx_reset(ZSTD_DCtx * dctx,ZSTD_ResetDirective reset)1507*a28cd43dSSascha Wildner size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)
1508*a28cd43dSSascha Wildner {
1509*a28cd43dSSascha Wildner     if ( (reset == ZSTD_reset_session_only)
1510*a28cd43dSSascha Wildner       || (reset == ZSTD_reset_session_and_parameters) ) {
1511*a28cd43dSSascha Wildner         dctx->streamStage = zdss_init;
1512*a28cd43dSSascha Wildner         dctx->noForwardProgress = 0;
1513*a28cd43dSSascha Wildner     }
1514*a28cd43dSSascha Wildner     if ( (reset == ZSTD_reset_parameters)
1515*a28cd43dSSascha Wildner       || (reset == ZSTD_reset_session_and_parameters) ) {
1516*a28cd43dSSascha Wildner         RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");
1517*a28cd43dSSascha Wildner         ZSTD_clearDict(dctx);
1518*a28cd43dSSascha Wildner         ZSTD_DCtx_resetParameters(dctx);
1519*a28cd43dSSascha Wildner     }
1520*a28cd43dSSascha Wildner     return 0;
1521*a28cd43dSSascha Wildner }
1522*a28cd43dSSascha Wildner 
1523*a28cd43dSSascha Wildner 
ZSTD_sizeof_DStream(const ZSTD_DStream * dctx)1524*a28cd43dSSascha Wildner size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)
1525*a28cd43dSSascha Wildner {
1526*a28cd43dSSascha Wildner     return ZSTD_sizeof_DCtx(dctx);
1527*a28cd43dSSascha Wildner }
1528*a28cd43dSSascha Wildner 
ZSTD_decodingBufferSize_min(unsigned long long windowSize,unsigned long long frameContentSize)1529*a28cd43dSSascha Wildner size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
1530*a28cd43dSSascha Wildner {
1531*a28cd43dSSascha Wildner     size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
1532*a28cd43dSSascha Wildner     unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2);
1533*a28cd43dSSascha Wildner     unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);
1534*a28cd43dSSascha Wildner     size_t const minRBSize = (size_t) neededSize;
1535*a28cd43dSSascha Wildner     RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize,
1536*a28cd43dSSascha Wildner                     frameParameter_windowTooLarge, "");
1537*a28cd43dSSascha Wildner     return minRBSize;
1538*a28cd43dSSascha Wildner }
1539*a28cd43dSSascha Wildner 
ZSTD_estimateDStreamSize(size_t windowSize)1540*a28cd43dSSascha Wildner size_t ZSTD_estimateDStreamSize(size_t windowSize)
1541*a28cd43dSSascha Wildner {
1542*a28cd43dSSascha Wildner     size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
1543*a28cd43dSSascha Wildner     size_t const inBuffSize = blockSize;  /* no block can be larger */
1544*a28cd43dSSascha Wildner     size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN);
1545*a28cd43dSSascha Wildner     return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;
1546*a28cd43dSSascha Wildner }
1547*a28cd43dSSascha Wildner 
ZSTD_estimateDStreamSize_fromFrame(const void * src,size_t srcSize)1548*a28cd43dSSascha Wildner size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
1549*a28cd43dSSascha Wildner {
1550*a28cd43dSSascha Wildner     U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX;   /* note : should be user-selectable, but requires an additional parameter (or a dctx) */
1551*a28cd43dSSascha Wildner     ZSTD_frameHeader zfh;
1552*a28cd43dSSascha Wildner     size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);
1553*a28cd43dSSascha Wildner     if (ZSTD_isError(err)) return err;
1554*a28cd43dSSascha Wildner     RETURN_ERROR_IF(err>0, srcSize_wrong, "");
1555*a28cd43dSSascha Wildner     RETURN_ERROR_IF(zfh.windowSize > windowSizeMax,
1556*a28cd43dSSascha Wildner                     frameParameter_windowTooLarge, "");
1557*a28cd43dSSascha Wildner     return ZSTD_estimateDStreamSize((size_t)zfh.windowSize);
1558*a28cd43dSSascha Wildner }
1559*a28cd43dSSascha Wildner 
1560*a28cd43dSSascha Wildner 
1561*a28cd43dSSascha Wildner /* *****   Decompression   ***** */
1562*a28cd43dSSascha Wildner 
ZSTD_DCtx_isOverflow(ZSTD_DStream * zds,size_t const neededInBuffSize,size_t const neededOutBuffSize)1563*a28cd43dSSascha Wildner static int ZSTD_DCtx_isOverflow(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)
1564*a28cd43dSSascha Wildner {
1565*a28cd43dSSascha Wildner     return (zds->inBuffSize + zds->outBuffSize) >= (neededInBuffSize + neededOutBuffSize) * ZSTD_WORKSPACETOOLARGE_FACTOR;
1566*a28cd43dSSascha Wildner }
1567*a28cd43dSSascha Wildner 
ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream * zds,size_t const neededInBuffSize,size_t const neededOutBuffSize)1568*a28cd43dSSascha Wildner static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)
1569*a28cd43dSSascha Wildner {
1570*a28cd43dSSascha Wildner     if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize))
1571*a28cd43dSSascha Wildner         zds->oversizedDuration++;
1572*a28cd43dSSascha Wildner     else
1573*a28cd43dSSascha Wildner         zds->oversizedDuration = 0;
1574*a28cd43dSSascha Wildner }
1575*a28cd43dSSascha Wildner 
ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream * zds)1576*a28cd43dSSascha Wildner static int ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream* zds)
1577*a28cd43dSSascha Wildner {
1578*a28cd43dSSascha Wildner     return zds->oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION;
1579*a28cd43dSSascha Wildner }
1580*a28cd43dSSascha Wildner 
1581*a28cd43dSSascha Wildner /* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */
ZSTD_checkOutBuffer(ZSTD_DStream const * zds,ZSTD_outBuffer const * output)1582*a28cd43dSSascha Wildner static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* output)
1583*a28cd43dSSascha Wildner {
1584*a28cd43dSSascha Wildner     ZSTD_outBuffer const expect = zds->expectedOutBuffer;
1585*a28cd43dSSascha Wildner     /* No requirement when ZSTD_obm_stable is not enabled. */
1586*a28cd43dSSascha Wildner     if (zds->outBufferMode != ZSTD_bm_stable)
1587*a28cd43dSSascha Wildner         return 0;
1588*a28cd43dSSascha Wildner     /* Any buffer is allowed in zdss_init, this must be the same for every other call until
1589*a28cd43dSSascha Wildner      * the context is reset.
1590*a28cd43dSSascha Wildner      */
1591*a28cd43dSSascha Wildner     if (zds->streamStage == zdss_init)
1592*a28cd43dSSascha Wildner         return 0;
1593*a28cd43dSSascha Wildner     /* The buffer must match our expectation exactly. */
1594*a28cd43dSSascha Wildner     if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size)
1595*a28cd43dSSascha Wildner         return 0;
1596*a28cd43dSSascha Wildner     RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!");
1597*a28cd43dSSascha Wildner }
1598*a28cd43dSSascha Wildner 
1599*a28cd43dSSascha Wildner /* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream()
1600*a28cd43dSSascha Wildner  * and updates the stage and the output buffer state. This call is extracted so it can be
1601*a28cd43dSSascha Wildner  * used both when reading directly from the ZSTD_inBuffer, and in buffered input mode.
1602*a28cd43dSSascha Wildner  * NOTE: You must break after calling this function since the streamStage is modified.
1603*a28cd43dSSascha Wildner  */
ZSTD_decompressContinueStream(ZSTD_DStream * zds,char ** op,char * oend,void const * src,size_t srcSize)1604*a28cd43dSSascha Wildner static size_t ZSTD_decompressContinueStream(
1605*a28cd43dSSascha Wildner             ZSTD_DStream* zds, char** op, char* oend,
1606*a28cd43dSSascha Wildner             void const* src, size_t srcSize) {
1607*a28cd43dSSascha Wildner     int const isSkipFrame = ZSTD_isSkipFrame(zds);
1608*a28cd43dSSascha Wildner     if (zds->outBufferMode == ZSTD_bm_buffered) {
1609*a28cd43dSSascha Wildner         size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart;
1610*a28cd43dSSascha Wildner         size_t const decodedSize = ZSTD_decompressContinue(zds,
1611*a28cd43dSSascha Wildner                 zds->outBuff + zds->outStart, dstSize, src, srcSize);
1612*a28cd43dSSascha Wildner         FORWARD_IF_ERROR(decodedSize, "");
1613*a28cd43dSSascha Wildner         if (!decodedSize && !isSkipFrame) {
1614*a28cd43dSSascha Wildner             zds->streamStage = zdss_read;
1615*a28cd43dSSascha Wildner         } else {
1616*a28cd43dSSascha Wildner             zds->outEnd = zds->outStart + decodedSize;
1617*a28cd43dSSascha Wildner             zds->streamStage = zdss_flush;
1618*a28cd43dSSascha Wildner         }
1619*a28cd43dSSascha Wildner     } else {
1620*a28cd43dSSascha Wildner         /* Write directly into the output buffer */
1621*a28cd43dSSascha Wildner         size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op);
1622*a28cd43dSSascha Wildner         size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize);
1623*a28cd43dSSascha Wildner         FORWARD_IF_ERROR(decodedSize, "");
1624*a28cd43dSSascha Wildner         *op += decodedSize;
1625*a28cd43dSSascha Wildner         /* Flushing is not needed. */
1626*a28cd43dSSascha Wildner         zds->streamStage = zdss_read;
1627*a28cd43dSSascha Wildner         assert(*op <= oend);
1628*a28cd43dSSascha Wildner         assert(zds->outBufferMode == ZSTD_bm_stable);
1629*a28cd43dSSascha Wildner     }
1630*a28cd43dSSascha Wildner     return 0;
1631*a28cd43dSSascha Wildner }
1632*a28cd43dSSascha Wildner 
ZSTD_decompressStream(ZSTD_DStream * zds,ZSTD_outBuffer * output,ZSTD_inBuffer * input)1633*a28cd43dSSascha Wildner size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
1634*a28cd43dSSascha Wildner {
1635*a28cd43dSSascha Wildner     const char* const src = (const char*)input->src;
1636*a28cd43dSSascha Wildner     const char* const istart = input->pos != 0 ? src + input->pos : src;
1637*a28cd43dSSascha Wildner     const char* const iend = input->size != 0 ? src + input->size : src;
1638*a28cd43dSSascha Wildner     const char* ip = istart;
1639*a28cd43dSSascha Wildner     char* const dst = (char*)output->dst;
1640*a28cd43dSSascha Wildner     char* const ostart = output->pos != 0 ? dst + output->pos : dst;
1641*a28cd43dSSascha Wildner     char* const oend = output->size != 0 ? dst + output->size : dst;
1642*a28cd43dSSascha Wildner     char* op = ostart;
1643*a28cd43dSSascha Wildner     U32 someMoreWork = 1;
1644*a28cd43dSSascha Wildner 
1645*a28cd43dSSascha Wildner     DEBUGLOG(5, "ZSTD_decompressStream");
1646*a28cd43dSSascha Wildner     RETURN_ERROR_IF(
1647*a28cd43dSSascha Wildner         input->pos > input->size,
1648*a28cd43dSSascha Wildner         srcSize_wrong,
1649*a28cd43dSSascha Wildner         "forbidden. in: pos: %u   vs size: %u",
1650*a28cd43dSSascha Wildner         (U32)input->pos, (U32)input->size);
1651*a28cd43dSSascha Wildner     RETURN_ERROR_IF(
1652*a28cd43dSSascha Wildner         output->pos > output->size,
1653*a28cd43dSSascha Wildner         dstSize_tooSmall,
1654*a28cd43dSSascha Wildner         "forbidden. out: pos: %u   vs size: %u",
1655*a28cd43dSSascha Wildner         (U32)output->pos, (U32)output->size);
1656*a28cd43dSSascha Wildner     DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));
1657*a28cd43dSSascha Wildner     FORWARD_IF_ERROR(ZSTD_checkOutBuffer(zds, output), "");
1658*a28cd43dSSascha Wildner 
1659*a28cd43dSSascha Wildner     while (someMoreWork) {
1660*a28cd43dSSascha Wildner         switch(zds->streamStage)
1661*a28cd43dSSascha Wildner         {
1662*a28cd43dSSascha Wildner         case zdss_init :
1663*a28cd43dSSascha Wildner             DEBUGLOG(5, "stage zdss_init => transparent reset ");
1664*a28cd43dSSascha Wildner             zds->streamStage = zdss_loadHeader;
1665*a28cd43dSSascha Wildner             zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
1666*a28cd43dSSascha Wildner             zds->legacyVersion = 0;
1667*a28cd43dSSascha Wildner             zds->hostageByte = 0;
1668*a28cd43dSSascha Wildner             zds->expectedOutBuffer = *output;
1669*a28cd43dSSascha Wildner             /* fall-through */
1670*a28cd43dSSascha Wildner 
1671*a28cd43dSSascha Wildner         case zdss_loadHeader :
1672*a28cd43dSSascha Wildner             DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));
1673*a28cd43dSSascha Wildner #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
1674*a28cd43dSSascha Wildner             if (zds->legacyVersion) {
1675*a28cd43dSSascha Wildner                 RETURN_ERROR_IF(zds->staticSize, memory_allocation,
1676*a28cd43dSSascha Wildner                     "legacy support is incompatible with static dctx");
1677*a28cd43dSSascha Wildner                 {   size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);
1678*a28cd43dSSascha Wildner                     if (hint==0) zds->streamStage = zdss_init;
1679*a28cd43dSSascha Wildner                     return hint;
1680*a28cd43dSSascha Wildner             }   }
1681*a28cd43dSSascha Wildner #endif
1682*a28cd43dSSascha Wildner             {   size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
1683*a28cd43dSSascha Wildner                 DEBUGLOG(5, "header size : %u", (U32)hSize);
1684*a28cd43dSSascha Wildner                 if (ZSTD_isError(hSize)) {
1685*a28cd43dSSascha Wildner #if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
1686*a28cd43dSSascha Wildner                     U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);
1687*a28cd43dSSascha Wildner                     if (legacyVersion) {
1688*a28cd43dSSascha Wildner                         ZSTD_DDict const* const ddict = ZSTD_getDDict(zds);
1689*a28cd43dSSascha Wildner                         const void* const dict = ddict ? ZSTD_DDict_dictContent(ddict) : NULL;
1690*a28cd43dSSascha Wildner                         size_t const dictSize = ddict ? ZSTD_DDict_dictSize(ddict) : 0;
1691*a28cd43dSSascha Wildner                         DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion);
1692*a28cd43dSSascha Wildner                         RETURN_ERROR_IF(zds->staticSize, memory_allocation,
1693*a28cd43dSSascha Wildner                             "legacy support is incompatible with static dctx");
1694*a28cd43dSSascha Wildner                         FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext,
1695*a28cd43dSSascha Wildner                                     zds->previousLegacyVersion, legacyVersion,
1696*a28cd43dSSascha Wildner                                     dict, dictSize), "");
1697*a28cd43dSSascha Wildner                         zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;
1698*a28cd43dSSascha Wildner                         {   size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);
1699*a28cd43dSSascha Wildner                             if (hint==0) zds->streamStage = zdss_init;   /* or stay in stage zdss_loadHeader */
1700*a28cd43dSSascha Wildner                             return hint;
1701*a28cd43dSSascha Wildner                     }   }
1702*a28cd43dSSascha Wildner #endif
1703*a28cd43dSSascha Wildner                     return hSize;   /* error */
1704*a28cd43dSSascha Wildner                 }
1705*a28cd43dSSascha Wildner                 if (hSize != 0) {   /* need more input */
1706*a28cd43dSSascha Wildner                     size_t const toLoad = hSize - zds->lhSize;   /* if hSize!=0, hSize > zds->lhSize */
1707*a28cd43dSSascha Wildner                     size_t const remainingInput = (size_t)(iend-ip);
1708*a28cd43dSSascha Wildner                     assert(iend >= ip);
1709*a28cd43dSSascha Wildner                     if (toLoad > remainingInput) {   /* not enough input to load full header */
1710*a28cd43dSSascha Wildner                         if (remainingInput > 0) {
1711*a28cd43dSSascha Wildner                             ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);
1712*a28cd43dSSascha Wildner                             zds->lhSize += remainingInput;
1713*a28cd43dSSascha Wildner                         }
1714*a28cd43dSSascha Wildner                         input->pos = input->size;
1715*a28cd43dSSascha Wildner                         return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize;   /* remaining header bytes + next block header */
1716*a28cd43dSSascha Wildner                     }
1717*a28cd43dSSascha Wildner                     assert(ip != NULL);
1718*a28cd43dSSascha Wildner                     ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;
1719*a28cd43dSSascha Wildner                     break;
1720*a28cd43dSSascha Wildner             }   }
1721*a28cd43dSSascha Wildner 
1722*a28cd43dSSascha Wildner             /* check for single-pass mode opportunity */
1723*a28cd43dSSascha Wildner             if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
1724*a28cd43dSSascha Wildner                 && zds->fParams.frameType != ZSTD_skippableFrame
1725*a28cd43dSSascha Wildner                 && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
1726*a28cd43dSSascha Wildner                 size_t const cSize = ZSTD_findFrameCompressedSize(istart, (size_t)(iend-istart));
1727*a28cd43dSSascha Wildner                 if (cSize <= (size_t)(iend-istart)) {
1728*a28cd43dSSascha Wildner                     /* shortcut : using single-pass mode */
1729*a28cd43dSSascha Wildner                     size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds));
1730*a28cd43dSSascha Wildner                     if (ZSTD_isError(decompressedSize)) return decompressedSize;
1731*a28cd43dSSascha Wildner                     DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
1732*a28cd43dSSascha Wildner                     ip = istart + cSize;
1733*a28cd43dSSascha Wildner                     op += decompressedSize;
1734*a28cd43dSSascha Wildner                     zds->expected = 0;
1735*a28cd43dSSascha Wildner                     zds->streamStage = zdss_init;
1736*a28cd43dSSascha Wildner                     someMoreWork = 0;
1737*a28cd43dSSascha Wildner                     break;
1738*a28cd43dSSascha Wildner             }   }
1739*a28cd43dSSascha Wildner 
1740*a28cd43dSSascha Wildner             /* Check output buffer is large enough for ZSTD_odm_stable. */
1741*a28cd43dSSascha Wildner             if (zds->outBufferMode == ZSTD_bm_stable
1742*a28cd43dSSascha Wildner                 && zds->fParams.frameType != ZSTD_skippableFrame
1743*a28cd43dSSascha Wildner                 && zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
1744*a28cd43dSSascha Wildner                 && (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) {
1745*a28cd43dSSascha Wildner                 RETURN_ERROR(dstSize_tooSmall, "ZSTD_obm_stable passed but ZSTD_outBuffer is too small");
1746*a28cd43dSSascha Wildner             }
1747*a28cd43dSSascha Wildner 
1748*a28cd43dSSascha Wildner             /* Consume header (see ZSTDds_decodeFrameHeader) */
1749*a28cd43dSSascha Wildner             DEBUGLOG(4, "Consume header");
1750*a28cd43dSSascha Wildner             FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), "");
1751*a28cd43dSSascha Wildner 
1752*a28cd43dSSascha Wildner             if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {  /* skippable frame */
1753*a28cd43dSSascha Wildner                 zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);
1754*a28cd43dSSascha Wildner                 zds->stage = ZSTDds_skipFrame;
1755*a28cd43dSSascha Wildner             } else {
1756*a28cd43dSSascha Wildner                 FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), "");
1757*a28cd43dSSascha Wildner                 zds->expected = ZSTD_blockHeaderSize;
1758*a28cd43dSSascha Wildner                 zds->stage = ZSTDds_decodeBlockHeader;
1759*a28cd43dSSascha Wildner             }
1760*a28cd43dSSascha Wildner 
1761*a28cd43dSSascha Wildner             /* control buffer memory usage */
1762*a28cd43dSSascha Wildner             DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)",
1763*a28cd43dSSascha Wildner                         (U32)(zds->fParams.windowSize >>10),
1764*a28cd43dSSascha Wildner                         (U32)(zds->maxWindowSize >> 10) );
1765*a28cd43dSSascha Wildner             zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
1766*a28cd43dSSascha Wildner             RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize,
1767*a28cd43dSSascha Wildner                             frameParameter_windowTooLarge, "");
1768*a28cd43dSSascha Wildner 
1769*a28cd43dSSascha Wildner             /* Adapt buffer sizes to frame header instructions */
1770*a28cd43dSSascha Wildner             {   size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);
1771*a28cd43dSSascha Wildner                 size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered
1772*a28cd43dSSascha Wildner                         ? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize)
1773*a28cd43dSSascha Wildner                         : 0;
1774*a28cd43dSSascha Wildner 
1775*a28cd43dSSascha Wildner                 ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize);
1776*a28cd43dSSascha Wildner 
1777*a28cd43dSSascha Wildner                 {   int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize);
1778*a28cd43dSSascha Wildner                     int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds);
1779*a28cd43dSSascha Wildner 
1780*a28cd43dSSascha Wildner                     if (tooSmall || tooLarge) {
1781*a28cd43dSSascha Wildner                         size_t const bufferSize = neededInBuffSize + neededOutBuffSize;
1782*a28cd43dSSascha Wildner                         DEBUGLOG(4, "inBuff  : from %u to %u",
1783*a28cd43dSSascha Wildner                                     (U32)zds->inBuffSize, (U32)neededInBuffSize);
1784*a28cd43dSSascha Wildner                         DEBUGLOG(4, "outBuff : from %u to %u",
1785*a28cd43dSSascha Wildner                                     (U32)zds->outBuffSize, (U32)neededOutBuffSize);
1786*a28cd43dSSascha Wildner                         if (zds->staticSize) {  /* static DCtx */
1787*a28cd43dSSascha Wildner                             DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize);
1788*a28cd43dSSascha Wildner                             assert(zds->staticSize >= sizeof(ZSTD_DCtx));  /* controlled at init */
1789*a28cd43dSSascha Wildner                             RETURN_ERROR_IF(
1790*a28cd43dSSascha Wildner                                 bufferSize > zds->staticSize - sizeof(ZSTD_DCtx),
1791*a28cd43dSSascha Wildner                                 memory_allocation, "");
1792*a28cd43dSSascha Wildner                         } else {
1793*a28cd43dSSascha Wildner                             ZSTD_customFree(zds->inBuff, zds->customMem);
1794*a28cd43dSSascha Wildner                             zds->inBuffSize = 0;
1795*a28cd43dSSascha Wildner                             zds->outBuffSize = 0;
1796*a28cd43dSSascha Wildner                             zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem);
1797*a28cd43dSSascha Wildner                             RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, "");
1798*a28cd43dSSascha Wildner                         }
1799*a28cd43dSSascha Wildner                         zds->inBuffSize = neededInBuffSize;
1800*a28cd43dSSascha Wildner                         zds->outBuff = zds->inBuff + zds->inBuffSize;
1801*a28cd43dSSascha Wildner                         zds->outBuffSize = neededOutBuffSize;
1802*a28cd43dSSascha Wildner             }   }   }
1803*a28cd43dSSascha Wildner             zds->streamStage = zdss_read;
1804*a28cd43dSSascha Wildner             /* fall-through */
1805*a28cd43dSSascha Wildner 
1806*a28cd43dSSascha Wildner         case zdss_read:
1807*a28cd43dSSascha Wildner             DEBUGLOG(5, "stage zdss_read");
1808*a28cd43dSSascha Wildner             {   size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip));
1809*a28cd43dSSascha Wildner                 DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize);
1810*a28cd43dSSascha Wildner                 if (neededInSize==0) {  /* end of frame */
1811*a28cd43dSSascha Wildner                     zds->streamStage = zdss_init;
1812*a28cd43dSSascha Wildner                     someMoreWork = 0;
1813*a28cd43dSSascha Wildner                     break;
1814*a28cd43dSSascha Wildner                 }
1815*a28cd43dSSascha Wildner                 if ((size_t)(iend-ip) >= neededInSize) {  /* decode directly from src */
1816*a28cd43dSSascha Wildner                     FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), "");
1817*a28cd43dSSascha Wildner                     ip += neededInSize;
1818*a28cd43dSSascha Wildner                     /* Function modifies the stage so we must break */
1819*a28cd43dSSascha Wildner                     break;
1820*a28cd43dSSascha Wildner             }   }
1821*a28cd43dSSascha Wildner             if (ip==iend) { someMoreWork = 0; break; }   /* no more input */
1822*a28cd43dSSascha Wildner             zds->streamStage = zdss_load;
1823*a28cd43dSSascha Wildner             /* fall-through */
1824*a28cd43dSSascha Wildner 
1825*a28cd43dSSascha Wildner         case zdss_load:
1826*a28cd43dSSascha Wildner             {   size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
1827*a28cd43dSSascha Wildner                 size_t const toLoad = neededInSize - zds->inPos;
1828*a28cd43dSSascha Wildner                 int const isSkipFrame = ZSTD_isSkipFrame(zds);
1829*a28cd43dSSascha Wildner                 size_t loadedSize;
1830*a28cd43dSSascha Wildner                 /* At this point we shouldn't be decompressing a block that we can stream. */
1831*a28cd43dSSascha Wildner                 assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip));
1832*a28cd43dSSascha Wildner                 if (isSkipFrame) {
1833*a28cd43dSSascha Wildner                     loadedSize = MIN(toLoad, (size_t)(iend-ip));
1834*a28cd43dSSascha Wildner                 } else {
1835*a28cd43dSSascha Wildner                     RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos,
1836*a28cd43dSSascha Wildner                                     corruption_detected,
1837*a28cd43dSSascha Wildner                                     "should never happen");
1838*a28cd43dSSascha Wildner                     loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip));
1839*a28cd43dSSascha Wildner                 }
1840*a28cd43dSSascha Wildner                 ip += loadedSize;
1841*a28cd43dSSascha Wildner                 zds->inPos += loadedSize;
1842*a28cd43dSSascha Wildner                 if (loadedSize < toLoad) { someMoreWork = 0; break; }   /* not enough input, wait for more */
1843*a28cd43dSSascha Wildner 
1844*a28cd43dSSascha Wildner                 /* decode loaded input */
1845*a28cd43dSSascha Wildner                 zds->inPos = 0;   /* input is consumed */
1846*a28cd43dSSascha Wildner                 FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, zds->inBuff, neededInSize), "");
1847*a28cd43dSSascha Wildner                 /* Function modifies the stage so we must break */
1848*a28cd43dSSascha Wildner                 break;
1849*a28cd43dSSascha Wildner             }
1850*a28cd43dSSascha Wildner         case zdss_flush:
1851*a28cd43dSSascha Wildner             {   size_t const toFlushSize = zds->outEnd - zds->outStart;
1852*a28cd43dSSascha Wildner                 size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize);
1853*a28cd43dSSascha Wildner                 op += flushedSize;
1854*a28cd43dSSascha Wildner                 zds->outStart += flushedSize;
1855*a28cd43dSSascha Wildner                 if (flushedSize == toFlushSize) {  /* flush completed */
1856*a28cd43dSSascha Wildner                     zds->streamStage = zdss_read;
1857*a28cd43dSSascha Wildner                     if ( (zds->outBuffSize < zds->fParams.frameContentSize)
1858*a28cd43dSSascha Wildner                       && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) {
1859*a28cd43dSSascha Wildner                         DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)",
1860*a28cd43dSSascha Wildner                                 (int)(zds->outBuffSize - zds->outStart),
1861*a28cd43dSSascha Wildner                                 (U32)zds->fParams.blockSizeMax);
1862*a28cd43dSSascha Wildner                         zds->outStart = zds->outEnd = 0;
1863*a28cd43dSSascha Wildner                     }
1864*a28cd43dSSascha Wildner                     break;
1865*a28cd43dSSascha Wildner             }   }
1866*a28cd43dSSascha Wildner             /* cannot complete flush */
1867*a28cd43dSSascha Wildner             someMoreWork = 0;
1868*a28cd43dSSascha Wildner             break;
1869*a28cd43dSSascha Wildner 
1870*a28cd43dSSascha Wildner         default:
1871*a28cd43dSSascha Wildner             assert(0);    /* impossible */
1872*a28cd43dSSascha Wildner             RETURN_ERROR(GENERIC, "impossible to reach");   /* some compiler require default to do something */
1873*a28cd43dSSascha Wildner     }   }
1874*a28cd43dSSascha Wildner 
1875*a28cd43dSSascha Wildner     /* result */
1876*a28cd43dSSascha Wildner     input->pos = (size_t)(ip - (const char*)(input->src));
1877*a28cd43dSSascha Wildner     output->pos = (size_t)(op - (char*)(output->dst));
1878*a28cd43dSSascha Wildner 
1879*a28cd43dSSascha Wildner     /* Update the expected output buffer for ZSTD_obm_stable. */
1880*a28cd43dSSascha Wildner     zds->expectedOutBuffer = *output;
1881*a28cd43dSSascha Wildner 
1882*a28cd43dSSascha Wildner     if ((ip==istart) && (op==ostart)) {  /* no forward progress */
1883*a28cd43dSSascha Wildner         zds->noForwardProgress ++;
1884*a28cd43dSSascha Wildner         if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {
1885*a28cd43dSSascha Wildner             RETURN_ERROR_IF(op==oend, dstSize_tooSmall, "");
1886*a28cd43dSSascha Wildner             RETURN_ERROR_IF(ip==iend, srcSize_wrong, "");
1887*a28cd43dSSascha Wildner             assert(0);
1888*a28cd43dSSascha Wildner         }
1889*a28cd43dSSascha Wildner     } else {
1890*a28cd43dSSascha Wildner         zds->noForwardProgress = 0;
1891*a28cd43dSSascha Wildner     }
1892*a28cd43dSSascha Wildner     {   size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds);
1893*a28cd43dSSascha Wildner         if (!nextSrcSizeHint) {   /* frame fully decoded */
1894*a28cd43dSSascha Wildner             if (zds->outEnd == zds->outStart) {  /* output fully flushed */
1895*a28cd43dSSascha Wildner                 if (zds->hostageByte) {
1896*a28cd43dSSascha Wildner                     if (input->pos >= input->size) {
1897*a28cd43dSSascha Wildner                         /* can't release hostage (not present) */
1898*a28cd43dSSascha Wildner                         zds->streamStage = zdss_read;
1899*a28cd43dSSascha Wildner                         return 1;
1900*a28cd43dSSascha Wildner                     }
1901*a28cd43dSSascha Wildner                     input->pos++;  /* release hostage */
1902*a28cd43dSSascha Wildner                 }   /* zds->hostageByte */
1903*a28cd43dSSascha Wildner                 return 0;
1904*a28cd43dSSascha Wildner             }  /* zds->outEnd == zds->outStart */
1905*a28cd43dSSascha Wildner             if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */
1906*a28cd43dSSascha Wildner                 input->pos--;   /* note : pos > 0, otherwise, impossible to finish reading last block */
1907*a28cd43dSSascha Wildner                 zds->hostageByte=1;
1908*a28cd43dSSascha Wildner             }
1909*a28cd43dSSascha Wildner             return 1;
1910*a28cd43dSSascha Wildner         }  /* nextSrcSizeHint==0 */
1911*a28cd43dSSascha Wildner         nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block);   /* preload header of next block */
1912*a28cd43dSSascha Wildner         assert(zds->inPos <= nextSrcSizeHint);
1913*a28cd43dSSascha Wildner         nextSrcSizeHint -= zds->inPos;   /* part already loaded*/
1914*a28cd43dSSascha Wildner         return nextSrcSizeHint;
1915*a28cd43dSSascha Wildner     }
1916*a28cd43dSSascha Wildner }
1917*a28cd43dSSascha Wildner 
ZSTD_decompressStream_simpleArgs(ZSTD_DCtx * dctx,void * dst,size_t dstCapacity,size_t * dstPos,const void * src,size_t srcSize,size_t * srcPos)1918*a28cd43dSSascha Wildner size_t ZSTD_decompressStream_simpleArgs (
1919*a28cd43dSSascha Wildner                             ZSTD_DCtx* dctx,
1920*a28cd43dSSascha Wildner                             void* dst, size_t dstCapacity, size_t* dstPos,
1921*a28cd43dSSascha Wildner                       const void* src, size_t srcSize, size_t* srcPos)
1922*a28cd43dSSascha Wildner {
1923*a28cd43dSSascha Wildner     ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
1924*a28cd43dSSascha Wildner     ZSTD_inBuffer  input  = { src, srcSize, *srcPos };
1925*a28cd43dSSascha Wildner     /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
1926*a28cd43dSSascha Wildner     size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);
1927*a28cd43dSSascha Wildner     *dstPos = output.pos;
1928*a28cd43dSSascha Wildner     *srcPos = input.pos;
1929*a28cd43dSSascha Wildner     return cErr;
1930*a28cd43dSSascha Wildner }
1931