blob: e42872ad96abe3daa639c1c19238899559fd1ae3 [file] [log] [blame]
Scott Bakereee8dd82019-09-24 12:52:34 -07001/*
2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under both the BSD-style license (found in the
6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7 * in the COPYING file in the root directory of this source tree).
8 * You may select, at your option, one of the above-listed licenses.
9 */
10
11
12/* ***************************************************************
13* Tuning parameters
14*****************************************************************/
15/*!
16 * HEAPMODE :
17 * Select how default decompression function ZSTD_decompress() allocates its context,
18 * on stack (0), or into heap (1, default; requires malloc()).
19 * Note that functions with explicit context such as ZSTD_decompressDCtx() are unaffected.
20 */
21#ifndef ZSTD_HEAPMODE
22# define ZSTD_HEAPMODE 1
23#endif
24
25/*!
26* LEGACY_SUPPORT :
27* if set to 1+, ZSTD_decompress() can decode older formats (v0.1+)
28*/
29#ifndef ZSTD_LEGACY_SUPPORT
30# define ZSTD_LEGACY_SUPPORT 0
31#endif
32
33/*!
34 * MAXWINDOWSIZE_DEFAULT :
35 * maximum window size accepted by DStream __by default__.
36 * Frames requiring more memory will be rejected.
37 * It's possible to set a different limit using ZSTD_DCtx_setMaxWindowSize().
38 */
39#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT
Scott Baker611f6bd2019-10-18 13:45:19 -070040# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1)
41#endif
42
43/*!
44 * NO_FORWARD_PROGRESS_MAX :
45 * maximum allowed nb of calls to ZSTD_decompressStream()
46 * without any forward progress
47 * (defined as: no byte read from input, and no byte flushed to output)
48 * before triggering an error.
49 */
50#ifndef ZSTD_NO_FORWARD_PROGRESS_MAX
51# define ZSTD_NO_FORWARD_PROGRESS_MAX 16
Scott Bakereee8dd82019-09-24 12:52:34 -070052#endif
53
54
55/*-*******************************************************
56* Dependencies
57*********************************************************/
58#include <string.h> /* memcpy, memmove, memset */
Scott Baker611f6bd2019-10-18 13:45:19 -070059#include "cpu.h" /* bmi2 */
Scott Bakereee8dd82019-09-24 12:52:34 -070060#include "mem.h" /* low level memory routines */
61#define FSE_STATIC_LINKING_ONLY
62#include "fse.h"
63#define HUF_STATIC_LINKING_ONLY
64#include "huf.h"
Scott Baker611f6bd2019-10-18 13:45:19 -070065#include "zstd_internal.h" /* blockProperties_t */
66#include "zstd_decompress_internal.h" /* ZSTD_DCtx */
67#include "zstd_ddict.h" /* ZSTD_DDictDictContent */
68#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */
Scott Bakereee8dd82019-09-24 12:52:34 -070069
70#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
71# include "zstd_legacy.h"
72#endif
73
74
Scott Bakereee8dd82019-09-24 12:52:34 -070075/*-*************************************************************
76* Context management
77***************************************************************/
Scott Bakereee8dd82019-09-24 12:52:34 -070078size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx)
79{
80 if (dctx==NULL) return 0; /* support sizeof NULL */
81 return sizeof(*dctx)
82 + ZSTD_sizeof_DDict(dctx->ddictLocal)
83 + dctx->inBuffSize + dctx->outBuffSize;
84}
85
86size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }
87
88
89static size_t ZSTD_startingInputLength(ZSTD_format_e format)
90{
91 size_t const startingInputLength = (format==ZSTD_f_zstd1_magicless) ?
Scott Baker611f6bd2019-10-18 13:45:19 -070092 ZSTD_FRAMEHEADERSIZE_PREFIX - ZSTD_FRAMEIDSIZE :
93 ZSTD_FRAMEHEADERSIZE_PREFIX;
Scott Bakereee8dd82019-09-24 12:52:34 -070094 ZSTD_STATIC_ASSERT(ZSTD_FRAMEHEADERSIZE_PREFIX >= ZSTD_FRAMEIDSIZE);
95 /* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */
96 assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) );
97 return startingInputLength;
98}
99
100static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)
101{
102 dctx->format = ZSTD_f_zstd1; /* ZSTD_decompressBegin() invokes ZSTD_startingInputLength() with argument dctx->format */
103 dctx->staticSize = 0;
104 dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
105 dctx->ddict = NULL;
106 dctx->ddictLocal = NULL;
Scott Baker611f6bd2019-10-18 13:45:19 -0700107 dctx->dictEnd = NULL;
108 dctx->ddictIsCold = 0;
109 dctx->dictUses = ZSTD_dont_use;
Scott Bakereee8dd82019-09-24 12:52:34 -0700110 dctx->inBuff = NULL;
111 dctx->inBuffSize = 0;
112 dctx->outBuffSize = 0;
113 dctx->streamStage = zdss_init;
Scott Baker611f6bd2019-10-18 13:45:19 -0700114 dctx->legacyContext = NULL;
115 dctx->previousLegacyVersion = 0;
116 dctx->noForwardProgress = 0;
Scott Bakereee8dd82019-09-24 12:52:34 -0700117 dctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
118}
119
120ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)
121{
122 ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace;
123
124 if ((size_t)workspace & 7) return NULL; /* 8-aligned */
125 if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */
126
127 ZSTD_initDCtx_internal(dctx);
128 dctx->staticSize = workspaceSize;
129 dctx->inBuff = (char*)(dctx+1);
130 return dctx;
131}
132
133ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)
134{
135 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
136
137 { ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_malloc(sizeof(*dctx), customMem);
138 if (!dctx) return NULL;
139 dctx->customMem = customMem;
Scott Bakereee8dd82019-09-24 12:52:34 -0700140 ZSTD_initDCtx_internal(dctx);
141 return dctx;
142 }
143}
144
145ZSTD_DCtx* ZSTD_createDCtx(void)
146{
147 DEBUGLOG(3, "ZSTD_createDCtx");
148 return ZSTD_createDCtx_advanced(ZSTD_defaultCMem);
149}
150
Scott Baker611f6bd2019-10-18 13:45:19 -0700151static void ZSTD_clearDict(ZSTD_DCtx* dctx)
152{
153 ZSTD_freeDDict(dctx->ddictLocal);
154 dctx->ddictLocal = NULL;
155 dctx->ddict = NULL;
156 dctx->dictUses = ZSTD_dont_use;
157}
158
Scott Bakereee8dd82019-09-24 12:52:34 -0700159size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)
160{
161 if (dctx==NULL) return 0; /* support free on NULL */
Scott Baker611f6bd2019-10-18 13:45:19 -0700162 RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx");
Scott Bakereee8dd82019-09-24 12:52:34 -0700163 { ZSTD_customMem const cMem = dctx->customMem;
Scott Baker611f6bd2019-10-18 13:45:19 -0700164 ZSTD_clearDict(dctx);
Scott Bakereee8dd82019-09-24 12:52:34 -0700165 ZSTD_free(dctx->inBuff, cMem);
166 dctx->inBuff = NULL;
167#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
168 if (dctx->legacyContext)
169 ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);
170#endif
171 ZSTD_free(dctx, cMem);
172 return 0;
173 }
174}
175
176/* no longer useful */
177void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)
178{
179 size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx);
180 memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */
181}
182
183
184/*-*************************************************************
185 * Frame header decoding
186 ***************************************************************/
187
188/*! ZSTD_isFrame() :
189 * Tells if the content of `buffer` starts with a valid Frame Identifier.
190 * Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.
191 * Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.
192 * Note 3 : Skippable Frame Identifiers are considered valid. */
193unsigned ZSTD_isFrame(const void* buffer, size_t size)
194{
Scott Baker611f6bd2019-10-18 13:45:19 -0700195 if (size < ZSTD_FRAMEIDSIZE) return 0;
Scott Bakereee8dd82019-09-24 12:52:34 -0700196 { U32 const magic = MEM_readLE32(buffer);
197 if (magic == ZSTD_MAGICNUMBER) return 1;
Scott Baker611f6bd2019-10-18 13:45:19 -0700198 if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;
Scott Bakereee8dd82019-09-24 12:52:34 -0700199 }
200#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
201 if (ZSTD_isLegacy(buffer, size)) return 1;
202#endif
203 return 0;
204}
205
206/** ZSTD_frameHeaderSize_internal() :
207 * srcSize must be large enough to reach header size fields.
208 * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless.
209 * @return : size of the Frame Header
210 * or an error code, which can be tested with ZSTD_isError() */
211static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)
212{
213 size_t const minInputSize = ZSTD_startingInputLength(format);
Scott Baker611f6bd2019-10-18 13:45:19 -0700214 RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong);
Scott Bakereee8dd82019-09-24 12:52:34 -0700215
216 { BYTE const fhd = ((const BYTE*)src)[minInputSize-1];
217 U32 const dictID= fhd & 3;
218 U32 const singleSegment = (fhd >> 5) & 1;
219 U32 const fcsId = fhd >> 6;
220 return minInputSize + !singleSegment
221 + ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]
222 + (singleSegment && !fcsId);
223 }
224}
225
226/** ZSTD_frameHeaderSize() :
227 * srcSize must be >= ZSTD_frameHeaderSize_prefix.
Scott Baker611f6bd2019-10-18 13:45:19 -0700228 * @return : size of the Frame Header,
229 * or an error code (if srcSize is too small) */
Scott Bakereee8dd82019-09-24 12:52:34 -0700230size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)
231{
232 return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);
233}
234
235
Scott Baker611f6bd2019-10-18 13:45:19 -0700236/** ZSTD_getFrameHeader_advanced() :
Scott Bakereee8dd82019-09-24 12:52:34 -0700237 * decode Frame Header, or require larger `srcSize`.
238 * note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless
239 * @return : 0, `zfhPtr` is correctly filled,
240 * >0, `srcSize` is too small, value is wanted `srcSize` amount,
241 * or an error code, which can be tested using ZSTD_isError() */
Scott Baker611f6bd2019-10-18 13:45:19 -0700242size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)
Scott Bakereee8dd82019-09-24 12:52:34 -0700243{
244 const BYTE* ip = (const BYTE*)src;
245 size_t const minInputSize = ZSTD_startingInputLength(format);
246
Scott Baker611f6bd2019-10-18 13:45:19 -0700247 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 */
Scott Bakereee8dd82019-09-24 12:52:34 -0700248 if (srcSize < minInputSize) return minInputSize;
Scott Baker611f6bd2019-10-18 13:45:19 -0700249 RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter");
Scott Bakereee8dd82019-09-24 12:52:34 -0700250
251 if ( (format != ZSTD_f_zstd1_magicless)
252 && (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {
Scott Baker611f6bd2019-10-18 13:45:19 -0700253 if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
Scott Bakereee8dd82019-09-24 12:52:34 -0700254 /* skippable frame */
Scott Baker611f6bd2019-10-18 13:45:19 -0700255 if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)
256 return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */
Scott Bakereee8dd82019-09-24 12:52:34 -0700257 memset(zfhPtr, 0, sizeof(*zfhPtr));
Scott Baker611f6bd2019-10-18 13:45:19 -0700258 zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);
Scott Bakereee8dd82019-09-24 12:52:34 -0700259 zfhPtr->frameType = ZSTD_skippableFrame;
260 return 0;
261 }
Scott Baker611f6bd2019-10-18 13:45:19 -0700262 RETURN_ERROR(prefix_unknown);
Scott Bakereee8dd82019-09-24 12:52:34 -0700263 }
264
265 /* ensure there is enough `srcSize` to fully read/decode frame header */
266 { size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format);
267 if (srcSize < fhsize) return fhsize;
268 zfhPtr->headerSize = (U32)fhsize;
269 }
270
271 { BYTE const fhdByte = ip[minInputSize-1];
272 size_t pos = minInputSize;
273 U32 const dictIDSizeCode = fhdByte&3;
274 U32 const checksumFlag = (fhdByte>>2)&1;
275 U32 const singleSegment = (fhdByte>>5)&1;
276 U32 const fcsID = fhdByte>>6;
277 U64 windowSize = 0;
278 U32 dictID = 0;
279 U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN;
Scott Baker611f6bd2019-10-18 13:45:19 -0700280 RETURN_ERROR_IF((fhdByte & 0x08) != 0, frameParameter_unsupported,
281 "reserved bits, must be zero");
Scott Bakereee8dd82019-09-24 12:52:34 -0700282
283 if (!singleSegment) {
284 BYTE const wlByte = ip[pos++];
285 U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;
Scott Baker611f6bd2019-10-18 13:45:19 -0700286 RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge);
Scott Bakereee8dd82019-09-24 12:52:34 -0700287 windowSize = (1ULL << windowLog);
288 windowSize += (windowSize >> 3) * (wlByte&7);
289 }
290 switch(dictIDSizeCode)
291 {
292 default: assert(0); /* impossible */
293 case 0 : break;
294 case 1 : dictID = ip[pos]; pos++; break;
295 case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break;
296 case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break;
297 }
298 switch(fcsID)
299 {
300 default: assert(0); /* impossible */
301 case 0 : if (singleSegment) frameContentSize = ip[pos]; break;
302 case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;
303 case 2 : frameContentSize = MEM_readLE32(ip+pos); break;
304 case 3 : frameContentSize = MEM_readLE64(ip+pos); break;
305 }
306 if (singleSegment) windowSize = frameContentSize;
307
308 zfhPtr->frameType = ZSTD_frame;
309 zfhPtr->frameContentSize = frameContentSize;
310 zfhPtr->windowSize = windowSize;
311 zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
312 zfhPtr->dictID = dictID;
313 zfhPtr->checksumFlag = checksumFlag;
314 }
315 return 0;
316}
317
318/** ZSTD_getFrameHeader() :
319 * decode Frame Header, or require larger `srcSize`.
320 * note : this function does not consume input, it only reads it.
321 * @return : 0, `zfhPtr` is correctly filled,
322 * >0, `srcSize` is too small, value is wanted `srcSize` amount,
323 * or an error code, which can be tested using ZSTD_isError() */
324size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)
325{
Scott Baker611f6bd2019-10-18 13:45:19 -0700326 return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);
Scott Bakereee8dd82019-09-24 12:52:34 -0700327}
328
329
330/** ZSTD_getFrameContentSize() :
331 * compatible with legacy mode
332 * @return : decompressed size of the single frame pointed to be `src` if known, otherwise
333 * - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined
334 * - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */
335unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)
336{
337#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
338 if (ZSTD_isLegacy(src, srcSize)) {
339 unsigned long long const ret = ZSTD_getDecompressedSize_legacy(src, srcSize);
340 return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret;
341 }
342#endif
343 { ZSTD_frameHeader zfh;
344 if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0)
345 return ZSTD_CONTENTSIZE_ERROR;
346 if (zfh.frameType == ZSTD_skippableFrame) {
347 return 0;
348 } else {
349 return zfh.frameContentSize;
350 } }
351}
352
Scott Baker611f6bd2019-10-18 13:45:19 -0700353static size_t readSkippableFrameSize(void const* src, size_t srcSize)
354{
355 size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE;
356 U32 sizeU32;
357
358 RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong);
359
360 sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);
361 RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32,
362 frameParameter_unsupported);
363 {
364 size_t const skippableSize = skippableHeaderSize + sizeU32;
365 RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong);
366 return skippableSize;
367 }
368}
369
Scott Bakereee8dd82019-09-24 12:52:34 -0700370/** ZSTD_findDecompressedSize() :
371 * compatible with legacy mode
372 * `srcSize` must be the exact length of some number of ZSTD compressed and/or
373 * skippable frames
374 * @return : decompressed size of the frames contained */
375unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)
376{
377 unsigned long long totalDstSize = 0;
378
Scott Baker611f6bd2019-10-18 13:45:19 -0700379 while (srcSize >= ZSTD_FRAMEHEADERSIZE_PREFIX) {
Scott Bakereee8dd82019-09-24 12:52:34 -0700380 U32 const magicNumber = MEM_readLE32(src);
381
Scott Baker611f6bd2019-10-18 13:45:19 -0700382 if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
383 size_t const skippableSize = readSkippableFrameSize(src, srcSize);
384 if (ZSTD_isError(skippableSize)) {
Scott Bakereee8dd82019-09-24 12:52:34 -0700385 return ZSTD_CONTENTSIZE_ERROR;
386 }
Scott Baker611f6bd2019-10-18 13:45:19 -0700387 assert(skippableSize <= srcSize);
Scott Bakereee8dd82019-09-24 12:52:34 -0700388
389 src = (const BYTE *)src + skippableSize;
390 srcSize -= skippableSize;
391 continue;
392 }
393
394 { unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
395 if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret;
396
397 /* check for overflow */
398 if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR;
399 totalDstSize += ret;
400 }
401 { size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);
402 if (ZSTD_isError(frameSrcSize)) {
403 return ZSTD_CONTENTSIZE_ERROR;
404 }
405
406 src = (const BYTE *)src + frameSrcSize;
407 srcSize -= frameSrcSize;
408 }
409 } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
410
411 if (srcSize) return ZSTD_CONTENTSIZE_ERROR;
412
413 return totalDstSize;
414}
415
416/** ZSTD_getDecompressedSize() :
Scott Baker611f6bd2019-10-18 13:45:19 -0700417 * compatible with legacy mode
418 * @return : decompressed size if known, 0 otherwise
419 note : 0 can mean any of the following :
Scott Bakereee8dd82019-09-24 12:52:34 -0700420 - frame content is empty
421 - decompressed size field is not present in frame header
422 - frame header unknown / not supported
423 - frame header not complete (`srcSize` too small) */
424unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)
425{
426 unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);
427 ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN);
428 return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret;
429}
430
431
432/** ZSTD_decodeFrameHeader() :
Scott Baker611f6bd2019-10-18 13:45:19 -0700433 * `headerSize` must be the size provided by ZSTD_frameHeaderSize().
434 * @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */
Scott Bakereee8dd82019-09-24 12:52:34 -0700435static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)
436{
Scott Baker611f6bd2019-10-18 13:45:19 -0700437 size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);
Scott Bakereee8dd82019-09-24 12:52:34 -0700438 if (ZSTD_isError(result)) return result; /* invalid header */
Scott Baker611f6bd2019-10-18 13:45:19 -0700439 RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small");
440#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
441 /* Skip the dictID check in fuzzing mode, because it makes the search
442 * harder.
443 */
444 RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID),
445 dictionary_wrong);
446#endif
Scott Bakereee8dd82019-09-24 12:52:34 -0700447 if (dctx->fParams.checksumFlag) XXH64_reset(&dctx->xxhState, 0);
448 return 0;
449}
450
Scott Baker611f6bd2019-10-18 13:45:19 -0700451static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret)
Scott Bakereee8dd82019-09-24 12:52:34 -0700452{
Scott Baker611f6bd2019-10-18 13:45:19 -0700453 ZSTD_frameSizeInfo frameSizeInfo;
454 frameSizeInfo.compressedSize = ret;
455 frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR;
456 return frameSizeInfo;
Scott Bakereee8dd82019-09-24 12:52:34 -0700457}
458
Scott Baker611f6bd2019-10-18 13:45:19 -0700459static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize)
Scott Bakereee8dd82019-09-24 12:52:34 -0700460{
Scott Baker611f6bd2019-10-18 13:45:19 -0700461 ZSTD_frameSizeInfo frameSizeInfo;
462 memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));
Scott Bakereee8dd82019-09-24 12:52:34 -0700463
Scott Baker611f6bd2019-10-18 13:45:19 -0700464#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
465 if (ZSTD_isLegacy(src, srcSize))
466 return ZSTD_findFrameSizeInfoLegacy(src, srcSize);
Scott Bakereee8dd82019-09-24 12:52:34 -0700467#endif
468
Scott Baker611f6bd2019-10-18 13:45:19 -0700469 if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE)
470 && (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
471 frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize);
472 assert(ZSTD_isError(frameSizeInfo.compressedSize) ||
473 frameSizeInfo.compressedSize <= srcSize);
474 return frameSizeInfo;
475 } else {
476 const BYTE* ip = (const BYTE*)src;
477 const BYTE* const ipstart = ip;
478 size_t remainingSize = srcSize;
479 size_t nbBlocks = 0;
480 ZSTD_frameHeader zfh;
Scott Bakereee8dd82019-09-24 12:52:34 -0700481
Scott Baker611f6bd2019-10-18 13:45:19 -0700482 /* Extract Frame Header */
483 { size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize);
484 if (ZSTD_isError(ret))
485 return ZSTD_errorFrameSizeInfo(ret);
486 if (ret > 0)
487 return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));
Scott Bakereee8dd82019-09-24 12:52:34 -0700488 }
489
Scott Baker611f6bd2019-10-18 13:45:19 -0700490 ip += zfh.headerSize;
491 remainingSize -= zfh.headerSize;
492
493 /* Iterate over each block */
494 while (1) {
495 blockProperties_t blockProperties;
496 size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);
497 if (ZSTD_isError(cBlockSize))
498 return ZSTD_errorFrameSizeInfo(cBlockSize);
499
500 if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)
501 return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));
502
503 ip += ZSTD_blockHeaderSize + cBlockSize;
504 remainingSize -= ZSTD_blockHeaderSize + cBlockSize;
505 nbBlocks++;
506
507 if (blockProperties.lastBlock) break;
508 }
509
510 /* Final frame content checksum */
511 if (zfh.checksumFlag) {
512 if (remainingSize < 4)
513 return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));
514 ip += 4;
515 }
516
517 frameSizeInfo.compressedSize = ip - ipstart;
518 frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN)
519 ? zfh.frameContentSize
520 : nbBlocks * zfh.blockSizeMax;
521 return frameSizeInfo;
Scott Bakereee8dd82019-09-24 12:52:34 -0700522 }
523}
524
Scott Bakereee8dd82019-09-24 12:52:34 -0700525/** ZSTD_findFrameCompressedSize() :
526 * compatible with legacy mode
527 * `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame
528 * `srcSize` must be at least as large as the frame contained
529 * @return : the compressed size of the frame starting at `src` */
530size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)
531{
Scott Baker611f6bd2019-10-18 13:45:19 -0700532 ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
533 return frameSizeInfo.compressedSize;
534}
Scott Bakereee8dd82019-09-24 12:52:34 -0700535
Scott Baker611f6bd2019-10-18 13:45:19 -0700536/** ZSTD_decompressBound() :
537 * compatible with legacy mode
538 * `src` must point to the start of a ZSTD frame or a skippeable frame
539 * `srcSize` must be at least as large as the frame contained
540 * @return : the maximum decompressed size of the compressed source
541 */
542unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)
543{
544 unsigned long long bound = 0;
545 /* Iterate over each frame */
546 while (srcSize > 0) {
547 ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);
548 size_t const compressedSize = frameSizeInfo.compressedSize;
549 unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;
550 if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)
551 return ZSTD_CONTENTSIZE_ERROR;
552 assert(srcSize >= compressedSize);
553 src = (const BYTE*)src + compressedSize;
554 srcSize -= compressedSize;
555 bound += decompressedBound;
556 }
557 return bound;
558}
Scott Bakereee8dd82019-09-24 12:52:34 -0700559
Scott Bakereee8dd82019-09-24 12:52:34 -0700560
Scott Baker611f6bd2019-10-18 13:45:19 -0700561/*-*************************************************************
562 * Frame decoding
563 ***************************************************************/
Scott Bakereee8dd82019-09-24 12:52:34 -0700564
Scott Bakereee8dd82019-09-24 12:52:34 -0700565
Scott Baker611f6bd2019-10-18 13:45:19 -0700566void ZSTD_checkContinuity(ZSTD_DCtx* dctx, const void* dst)
567{
568 if (dst != dctx->previousDstEnd) { /* not contiguous */
569 dctx->dictEnd = dctx->previousDstEnd;
570 dctx->virtualStart = (const char*)dst - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
571 dctx->prefixStart = dst;
572 dctx->previousDstEnd = dst;
Scott Bakereee8dd82019-09-24 12:52:34 -0700573 }
574}
575
Scott Baker611f6bd2019-10-18 13:45:19 -0700576/** ZSTD_insertBlock() :
577 insert `src` block into `dctx` history. Useful to track uncompressed blocks. */
578size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)
579{
580 ZSTD_checkContinuity(dctx, blockStart);
581 dctx->previousDstEnd = (const char*)blockStart + blockSize;
582 return blockSize;
583}
584
585
586static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity,
587 const void* src, size_t srcSize)
588{
589 DEBUGLOG(5, "ZSTD_copyRawBlock");
590 if (dst == NULL) {
591 if (srcSize == 0) return 0;
592 RETURN_ERROR(dstBuffer_null);
593 }
594 RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall);
595 memcpy(dst, src, srcSize);
596 return srcSize;
597}
598
599static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,
600 BYTE b,
601 size_t regenSize)
602{
603 if (dst == NULL) {
604 if (regenSize == 0) return 0;
605 RETURN_ERROR(dstBuffer_null);
606 }
607 RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall);
608 memset(dst, b, regenSize);
609 return regenSize;
610}
611
612
Scott Bakereee8dd82019-09-24 12:52:34 -0700613/*! ZSTD_decompressFrame() :
Scott Baker611f6bd2019-10-18 13:45:19 -0700614 * @dctx must be properly initialized
615 * will update *srcPtr and *srcSizePtr,
616 * to make *srcPtr progress by one frame. */
Scott Bakereee8dd82019-09-24 12:52:34 -0700617static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,
618 void* dst, size_t dstCapacity,
619 const void** srcPtr, size_t *srcSizePtr)
620{
621 const BYTE* ip = (const BYTE*)(*srcPtr);
622 BYTE* const ostart = (BYTE* const)dst;
623 BYTE* const oend = ostart + dstCapacity;
624 BYTE* op = ostart;
Scott Baker611f6bd2019-10-18 13:45:19 -0700625 size_t remainingSrcSize = *srcSizePtr;
626
627 DEBUGLOG(4, "ZSTD_decompressFrame (srcSize:%i)", (int)*srcSizePtr);
Scott Bakereee8dd82019-09-24 12:52:34 -0700628
629 /* check */
Scott Baker611f6bd2019-10-18 13:45:19 -0700630 RETURN_ERROR_IF(
631 remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN+ZSTD_blockHeaderSize,
632 srcSize_wrong);
Scott Bakereee8dd82019-09-24 12:52:34 -0700633
634 /* Frame Header */
Scott Baker611f6bd2019-10-18 13:45:19 -0700635 { size_t const frameHeaderSize = ZSTD_frameHeaderSize(ip, ZSTD_FRAMEHEADERSIZE_PREFIX);
Scott Bakereee8dd82019-09-24 12:52:34 -0700636 if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;
Scott Baker611f6bd2019-10-18 13:45:19 -0700637 RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize,
638 srcSize_wrong);
639 FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) );
640 ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;
Scott Bakereee8dd82019-09-24 12:52:34 -0700641 }
642
643 /* Loop on each block */
644 while (1) {
645 size_t decodedSize;
646 blockProperties_t blockProperties;
Scott Baker611f6bd2019-10-18 13:45:19 -0700647 size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties);
Scott Bakereee8dd82019-09-24 12:52:34 -0700648 if (ZSTD_isError(cBlockSize)) return cBlockSize;
649
650 ip += ZSTD_blockHeaderSize;
Scott Baker611f6bd2019-10-18 13:45:19 -0700651 remainingSrcSize -= ZSTD_blockHeaderSize;
652 RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong);
Scott Bakereee8dd82019-09-24 12:52:34 -0700653
654 switch(blockProperties.blockType)
655 {
656 case bt_compressed:
657 decodedSize = ZSTD_decompressBlock_internal(dctx, op, oend-op, ip, cBlockSize, /* frame */ 1);
658 break;
659 case bt_raw :
660 decodedSize = ZSTD_copyRawBlock(op, oend-op, ip, cBlockSize);
661 break;
662 case bt_rle :
Scott Baker611f6bd2019-10-18 13:45:19 -0700663 decodedSize = ZSTD_setRleBlock(op, oend-op, *ip, blockProperties.origSize);
Scott Bakereee8dd82019-09-24 12:52:34 -0700664 break;
665 case bt_reserved :
666 default:
Scott Baker611f6bd2019-10-18 13:45:19 -0700667 RETURN_ERROR(corruption_detected);
Scott Bakereee8dd82019-09-24 12:52:34 -0700668 }
669
670 if (ZSTD_isError(decodedSize)) return decodedSize;
671 if (dctx->fParams.checksumFlag)
672 XXH64_update(&dctx->xxhState, op, decodedSize);
673 op += decodedSize;
674 ip += cBlockSize;
Scott Baker611f6bd2019-10-18 13:45:19 -0700675 remainingSrcSize -= cBlockSize;
Scott Bakereee8dd82019-09-24 12:52:34 -0700676 if (blockProperties.lastBlock) break;
677 }
678
679 if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {
Scott Baker611f6bd2019-10-18 13:45:19 -0700680 RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize,
681 corruption_detected);
682 }
Scott Bakereee8dd82019-09-24 12:52:34 -0700683 if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */
684 U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);
685 U32 checkRead;
Scott Baker611f6bd2019-10-18 13:45:19 -0700686 RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong);
Scott Bakereee8dd82019-09-24 12:52:34 -0700687 checkRead = MEM_readLE32(ip);
Scott Baker611f6bd2019-10-18 13:45:19 -0700688 RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong);
Scott Bakereee8dd82019-09-24 12:52:34 -0700689 ip += 4;
Scott Baker611f6bd2019-10-18 13:45:19 -0700690 remainingSrcSize -= 4;
Scott Bakereee8dd82019-09-24 12:52:34 -0700691 }
692
693 /* Allow caller to get size read */
694 *srcPtr = ip;
Scott Baker611f6bd2019-10-18 13:45:19 -0700695 *srcSizePtr = remainingSrcSize;
Scott Bakereee8dd82019-09-24 12:52:34 -0700696 return op-ostart;
697}
698
Scott Bakereee8dd82019-09-24 12:52:34 -0700699static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,
700 void* dst, size_t dstCapacity,
701 const void* src, size_t srcSize,
702 const void* dict, size_t dictSize,
703 const ZSTD_DDict* ddict)
704{
705 void* const dststart = dst;
Scott Baker611f6bd2019-10-18 13:45:19 -0700706 int moreThan1Frame = 0;
707
708 DEBUGLOG(5, "ZSTD_decompressMultiFrame");
Scott Bakereee8dd82019-09-24 12:52:34 -0700709 assert(dict==NULL || ddict==NULL); /* either dict or ddict set, not both */
710
711 if (ddict) {
Scott Baker611f6bd2019-10-18 13:45:19 -0700712 dict = ZSTD_DDict_dictContent(ddict);
713 dictSize = ZSTD_DDict_dictSize(ddict);
Scott Bakereee8dd82019-09-24 12:52:34 -0700714 }
715
Scott Baker611f6bd2019-10-18 13:45:19 -0700716 while (srcSize >= ZSTD_FRAMEHEADERSIZE_PREFIX) {
Scott Bakereee8dd82019-09-24 12:52:34 -0700717
718#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)
719 if (ZSTD_isLegacy(src, srcSize)) {
720 size_t decodedSize;
721 size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize);
722 if (ZSTD_isError(frameSize)) return frameSize;
Scott Baker611f6bd2019-10-18 13:45:19 -0700723 RETURN_ERROR_IF(dctx->staticSize, memory_allocation,
724 "legacy support is not compatible with static dctx");
Scott Bakereee8dd82019-09-24 12:52:34 -0700725
726 decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);
Scott Baker611f6bd2019-10-18 13:45:19 -0700727 if (ZSTD_isError(decodedSize)) return decodedSize;
Scott Bakereee8dd82019-09-24 12:52:34 -0700728
Scott Baker611f6bd2019-10-18 13:45:19 -0700729 assert(decodedSize <=- dstCapacity);
Scott Bakereee8dd82019-09-24 12:52:34 -0700730 dst = (BYTE*)dst + decodedSize;
731 dstCapacity -= decodedSize;
732
733 src = (const BYTE*)src + frameSize;
734 srcSize -= frameSize;
735
736 continue;
737 }
738#endif
739
Scott Baker611f6bd2019-10-18 13:45:19 -0700740 { U32 const magicNumber = MEM_readLE32(src);
741 DEBUGLOG(4, "reading magic number %08X (expecting %08X)",
742 (unsigned)magicNumber, ZSTD_MAGICNUMBER);
743 if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {
744 size_t const skippableSize = readSkippableFrameSize(src, srcSize);
745 FORWARD_IF_ERROR(skippableSize);
746 assert(skippableSize <= srcSize);
Scott Bakereee8dd82019-09-24 12:52:34 -0700747
748 src = (const BYTE *)src + skippableSize;
749 srcSize -= skippableSize;
750 continue;
Scott Baker611f6bd2019-10-18 13:45:19 -0700751 } }
Scott Bakereee8dd82019-09-24 12:52:34 -0700752
753 if (ddict) {
754 /* we were called from ZSTD_decompress_usingDDict */
Scott Baker611f6bd2019-10-18 13:45:19 -0700755 FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict));
Scott Bakereee8dd82019-09-24 12:52:34 -0700756 } else {
757 /* this will initialize correctly with no dict if dict == NULL, so
758 * use this in all cases but ddict */
Scott Baker611f6bd2019-10-18 13:45:19 -0700759 FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize));
Scott Bakereee8dd82019-09-24 12:52:34 -0700760 }
761 ZSTD_checkContinuity(dctx, dst);
762
763 { const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,
764 &src, &srcSize);
Scott Baker611f6bd2019-10-18 13:45:19 -0700765 RETURN_ERROR_IF(
766 (ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown)
767 && (moreThan1Frame==1),
768 srcSize_wrong,
769 "at least one frame successfully completed, but following "
770 "bytes are garbage: it's more likely to be a srcSize error, "
771 "specifying more bytes than compressed size of frame(s). This "
772 "error message replaces ERROR(prefix_unknown), which would be "
773 "confusing, as the first header is actually correct. Note that "
774 "one could be unlucky, it might be a corruption error instead, "
775 "happening right at the place where we expect zstd magic "
776 "bytes. But this is _much_ less likely than a srcSize field "
777 "error.");
Scott Bakereee8dd82019-09-24 12:52:34 -0700778 if (ZSTD_isError(res)) return res;
Scott Baker611f6bd2019-10-18 13:45:19 -0700779 assert(res <= dstCapacity);
Scott Bakereee8dd82019-09-24 12:52:34 -0700780 dst = (BYTE*)dst + res;
781 dstCapacity -= res;
782 }
Scott Baker611f6bd2019-10-18 13:45:19 -0700783 moreThan1Frame = 1;
Scott Bakereee8dd82019-09-24 12:52:34 -0700784 } /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */
785
Scott Baker611f6bd2019-10-18 13:45:19 -0700786 RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed");
Scott Bakereee8dd82019-09-24 12:52:34 -0700787
788 return (BYTE*)dst - (BYTE*)dststart;
789}
790
791size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,
792 void* dst, size_t dstCapacity,
793 const void* src, size_t srcSize,
794 const void* dict, size_t dictSize)
795{
796 return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL);
797}
798
799
Scott Baker611f6bd2019-10-18 13:45:19 -0700800static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx)
801{
802 switch (dctx->dictUses) {
803 default:
804 assert(0 /* Impossible */);
805 /* fall-through */
806 case ZSTD_dont_use:
807 ZSTD_clearDict(dctx);
808 return NULL;
809 case ZSTD_use_indefinitely:
810 return dctx->ddict;
811 case ZSTD_use_once:
812 dctx->dictUses = ZSTD_dont_use;
813 return dctx->ddict;
814 }
815}
816
Scott Bakereee8dd82019-09-24 12:52:34 -0700817size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
818{
Scott Baker611f6bd2019-10-18 13:45:19 -0700819 return ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ZSTD_getDDict(dctx));
Scott Bakereee8dd82019-09-24 12:52:34 -0700820}
821
822
823size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
824{
825#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1)
826 size_t regenSize;
827 ZSTD_DCtx* const dctx = ZSTD_createDCtx();
Scott Baker611f6bd2019-10-18 13:45:19 -0700828 RETURN_ERROR_IF(dctx==NULL, memory_allocation);
Scott Bakereee8dd82019-09-24 12:52:34 -0700829 regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);
830 ZSTD_freeDCtx(dctx);
831 return regenSize;
832#else /* stack mode */
833 ZSTD_DCtx dctx;
Scott Baker611f6bd2019-10-18 13:45:19 -0700834 ZSTD_initDCtx_internal(&dctx);
Scott Bakereee8dd82019-09-24 12:52:34 -0700835 return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize);
836#endif
837}
838
839
840/*-**************************************
841* Advanced Streaming Decompression API
842* Bufferless and synchronous
843****************************************/
844size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }
845
846ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {
847 switch(dctx->stage)
848 {
849 default: /* should not happen */
850 assert(0);
851 case ZSTDds_getFrameHeaderSize:
852 case ZSTDds_decodeFrameHeader:
853 return ZSTDnit_frameHeader;
854 case ZSTDds_decodeBlockHeader:
855 return ZSTDnit_blockHeader;
856 case ZSTDds_decompressBlock:
857 return ZSTDnit_block;
858 case ZSTDds_decompressLastBlock:
859 return ZSTDnit_lastBlock;
860 case ZSTDds_checkChecksum:
861 return ZSTDnit_checksum;
862 case ZSTDds_decodeSkippableHeader:
863 case ZSTDds_skipFrame:
864 return ZSTDnit_skippableFrame;
865 }
866}
867
868static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; }
869
870/** ZSTD_decompressContinue() :
871 * srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress())
872 * @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)
873 * or an error code, which can be tested using ZSTD_isError() */
874size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
875{
Scott Baker611f6bd2019-10-18 13:45:19 -0700876 DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);
Scott Bakereee8dd82019-09-24 12:52:34 -0700877 /* Sanity check */
Scott Baker611f6bd2019-10-18 13:45:19 -0700878 RETURN_ERROR_IF(srcSize != dctx->expected, srcSize_wrong, "not allowed");
Scott Bakereee8dd82019-09-24 12:52:34 -0700879 if (dstCapacity) ZSTD_checkContinuity(dctx, dst);
880
881 switch (dctx->stage)
882 {
883 case ZSTDds_getFrameHeaderSize :
884 assert(src != NULL);
885 if (dctx->format == ZSTD_f_zstd1) { /* allows header */
Scott Baker611f6bd2019-10-18 13:45:19 -0700886 assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */
887 if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
Scott Bakereee8dd82019-09-24 12:52:34 -0700888 memcpy(dctx->headerBuffer, src, srcSize);
Scott Baker611f6bd2019-10-18 13:45:19 -0700889 dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */
Scott Bakereee8dd82019-09-24 12:52:34 -0700890 dctx->stage = ZSTDds_decodeSkippableHeader;
891 return 0;
892 } }
893 dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);
894 if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;
895 memcpy(dctx->headerBuffer, src, srcSize);
896 dctx->expected = dctx->headerSize - srcSize;
897 dctx->stage = ZSTDds_decodeFrameHeader;
898 return 0;
899
900 case ZSTDds_decodeFrameHeader:
901 assert(src != NULL);
902 memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);
Scott Baker611f6bd2019-10-18 13:45:19 -0700903 FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize));
Scott Bakereee8dd82019-09-24 12:52:34 -0700904 dctx->expected = ZSTD_blockHeaderSize;
905 dctx->stage = ZSTDds_decodeBlockHeader;
906 return 0;
907
908 case ZSTDds_decodeBlockHeader:
909 { blockProperties_t bp;
910 size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);
911 if (ZSTD_isError(cBlockSize)) return cBlockSize;
912 dctx->expected = cBlockSize;
913 dctx->bType = bp.blockType;
914 dctx->rleSize = bp.origSize;
915 if (cBlockSize) {
916 dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;
917 return 0;
918 }
919 /* empty block */
920 if (bp.lastBlock) {
921 if (dctx->fParams.checksumFlag) {
922 dctx->expected = 4;
923 dctx->stage = ZSTDds_checkChecksum;
924 } else {
925 dctx->expected = 0; /* end of frame */
926 dctx->stage = ZSTDds_getFrameHeaderSize;
927 }
928 } else {
929 dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */
930 dctx->stage = ZSTDds_decodeBlockHeader;
931 }
932 return 0;
933 }
934
935 case ZSTDds_decompressLastBlock:
936 case ZSTDds_decompressBlock:
937 DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock");
938 { size_t rSize;
939 switch(dctx->bType)
940 {
941 case bt_compressed:
942 DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");
943 rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1);
944 break;
945 case bt_raw :
946 rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);
947 break;
948 case bt_rle :
Scott Baker611f6bd2019-10-18 13:45:19 -0700949 rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize);
Scott Bakereee8dd82019-09-24 12:52:34 -0700950 break;
951 case bt_reserved : /* should never happen */
952 default:
Scott Baker611f6bd2019-10-18 13:45:19 -0700953 RETURN_ERROR(corruption_detected);
Scott Bakereee8dd82019-09-24 12:52:34 -0700954 }
955 if (ZSTD_isError(rSize)) return rSize;
Scott Baker611f6bd2019-10-18 13:45:19 -0700956 DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);
Scott Bakereee8dd82019-09-24 12:52:34 -0700957 dctx->decodedSize += rSize;
958 if (dctx->fParams.checksumFlag) XXH64_update(&dctx->xxhState, dst, rSize);
959
960 if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */
Scott Baker611f6bd2019-10-18 13:45:19 -0700961 DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize);
962 RETURN_ERROR_IF(
963 dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN
964 && dctx->decodedSize != dctx->fParams.frameContentSize,
965 corruption_detected);
Scott Bakereee8dd82019-09-24 12:52:34 -0700966 if (dctx->fParams.checksumFlag) { /* another round for frame checksum */
967 dctx->expected = 4;
968 dctx->stage = ZSTDds_checkChecksum;
969 } else {
970 dctx->expected = 0; /* ends here */
971 dctx->stage = ZSTDds_getFrameHeaderSize;
972 }
973 } else {
974 dctx->stage = ZSTDds_decodeBlockHeader;
975 dctx->expected = ZSTD_blockHeaderSize;
976 dctx->previousDstEnd = (char*)dst + rSize;
977 }
978 return rSize;
979 }
980
981 case ZSTDds_checkChecksum:
982 assert(srcSize == 4); /* guaranteed by dctx->expected */
983 { U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);
984 U32 const check32 = MEM_readLE32(src);
Scott Baker611f6bd2019-10-18 13:45:19 -0700985 DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);
986 RETURN_ERROR_IF(check32 != h32, checksum_wrong);
Scott Bakereee8dd82019-09-24 12:52:34 -0700987 dctx->expected = 0;
988 dctx->stage = ZSTDds_getFrameHeaderSize;
989 return 0;
990 }
991
992 case ZSTDds_decodeSkippableHeader:
993 assert(src != NULL);
Scott Baker611f6bd2019-10-18 13:45:19 -0700994 assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);
995 memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */
996 dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */
Scott Bakereee8dd82019-09-24 12:52:34 -0700997 dctx->stage = ZSTDds_skipFrame;
998 return 0;
999
1000 case ZSTDds_skipFrame:
1001 dctx->expected = 0;
1002 dctx->stage = ZSTDds_getFrameHeaderSize;
1003 return 0;
1004
1005 default:
Scott Baker611f6bd2019-10-18 13:45:19 -07001006 assert(0); /* impossible */
1007 RETURN_ERROR(GENERIC); /* some compiler require default to do something */
Scott Bakereee8dd82019-09-24 12:52:34 -07001008 }
1009}
1010
1011
1012static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
1013{
1014 dctx->dictEnd = dctx->previousDstEnd;
Scott Baker611f6bd2019-10-18 13:45:19 -07001015 dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));
1016 dctx->prefixStart = dict;
Scott Bakereee8dd82019-09-24 12:52:34 -07001017 dctx->previousDstEnd = (const char*)dict + dictSize;
1018 return 0;
1019}
1020
Scott Baker611f6bd2019-10-18 13:45:19 -07001021/*! ZSTD_loadDEntropy() :
1022 * dict : must point at beginning of a valid zstd dictionary.
Scott Bakereee8dd82019-09-24 12:52:34 -07001023 * @return : size of entropy tables read */
Scott Baker611f6bd2019-10-18 13:45:19 -07001024size_t
1025ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,
1026 const void* const dict, size_t const dictSize)
Scott Bakereee8dd82019-09-24 12:52:34 -07001027{
1028 const BYTE* dictPtr = (const BYTE*)dict;
1029 const BYTE* const dictEnd = dictPtr + dictSize;
1030
Scott Baker611f6bd2019-10-18 13:45:19 -07001031 RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted);
1032 assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */
Scott Bakereee8dd82019-09-24 12:52:34 -07001033 dictPtr += 8; /* skip header = magic + dictID */
1034
Scott Baker611f6bd2019-10-18 13:45:19 -07001035 ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, OFTable) == offsetof(ZSTD_entropyDTables_t, LLTable) + sizeof(entropy->LLTable));
1036 ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, MLTable) == offsetof(ZSTD_entropyDTables_t, OFTable) + sizeof(entropy->OFTable));
1037 ZSTD_STATIC_ASSERT(sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable) >= HUF_DECOMPRESS_WORKSPACE_SIZE);
1038 { void* const workspace = &entropy->LLTable; /* use fse tables as temporary workspace; implies fse tables are grouped together */
1039 size_t const workspaceSize = sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable);
1040#ifdef HUF_FORCE_DECOMPRESS_X1
1041 /* in minimal huffman, we always use X1 variants */
1042 size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable,
1043 dictPtr, dictEnd - dictPtr,
1044 workspace, workspaceSize);
1045#else
1046 size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,
1047 dictPtr, dictEnd - dictPtr,
1048 workspace, workspaceSize);
1049#endif
1050 RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted);
Scott Bakereee8dd82019-09-24 12:52:34 -07001051 dictPtr += hSize;
1052 }
1053
1054 { short offcodeNCount[MaxOff+1];
Scott Baker611f6bd2019-10-18 13:45:19 -07001055 unsigned offcodeMaxValue = MaxOff, offcodeLog;
Scott Bakereee8dd82019-09-24 12:52:34 -07001056 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Scott Baker611f6bd2019-10-18 13:45:19 -07001057 RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted);
1058 RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted);
1059 RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted);
1060 ZSTD_buildFSETable( entropy->OFTable,
Scott Bakereee8dd82019-09-24 12:52:34 -07001061 offcodeNCount, offcodeMaxValue,
1062 OF_base, OF_bits,
1063 offcodeLog);
1064 dictPtr += offcodeHeaderSize;
1065 }
1066
1067 { short matchlengthNCount[MaxML+1];
1068 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
1069 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Scott Baker611f6bd2019-10-18 13:45:19 -07001070 RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted);
1071 RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted);
1072 RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted);
1073 ZSTD_buildFSETable( entropy->MLTable,
Scott Bakereee8dd82019-09-24 12:52:34 -07001074 matchlengthNCount, matchlengthMaxValue,
1075 ML_base, ML_bits,
1076 matchlengthLog);
1077 dictPtr += matchlengthHeaderSize;
1078 }
1079
1080 { short litlengthNCount[MaxLL+1];
1081 unsigned litlengthMaxValue = MaxLL, litlengthLog;
1082 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Scott Baker611f6bd2019-10-18 13:45:19 -07001083 RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted);
1084 RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted);
1085 RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted);
1086 ZSTD_buildFSETable( entropy->LLTable,
Scott Bakereee8dd82019-09-24 12:52:34 -07001087 litlengthNCount, litlengthMaxValue,
1088 LL_base, LL_bits,
1089 litlengthLog);
1090 dictPtr += litlengthHeaderSize;
1091 }
1092
Scott Baker611f6bd2019-10-18 13:45:19 -07001093 RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted);
Scott Bakereee8dd82019-09-24 12:52:34 -07001094 { int i;
1095 size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12));
1096 for (i=0; i<3; i++) {
1097 U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4;
Scott Baker611f6bd2019-10-18 13:45:19 -07001098 RETURN_ERROR_IF(rep==0 || rep >= dictContentSize,
1099 dictionary_corrupted);
Scott Bakereee8dd82019-09-24 12:52:34 -07001100 entropy->rep[i] = rep;
1101 } }
1102
1103 return dictPtr - (const BYTE*)dict;
1104}
1105
1106static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
1107{
1108 if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize);
1109 { U32 const magic = MEM_readLE32(dict);
1110 if (magic != ZSTD_MAGIC_DICTIONARY) {
1111 return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */
1112 } }
Scott Baker611f6bd2019-10-18 13:45:19 -07001113 dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);
Scott Bakereee8dd82019-09-24 12:52:34 -07001114
1115 /* load entropy tables */
Scott Baker611f6bd2019-10-18 13:45:19 -07001116 { size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize);
1117 RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted);
Scott Bakereee8dd82019-09-24 12:52:34 -07001118 dict = (const char*)dict + eSize;
1119 dictSize -= eSize;
1120 }
1121 dctx->litEntropy = dctx->fseEntropy = 1;
1122
1123 /* reference dictionary content */
1124 return ZSTD_refDictContent(dctx, dict, dictSize);
1125}
1126
Scott Bakereee8dd82019-09-24 12:52:34 -07001127size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)
1128{
1129 assert(dctx != NULL);
1130 dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */
1131 dctx->stage = ZSTDds_getFrameHeaderSize;
1132 dctx->decodedSize = 0;
1133 dctx->previousDstEnd = NULL;
Scott Baker611f6bd2019-10-18 13:45:19 -07001134 dctx->prefixStart = NULL;
1135 dctx->virtualStart = NULL;
Scott Bakereee8dd82019-09-24 12:52:34 -07001136 dctx->dictEnd = NULL;
1137 dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */
1138 dctx->litEntropy = dctx->fseEntropy = 0;
1139 dctx->dictID = 0;
1140 ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));
1141 memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */
1142 dctx->LLTptr = dctx->entropy.LLTable;
1143 dctx->MLTptr = dctx->entropy.MLTable;
1144 dctx->OFTptr = dctx->entropy.OFTable;
1145 dctx->HUFptr = dctx->entropy.hufTable;
1146 return 0;
1147}
1148
1149size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
1150{
Scott Baker611f6bd2019-10-18 13:45:19 -07001151 FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) );
Scott Bakereee8dd82019-09-24 12:52:34 -07001152 if (dict && dictSize)
Scott Baker611f6bd2019-10-18 13:45:19 -07001153 RETURN_ERROR_IF(
1154 ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)),
1155 dictionary_corrupted);
Scott Bakereee8dd82019-09-24 12:52:34 -07001156 return 0;
1157}
1158
1159
1160/* ====== ZSTD_DDict ====== */
1161
Scott Baker611f6bd2019-10-18 13:45:19 -07001162size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
Scott Bakereee8dd82019-09-24 12:52:34 -07001163{
Scott Baker611f6bd2019-10-18 13:45:19 -07001164 DEBUGLOG(4, "ZSTD_decompressBegin_usingDDict");
1165 assert(dctx != NULL);
1166 if (ddict) {
1167 const char* const dictStart = (const char*)ZSTD_DDict_dictContent(ddict);
1168 size_t const dictSize = ZSTD_DDict_dictSize(ddict);
1169 const void* const dictEnd = dictStart + dictSize;
1170 dctx->ddictIsCold = (dctx->dictEnd != dictEnd);
1171 DEBUGLOG(4, "DDict is %s",
1172 dctx->ddictIsCold ? "~cold~" : "hot!");
1173 }
1174 FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) );
1175 if (ddict) { /* NULL ddict is equivalent to no dictionary */
1176 ZSTD_copyDDictParameters(dctx, ddict);
Scott Bakereee8dd82019-09-24 12:52:34 -07001177 }
1178 return 0;
1179}
1180
Scott Bakereee8dd82019-09-24 12:52:34 -07001181/*! ZSTD_getDictID_fromDict() :
1182 * Provides the dictID stored within dictionary.
1183 * if @return == 0, the dictionary is not conformant with Zstandard specification.
1184 * It can still be loaded, but as a content-only dictionary. */
1185unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)
1186{
1187 if (dictSize < 8) return 0;
1188 if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0;
Scott Baker611f6bd2019-10-18 13:45:19 -07001189 return MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);
Scott Bakereee8dd82019-09-24 12:52:34 -07001190}
1191
1192/*! ZSTD_getDictID_fromFrame() :
Scott Baker611f6bd2019-10-18 13:45:19 -07001193 * Provides the dictID required to decompress frame stored within `src`.
Scott Bakereee8dd82019-09-24 12:52:34 -07001194 * If @return == 0, the dictID could not be decoded.
1195 * This could for one of the following reasons :
1196 * - The frame does not require a dictionary (most common case).
1197 * - The frame was built with dictID intentionally removed.
1198 * Needed dictionary is a hidden information.
1199 * Note : this use case also happens when using a non-conformant dictionary.
1200 * - `srcSize` is too small, and as a result, frame header could not be decoded.
1201 * Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`.
1202 * - This is not a Zstandard frame.
1203 * When identifying the exact failure cause, it's possible to use
1204 * ZSTD_getFrameHeader(), which will provide a more precise error code. */
1205unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)
1206{
1207 ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 };
1208 size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);
1209 if (ZSTD_isError(hError)) return 0;
1210 return zfp.dictID;
1211}
1212
1213
1214/*! ZSTD_decompress_usingDDict() :
1215* Decompression using a pre-digested Dictionary
1216* Use dictionary without significant overhead. */
1217size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,
1218 void* dst, size_t dstCapacity,
1219 const void* src, size_t srcSize,
1220 const ZSTD_DDict* ddict)
1221{
1222 /* pass content and size in case legacy frames are encountered */
1223 return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize,
1224 NULL, 0,
1225 ddict);
1226}
1227
1228
1229/*=====================================
1230* Streaming decompression
1231*====================================*/
1232
1233ZSTD_DStream* ZSTD_createDStream(void)
1234{
1235 DEBUGLOG(3, "ZSTD_createDStream");
1236 return ZSTD_createDStream_advanced(ZSTD_defaultCMem);
1237}
1238
1239ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize)
1240{
1241 return ZSTD_initStaticDCtx(workspace, workspaceSize);
1242}
1243
1244ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem)
1245{
1246 return ZSTD_createDCtx_advanced(customMem);
1247}
1248
1249size_t ZSTD_freeDStream(ZSTD_DStream* zds)
1250{
1251 return ZSTD_freeDCtx(zds);
1252}
1253
1254
Scott Baker611f6bd2019-10-18 13:45:19 -07001255/* *** Initialization *** */
Scott Bakereee8dd82019-09-24 12:52:34 -07001256
1257size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; }
1258size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }
1259
Scott Baker611f6bd2019-10-18 13:45:19 -07001260size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx,
1261 const void* dict, size_t dictSize,
1262 ZSTD_dictLoadMethod_e dictLoadMethod,
1263 ZSTD_dictContentType_e dictContentType)
Scott Bakereee8dd82019-09-24 12:52:34 -07001264{
Scott Baker611f6bd2019-10-18 13:45:19 -07001265 RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong);
1266 ZSTD_clearDict(dctx);
Scott Bakereee8dd82019-09-24 12:52:34 -07001267 if (dict && dictSize >= 8) {
1268 dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem);
Scott Baker611f6bd2019-10-18 13:45:19 -07001269 RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation);
1270 dctx->ddict = dctx->ddictLocal;
1271 dctx->dictUses = ZSTD_use_indefinitely;
Scott Bakereee8dd82019-09-24 12:52:34 -07001272 }
Scott Bakereee8dd82019-09-24 12:52:34 -07001273 return 0;
1274}
1275
1276size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
1277{
1278 return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
1279}
1280
1281size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)
1282{
1283 return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
1284}
1285
1286size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
1287{
Scott Baker611f6bd2019-10-18 13:45:19 -07001288 FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType));
1289 dctx->dictUses = ZSTD_use_once;
1290 return 0;
Scott Bakereee8dd82019-09-24 12:52:34 -07001291}
1292
1293size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize)
1294{
1295 return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent);
1296}
1297
1298
1299/* ZSTD_initDStream_usingDict() :
Scott Baker611f6bd2019-10-18 13:45:19 -07001300 * return : expected size, aka ZSTD_FRAMEHEADERSIZE_PREFIX.
Scott Bakereee8dd82019-09-24 12:52:34 -07001301 * this function cannot fail */
1302size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)
1303{
1304 DEBUGLOG(4, "ZSTD_initDStream_usingDict");
Scott Baker611f6bd2019-10-18 13:45:19 -07001305 FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) );
1306 FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) );
1307 return ZSTD_FRAMEHEADERSIZE_PREFIX;
Scott Bakereee8dd82019-09-24 12:52:34 -07001308}
1309
1310/* note : this variant can't fail */
1311size_t ZSTD_initDStream(ZSTD_DStream* zds)
1312{
1313 DEBUGLOG(4, "ZSTD_initDStream");
Scott Baker611f6bd2019-10-18 13:45:19 -07001314 return ZSTD_initDStream_usingDDict(zds, NULL);
Scott Bakereee8dd82019-09-24 12:52:34 -07001315}
1316
1317/* ZSTD_initDStream_usingDDict() :
1318 * ddict will just be referenced, and must outlive decompression session
1319 * this function cannot fail */
1320size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)
1321{
Scott Baker611f6bd2019-10-18 13:45:19 -07001322 FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) );
1323 FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) );
1324 return ZSTD_FRAMEHEADERSIZE_PREFIX;
Scott Bakereee8dd82019-09-24 12:52:34 -07001325}
1326
1327/* ZSTD_resetDStream() :
Scott Baker611f6bd2019-10-18 13:45:19 -07001328 * return : expected size, aka ZSTD_FRAMEHEADERSIZE_PREFIX.
Scott Bakereee8dd82019-09-24 12:52:34 -07001329 * this function cannot fail */
1330size_t ZSTD_resetDStream(ZSTD_DStream* dctx)
1331{
Scott Baker611f6bd2019-10-18 13:45:19 -07001332 FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only));
1333 return ZSTD_FRAMEHEADERSIZE_PREFIX;
Scott Bakereee8dd82019-09-24 12:52:34 -07001334}
1335
Scott Baker611f6bd2019-10-18 13:45:19 -07001336
1337size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)
Scott Bakereee8dd82019-09-24 12:52:34 -07001338{
Scott Baker611f6bd2019-10-18 13:45:19 -07001339 RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong);
1340 ZSTD_clearDict(dctx);
1341 if (ddict) {
1342 dctx->ddict = ddict;
1343 dctx->dictUses = ZSTD_use_indefinitely;
Scott Bakereee8dd82019-09-24 12:52:34 -07001344 }
1345 return 0;
1346}
1347
Scott Baker611f6bd2019-10-18 13:45:19 -07001348/* ZSTD_DCtx_setMaxWindowSize() :
1349 * note : no direct equivalence in ZSTD_DCtx_setParameter,
1350 * since this version sets windowSize, and the other sets windowLog */
Scott Bakereee8dd82019-09-24 12:52:34 -07001351size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)
1352{
Scott Baker611f6bd2019-10-18 13:45:19 -07001353 ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax);
1354 size_t const min = (size_t)1 << bounds.lowerBound;
1355 size_t const max = (size_t)1 << bounds.upperBound;
1356 RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong);
1357 RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound);
1358 RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound);
Scott Bakereee8dd82019-09-24 12:52:34 -07001359 dctx->maxWindowSize = maxWindowSize;
1360 return 0;
1361}
1362
1363size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)
1364{
Scott Baker611f6bd2019-10-18 13:45:19 -07001365 return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, format);
1366}
1367
1368ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)
1369{
1370 ZSTD_bounds bounds = { 0, 0, 0 };
1371 switch(dParam) {
1372 case ZSTD_d_windowLogMax:
1373 bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN;
1374 bounds.upperBound = ZSTD_WINDOWLOG_MAX;
1375 return bounds;
1376 case ZSTD_d_format:
1377 bounds.lowerBound = (int)ZSTD_f_zstd1;
1378 bounds.upperBound = (int)ZSTD_f_zstd1_magicless;
1379 ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
1380 return bounds;
1381 default:;
1382 }
1383 bounds.error = ERROR(parameter_unsupported);
1384 return bounds;
1385}
1386
1387/* ZSTD_dParam_withinBounds:
1388 * @return 1 if value is within dParam bounds,
1389 * 0 otherwise */
1390static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value)
1391{
1392 ZSTD_bounds const bounds = ZSTD_dParam_getBounds(dParam);
1393 if (ZSTD_isError(bounds.error)) return 0;
1394 if (value < bounds.lowerBound) return 0;
1395 if (value > bounds.upperBound) return 0;
1396 return 1;
1397}
1398
1399#define CHECK_DBOUNDS(p,v) { \
1400 RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound); \
1401}
1402
1403size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value)
1404{
1405 RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong);
1406 switch(dParam) {
1407 case ZSTD_d_windowLogMax:
1408 if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT;
1409 CHECK_DBOUNDS(ZSTD_d_windowLogMax, value);
1410 dctx->maxWindowSize = ((size_t)1) << value;
1411 return 0;
1412 case ZSTD_d_format:
1413 CHECK_DBOUNDS(ZSTD_d_format, value);
1414 dctx->format = (ZSTD_format_e)value;
1415 return 0;
1416 default:;
1417 }
1418 RETURN_ERROR(parameter_unsupported);
1419}
1420
1421size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)
1422{
1423 if ( (reset == ZSTD_reset_session_only)
1424 || (reset == ZSTD_reset_session_and_parameters) ) {
1425 dctx->streamStage = zdss_init;
1426 dctx->noForwardProgress = 0;
1427 }
1428 if ( (reset == ZSTD_reset_parameters)
1429 || (reset == ZSTD_reset_session_and_parameters) ) {
1430 RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong);
1431 ZSTD_clearDict(dctx);
1432 dctx->format = ZSTD_f_zstd1;
1433 dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;
1434 }
Scott Bakereee8dd82019-09-24 12:52:34 -07001435 return 0;
1436}
1437
1438
1439size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)
1440{
1441 return ZSTD_sizeof_DCtx(dctx);
1442}
1443
1444size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)
1445{
1446 size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
1447 unsigned long long const neededRBSize = windowSize + blockSize + (WILDCOPY_OVERLENGTH * 2);
1448 unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);
1449 size_t const minRBSize = (size_t) neededSize;
Scott Baker611f6bd2019-10-18 13:45:19 -07001450 RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize,
1451 frameParameter_windowTooLarge);
Scott Bakereee8dd82019-09-24 12:52:34 -07001452 return minRBSize;
1453}
1454
1455size_t ZSTD_estimateDStreamSize(size_t windowSize)
1456{
1457 size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);
1458 size_t const inBuffSize = blockSize; /* no block can be larger */
1459 size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN);
1460 return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;
1461}
1462
1463size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)
1464{
Scott Baker611f6bd2019-10-18 13:45:19 -07001465 U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */
Scott Bakereee8dd82019-09-24 12:52:34 -07001466 ZSTD_frameHeader zfh;
1467 size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);
1468 if (ZSTD_isError(err)) return err;
Scott Baker611f6bd2019-10-18 13:45:19 -07001469 RETURN_ERROR_IF(err>0, srcSize_wrong);
1470 RETURN_ERROR_IF(zfh.windowSize > windowSizeMax,
1471 frameParameter_windowTooLarge);
Scott Bakereee8dd82019-09-24 12:52:34 -07001472 return ZSTD_estimateDStreamSize((size_t)zfh.windowSize);
1473}
1474
1475
1476/* ***** Decompression ***** */
1477
1478MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
1479{
1480 size_t const length = MIN(dstCapacity, srcSize);
1481 memcpy(dst, src, length);
1482 return length;
1483}
1484
1485
1486size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
1487{
1488 const char* const istart = (const char*)(input->src) + input->pos;
1489 const char* const iend = (const char*)(input->src) + input->size;
1490 const char* ip = istart;
1491 char* const ostart = (char*)(output->dst) + output->pos;
1492 char* const oend = (char*)(output->dst) + output->size;
1493 char* op = ostart;
1494 U32 someMoreWork = 1;
1495
1496 DEBUGLOG(5, "ZSTD_decompressStream");
Scott Baker611f6bd2019-10-18 13:45:19 -07001497 RETURN_ERROR_IF(
1498 input->pos > input->size,
1499 srcSize_wrong,
1500 "forbidden. in: pos: %u vs size: %u",
1501 (U32)input->pos, (U32)input->size);
1502 RETURN_ERROR_IF(
1503 output->pos > output->size,
1504 dstSize_tooSmall,
1505 "forbidden. out: pos: %u vs size: %u",
1506 (U32)output->pos, (U32)output->size);
Scott Bakereee8dd82019-09-24 12:52:34 -07001507 DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));
1508
1509 while (someMoreWork) {
1510 switch(zds->streamStage)
1511 {
1512 case zdss_init :
1513 DEBUGLOG(5, "stage zdss_init => transparent reset ");
Scott Baker611f6bd2019-10-18 13:45:19 -07001514 zds->streamStage = zdss_loadHeader;
1515 zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;
1516 zds->legacyVersion = 0;
1517 zds->hostageByte = 0;
Scott Bakereee8dd82019-09-24 12:52:34 -07001518 /* fall-through */
1519
1520 case zdss_loadHeader :
1521 DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));
1522#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
1523 if (zds->legacyVersion) {
Scott Baker611f6bd2019-10-18 13:45:19 -07001524 RETURN_ERROR_IF(zds->staticSize, memory_allocation,
1525 "legacy support is incompatible with static dctx");
Scott Bakereee8dd82019-09-24 12:52:34 -07001526 { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);
1527 if (hint==0) zds->streamStage = zdss_init;
1528 return hint;
1529 } }
1530#endif
Scott Baker611f6bd2019-10-18 13:45:19 -07001531 { size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);
Scott Bakereee8dd82019-09-24 12:52:34 -07001532 DEBUGLOG(5, "header size : %u", (U32)hSize);
1533 if (ZSTD_isError(hSize)) {
1534#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)
1535 U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);
1536 if (legacyVersion) {
Scott Baker611f6bd2019-10-18 13:45:19 -07001537 ZSTD_DDict const* const ddict = ZSTD_getDDict(zds);
1538 const void* const dict = ddict ? ZSTD_DDict_dictContent(ddict) : NULL;
1539 size_t const dictSize = ddict ? ZSTD_DDict_dictSize(ddict) : 0;
Scott Bakereee8dd82019-09-24 12:52:34 -07001540 DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion);
Scott Baker611f6bd2019-10-18 13:45:19 -07001541 RETURN_ERROR_IF(zds->staticSize, memory_allocation,
1542 "legacy support is incompatible with static dctx");
1543 FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext,
Scott Bakereee8dd82019-09-24 12:52:34 -07001544 zds->previousLegacyVersion, legacyVersion,
1545 dict, dictSize));
1546 zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;
1547 { size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);
1548 if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */
1549 return hint;
1550 } }
1551#endif
1552 return hSize; /* error */
1553 }
1554 if (hSize != 0) { /* need more input */
1555 size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */
1556 size_t const remainingInput = (size_t)(iend-ip);
1557 assert(iend >= ip);
1558 if (toLoad > remainingInput) { /* not enough input to load full header */
1559 if (remainingInput > 0) {
1560 memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);
1561 zds->lhSize += remainingInput;
1562 }
1563 input->pos = input->size;
Scott Baker611f6bd2019-10-18 13:45:19 -07001564 return (MAX(ZSTD_FRAMEHEADERSIZE_MIN, hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */
Scott Bakereee8dd82019-09-24 12:52:34 -07001565 }
1566 assert(ip != NULL);
1567 memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;
1568 break;
1569 } }
1570
1571 /* check for single-pass mode opportunity */
1572 if (zds->fParams.frameContentSize && zds->fParams.windowSize /* skippable frame if == 0 */
1573 && (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {
1574 size_t const cSize = ZSTD_findFrameCompressedSize(istart, iend-istart);
1575 if (cSize <= (size_t)(iend-istart)) {
1576 /* shortcut : using single-pass mode */
Scott Baker611f6bd2019-10-18 13:45:19 -07001577 size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, oend-op, istart, cSize, ZSTD_getDDict(zds));
Scott Bakereee8dd82019-09-24 12:52:34 -07001578 if (ZSTD_isError(decompressedSize)) return decompressedSize;
1579 DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")
1580 ip = istart + cSize;
1581 op += decompressedSize;
1582 zds->expected = 0;
1583 zds->streamStage = zdss_init;
1584 someMoreWork = 0;
1585 break;
1586 } }
1587
1588 /* Consume header (see ZSTDds_decodeFrameHeader) */
1589 DEBUGLOG(4, "Consume header");
Scott Baker611f6bd2019-10-18 13:45:19 -07001590 FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)));
Scott Bakereee8dd82019-09-24 12:52:34 -07001591
Scott Baker611f6bd2019-10-18 13:45:19 -07001592 if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */
1593 zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);
Scott Bakereee8dd82019-09-24 12:52:34 -07001594 zds->stage = ZSTDds_skipFrame;
1595 } else {
Scott Baker611f6bd2019-10-18 13:45:19 -07001596 FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize));
Scott Bakereee8dd82019-09-24 12:52:34 -07001597 zds->expected = ZSTD_blockHeaderSize;
1598 zds->stage = ZSTDds_decodeBlockHeader;
1599 }
1600
1601 /* control buffer memory usage */
1602 DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)",
1603 (U32)(zds->fParams.windowSize >>10),
1604 (U32)(zds->maxWindowSize >> 10) );
1605 zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);
Scott Baker611f6bd2019-10-18 13:45:19 -07001606 RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize,
1607 frameParameter_windowTooLarge);
Scott Bakereee8dd82019-09-24 12:52:34 -07001608
1609 /* Adapt buffer sizes to frame header instructions */
1610 { size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);
1611 size_t const neededOutBuffSize = ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize);
1612 if ((zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize)) {
1613 size_t const bufferSize = neededInBuffSize + neededOutBuffSize;
1614 DEBUGLOG(4, "inBuff : from %u to %u",
1615 (U32)zds->inBuffSize, (U32)neededInBuffSize);
1616 DEBUGLOG(4, "outBuff : from %u to %u",
1617 (U32)zds->outBuffSize, (U32)neededOutBuffSize);
1618 if (zds->staticSize) { /* static DCtx */
1619 DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize);
1620 assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */
Scott Baker611f6bd2019-10-18 13:45:19 -07001621 RETURN_ERROR_IF(
1622 bufferSize > zds->staticSize - sizeof(ZSTD_DCtx),
1623 memory_allocation);
Scott Bakereee8dd82019-09-24 12:52:34 -07001624 } else {
1625 ZSTD_free(zds->inBuff, zds->customMem);
1626 zds->inBuffSize = 0;
1627 zds->outBuffSize = 0;
1628 zds->inBuff = (char*)ZSTD_malloc(bufferSize, zds->customMem);
Scott Baker611f6bd2019-10-18 13:45:19 -07001629 RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation);
Scott Bakereee8dd82019-09-24 12:52:34 -07001630 }
1631 zds->inBuffSize = neededInBuffSize;
1632 zds->outBuff = zds->inBuff + zds->inBuffSize;
1633 zds->outBuffSize = neededOutBuffSize;
1634 } }
1635 zds->streamStage = zdss_read;
1636 /* fall-through */
1637
1638 case zdss_read:
1639 DEBUGLOG(5, "stage zdss_read");
1640 { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
1641 DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize);
1642 if (neededInSize==0) { /* end of frame */
1643 zds->streamStage = zdss_init;
1644 someMoreWork = 0;
1645 break;
1646 }
1647 if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */
1648 int const isSkipFrame = ZSTD_isSkipFrame(zds);
1649 size_t const decodedSize = ZSTD_decompressContinue(zds,
1650 zds->outBuff + zds->outStart, (isSkipFrame ? 0 : zds->outBuffSize - zds->outStart),
1651 ip, neededInSize);
1652 if (ZSTD_isError(decodedSize)) return decodedSize;
1653 ip += neededInSize;
1654 if (!decodedSize && !isSkipFrame) break; /* this was just a header */
1655 zds->outEnd = zds->outStart + decodedSize;
1656 zds->streamStage = zdss_flush;
1657 break;
1658 } }
1659 if (ip==iend) { someMoreWork = 0; break; } /* no more input */
1660 zds->streamStage = zdss_load;
1661 /* fall-through */
1662
1663 case zdss_load:
1664 { size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);
1665 size_t const toLoad = neededInSize - zds->inPos;
1666 int const isSkipFrame = ZSTD_isSkipFrame(zds);
1667 size_t loadedSize;
1668 if (isSkipFrame) {
1669 loadedSize = MIN(toLoad, (size_t)(iend-ip));
1670 } else {
Scott Baker611f6bd2019-10-18 13:45:19 -07001671 RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos,
1672 corruption_detected,
1673 "should never happen");
Scott Bakereee8dd82019-09-24 12:52:34 -07001674 loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, iend-ip);
1675 }
1676 ip += loadedSize;
1677 zds->inPos += loadedSize;
1678 if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */
1679
1680 /* decode loaded input */
1681 { size_t const decodedSize = ZSTD_decompressContinue(zds,
1682 zds->outBuff + zds->outStart, zds->outBuffSize - zds->outStart,
1683 zds->inBuff, neededInSize);
1684 if (ZSTD_isError(decodedSize)) return decodedSize;
1685 zds->inPos = 0; /* input is consumed */
1686 if (!decodedSize && !isSkipFrame) { zds->streamStage = zdss_read; break; } /* this was just a header */
1687 zds->outEnd = zds->outStart + decodedSize;
1688 } }
1689 zds->streamStage = zdss_flush;
1690 /* fall-through */
1691
1692 case zdss_flush:
1693 { size_t const toFlushSize = zds->outEnd - zds->outStart;
1694 size_t const flushedSize = ZSTD_limitCopy(op, oend-op, zds->outBuff + zds->outStart, toFlushSize);
1695 op += flushedSize;
1696 zds->outStart += flushedSize;
1697 if (flushedSize == toFlushSize) { /* flush completed */
1698 zds->streamStage = zdss_read;
1699 if ( (zds->outBuffSize < zds->fParams.frameContentSize)
1700 && (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) {
1701 DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)",
1702 (int)(zds->outBuffSize - zds->outStart),
1703 (U32)zds->fParams.blockSizeMax);
1704 zds->outStart = zds->outEnd = 0;
1705 }
1706 break;
1707 } }
1708 /* cannot complete flush */
1709 someMoreWork = 0;
1710 break;
1711
Scott Baker611f6bd2019-10-18 13:45:19 -07001712 default:
1713 assert(0); /* impossible */
1714 RETURN_ERROR(GENERIC); /* some compiler require default to do something */
Scott Bakereee8dd82019-09-24 12:52:34 -07001715 } }
1716
1717 /* result */
Scott Baker611f6bd2019-10-18 13:45:19 -07001718 input->pos = (size_t)(ip - (const char*)(input->src));
1719 output->pos = (size_t)(op - (char*)(output->dst));
1720 if ((ip==istart) && (op==ostart)) { /* no forward progress */
1721 zds->noForwardProgress ++;
1722 if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {
1723 RETURN_ERROR_IF(op==oend, dstSize_tooSmall);
1724 RETURN_ERROR_IF(ip==iend, srcSize_wrong);
1725 assert(0);
1726 }
1727 } else {
1728 zds->noForwardProgress = 0;
1729 }
Scott Bakereee8dd82019-09-24 12:52:34 -07001730 { size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds);
1731 if (!nextSrcSizeHint) { /* frame fully decoded */
1732 if (zds->outEnd == zds->outStart) { /* output fully flushed */
1733 if (zds->hostageByte) {
1734 if (input->pos >= input->size) {
1735 /* can't release hostage (not present) */
1736 zds->streamStage = zdss_read;
1737 return 1;
1738 }
1739 input->pos++; /* release hostage */
1740 } /* zds->hostageByte */
1741 return 0;
1742 } /* zds->outEnd == zds->outStart */
1743 if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */
1744 input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */
1745 zds->hostageByte=1;
1746 }
1747 return 1;
1748 } /* nextSrcSizeHint==0 */
1749 nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */
1750 assert(zds->inPos <= nextSrcSizeHint);
1751 nextSrcSizeHint -= zds->inPos; /* part already loaded*/
1752 return nextSrcSizeHint;
1753 }
1754}
1755
Scott Baker611f6bd2019-10-18 13:45:19 -07001756size_t ZSTD_decompressStream_simpleArgs (
Scott Bakereee8dd82019-09-24 12:52:34 -07001757 ZSTD_DCtx* dctx,
1758 void* dst, size_t dstCapacity, size_t* dstPos,
1759 const void* src, size_t srcSize, size_t* srcPos)
1760{
1761 ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
1762 ZSTD_inBuffer input = { src, srcSize, *srcPos };
1763 /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
Scott Baker611f6bd2019-10-18 13:45:19 -07001764 size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);
Scott Bakereee8dd82019-09-24 12:52:34 -07001765 *dstPos = output.pos;
1766 *srcPos = input.pos;
1767 return cErr;
1768}