Path: blob/master/Utilities/cmzstd/lib/decompress/zstd_decompress.c
3158 views
/*1* Copyright (c) Meta Platforms, Inc. and affiliates.2* All rights reserved.3*4* This source code is licensed under both the BSD-style license (found in the5* LICENSE file in the root directory of this source tree) and the GPLv2 (found6* in the COPYING file in the root directory of this source tree).7* You may select, at your option, one of the above-listed licenses.8*/91011/* ***************************************************************12* Tuning parameters13*****************************************************************/14/*!15* HEAPMODE :16* Select how default decompression function ZSTD_decompress() allocates its context,17* on stack (0), or into heap (1, default; requires malloc()).18* Note that functions with explicit context such as ZSTD_decompressDCtx() are unaffected.19*/20#ifndef ZSTD_HEAPMODE21# define ZSTD_HEAPMODE 122#endif2324/*!25* LEGACY_SUPPORT :26* if set to 1+, ZSTD_decompress() can decode older formats (v0.1+)27*/28#ifndef ZSTD_LEGACY_SUPPORT29# define ZSTD_LEGACY_SUPPORT 030#endif3132/*!33* MAXWINDOWSIZE_DEFAULT :34* maximum window size accepted by DStream __by default__.35* Frames requiring more memory will be rejected.36* It's possible to set a different limit using ZSTD_DCtx_setMaxWindowSize().37*/38#ifndef ZSTD_MAXWINDOWSIZE_DEFAULT39# define ZSTD_MAXWINDOWSIZE_DEFAULT (((U32)1 << ZSTD_WINDOWLOG_LIMIT_DEFAULT) + 1)40#endif4142/*!43* NO_FORWARD_PROGRESS_MAX :44* maximum allowed nb of calls to ZSTD_decompressStream()45* without any forward progress46* (defined as: no byte read from input, and no byte flushed to output)47* before triggering an error.48*/49#ifndef ZSTD_NO_FORWARD_PROGRESS_MAX50# define ZSTD_NO_FORWARD_PROGRESS_MAX 1651#endif525354/*-*******************************************************55* Dependencies56*********************************************************/57#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */58#include "../common/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */59#include "../common/mem.h" /* low level memory routines */60#define FSE_STATIC_LINKING_ONLY61#include "../common/fse.h"62#include "../common/huf.h"63#include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */64#include "../common/zstd_internal.h" /* blockProperties_t */65#include "zstd_decompress_internal.h" /* ZSTD_DCtx */66#include "zstd_ddict.h" /* ZSTD_DDictDictContent */67#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */68#include "../common/bits.h" /* ZSTD_highbit32 */6970#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)71# include "../legacy/zstd_legacy.h"72#endif73747576/*************************************77* Multiple DDicts Hashset internals *78*************************************/7980#define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 481#define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float.82* Currently, that means a 0.75 load factor.83* So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded84* the load factor of the ddict hash set.85*/8687#define DDICT_HASHSET_TABLE_BASE_SIZE 6488#define DDICT_HASHSET_RESIZE_FACTOR 28990/* Hash function to determine starting position of dict insertion within the table91* Returns an index between [0, hashSet->ddictPtrTableSize]92*/93static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) {94const U64 hash = XXH64(&dictID, sizeof(U32), 0);95/* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */96return hash & (hashSet->ddictPtrTableSize - 1);97}9899/* Adds DDict to a hashset without resizing it.100* If inserting a DDict with a dictID that already exists in the set, replaces the one in the set.101* Returns 0 if successful, or a zstd error code if something went wrong.102*/103static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) {104const U32 dictID = ZSTD_getDictID_fromDDict(ddict);105size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);106const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;107RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!");108DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);109while (hashSet->ddictPtrTable[idx] != NULL) {110/* Replace existing ddict if inserting ddict with same dictID */111if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) {112DEBUGLOG(4, "DictID already exists, replacing rather than adding");113hashSet->ddictPtrTable[idx] = ddict;114return 0;115}116idx &= idxRangeMask;117idx++;118}119DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);120hashSet->ddictPtrTable[idx] = ddict;121hashSet->ddictPtrCount++;122return 0;123}124125/* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and126* rehashes all values, allocates new table, frees old table.127* Returns 0 on success, otherwise a zstd error code.128*/129static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {130size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR;131const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem);132const ZSTD_DDict** oldTable = hashSet->ddictPtrTable;133size_t oldTableSize = hashSet->ddictPtrTableSize;134size_t i;135136DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize);137RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!");138hashSet->ddictPtrTable = newTable;139hashSet->ddictPtrTableSize = newTableSize;140hashSet->ddictPtrCount = 0;141for (i = 0; i < oldTableSize; ++i) {142if (oldTable[i] != NULL) {143FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), "");144}145}146ZSTD_customFree((void*)oldTable, customMem);147DEBUGLOG(4, "Finished re-hash");148return 0;149}150151/* Fetches a DDict with the given dictID152* Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL.153*/154static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) {155size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);156const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;157DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);158for (;;) {159size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]);160if (currDictID == dictID || currDictID == 0) {161/* currDictID == 0 implies a NULL ddict entry */162break;163} else {164idx &= idxRangeMask; /* Goes to start of table when we reach the end */165idx++;166}167}168DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);169return hashSet->ddictPtrTable[idx];170}171172/* Allocates space for and returns a ddict hash set173* The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with.174* Returns NULL if allocation failed.175*/176static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) {177ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem);178DEBUGLOG(4, "Allocating new hash set");179if (!ret)180return NULL;181ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem);182if (!ret->ddictPtrTable) {183ZSTD_customFree(ret, customMem);184return NULL;185}186ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE;187ret->ddictPtrCount = 0;188return ret;189}190191/* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself.192* Note: The ZSTD_DDict* within the table are NOT freed.193*/194static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {195DEBUGLOG(4, "Freeing ddict hash set");196if (hashSet && hashSet->ddictPtrTable) {197ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem);198}199if (hashSet) {200ZSTD_customFree(hashSet, customMem);201}202}203204/* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set.205* Returns 0 on success, or a ZSTD error.206*/207static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) {208DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize);209if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) {210FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), "");211}212FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), "");213return 0;214}215216/*-*************************************************************217* Context management218***************************************************************/219size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx)220{221if (dctx==NULL) return 0; /* support sizeof NULL */222return sizeof(*dctx)223+ ZSTD_sizeof_DDict(dctx->ddictLocal)224+ dctx->inBuffSize + dctx->outBuffSize;225}226227size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }228229230static size_t ZSTD_startingInputLength(ZSTD_format_e format)231{232size_t const startingInputLength = ZSTD_FRAMEHEADERSIZE_PREFIX(format);233/* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */234assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) );235return startingInputLength;236}237238static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx)239{240assert(dctx->streamStage == zdss_init);241dctx->format = ZSTD_f_zstd1;242dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;243dctx->outBufferMode = ZSTD_bm_buffered;244dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum;245dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict;246dctx->disableHufAsm = 0;247}248249static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)250{251dctx->staticSize = 0;252dctx->ddict = NULL;253dctx->ddictLocal = NULL;254dctx->dictEnd = NULL;255dctx->ddictIsCold = 0;256dctx->dictUses = ZSTD_dont_use;257dctx->inBuff = NULL;258dctx->inBuffSize = 0;259dctx->outBuffSize = 0;260dctx->streamStage = zdss_init;261#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)262dctx->legacyContext = NULL;263dctx->previousLegacyVersion = 0;264#endif265dctx->noForwardProgress = 0;266dctx->oversizedDuration = 0;267#if DYNAMIC_BMI2268dctx->bmi2 = ZSTD_cpuSupportsBmi2();269#endif270dctx->ddictSet = NULL;271ZSTD_DCtx_resetParameters(dctx);272#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION273dctx->dictContentEndForFuzzing = NULL;274#endif275}276277ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)278{279ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace;280281if ((size_t)workspace & 7) return NULL; /* 8-aligned */282if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */283284ZSTD_initDCtx_internal(dctx);285dctx->staticSize = workspaceSize;286dctx->inBuff = (char*)(dctx+1);287return dctx;288}289290static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) {291if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;292293{ ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem);294if (!dctx) return NULL;295dctx->customMem = customMem;296ZSTD_initDCtx_internal(dctx);297return dctx;298}299}300301ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)302{303return ZSTD_createDCtx_internal(customMem);304}305306ZSTD_DCtx* ZSTD_createDCtx(void)307{308DEBUGLOG(3, "ZSTD_createDCtx");309return ZSTD_createDCtx_internal(ZSTD_defaultCMem);310}311312static void ZSTD_clearDict(ZSTD_DCtx* dctx)313{314ZSTD_freeDDict(dctx->ddictLocal);315dctx->ddictLocal = NULL;316dctx->ddict = NULL;317dctx->dictUses = ZSTD_dont_use;318}319320size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)321{322if (dctx==NULL) return 0; /* support free on NULL */323RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx");324{ ZSTD_customMem const cMem = dctx->customMem;325ZSTD_clearDict(dctx);326ZSTD_customFree(dctx->inBuff, cMem);327dctx->inBuff = NULL;328#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)329if (dctx->legacyContext)330ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);331#endif332if (dctx->ddictSet) {333ZSTD_freeDDictHashSet(dctx->ddictSet, cMem);334dctx->ddictSet = NULL;335}336ZSTD_customFree(dctx, cMem);337return 0;338}339}340341/* no longer useful */342void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)343{344size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx);345ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */346}347348/* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on349* the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then350* accordingly sets the ddict to be used to decompress the frame.351*352* If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is.353*354* ZSTD_d_refMultipleDDicts must be enabled for this function to be called.355*/356static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) {357assert(dctx->refMultipleDDicts && dctx->ddictSet);358DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame");359if (dctx->ddict) {360const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID);361if (frameDDict) {362DEBUGLOG(4, "DDict found!");363ZSTD_clearDict(dctx);364dctx->dictID = dctx->fParams.dictID;365dctx->ddict = frameDDict;366dctx->dictUses = ZSTD_use_indefinitely;367}368}369}370371372/*-*************************************************************373* Frame header decoding374***************************************************************/375376/*! ZSTD_isFrame() :377* Tells if the content of `buffer` starts with a valid Frame Identifier.378* Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.379* Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.380* Note 3 : Skippable Frame Identifiers are considered valid. */381unsigned ZSTD_isFrame(const void* buffer, size_t size)382{383if (size < ZSTD_FRAMEIDSIZE) return 0;384{ U32 const magic = MEM_readLE32(buffer);385if (magic == ZSTD_MAGICNUMBER) return 1;386if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;387}388#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)389if (ZSTD_isLegacy(buffer, size)) return 1;390#endif391return 0;392}393394/*! ZSTD_isSkippableFrame() :395* Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame.396* Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.397*/398unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size)399{400if (size < ZSTD_FRAMEIDSIZE) return 0;401{ U32 const magic = MEM_readLE32(buffer);402if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;403}404return 0;405}406407/** ZSTD_frameHeaderSize_internal() :408* srcSize must be large enough to reach header size fields.409* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless.410* @return : size of the Frame Header411* or an error code, which can be tested with ZSTD_isError() */412static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)413{414size_t const minInputSize = ZSTD_startingInputLength(format);415RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong, "");416417{ BYTE const fhd = ((const BYTE*)src)[minInputSize-1];418U32 const dictID= fhd & 3;419U32 const singleSegment = (fhd >> 5) & 1;420U32 const fcsId = fhd >> 6;421return minInputSize + !singleSegment422+ ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]423+ (singleSegment && !fcsId);424}425}426427/** ZSTD_frameHeaderSize() :428* srcSize must be >= ZSTD_frameHeaderSize_prefix.429* @return : size of the Frame Header,430* or an error code (if srcSize is too small) */431size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)432{433return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);434}435436437/** ZSTD_getFrameHeader_advanced() :438* decode Frame Header, or require larger `srcSize`.439* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless440* @return : 0, `zfhPtr` is correctly filled,441* >0, `srcSize` is too small, value is wanted `srcSize` amount,442** or an error code, which can be tested using ZSTD_isError() */443size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)444{445const BYTE* ip = (const BYTE*)src;446size_t const minInputSize = ZSTD_startingInputLength(format);447448DEBUGLOG(5, "ZSTD_getFrameHeader_advanced: minInputSize = %zu, srcSize = %zu", minInputSize, srcSize);449450if (srcSize > 0) {451/* note : technically could be considered an assert(), since it's an invalid entry */452RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter : src==NULL, but srcSize>0");453}454if (srcSize < minInputSize) {455if (srcSize > 0 && format != ZSTD_f_zstd1_magicless) {456/* when receiving less than @minInputSize bytes,457* control these bytes at least correspond to a supported magic number458* in order to error out early if they don't.459**/460size_t const toCopy = MIN(4, srcSize);461unsigned char hbuf[4]; MEM_writeLE32(hbuf, ZSTD_MAGICNUMBER);462assert(src != NULL);463ZSTD_memcpy(hbuf, src, toCopy);464if ( MEM_readLE32(hbuf) != ZSTD_MAGICNUMBER ) {465/* not a zstd frame : let's check if it's a skippable frame */466MEM_writeLE32(hbuf, ZSTD_MAGIC_SKIPPABLE_START);467ZSTD_memcpy(hbuf, src, toCopy);468if ((MEM_readLE32(hbuf) & ZSTD_MAGIC_SKIPPABLE_MASK) != ZSTD_MAGIC_SKIPPABLE_START) {469RETURN_ERROR(prefix_unknown,470"first bytes don't correspond to any supported magic number");471} } }472return minInputSize;473}474475ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzers may not understand that zfhPtr will be read only if return value is zero, since they are 2 different signals */476if ( (format != ZSTD_f_zstd1_magicless)477&& (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {478if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {479/* skippable frame */480if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)481return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */482ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr));483zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);484zfhPtr->frameType = ZSTD_skippableFrame;485return 0;486}487RETURN_ERROR(prefix_unknown, "");488}489490/* ensure there is enough `srcSize` to fully read/decode frame header */491{ size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format);492if (srcSize < fhsize) return fhsize;493zfhPtr->headerSize = (U32)fhsize;494}495496{ BYTE const fhdByte = ip[minInputSize-1];497size_t pos = minInputSize;498U32 const dictIDSizeCode = fhdByte&3;499U32 const checksumFlag = (fhdByte>>2)&1;500U32 const singleSegment = (fhdByte>>5)&1;501U32 const fcsID = fhdByte>>6;502U64 windowSize = 0;503U32 dictID = 0;504U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN;505RETURN_ERROR_IF((fhdByte & 0x08) != 0, frameParameter_unsupported,506"reserved bits, must be zero");507508if (!singleSegment) {509BYTE const wlByte = ip[pos++];510U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;511RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge, "");512windowSize = (1ULL << windowLog);513windowSize += (windowSize >> 3) * (wlByte&7);514}515switch(dictIDSizeCode)516{517default:518assert(0); /* impossible */519ZSTD_FALLTHROUGH;520case 0 : break;521case 1 : dictID = ip[pos]; pos++; break;522case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break;523case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break;524}525switch(fcsID)526{527default:528assert(0); /* impossible */529ZSTD_FALLTHROUGH;530case 0 : if (singleSegment) frameContentSize = ip[pos]; break;531case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;532case 2 : frameContentSize = MEM_readLE32(ip+pos); break;533case 3 : frameContentSize = MEM_readLE64(ip+pos); break;534}535if (singleSegment) windowSize = frameContentSize;536537zfhPtr->frameType = ZSTD_frame;538zfhPtr->frameContentSize = frameContentSize;539zfhPtr->windowSize = windowSize;540zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);541zfhPtr->dictID = dictID;542zfhPtr->checksumFlag = checksumFlag;543}544return 0;545}546547/** ZSTD_getFrameHeader() :548* decode Frame Header, or require larger `srcSize`.549* note : this function does not consume input, it only reads it.550* @return : 0, `zfhPtr` is correctly filled,551* >0, `srcSize` is too small, value is wanted `srcSize` amount,552* or an error code, which can be tested using ZSTD_isError() */553size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)554{555return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);556}557558/** ZSTD_getFrameContentSize() :559* compatible with legacy mode560* @return : decompressed size of the single frame pointed to be `src` if known, otherwise561* - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined562* - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */563unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)564{565#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)566if (ZSTD_isLegacy(src, srcSize)) {567unsigned long long const ret = ZSTD_getDecompressedSize_legacy(src, srcSize);568return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret;569}570#endif571{ ZSTD_frameHeader zfh;572if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0)573return ZSTD_CONTENTSIZE_ERROR;574if (zfh.frameType == ZSTD_skippableFrame) {575return 0;576} else {577return zfh.frameContentSize;578} }579}580581static size_t readSkippableFrameSize(void const* src, size_t srcSize)582{583size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE;584U32 sizeU32;585586RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, "");587588sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);589RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32,590frameParameter_unsupported, "");591{ size_t const skippableSize = skippableHeaderSize + sizeU32;592RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, "");593return skippableSize;594}595}596597/*! ZSTD_readSkippableFrame() :598* Retrieves content of a skippable frame, and writes it to dst buffer.599*600* The parameter magicVariant will receive the magicVariant that was supplied when the frame was written,601* i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested602* in the magicVariant.603*604* Returns an error if destination buffer is not large enough, or if this is not a valid skippable frame.605*606* @return : number of bytes written or a ZSTD error.607*/608size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity,609unsigned* magicVariant, /* optional, can be NULL */610const void* src, size_t srcSize)611{612RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, "");613614{ U32 const magicNumber = MEM_readLE32(src);615size_t skippableFrameSize = readSkippableFrameSize(src, srcSize);616size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE;617618/* check input validity */619RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, "");620RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, "");621RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, "");622623/* deliver payload */624if (skippableContentSize > 0 && dst != NULL)625ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize);626if (magicVariant != NULL)627*magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START;628return skippableContentSize;629}630}631632/** ZSTD_findDecompressedSize() :633* `srcSize` must be the exact length of some number of ZSTD compressed and/or634* skippable frames635* note: compatible with legacy mode636* @return : decompressed size of the frames contained */637unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)638{639unsigned long long totalDstSize = 0;640641while (srcSize >= ZSTD_startingInputLength(ZSTD_f_zstd1)) {642U32 const magicNumber = MEM_readLE32(src);643644if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {645size_t const skippableSize = readSkippableFrameSize(src, srcSize);646if (ZSTD_isError(skippableSize)) return ZSTD_CONTENTSIZE_ERROR;647assert(skippableSize <= srcSize);648649src = (const BYTE *)src + skippableSize;650srcSize -= skippableSize;651continue;652}653654{ unsigned long long const fcs = ZSTD_getFrameContentSize(src, srcSize);655if (fcs >= ZSTD_CONTENTSIZE_ERROR) return fcs;656657if (totalDstSize + fcs < totalDstSize)658return ZSTD_CONTENTSIZE_ERROR; /* check for overflow */659totalDstSize += fcs;660}661/* skip to next frame */662{ size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);663if (ZSTD_isError(frameSrcSize)) return ZSTD_CONTENTSIZE_ERROR;664assert(frameSrcSize <= srcSize);665666src = (const BYTE *)src + frameSrcSize;667srcSize -= frameSrcSize;668}669} /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */670671if (srcSize) return ZSTD_CONTENTSIZE_ERROR;672673return totalDstSize;674}675676/** ZSTD_getDecompressedSize() :677* compatible with legacy mode678* @return : decompressed size if known, 0 otherwise679note : 0 can mean any of the following :680- frame content is empty681- decompressed size field is not present in frame header682- frame header unknown / not supported683- frame header not complete (`srcSize` too small) */684unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)685{686unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);687ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN);688return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret;689}690691692/** ZSTD_decodeFrameHeader() :693* `headerSize` must be the size provided by ZSTD_frameHeaderSize().694* If multiple DDict references are enabled, also will choose the correct DDict to use.695* @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */696static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)697{698size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);699if (ZSTD_isError(result)) return result; /* invalid header */700RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small");701702/* Reference DDict requested by frame if dctx references multiple ddicts */703if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) {704ZSTD_DCtx_selectFrameDDict(dctx);705}706707#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION708/* Skip the dictID check in fuzzing mode, because it makes the search709* harder.710*/711RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID),712dictionary_wrong, "");713#endif714dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0;715if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0);716dctx->processedCSize += headerSize;717return 0;718}719720static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret)721{722ZSTD_frameSizeInfo frameSizeInfo;723frameSizeInfo.compressedSize = ret;724frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR;725return frameSizeInfo;726}727728static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize)729{730ZSTD_frameSizeInfo frameSizeInfo;731ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));732733#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)734if (ZSTD_isLegacy(src, srcSize))735return ZSTD_findFrameSizeInfoLegacy(src, srcSize);736#endif737738if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE)739&& (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {740frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize);741assert(ZSTD_isError(frameSizeInfo.compressedSize) ||742frameSizeInfo.compressedSize <= srcSize);743return frameSizeInfo;744} else {745const BYTE* ip = (const BYTE*)src;746const BYTE* const ipstart = ip;747size_t remainingSize = srcSize;748size_t nbBlocks = 0;749ZSTD_frameHeader zfh;750751/* Extract Frame Header */752{ size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize);753if (ZSTD_isError(ret))754return ZSTD_errorFrameSizeInfo(ret);755if (ret > 0)756return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));757}758759ip += zfh.headerSize;760remainingSize -= zfh.headerSize;761762/* Iterate over each block */763while (1) {764blockProperties_t blockProperties;765size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);766if (ZSTD_isError(cBlockSize))767return ZSTD_errorFrameSizeInfo(cBlockSize);768769if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)770return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));771772ip += ZSTD_blockHeaderSize + cBlockSize;773remainingSize -= ZSTD_blockHeaderSize + cBlockSize;774nbBlocks++;775776if (blockProperties.lastBlock) break;777}778779/* Final frame content checksum */780if (zfh.checksumFlag) {781if (remainingSize < 4)782return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));783ip += 4;784}785786frameSizeInfo.nbBlocks = nbBlocks;787frameSizeInfo.compressedSize = (size_t)(ip - ipstart);788frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN)789? zfh.frameContentSize790: (unsigned long long)nbBlocks * zfh.blockSizeMax;791return frameSizeInfo;792}793}794795/** ZSTD_findFrameCompressedSize() :796* compatible with legacy mode797* `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame798* `srcSize` must be at least as large as the frame contained799* @return : the compressed size of the frame starting at `src` */800size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)801{802ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);803return frameSizeInfo.compressedSize;804}805806/** ZSTD_decompressBound() :807* compatible with legacy mode808* `src` must point to the start of a ZSTD frame or a skippeable frame809* `srcSize` must be at least as large as the frame contained810* @return : the maximum decompressed size of the compressed source811*/812unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)813{814unsigned long long bound = 0;815/* Iterate over each frame */816while (srcSize > 0) {817ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);818size_t const compressedSize = frameSizeInfo.compressedSize;819unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;820if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)821return ZSTD_CONTENTSIZE_ERROR;822assert(srcSize >= compressedSize);823src = (const BYTE*)src + compressedSize;824srcSize -= compressedSize;825bound += decompressedBound;826}827return bound;828}829830size_t ZSTD_decompressionMargin(void const* src, size_t srcSize)831{832size_t margin = 0;833unsigned maxBlockSize = 0;834835/* Iterate over each frame */836while (srcSize > 0) {837ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);838size_t const compressedSize = frameSizeInfo.compressedSize;839unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;840ZSTD_frameHeader zfh;841842FORWARD_IF_ERROR(ZSTD_getFrameHeader(&zfh, src, srcSize), "");843if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)844return ERROR(corruption_detected);845846if (zfh.frameType == ZSTD_frame) {847/* Add the frame header to our margin */848margin += zfh.headerSize;849/* Add the checksum to our margin */850margin += zfh.checksumFlag ? 4 : 0;851/* Add 3 bytes per block */852margin += 3 * frameSizeInfo.nbBlocks;853854/* Compute the max block size */855maxBlockSize = MAX(maxBlockSize, zfh.blockSizeMax);856} else {857assert(zfh.frameType == ZSTD_skippableFrame);858/* Add the entire skippable frame size to our margin. */859margin += compressedSize;860}861862assert(srcSize >= compressedSize);863src = (const BYTE*)src + compressedSize;864srcSize -= compressedSize;865}866867/* Add the max block size back to the margin. */868margin += maxBlockSize;869870return margin;871}872873/*-*************************************************************874* Frame decoding875***************************************************************/876877/** ZSTD_insertBlock() :878* insert `src` block into `dctx` history. Useful to track uncompressed blocks. */879size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)880{881DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize);882ZSTD_checkContinuity(dctx, blockStart, blockSize);883dctx->previousDstEnd = (const char*)blockStart + blockSize;884return blockSize;885}886887888static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity,889const void* src, size_t srcSize)890{891DEBUGLOG(5, "ZSTD_copyRawBlock");892RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, "");893if (dst == NULL) {894if (srcSize == 0) return 0;895RETURN_ERROR(dstBuffer_null, "");896}897ZSTD_memmove(dst, src, srcSize);898return srcSize;899}900901static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,902BYTE b,903size_t regenSize)904{905RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, "");906if (dst == NULL) {907if (regenSize == 0) return 0;908RETURN_ERROR(dstBuffer_null, "");909}910ZSTD_memset(dst, b, regenSize);911return regenSize;912}913914static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming)915{916#if ZSTD_TRACE917if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) {918ZSTD_Trace trace;919ZSTD_memset(&trace, 0, sizeof(trace));920trace.version = ZSTD_VERSION_NUMBER;921trace.streaming = streaming;922if (dctx->ddict) {923trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict);924trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict);925trace.dictionaryIsCold = dctx->ddictIsCold;926}927trace.uncompressedSize = (size_t)uncompressedSize;928trace.compressedSize = (size_t)compressedSize;929trace.dctx = dctx;930ZSTD_trace_decompress_end(dctx->traceCtx, &trace);931}932#else933(void)dctx;934(void)uncompressedSize;935(void)compressedSize;936(void)streaming;937#endif938}939940941/*! ZSTD_decompressFrame() :942* @dctx must be properly initialized943* will update *srcPtr and *srcSizePtr,944* to make *srcPtr progress by one frame. */945static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,946void* dst, size_t dstCapacity,947const void** srcPtr, size_t *srcSizePtr)948{949const BYTE* const istart = (const BYTE*)(*srcPtr);950const BYTE* ip = istart;951BYTE* const ostart = (BYTE*)dst;952BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart;953BYTE* op = ostart;954size_t remainingSrcSize = *srcSizePtr;955956DEBUGLOG(4, "ZSTD_decompressFrame (srcSize:%i)", (int)*srcSizePtr);957958/* check */959RETURN_ERROR_IF(960remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize,961srcSize_wrong, "");962963/* Frame Header */964{ size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal(965ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format);966if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;967RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize,968srcSize_wrong, "");969FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , "");970ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;971}972973/* Loop on each block */974while (1) {975BYTE* oBlockEnd = oend;976size_t decodedSize;977blockProperties_t blockProperties;978size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties);979if (ZSTD_isError(cBlockSize)) return cBlockSize;980981ip += ZSTD_blockHeaderSize;982remainingSrcSize -= ZSTD_blockHeaderSize;983RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, "");984985if (ip >= op && ip < oBlockEnd) {986/* We are decompressing in-place. Limit the output pointer so that we987* don't overwrite the block that we are currently reading. This will988* fail decompression if the input & output pointers aren't spaced989* far enough apart.990*991* This is important to set, even when the pointers are far enough992* apart, because ZSTD_decompressBlock_internal() can decide to store993* literals in the output buffer, after the block it is decompressing.994* Since we don't want anything to overwrite our input, we have to tell995* ZSTD_decompressBlock_internal to never write past ip.996*997* See ZSTD_allocateLiteralsBuffer() for reference.998*/999oBlockEnd = op + (ip - op);1000}10011002switch(blockProperties.blockType)1003{1004case bt_compressed:1005decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oBlockEnd-op), ip, cBlockSize, /* frame */ 1, not_streaming);1006break;1007case bt_raw :1008/* Use oend instead of oBlockEnd because this function is safe to overlap. It uses memmove. */1009decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize);1010break;1011case bt_rle :1012decodedSize = ZSTD_setRleBlock(op, (size_t)(oBlockEnd-op), *ip, blockProperties.origSize);1013break;1014case bt_reserved :1015default:1016RETURN_ERROR(corruption_detected, "invalid block type");1017}10181019if (ZSTD_isError(decodedSize)) return decodedSize;1020if (dctx->validateChecksum)1021XXH64_update(&dctx->xxhState, op, decodedSize);1022if (decodedSize != 0)1023op += decodedSize;1024assert(ip != NULL);1025ip += cBlockSize;1026remainingSrcSize -= cBlockSize;1027if (blockProperties.lastBlock) break;1028}10291030if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {1031RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize,1032corruption_detected, "");1033}1034if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */1035RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, "");1036if (!dctx->forceIgnoreChecksum) {1037U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);1038U32 checkRead;1039checkRead = MEM_readLE32(ip);1040RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, "");1041}1042ip += 4;1043remainingSrcSize -= 4;1044}1045ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0);1046/* Allow caller to get size read */1047DEBUGLOG(4, "ZSTD_decompressFrame: decompressed frame of size %zi, consuming %zi bytes of input", op-ostart, ip - (const BYTE*)*srcPtr);1048*srcPtr = ip;1049*srcSizePtr = remainingSrcSize;1050return (size_t)(op-ostart);1051}10521053static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,1054void* dst, size_t dstCapacity,1055const void* src, size_t srcSize,1056const void* dict, size_t dictSize,1057const ZSTD_DDict* ddict)1058{1059void* const dststart = dst;1060int moreThan1Frame = 0;10611062DEBUGLOG(5, "ZSTD_decompressMultiFrame");1063assert(dict==NULL || ddict==NULL); /* either dict or ddict set, not both */10641065if (ddict) {1066dict = ZSTD_DDict_dictContent(ddict);1067dictSize = ZSTD_DDict_dictSize(ddict);1068}10691070while (srcSize >= ZSTD_startingInputLength(dctx->format)) {10711072#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)1073if (ZSTD_isLegacy(src, srcSize)) {1074size_t decodedSize;1075size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize);1076if (ZSTD_isError(frameSize)) return frameSize;1077RETURN_ERROR_IF(dctx->staticSize, memory_allocation,1078"legacy support is not compatible with static dctx");10791080decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);1081if (ZSTD_isError(decodedSize)) return decodedSize;10821083assert(decodedSize <= dstCapacity);1084dst = (BYTE*)dst + decodedSize;1085dstCapacity -= decodedSize;10861087src = (const BYTE*)src + frameSize;1088srcSize -= frameSize;10891090continue;1091}1092#endif10931094if (srcSize >= 4) {1095U32 const magicNumber = MEM_readLE32(src);1096DEBUGLOG(5, "reading magic number %08X", (unsigned)magicNumber);1097if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {1098/* skippable frame detected : skip it */1099size_t const skippableSize = readSkippableFrameSize(src, srcSize);1100FORWARD_IF_ERROR(skippableSize, "invalid skippable frame");1101assert(skippableSize <= srcSize);11021103src = (const BYTE *)src + skippableSize;1104srcSize -= skippableSize;1105continue; /* check next frame */1106} }11071108if (ddict) {1109/* we were called from ZSTD_decompress_usingDDict */1110FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict), "");1111} else {1112/* this will initialize correctly with no dict if dict == NULL, so1113* use this in all cases but ddict */1114FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), "");1115}1116ZSTD_checkContinuity(dctx, dst, dstCapacity);11171118{ const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,1119&src, &srcSize);1120RETURN_ERROR_IF(1121(ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown)1122&& (moreThan1Frame==1),1123srcSize_wrong,1124"At least one frame successfully completed, "1125"but following bytes are garbage: "1126"it's more likely to be a srcSize error, "1127"specifying more input bytes than size of frame(s). "1128"Note: one could be unlucky, it might be a corruption error instead, "1129"happening right at the place where we expect zstd magic bytes. "1130"But this is _much_ less likely than a srcSize field error.");1131if (ZSTD_isError(res)) return res;1132assert(res <= dstCapacity);1133if (res != 0)1134dst = (BYTE*)dst + res;1135dstCapacity -= res;1136}1137moreThan1Frame = 1;1138} /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */11391140RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed");11411142return (size_t)((BYTE*)dst - (BYTE*)dststart);1143}11441145size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,1146void* dst, size_t dstCapacity,1147const void* src, size_t srcSize,1148const void* dict, size_t dictSize)1149{1150return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL);1151}115211531154static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx)1155{1156switch (dctx->dictUses) {1157default:1158assert(0 /* Impossible */);1159ZSTD_FALLTHROUGH;1160case ZSTD_dont_use:1161ZSTD_clearDict(dctx);1162return NULL;1163case ZSTD_use_indefinitely:1164return dctx->ddict;1165case ZSTD_use_once:1166dctx->dictUses = ZSTD_dont_use;1167return dctx->ddict;1168}1169}11701171size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)1172{1173return ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ZSTD_getDDict(dctx));1174}117511761177size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize)1178{1179#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1)1180size_t regenSize;1181ZSTD_DCtx* const dctx = ZSTD_createDCtx_internal(ZSTD_defaultCMem);1182RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!");1183regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);1184ZSTD_freeDCtx(dctx);1185return regenSize;1186#else /* stack mode */1187ZSTD_DCtx dctx;1188ZSTD_initDCtx_internal(&dctx);1189return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize);1190#endif1191}119211931194/*-**************************************1195* Advanced Streaming Decompression API1196* Bufferless and synchronous1197****************************************/1198size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }11991200/**1201* Similar to ZSTD_nextSrcSizeToDecompress(), but when a block input can be streamed, we1202* allow taking a partial block as the input. Currently only raw uncompressed blocks can1203* be streamed.1204*1205* For blocks that can be streamed, this allows us to reduce the latency until we produce1206* output, and avoid copying the input.1207*1208* @param inputSize - The total amount of input that the caller currently has.1209*/1210static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t inputSize) {1211if (!(dctx->stage == ZSTDds_decompressBlock || dctx->stage == ZSTDds_decompressLastBlock))1212return dctx->expected;1213if (dctx->bType != bt_raw)1214return dctx->expected;1215return BOUNDED(1, inputSize, dctx->expected);1216}12171218ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {1219switch(dctx->stage)1220{1221default: /* should not happen */1222assert(0);1223ZSTD_FALLTHROUGH;1224case ZSTDds_getFrameHeaderSize:1225ZSTD_FALLTHROUGH;1226case ZSTDds_decodeFrameHeader:1227return ZSTDnit_frameHeader;1228case ZSTDds_decodeBlockHeader:1229return ZSTDnit_blockHeader;1230case ZSTDds_decompressBlock:1231return ZSTDnit_block;1232case ZSTDds_decompressLastBlock:1233return ZSTDnit_lastBlock;1234case ZSTDds_checkChecksum:1235return ZSTDnit_checksum;1236case ZSTDds_decodeSkippableHeader:1237ZSTD_FALLTHROUGH;1238case ZSTDds_skipFrame:1239return ZSTDnit_skippableFrame;1240}1241}12421243static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; }12441245/** ZSTD_decompressContinue() :1246* srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress())1247* @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)1248* or an error code, which can be tested using ZSTD_isError() */1249size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)1250{1251DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);1252/* Sanity check */1253RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed");1254ZSTD_checkContinuity(dctx, dst, dstCapacity);12551256dctx->processedCSize += srcSize;12571258switch (dctx->stage)1259{1260case ZSTDds_getFrameHeaderSize :1261assert(src != NULL);1262if (dctx->format == ZSTD_f_zstd1) { /* allows header */1263assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */1264if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */1265ZSTD_memcpy(dctx->headerBuffer, src, srcSize);1266dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */1267dctx->stage = ZSTDds_decodeSkippableHeader;1268return 0;1269} }1270dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);1271if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;1272ZSTD_memcpy(dctx->headerBuffer, src, srcSize);1273dctx->expected = dctx->headerSize - srcSize;1274dctx->stage = ZSTDds_decodeFrameHeader;1275return 0;12761277case ZSTDds_decodeFrameHeader:1278assert(src != NULL);1279ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);1280FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), "");1281dctx->expected = ZSTD_blockHeaderSize;1282dctx->stage = ZSTDds_decodeBlockHeader;1283return 0;12841285case ZSTDds_decodeBlockHeader:1286{ blockProperties_t bp;1287size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);1288if (ZSTD_isError(cBlockSize)) return cBlockSize;1289RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum");1290dctx->expected = cBlockSize;1291dctx->bType = bp.blockType;1292dctx->rleSize = bp.origSize;1293if (cBlockSize) {1294dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;1295return 0;1296}1297/* empty block */1298if (bp.lastBlock) {1299if (dctx->fParams.checksumFlag) {1300dctx->expected = 4;1301dctx->stage = ZSTDds_checkChecksum;1302} else {1303dctx->expected = 0; /* end of frame */1304dctx->stage = ZSTDds_getFrameHeaderSize;1305}1306} else {1307dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */1308dctx->stage = ZSTDds_decodeBlockHeader;1309}1310return 0;1311}13121313case ZSTDds_decompressLastBlock:1314case ZSTDds_decompressBlock:1315DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock");1316{ size_t rSize;1317switch(dctx->bType)1318{1319case bt_compressed:1320DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");1321rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1, is_streaming);1322dctx->expected = 0; /* Streaming not supported */1323break;1324case bt_raw :1325assert(srcSize <= dctx->expected);1326rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);1327FORWARD_IF_ERROR(rSize, "ZSTD_copyRawBlock failed");1328assert(rSize == srcSize);1329dctx->expected -= rSize;1330break;1331case bt_rle :1332rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize);1333dctx->expected = 0; /* Streaming not supported */1334break;1335case bt_reserved : /* should never happen */1336default:1337RETURN_ERROR(corruption_detected, "invalid block type");1338}1339FORWARD_IF_ERROR(rSize, "");1340RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum");1341DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);1342dctx->decodedSize += rSize;1343if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize);1344dctx->previousDstEnd = (char*)dst + rSize;13451346/* Stay on the same stage until we are finished streaming the block. */1347if (dctx->expected > 0) {1348return rSize;1349}13501351if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */1352DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize);1353RETURN_ERROR_IF(1354dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN1355&& dctx->decodedSize != dctx->fParams.frameContentSize,1356corruption_detected, "");1357if (dctx->fParams.checksumFlag) { /* another round for frame checksum */1358dctx->expected = 4;1359dctx->stage = ZSTDds_checkChecksum;1360} else {1361ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);1362dctx->expected = 0; /* ends here */1363dctx->stage = ZSTDds_getFrameHeaderSize;1364}1365} else {1366dctx->stage = ZSTDds_decodeBlockHeader;1367dctx->expected = ZSTD_blockHeaderSize;1368}1369return rSize;1370}13711372case ZSTDds_checkChecksum:1373assert(srcSize == 4); /* guaranteed by dctx->expected */1374{1375if (dctx->validateChecksum) {1376U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);1377U32 const check32 = MEM_readLE32(src);1378DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);1379RETURN_ERROR_IF(check32 != h32, checksum_wrong, "");1380}1381ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);1382dctx->expected = 0;1383dctx->stage = ZSTDds_getFrameHeaderSize;1384return 0;1385}13861387case ZSTDds_decodeSkippableHeader:1388assert(src != NULL);1389assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);1390ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */1391dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */1392dctx->stage = ZSTDds_skipFrame;1393return 0;13941395case ZSTDds_skipFrame:1396dctx->expected = 0;1397dctx->stage = ZSTDds_getFrameHeaderSize;1398return 0;13991400default:1401assert(0); /* impossible */1402RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */1403}1404}140514061407static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1408{1409dctx->dictEnd = dctx->previousDstEnd;1410dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));1411dctx->prefixStart = dict;1412dctx->previousDstEnd = (const char*)dict + dictSize;1413#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION1414dctx->dictContentBeginForFuzzing = dctx->prefixStart;1415dctx->dictContentEndForFuzzing = dctx->previousDstEnd;1416#endif1417return 0;1418}14191420/*! ZSTD_loadDEntropy() :1421* dict : must point at beginning of a valid zstd dictionary.1422* @return : size of entropy tables read */1423size_t1424ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,1425const void* const dict, size_t const dictSize)1426{1427const BYTE* dictPtr = (const BYTE*)dict;1428const BYTE* const dictEnd = dictPtr + dictSize;14291430RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted, "dict is too small");1431assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */1432dictPtr += 8; /* skip header = magic + dictID */14331434ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, OFTable) == offsetof(ZSTD_entropyDTables_t, LLTable) + sizeof(entropy->LLTable));1435ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, MLTable) == offsetof(ZSTD_entropyDTables_t, OFTable) + sizeof(entropy->OFTable));1436ZSTD_STATIC_ASSERT(sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable) >= HUF_DECOMPRESS_WORKSPACE_SIZE);1437{ void* const workspace = &entropy->LLTable; /* use fse tables as temporary workspace; implies fse tables are grouped together */1438size_t const workspaceSize = sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable);1439#ifdef HUF_FORCE_DECOMPRESS_X11440/* in minimal huffman, we always use X1 variants */1441size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable,1442dictPtr, dictEnd - dictPtr,1443workspace, workspaceSize, /* flags */ 0);1444#else1445size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,1446dictPtr, (size_t)(dictEnd - dictPtr),1447workspace, workspaceSize, /* flags */ 0);1448#endif1449RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, "");1450dictPtr += hSize;1451}14521453{ short offcodeNCount[MaxOff+1];1454unsigned offcodeMaxValue = MaxOff, offcodeLog;1455size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr));1456RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");1457RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, "");1458RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");1459ZSTD_buildFSETable( entropy->OFTable,1460offcodeNCount, offcodeMaxValue,1461OF_base, OF_bits,1462offcodeLog,1463entropy->workspace, sizeof(entropy->workspace),1464/* bmi2 */0);1465dictPtr += offcodeHeaderSize;1466}14671468{ short matchlengthNCount[MaxML+1];1469unsigned matchlengthMaxValue = MaxML, matchlengthLog;1470size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr));1471RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");1472RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, "");1473RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");1474ZSTD_buildFSETable( entropy->MLTable,1475matchlengthNCount, matchlengthMaxValue,1476ML_base, ML_bits,1477matchlengthLog,1478entropy->workspace, sizeof(entropy->workspace),1479/* bmi2 */ 0);1480dictPtr += matchlengthHeaderSize;1481}14821483{ short litlengthNCount[MaxLL+1];1484unsigned litlengthMaxValue = MaxLL, litlengthLog;1485size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr));1486RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");1487RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, "");1488RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");1489ZSTD_buildFSETable( entropy->LLTable,1490litlengthNCount, litlengthMaxValue,1491LL_base, LL_bits,1492litlengthLog,1493entropy->workspace, sizeof(entropy->workspace),1494/* bmi2 */ 0);1495dictPtr += litlengthHeaderSize;1496}14971498RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, "");1499{ int i;1500size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12));1501for (i=0; i<3; i++) {1502U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4;1503RETURN_ERROR_IF(rep==0 || rep > dictContentSize,1504dictionary_corrupted, "");1505entropy->rep[i] = rep;1506} }15071508return (size_t)(dictPtr - (const BYTE*)dict);1509}15101511static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1512{1513if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize);1514{ U32 const magic = MEM_readLE32(dict);1515if (magic != ZSTD_MAGIC_DICTIONARY) {1516return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */1517} }1518dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);15191520/* load entropy tables */1521{ size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize);1522RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted, "");1523dict = (const char*)dict + eSize;1524dictSize -= eSize;1525}1526dctx->litEntropy = dctx->fseEntropy = 1;15271528/* reference dictionary content */1529return ZSTD_refDictContent(dctx, dict, dictSize);1530}15311532size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)1533{1534assert(dctx != NULL);1535#if ZSTD_TRACE1536dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0;1537#endif1538dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */1539dctx->stage = ZSTDds_getFrameHeaderSize;1540dctx->processedCSize = 0;1541dctx->decodedSize = 0;1542dctx->previousDstEnd = NULL;1543dctx->prefixStart = NULL;1544dctx->virtualStart = NULL;1545dctx->dictEnd = NULL;1546dctx->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */1547dctx->litEntropy = dctx->fseEntropy = 0;1548dctx->dictID = 0;1549dctx->bType = bt_reserved;1550ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));1551ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */1552dctx->LLTptr = dctx->entropy.LLTable;1553dctx->MLTptr = dctx->entropy.MLTable;1554dctx->OFTptr = dctx->entropy.OFTable;1555dctx->HUFptr = dctx->entropy.hufTable;1556return 0;1557}15581559size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1560{1561FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");1562if (dict && dictSize)1563RETURN_ERROR_IF(1564ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)),1565dictionary_corrupted, "");1566return 0;1567}156815691570/* ====== ZSTD_DDict ====== */15711572size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)1573{1574DEBUGLOG(4, "ZSTD_decompressBegin_usingDDict");1575assert(dctx != NULL);1576if (ddict) {1577const char* const dictStart = (const char*)ZSTD_DDict_dictContent(ddict);1578size_t const dictSize = ZSTD_DDict_dictSize(ddict);1579const void* const dictEnd = dictStart + dictSize;1580dctx->ddictIsCold = (dctx->dictEnd != dictEnd);1581DEBUGLOG(4, "DDict is %s",1582dctx->ddictIsCold ? "~cold~" : "hot!");1583}1584FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");1585if (ddict) { /* NULL ddict is equivalent to no dictionary */1586ZSTD_copyDDictParameters(dctx, ddict);1587}1588return 0;1589}15901591/*! ZSTD_getDictID_fromDict() :1592* Provides the dictID stored within dictionary.1593* if @return == 0, the dictionary is not conformant with Zstandard specification.1594* It can still be loaded, but as a content-only dictionary. */1595unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)1596{1597if (dictSize < 8) return 0;1598if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0;1599return MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);1600}16011602/*! ZSTD_getDictID_fromFrame() :1603* Provides the dictID required to decompress frame stored within `src`.1604* If @return == 0, the dictID could not be decoded.1605* This could for one of the following reasons :1606* - The frame does not require a dictionary (most common case).1607* - The frame was built with dictID intentionally removed.1608* Needed dictionary is a hidden piece of information.1609* Note : this use case also happens when using a non-conformant dictionary.1610* - `srcSize` is too small, and as a result, frame header could not be decoded.1611* Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`.1612* - This is not a Zstandard frame.1613* When identifying the exact failure cause, it's possible to use1614* ZSTD_getFrameHeader(), which will provide a more precise error code. */1615unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)1616{1617ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0, 0, 0 };1618size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);1619if (ZSTD_isError(hError)) return 0;1620return zfp.dictID;1621}162216231624/*! ZSTD_decompress_usingDDict() :1625* Decompression using a pre-digested Dictionary1626* Use dictionary without significant overhead. */1627size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,1628void* dst, size_t dstCapacity,1629const void* src, size_t srcSize,1630const ZSTD_DDict* ddict)1631{1632/* pass content and size in case legacy frames are encountered */1633return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize,1634NULL, 0,1635ddict);1636}163716381639/*=====================================1640* Streaming decompression1641*====================================*/16421643ZSTD_DStream* ZSTD_createDStream(void)1644{1645DEBUGLOG(3, "ZSTD_createDStream");1646return ZSTD_createDCtx_internal(ZSTD_defaultCMem);1647}16481649ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize)1650{1651return ZSTD_initStaticDCtx(workspace, workspaceSize);1652}16531654ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem)1655{1656return ZSTD_createDCtx_internal(customMem);1657}16581659size_t ZSTD_freeDStream(ZSTD_DStream* zds)1660{1661return ZSTD_freeDCtx(zds);1662}166316641665/* *** Initialization *** */16661667size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; }1668size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }16691670size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx,1671const void* dict, size_t dictSize,1672ZSTD_dictLoadMethod_e dictLoadMethod,1673ZSTD_dictContentType_e dictContentType)1674{1675RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1676ZSTD_clearDict(dctx);1677if (dict && dictSize != 0) {1678dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem);1679RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation, "NULL pointer!");1680dctx->ddict = dctx->ddictLocal;1681dctx->dictUses = ZSTD_use_indefinitely;1682}1683return 0;1684}16851686size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1687{1688return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);1689}16901691size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1692{1693return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);1694}16951696size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)1697{1698FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType), "");1699dctx->dictUses = ZSTD_use_once;1700return 0;1701}17021703size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize)1704{1705return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent);1706}170717081709/* ZSTD_initDStream_usingDict() :1710* return : expected size, aka ZSTD_startingInputLength().1711* this function cannot fail */1712size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)1713{1714DEBUGLOG(4, "ZSTD_initDStream_usingDict");1715FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) , "");1716FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) , "");1717return ZSTD_startingInputLength(zds->format);1718}17191720/* note : this variant can't fail */1721size_t ZSTD_initDStream(ZSTD_DStream* zds)1722{1723DEBUGLOG(4, "ZSTD_initDStream");1724FORWARD_IF_ERROR(ZSTD_DCtx_reset(zds, ZSTD_reset_session_only), "");1725FORWARD_IF_ERROR(ZSTD_DCtx_refDDict(zds, NULL), "");1726return ZSTD_startingInputLength(zds->format);1727}17281729/* ZSTD_initDStream_usingDDict() :1730* ddict will just be referenced, and must outlive decompression session1731* this function cannot fail */1732size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)1733{1734DEBUGLOG(4, "ZSTD_initDStream_usingDDict");1735FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , "");1736FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , "");1737return ZSTD_startingInputLength(dctx->format);1738}17391740/* ZSTD_resetDStream() :1741* return : expected size, aka ZSTD_startingInputLength().1742* this function cannot fail */1743size_t ZSTD_resetDStream(ZSTD_DStream* dctx)1744{1745DEBUGLOG(4, "ZSTD_resetDStream");1746FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), "");1747return ZSTD_startingInputLength(dctx->format);1748}174917501751size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)1752{1753RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1754ZSTD_clearDict(dctx);1755if (ddict) {1756dctx->ddict = ddict;1757dctx->dictUses = ZSTD_use_indefinitely;1758if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) {1759if (dctx->ddictSet == NULL) {1760dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem);1761if (!dctx->ddictSet) {1762RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!");1763}1764}1765assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */1766FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), "");1767}1768}1769return 0;1770}17711772/* ZSTD_DCtx_setMaxWindowSize() :1773* note : no direct equivalence in ZSTD_DCtx_setParameter,1774* since this version sets windowSize, and the other sets windowLog */1775size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)1776{1777ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax);1778size_t const min = (size_t)1 << bounds.lowerBound;1779size_t const max = (size_t)1 << bounds.upperBound;1780RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1781RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound, "");1782RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound, "");1783dctx->maxWindowSize = maxWindowSize;1784return 0;1785}17861787size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)1788{1789return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format);1790}17911792ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)1793{1794ZSTD_bounds bounds = { 0, 0, 0 };1795switch(dParam) {1796case ZSTD_d_windowLogMax:1797bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN;1798bounds.upperBound = ZSTD_WINDOWLOG_MAX;1799return bounds;1800case ZSTD_d_format:1801bounds.lowerBound = (int)ZSTD_f_zstd1;1802bounds.upperBound = (int)ZSTD_f_zstd1_magicless;1803ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);1804return bounds;1805case ZSTD_d_stableOutBuffer:1806bounds.lowerBound = (int)ZSTD_bm_buffered;1807bounds.upperBound = (int)ZSTD_bm_stable;1808return bounds;1809case ZSTD_d_forceIgnoreChecksum:1810bounds.lowerBound = (int)ZSTD_d_validateChecksum;1811bounds.upperBound = (int)ZSTD_d_ignoreChecksum;1812return bounds;1813case ZSTD_d_refMultipleDDicts:1814bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict;1815bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts;1816return bounds;1817case ZSTD_d_disableHuffmanAssembly:1818bounds.lowerBound = 0;1819bounds.upperBound = 1;1820return bounds;18211822default:;1823}1824bounds.error = ERROR(parameter_unsupported);1825return bounds;1826}18271828/* ZSTD_dParam_withinBounds:1829* @return 1 if value is within dParam bounds,1830* 0 otherwise */1831static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value)1832{1833ZSTD_bounds const bounds = ZSTD_dParam_getBounds(dParam);1834if (ZSTD_isError(bounds.error)) return 0;1835if (value < bounds.lowerBound) return 0;1836if (value > bounds.upperBound) return 0;1837return 1;1838}18391840#define CHECK_DBOUNDS(p,v) { \1841RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \1842}18431844size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value)1845{1846switch (param) {1847case ZSTD_d_windowLogMax:1848*value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize);1849return 0;1850case ZSTD_d_format:1851*value = (int)dctx->format;1852return 0;1853case ZSTD_d_stableOutBuffer:1854*value = (int)dctx->outBufferMode;1855return 0;1856case ZSTD_d_forceIgnoreChecksum:1857*value = (int)dctx->forceIgnoreChecksum;1858return 0;1859case ZSTD_d_refMultipleDDicts:1860*value = (int)dctx->refMultipleDDicts;1861return 0;1862case ZSTD_d_disableHuffmanAssembly:1863*value = (int)dctx->disableHufAsm;1864return 0;1865default:;1866}1867RETURN_ERROR(parameter_unsupported, "");1868}18691870size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value)1871{1872RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1873switch(dParam) {1874case ZSTD_d_windowLogMax:1875if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT;1876CHECK_DBOUNDS(ZSTD_d_windowLogMax, value);1877dctx->maxWindowSize = ((size_t)1) << value;1878return 0;1879case ZSTD_d_format:1880CHECK_DBOUNDS(ZSTD_d_format, value);1881dctx->format = (ZSTD_format_e)value;1882return 0;1883case ZSTD_d_stableOutBuffer:1884CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value);1885dctx->outBufferMode = (ZSTD_bufferMode_e)value;1886return 0;1887case ZSTD_d_forceIgnoreChecksum:1888CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value);1889dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value;1890return 0;1891case ZSTD_d_refMultipleDDicts:1892CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value);1893if (dctx->staticSize != 0) {1894RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!");1895}1896dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value;1897return 0;1898case ZSTD_d_disableHuffmanAssembly:1899CHECK_DBOUNDS(ZSTD_d_disableHuffmanAssembly, value);1900dctx->disableHufAsm = value != 0;1901return 0;1902default:;1903}1904RETURN_ERROR(parameter_unsupported, "");1905}19061907size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)1908{1909if ( (reset == ZSTD_reset_session_only)1910|| (reset == ZSTD_reset_session_and_parameters) ) {1911dctx->streamStage = zdss_init;1912dctx->noForwardProgress = 0;1913}1914if ( (reset == ZSTD_reset_parameters)1915|| (reset == ZSTD_reset_session_and_parameters) ) {1916RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1917ZSTD_clearDict(dctx);1918ZSTD_DCtx_resetParameters(dctx);1919}1920return 0;1921}192219231924size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)1925{1926return ZSTD_sizeof_DCtx(dctx);1927}19281929size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)1930{1931size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);1932/* space is needed to store the litbuffer after the output of a given block without stomping the extDict of a previous run, as well as to cover both windows against wildcopy*/1933unsigned long long const neededRBSize = windowSize + blockSize + ZSTD_BLOCKSIZE_MAX + (WILDCOPY_OVERLENGTH * 2);1934unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);1935size_t const minRBSize = (size_t) neededSize;1936RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize,1937frameParameter_windowTooLarge, "");1938return minRBSize;1939}19401941size_t ZSTD_estimateDStreamSize(size_t windowSize)1942{1943size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);1944size_t const inBuffSize = blockSize; /* no block can be larger */1945size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN);1946return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;1947}19481949size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)1950{1951U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */1952ZSTD_frameHeader zfh;1953size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);1954if (ZSTD_isError(err)) return err;1955RETURN_ERROR_IF(err>0, srcSize_wrong, "");1956RETURN_ERROR_IF(zfh.windowSize > windowSizeMax,1957frameParameter_windowTooLarge, "");1958return ZSTD_estimateDStreamSize((size_t)zfh.windowSize);1959}196019611962/* ***** Decompression ***** */19631964static int ZSTD_DCtx_isOverflow(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)1965{1966return (zds->inBuffSize + zds->outBuffSize) >= (neededInBuffSize + neededOutBuffSize) * ZSTD_WORKSPACETOOLARGE_FACTOR;1967}19681969static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)1970{1971if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize))1972zds->oversizedDuration++;1973else1974zds->oversizedDuration = 0;1975}19761977static int ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream* zds)1978{1979return zds->oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION;1980}19811982/* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */1983static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* output)1984{1985ZSTD_outBuffer const expect = zds->expectedOutBuffer;1986/* No requirement when ZSTD_obm_stable is not enabled. */1987if (zds->outBufferMode != ZSTD_bm_stable)1988return 0;1989/* Any buffer is allowed in zdss_init, this must be the same for every other call until1990* the context is reset.1991*/1992if (zds->streamStage == zdss_init)1993return 0;1994/* The buffer must match our expectation exactly. */1995if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size)1996return 0;1997RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!");1998}19992000/* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream()2001* and updates the stage and the output buffer state. This call is extracted so it can be2002* used both when reading directly from the ZSTD_inBuffer, and in buffered input mode.2003* NOTE: You must break after calling this function since the streamStage is modified.2004*/2005static size_t ZSTD_decompressContinueStream(2006ZSTD_DStream* zds, char** op, char* oend,2007void const* src, size_t srcSize) {2008int const isSkipFrame = ZSTD_isSkipFrame(zds);2009if (zds->outBufferMode == ZSTD_bm_buffered) {2010size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart;2011size_t const decodedSize = ZSTD_decompressContinue(zds,2012zds->outBuff + zds->outStart, dstSize, src, srcSize);2013FORWARD_IF_ERROR(decodedSize, "");2014if (!decodedSize && !isSkipFrame) {2015zds->streamStage = zdss_read;2016} else {2017zds->outEnd = zds->outStart + decodedSize;2018zds->streamStage = zdss_flush;2019}2020} else {2021/* Write directly into the output buffer */2022size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op);2023size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize);2024FORWARD_IF_ERROR(decodedSize, "");2025*op += decodedSize;2026/* Flushing is not needed. */2027zds->streamStage = zdss_read;2028assert(*op <= oend);2029assert(zds->outBufferMode == ZSTD_bm_stable);2030}2031return 0;2032}20332034size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input)2035{2036const char* const src = (const char*)input->src;2037const char* const istart = input->pos != 0 ? src + input->pos : src;2038const char* const iend = input->size != 0 ? src + input->size : src;2039const char* ip = istart;2040char* const dst = (char*)output->dst;2041char* const ostart = output->pos != 0 ? dst + output->pos : dst;2042char* const oend = output->size != 0 ? dst + output->size : dst;2043char* op = ostart;2044U32 someMoreWork = 1;20452046DEBUGLOG(5, "ZSTD_decompressStream");2047RETURN_ERROR_IF(2048input->pos > input->size,2049srcSize_wrong,2050"forbidden. in: pos: %u vs size: %u",2051(U32)input->pos, (U32)input->size);2052RETURN_ERROR_IF(2053output->pos > output->size,2054dstSize_tooSmall,2055"forbidden. out: pos: %u vs size: %u",2056(U32)output->pos, (U32)output->size);2057DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));2058FORWARD_IF_ERROR(ZSTD_checkOutBuffer(zds, output), "");20592060while (someMoreWork) {2061switch(zds->streamStage)2062{2063case zdss_init :2064DEBUGLOG(5, "stage zdss_init => transparent reset ");2065zds->streamStage = zdss_loadHeader;2066zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;2067#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)2068zds->legacyVersion = 0;2069#endif2070zds->hostageByte = 0;2071zds->expectedOutBuffer = *output;2072ZSTD_FALLTHROUGH;20732074case zdss_loadHeader :2075DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));2076#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)2077if (zds->legacyVersion) {2078RETURN_ERROR_IF(zds->staticSize, memory_allocation,2079"legacy support is incompatible with static dctx");2080{ size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);2081if (hint==0) zds->streamStage = zdss_init;2082return hint;2083} }2084#endif2085{ size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);2086if (zds->refMultipleDDicts && zds->ddictSet) {2087ZSTD_DCtx_selectFrameDDict(zds);2088}2089if (ZSTD_isError(hSize)) {2090#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)2091U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);2092if (legacyVersion) {2093ZSTD_DDict const* const ddict = ZSTD_getDDict(zds);2094const void* const dict = ddict ? ZSTD_DDict_dictContent(ddict) : NULL;2095size_t const dictSize = ddict ? ZSTD_DDict_dictSize(ddict) : 0;2096DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion);2097RETURN_ERROR_IF(zds->staticSize, memory_allocation,2098"legacy support is incompatible with static dctx");2099FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext,2100zds->previousLegacyVersion, legacyVersion,2101dict, dictSize), "");2102zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;2103{ size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);2104if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */2105return hint;2106} }2107#endif2108return hSize; /* error */2109}2110if (hSize != 0) { /* need more input */2111size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */2112size_t const remainingInput = (size_t)(iend-ip);2113assert(iend >= ip);2114if (toLoad > remainingInput) { /* not enough input to load full header */2115if (remainingInput > 0) {2116ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);2117zds->lhSize += remainingInput;2118}2119input->pos = input->size;2120/* check first few bytes */2121FORWARD_IF_ERROR(2122ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format),2123"First few bytes detected incorrect" );2124/* return hint input size */2125return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */2126}2127assert(ip != NULL);2128ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;2129break;2130} }21312132/* check for single-pass mode opportunity */2133if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN2134&& zds->fParams.frameType != ZSTD_skippableFrame2135&& (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {2136size_t const cSize = ZSTD_findFrameCompressedSize(istart, (size_t)(iend-istart));2137if (cSize <= (size_t)(iend-istart)) {2138/* shortcut : using single-pass mode */2139size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds));2140if (ZSTD_isError(decompressedSize)) return decompressedSize;2141DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")2142assert(istart != NULL);2143ip = istart + cSize;2144op = op ? op + decompressedSize : op; /* can occur if frameContentSize = 0 (empty frame) */2145zds->expected = 0;2146zds->streamStage = zdss_init;2147someMoreWork = 0;2148break;2149} }21502151/* Check output buffer is large enough for ZSTD_odm_stable. */2152if (zds->outBufferMode == ZSTD_bm_stable2153&& zds->fParams.frameType != ZSTD_skippableFrame2154&& zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN2155&& (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) {2156RETURN_ERROR(dstSize_tooSmall, "ZSTD_obm_stable passed but ZSTD_outBuffer is too small");2157}21582159/* Consume header (see ZSTDds_decodeFrameHeader) */2160DEBUGLOG(4, "Consume header");2161FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), "");21622163if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */2164zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);2165zds->stage = ZSTDds_skipFrame;2166} else {2167FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), "");2168zds->expected = ZSTD_blockHeaderSize;2169zds->stage = ZSTDds_decodeBlockHeader;2170}21712172/* control buffer memory usage */2173DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)",2174(U32)(zds->fParams.windowSize >>10),2175(U32)(zds->maxWindowSize >> 10) );2176zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);2177RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize,2178frameParameter_windowTooLarge, "");21792180/* Adapt buffer sizes to frame header instructions */2181{ size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);2182size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered2183? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize)2184: 0;21852186ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize);21872188{ int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize);2189int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds);21902191if (tooSmall || tooLarge) {2192size_t const bufferSize = neededInBuffSize + neededOutBuffSize;2193DEBUGLOG(4, "inBuff : from %u to %u",2194(U32)zds->inBuffSize, (U32)neededInBuffSize);2195DEBUGLOG(4, "outBuff : from %u to %u",2196(U32)zds->outBuffSize, (U32)neededOutBuffSize);2197if (zds->staticSize) { /* static DCtx */2198DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize);2199assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */2200RETURN_ERROR_IF(2201bufferSize > zds->staticSize - sizeof(ZSTD_DCtx),2202memory_allocation, "");2203} else {2204ZSTD_customFree(zds->inBuff, zds->customMem);2205zds->inBuffSize = 0;2206zds->outBuffSize = 0;2207zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem);2208RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, "");2209}2210zds->inBuffSize = neededInBuffSize;2211zds->outBuff = zds->inBuff + zds->inBuffSize;2212zds->outBuffSize = neededOutBuffSize;2213} } }2214zds->streamStage = zdss_read;2215ZSTD_FALLTHROUGH;22162217case zdss_read:2218DEBUGLOG(5, "stage zdss_read");2219{ size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip));2220DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize);2221if (neededInSize==0) { /* end of frame */2222zds->streamStage = zdss_init;2223someMoreWork = 0;2224break;2225}2226if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */2227FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), "");2228assert(ip != NULL);2229ip += neededInSize;2230/* Function modifies the stage so we must break */2231break;2232} }2233if (ip==iend) { someMoreWork = 0; break; } /* no more input */2234zds->streamStage = zdss_load;2235ZSTD_FALLTHROUGH;22362237case zdss_load:2238{ size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);2239size_t const toLoad = neededInSize - zds->inPos;2240int const isSkipFrame = ZSTD_isSkipFrame(zds);2241size_t loadedSize;2242/* At this point we shouldn't be decompressing a block that we can stream. */2243assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip)));2244if (isSkipFrame) {2245loadedSize = MIN(toLoad, (size_t)(iend-ip));2246} else {2247RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos,2248corruption_detected,2249"should never happen");2250loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip));2251}2252if (loadedSize != 0) {2253/* ip may be NULL */2254ip += loadedSize;2255zds->inPos += loadedSize;2256}2257if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */22582259/* decode loaded input */2260zds->inPos = 0; /* input is consumed */2261FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, zds->inBuff, neededInSize), "");2262/* Function modifies the stage so we must break */2263break;2264}2265case zdss_flush:2266{2267size_t const toFlushSize = zds->outEnd - zds->outStart;2268size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize);22692270op = op ? op + flushedSize : op;22712272zds->outStart += flushedSize;2273if (flushedSize == toFlushSize) { /* flush completed */2274zds->streamStage = zdss_read;2275if ( (zds->outBuffSize < zds->fParams.frameContentSize)2276&& (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) {2277DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)",2278(int)(zds->outBuffSize - zds->outStart),2279(U32)zds->fParams.blockSizeMax);2280zds->outStart = zds->outEnd = 0;2281}2282break;2283} }2284/* cannot complete flush */2285someMoreWork = 0;2286break;22872288default:2289assert(0); /* impossible */2290RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */2291} }22922293/* result */2294input->pos = (size_t)(ip - (const char*)(input->src));2295output->pos = (size_t)(op - (char*)(output->dst));22962297/* Update the expected output buffer for ZSTD_obm_stable. */2298zds->expectedOutBuffer = *output;22992300if ((ip==istart) && (op==ostart)) { /* no forward progress */2301zds->noForwardProgress ++;2302if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {2303RETURN_ERROR_IF(op==oend, noForwardProgress_destFull, "");2304RETURN_ERROR_IF(ip==iend, noForwardProgress_inputEmpty, "");2305assert(0);2306}2307} else {2308zds->noForwardProgress = 0;2309}2310{ size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds);2311if (!nextSrcSizeHint) { /* frame fully decoded */2312if (zds->outEnd == zds->outStart) { /* output fully flushed */2313if (zds->hostageByte) {2314if (input->pos >= input->size) {2315/* can't release hostage (not present) */2316zds->streamStage = zdss_read;2317return 1;2318}2319input->pos++; /* release hostage */2320} /* zds->hostageByte */2321return 0;2322} /* zds->outEnd == zds->outStart */2323if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */2324input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */2325zds->hostageByte=1;2326}2327return 1;2328} /* nextSrcSizeHint==0 */2329nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */2330assert(zds->inPos <= nextSrcSizeHint);2331nextSrcSizeHint -= zds->inPos; /* part already loaded*/2332return nextSrcSizeHint;2333}2334}23352336size_t ZSTD_decompressStream_simpleArgs (2337ZSTD_DCtx* dctx,2338void* dst, size_t dstCapacity, size_t* dstPos,2339const void* src, size_t srcSize, size_t* srcPos)2340{2341ZSTD_outBuffer output;2342ZSTD_inBuffer input;2343output.dst = dst;2344output.size = dstCapacity;2345output.pos = *dstPos;2346input.src = src;2347input.size = srcSize;2348input.pos = *srcPos;2349{ size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);2350*dstPos = output.pos;2351*srcPos = input.pos;2352return cErr;2353}2354}235523562357