Path: blob/master/Utilities/cmzstd/lib/decompress/zstd_decompress.c
5020 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/zstd_deps.h" /* ZSTD_memcpy, ZSTD_memmove, ZSTD_memset */58#include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */59#include "../common/error_private.h"60#include "../common/zstd_internal.h" /* blockProperties_t */61#include "../common/mem.h" /* low level memory routines */62#include "../common/bits.h" /* ZSTD_highbit32 */63#define FSE_STATIC_LINKING_ONLY64#include "../common/fse.h"65#include "../common/huf.h"66#include "../common/xxhash.h" /* XXH64_reset, XXH64_update, XXH64_digest, XXH64 */67#include "zstd_decompress_internal.h" /* ZSTD_DCtx */68#include "zstd_ddict.h" /* ZSTD_DDictDictContent */69#include "zstd_decompress_block.h" /* ZSTD_decompressBlock_internal */7071#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)72# include "../legacy/zstd_legacy.h"73#endif74757677/*************************************78* Multiple DDicts Hashset internals *79*************************************/8081#define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 482#define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float.83* Currently, that means a 0.75 load factor.84* So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded85* the load factor of the ddict hash set.86*/8788#define DDICT_HASHSET_TABLE_BASE_SIZE 6489#define DDICT_HASHSET_RESIZE_FACTOR 29091/* Hash function to determine starting position of dict insertion within the table92* Returns an index between [0, hashSet->ddictPtrTableSize]93*/94static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) {95const U64 hash = XXH64(&dictID, sizeof(U32), 0);96/* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */97return hash & (hashSet->ddictPtrTableSize - 1);98}99100/* Adds DDict to a hashset without resizing it.101* If inserting a DDict with a dictID that already exists in the set, replaces the one in the set.102* Returns 0 if successful, or a zstd error code if something went wrong.103*/104static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) {105const U32 dictID = ZSTD_getDictID_fromDDict(ddict);106size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);107const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;108RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!");109DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);110while (hashSet->ddictPtrTable[idx] != NULL) {111/* Replace existing ddict if inserting ddict with same dictID */112if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) {113DEBUGLOG(4, "DictID already exists, replacing rather than adding");114hashSet->ddictPtrTable[idx] = ddict;115return 0;116}117idx &= idxRangeMask;118idx++;119}120DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);121hashSet->ddictPtrTable[idx] = ddict;122hashSet->ddictPtrCount++;123return 0;124}125126/* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and127* rehashes all values, allocates new table, frees old table.128* Returns 0 on success, otherwise a zstd error code.129*/130static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {131size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR;132const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem);133const ZSTD_DDict** oldTable = hashSet->ddictPtrTable;134size_t oldTableSize = hashSet->ddictPtrTableSize;135size_t i;136137DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize);138RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!");139hashSet->ddictPtrTable = newTable;140hashSet->ddictPtrTableSize = newTableSize;141hashSet->ddictPtrCount = 0;142for (i = 0; i < oldTableSize; ++i) {143if (oldTable[i] != NULL) {144FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), "");145}146}147ZSTD_customFree((void*)oldTable, customMem);148DEBUGLOG(4, "Finished re-hash");149return 0;150}151152/* Fetches a DDict with the given dictID153* Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL.154*/155static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) {156size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);157const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;158DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);159for (;;) {160size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]);161if (currDictID == dictID || currDictID == 0) {162/* currDictID == 0 implies a NULL ddict entry */163break;164} else {165idx &= idxRangeMask; /* Goes to start of table when we reach the end */166idx++;167}168}169DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);170return hashSet->ddictPtrTable[idx];171}172173/* Allocates space for and returns a ddict hash set174* The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with.175* Returns NULL if allocation failed.176*/177static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) {178ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem);179DEBUGLOG(4, "Allocating new hash set");180if (!ret)181return NULL;182ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem);183if (!ret->ddictPtrTable) {184ZSTD_customFree(ret, customMem);185return NULL;186}187ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE;188ret->ddictPtrCount = 0;189return ret;190}191192/* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself.193* Note: The ZSTD_DDict* within the table are NOT freed.194*/195static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {196DEBUGLOG(4, "Freeing ddict hash set");197if (hashSet && hashSet->ddictPtrTable) {198ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem);199}200if (hashSet) {201ZSTD_customFree(hashSet, customMem);202}203}204205/* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set.206* Returns 0 on success, or a ZSTD error.207*/208static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) {209DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize);210if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) {211FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), "");212}213FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), "");214return 0;215}216217/*-*************************************************************218* Context management219***************************************************************/220size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx)221{222if (dctx==NULL) return 0; /* support sizeof NULL */223return sizeof(*dctx)224+ ZSTD_sizeof_DDict(dctx->ddictLocal)225+ dctx->inBuffSize + dctx->outBuffSize;226}227228size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }229230231static size_t ZSTD_startingInputLength(ZSTD_format_e format)232{233size_t const startingInputLength = ZSTD_FRAMEHEADERSIZE_PREFIX(format);234/* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */235assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) );236return startingInputLength;237}238239static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx)240{241assert(dctx->streamStage == zdss_init);242dctx->format = ZSTD_f_zstd1;243dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;244dctx->outBufferMode = ZSTD_bm_buffered;245dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum;246dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict;247dctx->disableHufAsm = 0;248dctx->maxBlockSizeParam = 0;249}250251static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)252{253dctx->staticSize = 0;254dctx->ddict = NULL;255dctx->ddictLocal = NULL;256dctx->dictEnd = NULL;257dctx->ddictIsCold = 0;258dctx->dictUses = ZSTD_dont_use;259dctx->inBuff = NULL;260dctx->inBuffSize = 0;261dctx->outBuffSize = 0;262dctx->streamStage = zdss_init;263#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)264dctx->legacyContext = NULL;265dctx->previousLegacyVersion = 0;266#endif267dctx->noForwardProgress = 0;268dctx->oversizedDuration = 0;269dctx->isFrameDecompression = 1;270#if DYNAMIC_BMI2271dctx->bmi2 = ZSTD_cpuSupportsBmi2();272#endif273dctx->ddictSet = NULL;274ZSTD_DCtx_resetParameters(dctx);275#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION276dctx->dictContentEndForFuzzing = NULL;277#endif278}279280ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)281{282ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace;283284if ((size_t)workspace & 7) return NULL; /* 8-aligned */285if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */286287ZSTD_initDCtx_internal(dctx);288dctx->staticSize = workspaceSize;289dctx->inBuff = (char*)(dctx+1);290return dctx;291}292293static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) {294if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;295296{ ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem);297if (!dctx) return NULL;298dctx->customMem = customMem;299ZSTD_initDCtx_internal(dctx);300return dctx;301}302}303304ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)305{306return ZSTD_createDCtx_internal(customMem);307}308309ZSTD_DCtx* ZSTD_createDCtx(void)310{311DEBUGLOG(3, "ZSTD_createDCtx");312return ZSTD_createDCtx_internal(ZSTD_defaultCMem);313}314315static void ZSTD_clearDict(ZSTD_DCtx* dctx)316{317ZSTD_freeDDict(dctx->ddictLocal);318dctx->ddictLocal = NULL;319dctx->ddict = NULL;320dctx->dictUses = ZSTD_dont_use;321}322323size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)324{325if (dctx==NULL) return 0; /* support free on NULL */326RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx");327{ ZSTD_customMem const cMem = dctx->customMem;328ZSTD_clearDict(dctx);329ZSTD_customFree(dctx->inBuff, cMem);330dctx->inBuff = NULL;331#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)332if (dctx->legacyContext)333ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);334#endif335if (dctx->ddictSet) {336ZSTD_freeDDictHashSet(dctx->ddictSet, cMem);337dctx->ddictSet = NULL;338}339ZSTD_customFree(dctx, cMem);340return 0;341}342}343344/* no longer useful */345void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)346{347size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx);348ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */349}350351/* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on352* the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then353* accordingly sets the ddict to be used to decompress the frame.354*355* If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is.356*357* ZSTD_d_refMultipleDDicts must be enabled for this function to be called.358*/359static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) {360assert(dctx->refMultipleDDicts && dctx->ddictSet);361DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame");362if (dctx->ddict) {363const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID);364if (frameDDict) {365DEBUGLOG(4, "DDict found!");366ZSTD_clearDict(dctx);367dctx->dictID = dctx->fParams.dictID;368dctx->ddict = frameDDict;369dctx->dictUses = ZSTD_use_indefinitely;370}371}372}373374375/*-*************************************************************376* Frame header decoding377***************************************************************/378379/*! ZSTD_isFrame() :380* Tells if the content of `buffer` starts with a valid Frame Identifier.381* Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.382* Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.383* Note 3 : Skippable Frame Identifiers are considered valid. */384unsigned ZSTD_isFrame(const void* buffer, size_t size)385{386if (size < ZSTD_FRAMEIDSIZE) return 0;387{ U32 const magic = MEM_readLE32(buffer);388if (magic == ZSTD_MAGICNUMBER) return 1;389if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;390}391#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)392if (ZSTD_isLegacy(buffer, size)) return 1;393#endif394return 0;395}396397/*! ZSTD_isSkippableFrame() :398* Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame.399* Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.400*/401unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size)402{403if (size < ZSTD_FRAMEIDSIZE) return 0;404{ U32 const magic = MEM_readLE32(buffer);405if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;406}407return 0;408}409410/** ZSTD_frameHeaderSize_internal() :411* srcSize must be large enough to reach header size fields.412* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless.413* @return : size of the Frame Header414* or an error code, which can be tested with ZSTD_isError() */415static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)416{417size_t const minInputSize = ZSTD_startingInputLength(format);418RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong, "");419420{ BYTE const fhd = ((const BYTE*)src)[minInputSize-1];421U32 const dictID= fhd & 3;422U32 const singleSegment = (fhd >> 5) & 1;423U32 const fcsId = fhd >> 6;424return minInputSize + !singleSegment425+ ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]426+ (singleSegment && !fcsId);427}428}429430/** ZSTD_frameHeaderSize() :431* srcSize must be >= ZSTD_frameHeaderSize_prefix.432* @return : size of the Frame Header,433* or an error code (if srcSize is too small) */434size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)435{436return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);437}438439440/** ZSTD_getFrameHeader_advanced() :441* decode Frame Header, or require larger `srcSize`.442* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless443* @return : 0, `zfhPtr` is correctly filled,444* >0, `srcSize` is too small, value is wanted `srcSize` amount,445** or an error code, which can be tested using ZSTD_isError() */446size_t ZSTD_getFrameHeader_advanced(ZSTD_FrameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)447{448const BYTE* ip = (const BYTE*)src;449size_t const minInputSize = ZSTD_startingInputLength(format);450451DEBUGLOG(5, "ZSTD_getFrameHeader_advanced: minInputSize = %zu, srcSize = %zu", minInputSize, srcSize);452453if (srcSize > 0) {454/* note : technically could be considered an assert(), since it's an invalid entry */455RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter : src==NULL, but srcSize>0");456}457if (srcSize < minInputSize) {458if (srcSize > 0 && format != ZSTD_f_zstd1_magicless) {459/* when receiving less than @minInputSize bytes,460* control these bytes at least correspond to a supported magic number461* in order to error out early if they don't.462**/463size_t const toCopy = MIN(4, srcSize);464unsigned char hbuf[4]; MEM_writeLE32(hbuf, ZSTD_MAGICNUMBER);465assert(src != NULL);466ZSTD_memcpy(hbuf, src, toCopy);467if ( MEM_readLE32(hbuf) != ZSTD_MAGICNUMBER ) {468/* not a zstd frame : let's check if it's a skippable frame */469MEM_writeLE32(hbuf, ZSTD_MAGIC_SKIPPABLE_START);470ZSTD_memcpy(hbuf, src, toCopy);471if ((MEM_readLE32(hbuf) & ZSTD_MAGIC_SKIPPABLE_MASK) != ZSTD_MAGIC_SKIPPABLE_START) {472RETURN_ERROR(prefix_unknown,473"first bytes don't correspond to any supported magic number");474} } }475return minInputSize;476}477478ZSTD_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 */479if ( (format != ZSTD_f_zstd1_magicless)480&& (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {481if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {482/* skippable frame */483if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)484return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */485ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr));486zfhPtr->frameType = ZSTD_skippableFrame;487zfhPtr->dictID = MEM_readLE32(src) - ZSTD_MAGIC_SKIPPABLE_START;488zfhPtr->headerSize = ZSTD_SKIPPABLEHEADERSIZE;489zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);490return 0;491}492RETURN_ERROR(prefix_unknown, "");493}494495/* ensure there is enough `srcSize` to fully read/decode frame header */496{ size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format);497if (srcSize < fhsize) return fhsize;498zfhPtr->headerSize = (U32)fhsize;499}500501{ BYTE const fhdByte = ip[minInputSize-1];502size_t pos = minInputSize;503U32 const dictIDSizeCode = fhdByte&3;504U32 const checksumFlag = (fhdByte>>2)&1;505U32 const singleSegment = (fhdByte>>5)&1;506U32 const fcsID = fhdByte>>6;507U64 windowSize = 0;508U32 dictID = 0;509U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN;510RETURN_ERROR_IF((fhdByte & 0x08) != 0, frameParameter_unsupported,511"reserved bits, must be zero");512513if (!singleSegment) {514BYTE const wlByte = ip[pos++];515U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;516RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge, "");517windowSize = (1ULL << windowLog);518windowSize += (windowSize >> 3) * (wlByte&7);519}520switch(dictIDSizeCode)521{522default:523assert(0); /* impossible */524ZSTD_FALLTHROUGH;525case 0 : break;526case 1 : dictID = ip[pos]; pos++; break;527case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break;528case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break;529}530switch(fcsID)531{532default:533assert(0); /* impossible */534ZSTD_FALLTHROUGH;535case 0 : if (singleSegment) frameContentSize = ip[pos]; break;536case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;537case 2 : frameContentSize = MEM_readLE32(ip+pos); break;538case 3 : frameContentSize = MEM_readLE64(ip+pos); break;539}540if (singleSegment) windowSize = frameContentSize;541542zfhPtr->frameType = ZSTD_frame;543zfhPtr->frameContentSize = frameContentSize;544zfhPtr->windowSize = windowSize;545zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);546zfhPtr->dictID = dictID;547zfhPtr->checksumFlag = checksumFlag;548}549return 0;550}551552/** ZSTD_getFrameHeader() :553* decode Frame Header, or require larger `srcSize`.554* note : this function does not consume input, it only reads it.555* @return : 0, `zfhPtr` is correctly filled,556* >0, `srcSize` is too small, value is wanted `srcSize` amount,557* or an error code, which can be tested using ZSTD_isError() */558size_t ZSTD_getFrameHeader(ZSTD_FrameHeader* zfhPtr, const void* src, size_t srcSize)559{560return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);561}562563/** ZSTD_getFrameContentSize() :564* compatible with legacy mode565* @return : decompressed size of the single frame pointed to be `src` if known, otherwise566* - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined567* - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */568unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)569{570#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)571if (ZSTD_isLegacy(src, srcSize)) {572unsigned long long const ret = ZSTD_getDecompressedSize_legacy(src, srcSize);573return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret;574}575#endif576{ ZSTD_FrameHeader zfh;577if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0)578return ZSTD_CONTENTSIZE_ERROR;579if (zfh.frameType == ZSTD_skippableFrame) {580return 0;581} else {582return zfh.frameContentSize;583} }584}585586static size_t readSkippableFrameSize(void const* src, size_t srcSize)587{588size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE;589U32 sizeU32;590591RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, "");592593sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);594RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32,595frameParameter_unsupported, "");596{ size_t const skippableSize = skippableHeaderSize + sizeU32;597RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, "");598return skippableSize;599}600}601602/*! ZSTD_readSkippableFrame() :603* Retrieves content of a skippable frame, and writes it to dst buffer.604*605* The parameter magicVariant will receive the magicVariant that was supplied when the frame was written,606* i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested607* in the magicVariant.608*609* Returns an error if destination buffer is not large enough, or if this is not a valid skippable frame.610*611* @return : number of bytes written or a ZSTD error.612*/613size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity,614unsigned* magicVariant, /* optional, can be NULL */615const void* src, size_t srcSize)616{617RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, "");618619{ U32 const magicNumber = MEM_readLE32(src);620size_t skippableFrameSize = readSkippableFrameSize(src, srcSize);621size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE;622623/* check input validity */624RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, "");625RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, "");626RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, "");627628/* deliver payload */629if (skippableContentSize > 0 && dst != NULL)630ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize);631if (magicVariant != NULL)632*magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START;633return skippableContentSize;634}635}636637/** ZSTD_findDecompressedSize() :638* `srcSize` must be the exact length of some number of ZSTD compressed and/or639* skippable frames640* note: compatible with legacy mode641* @return : decompressed size of the frames contained */642unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)643{644unsigned long long totalDstSize = 0;645646while (srcSize >= ZSTD_startingInputLength(ZSTD_f_zstd1)) {647U32 const magicNumber = MEM_readLE32(src);648649if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {650size_t const skippableSize = readSkippableFrameSize(src, srcSize);651if (ZSTD_isError(skippableSize)) return ZSTD_CONTENTSIZE_ERROR;652assert(skippableSize <= srcSize);653654src = (const BYTE *)src + skippableSize;655srcSize -= skippableSize;656continue;657}658659{ unsigned long long const fcs = ZSTD_getFrameContentSize(src, srcSize);660if (fcs >= ZSTD_CONTENTSIZE_ERROR) return fcs;661662if (totalDstSize + fcs < totalDstSize)663return ZSTD_CONTENTSIZE_ERROR; /* check for overflow */664totalDstSize += fcs;665}666/* skip to next frame */667{ size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);668if (ZSTD_isError(frameSrcSize)) return ZSTD_CONTENTSIZE_ERROR;669assert(frameSrcSize <= srcSize);670671src = (const BYTE *)src + frameSrcSize;672srcSize -= frameSrcSize;673}674} /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */675676if (srcSize) return ZSTD_CONTENTSIZE_ERROR;677678return totalDstSize;679}680681/** ZSTD_getDecompressedSize() :682* compatible with legacy mode683* @return : decompressed size if known, 0 otherwise684note : 0 can mean any of the following :685- frame content is empty686- decompressed size field is not present in frame header687- frame header unknown / not supported688- frame header not complete (`srcSize` too small) */689unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)690{691unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);692ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN);693return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret;694}695696697/** ZSTD_decodeFrameHeader() :698* `headerSize` must be the size provided by ZSTD_frameHeaderSize().699* If multiple DDict references are enabled, also will choose the correct DDict to use.700* @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */701static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)702{703size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);704if (ZSTD_isError(result)) return result; /* invalid header */705RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small");706707/* Reference DDict requested by frame if dctx references multiple ddicts */708if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) {709ZSTD_DCtx_selectFrameDDict(dctx);710}711712#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION713/* Skip the dictID check in fuzzing mode, because it makes the search714* harder.715*/716RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID),717dictionary_wrong, "");718#endif719dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0;720if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0);721dctx->processedCSize += headerSize;722return 0;723}724725static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret)726{727ZSTD_frameSizeInfo frameSizeInfo;728frameSizeInfo.compressedSize = ret;729frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR;730return frameSizeInfo;731}732733static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize, ZSTD_format_e format)734{735ZSTD_frameSizeInfo frameSizeInfo;736ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));737738#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)739if (format == ZSTD_f_zstd1 && ZSTD_isLegacy(src, srcSize))740return ZSTD_findFrameSizeInfoLegacy(src, srcSize);741#endif742743if (format == ZSTD_f_zstd1 && (srcSize >= ZSTD_SKIPPABLEHEADERSIZE)744&& (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {745frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize);746assert(ZSTD_isError(frameSizeInfo.compressedSize) ||747frameSizeInfo.compressedSize <= srcSize);748return frameSizeInfo;749} else {750const BYTE* ip = (const BYTE*)src;751const BYTE* const ipstart = ip;752size_t remainingSize = srcSize;753size_t nbBlocks = 0;754ZSTD_FrameHeader zfh;755756/* Extract Frame Header */757{ size_t const ret = ZSTD_getFrameHeader_advanced(&zfh, src, srcSize, format);758if (ZSTD_isError(ret))759return ZSTD_errorFrameSizeInfo(ret);760if (ret > 0)761return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));762}763764ip += zfh.headerSize;765remainingSize -= zfh.headerSize;766767/* Iterate over each block */768while (1) {769blockProperties_t blockProperties;770size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);771if (ZSTD_isError(cBlockSize))772return ZSTD_errorFrameSizeInfo(cBlockSize);773774if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)775return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));776777ip += ZSTD_blockHeaderSize + cBlockSize;778remainingSize -= ZSTD_blockHeaderSize + cBlockSize;779nbBlocks++;780781if (blockProperties.lastBlock) break;782}783784/* Final frame content checksum */785if (zfh.checksumFlag) {786if (remainingSize < 4)787return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));788ip += 4;789}790791frameSizeInfo.nbBlocks = nbBlocks;792frameSizeInfo.compressedSize = (size_t)(ip - ipstart);793frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN)794? zfh.frameContentSize795: (unsigned long long)nbBlocks * zfh.blockSizeMax;796return frameSizeInfo;797}798}799800static size_t ZSTD_findFrameCompressedSize_advanced(const void *src, size_t srcSize, ZSTD_format_e format) {801ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, format);802return frameSizeInfo.compressedSize;803}804805/** ZSTD_findFrameCompressedSize() :806* See docs in zstd.h807* Note: compatible with legacy mode */808size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)809{810return ZSTD_findFrameCompressedSize_advanced(src, srcSize, ZSTD_f_zstd1);811}812813/** ZSTD_decompressBound() :814* compatible with legacy mode815* `src` must point to the start of a ZSTD frame or a skippable frame816* `srcSize` must be at least as large as the frame contained817* @return : the maximum decompressed size of the compressed source818*/819unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)820{821unsigned long long bound = 0;822/* Iterate over each frame */823while (srcSize > 0) {824ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, ZSTD_f_zstd1);825size_t const compressedSize = frameSizeInfo.compressedSize;826unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;827if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)828return ZSTD_CONTENTSIZE_ERROR;829assert(srcSize >= compressedSize);830src = (const BYTE*)src + compressedSize;831srcSize -= compressedSize;832bound += decompressedBound;833}834return bound;835}836837size_t ZSTD_decompressionMargin(void const* src, size_t srcSize)838{839size_t margin = 0;840unsigned maxBlockSize = 0;841842/* Iterate over each frame */843while (srcSize > 0) {844ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize, ZSTD_f_zstd1);845size_t const compressedSize = frameSizeInfo.compressedSize;846unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;847ZSTD_FrameHeader zfh;848849FORWARD_IF_ERROR(ZSTD_getFrameHeader(&zfh, src, srcSize), "");850if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)851return ERROR(corruption_detected);852853if (zfh.frameType == ZSTD_frame) {854/* Add the frame header to our margin */855margin += zfh.headerSize;856/* Add the checksum to our margin */857margin += zfh.checksumFlag ? 4 : 0;858/* Add 3 bytes per block */859margin += 3 * frameSizeInfo.nbBlocks;860861/* Compute the max block size */862maxBlockSize = MAX(maxBlockSize, zfh.blockSizeMax);863} else {864assert(zfh.frameType == ZSTD_skippableFrame);865/* Add the entire skippable frame size to our margin. */866margin += compressedSize;867}868869assert(srcSize >= compressedSize);870src = (const BYTE*)src + compressedSize;871srcSize -= compressedSize;872}873874/* Add the max block size back to the margin. */875margin += maxBlockSize;876877return margin;878}879880/*-*************************************************************881* Frame decoding882***************************************************************/883884/** ZSTD_insertBlock() :885* insert `src` block into `dctx` history. Useful to track uncompressed blocks. */886size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)887{888DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize);889ZSTD_checkContinuity(dctx, blockStart, blockSize);890dctx->previousDstEnd = (const char*)blockStart + blockSize;891return blockSize;892}893894895static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity,896const void* src, size_t srcSize)897{898DEBUGLOG(5, "ZSTD_copyRawBlock");899RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, "");900if (dst == NULL) {901if (srcSize == 0) return 0;902RETURN_ERROR(dstBuffer_null, "");903}904ZSTD_memmove(dst, src, srcSize);905return srcSize;906}907908static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,909BYTE b,910size_t regenSize)911{912RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, "");913if (dst == NULL) {914if (regenSize == 0) return 0;915RETURN_ERROR(dstBuffer_null, "");916}917ZSTD_memset(dst, b, regenSize);918return regenSize;919}920921static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, int streaming)922{923#if ZSTD_TRACE924if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) {925ZSTD_Trace trace;926ZSTD_memset(&trace, 0, sizeof(trace));927trace.version = ZSTD_VERSION_NUMBER;928trace.streaming = streaming;929if (dctx->ddict) {930trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict);931trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict);932trace.dictionaryIsCold = dctx->ddictIsCold;933}934trace.uncompressedSize = (size_t)uncompressedSize;935trace.compressedSize = (size_t)compressedSize;936trace.dctx = dctx;937ZSTD_trace_decompress_end(dctx->traceCtx, &trace);938}939#else940(void)dctx;941(void)uncompressedSize;942(void)compressedSize;943(void)streaming;944#endif945}946947948/*! ZSTD_decompressFrame() :949* @dctx must be properly initialized950* will update *srcPtr and *srcSizePtr,951* to make *srcPtr progress by one frame. */952static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,953void* dst, size_t dstCapacity,954const void** srcPtr, size_t *srcSizePtr)955{956const BYTE* const istart = (const BYTE*)(*srcPtr);957const BYTE* ip = istart;958BYTE* const ostart = (BYTE*)dst;959BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart;960BYTE* op = ostart;961size_t remainingSrcSize = *srcSizePtr;962963DEBUGLOG(4, "ZSTD_decompressFrame (srcSize:%i)", (int)*srcSizePtr);964965/* check */966RETURN_ERROR_IF(967remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize,968srcSize_wrong, "");969970/* Frame Header */971{ size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal(972ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format);973if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;974RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize,975srcSize_wrong, "");976FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , "");977ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;978}979980/* Shrink the blockSizeMax if enabled */981if (dctx->maxBlockSizeParam != 0)982dctx->fParams.blockSizeMax = MIN(dctx->fParams.blockSizeMax, (unsigned)dctx->maxBlockSizeParam);983984/* Loop on each block */985while (1) {986BYTE* oBlockEnd = oend;987size_t decodedSize;988blockProperties_t blockProperties;989size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties);990if (ZSTD_isError(cBlockSize)) return cBlockSize;991992ip += ZSTD_blockHeaderSize;993remainingSrcSize -= ZSTD_blockHeaderSize;994RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, "");995996if (ip >= op && ip < oBlockEnd) {997/* We are decompressing in-place. Limit the output pointer so that we998* don't overwrite the block that we are currently reading. This will999* fail decompression if the input & output pointers aren't spaced1000* far enough apart.1001*1002* This is important to set, even when the pointers are far enough1003* apart, because ZSTD_decompressBlock_internal() can decide to store1004* literals in the output buffer, after the block it is decompressing.1005* Since we don't want anything to overwrite our input, we have to tell1006* ZSTD_decompressBlock_internal to never write past ip.1007*1008* See ZSTD_allocateLiteralsBuffer() for reference.1009*/1010oBlockEnd = op + (ip - op);1011}10121013switch(blockProperties.blockType)1014{1015case bt_compressed:1016assert(dctx->isFrameDecompression == 1);1017decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oBlockEnd-op), ip, cBlockSize, not_streaming);1018break;1019case bt_raw :1020/* Use oend instead of oBlockEnd because this function is safe to overlap. It uses memmove. */1021decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize);1022break;1023case bt_rle :1024decodedSize = ZSTD_setRleBlock(op, (size_t)(oBlockEnd-op), *ip, blockProperties.origSize);1025break;1026case bt_reserved :1027default:1028RETURN_ERROR(corruption_detected, "invalid block type");1029}1030FORWARD_IF_ERROR(decodedSize, "Block decompression failure");1031DEBUGLOG(5, "Decompressed block of dSize = %u", (unsigned)decodedSize);1032if (dctx->validateChecksum) {1033XXH64_update(&dctx->xxhState, op, decodedSize);1034}1035if (decodedSize) /* support dst = NULL,0 */ {1036op += decodedSize;1037}1038assert(ip != NULL);1039ip += cBlockSize;1040remainingSrcSize -= cBlockSize;1041if (blockProperties.lastBlock) break;1042}10431044if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {1045RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize,1046corruption_detected, "");1047}1048if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */1049RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, "");1050if (!dctx->forceIgnoreChecksum) {1051U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);1052U32 checkRead;1053checkRead = MEM_readLE32(ip);1054RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, "");1055}1056ip += 4;1057remainingSrcSize -= 4;1058}1059ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0);1060/* Allow caller to get size read */1061DEBUGLOG(4, "ZSTD_decompressFrame: decompressed frame of size %i, consuming %i bytes of input", (int)(op-ostart), (int)(ip - (const BYTE*)*srcPtr));1062*srcPtr = ip;1063*srcSizePtr = remainingSrcSize;1064return (size_t)(op-ostart);1065}10661067static1068ZSTD_ALLOW_POINTER_OVERFLOW_ATTR1069size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,1070void* dst, size_t dstCapacity,1071const void* src, size_t srcSize,1072const void* dict, size_t dictSize,1073const ZSTD_DDict* ddict)1074{1075void* const dststart = dst;1076int moreThan1Frame = 0;10771078DEBUGLOG(5, "ZSTD_decompressMultiFrame");1079assert(dict==NULL || ddict==NULL); /* either dict or ddict set, not both */10801081if (ddict) {1082dict = ZSTD_DDict_dictContent(ddict);1083dictSize = ZSTD_DDict_dictSize(ddict);1084}10851086while (srcSize >= ZSTD_startingInputLength(dctx->format)) {10871088#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)1089if (dctx->format == ZSTD_f_zstd1 && ZSTD_isLegacy(src, srcSize)) {1090size_t decodedSize;1091size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize);1092if (ZSTD_isError(frameSize)) return frameSize;1093RETURN_ERROR_IF(dctx->staticSize, memory_allocation,1094"legacy support is not compatible with static dctx");10951096decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);1097if (ZSTD_isError(decodedSize)) return decodedSize;10981099{1100unsigned long long const expectedSize = ZSTD_getFrameContentSize(src, srcSize);1101RETURN_ERROR_IF(expectedSize == ZSTD_CONTENTSIZE_ERROR, corruption_detected, "Corrupted frame header!");1102if (expectedSize != ZSTD_CONTENTSIZE_UNKNOWN) {1103RETURN_ERROR_IF(expectedSize != decodedSize, corruption_detected,1104"Frame header size does not match decoded size!");1105}1106}11071108assert(decodedSize <= dstCapacity);1109dst = (BYTE*)dst + decodedSize;1110dstCapacity -= decodedSize;11111112src = (const BYTE*)src + frameSize;1113srcSize -= frameSize;11141115continue;1116}1117#endif11181119if (dctx->format == ZSTD_f_zstd1 && srcSize >= 4) {1120U32 const magicNumber = MEM_readLE32(src);1121DEBUGLOG(5, "reading magic number %08X", (unsigned)magicNumber);1122if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {1123/* skippable frame detected : skip it */1124size_t const skippableSize = readSkippableFrameSize(src, srcSize);1125FORWARD_IF_ERROR(skippableSize, "invalid skippable frame");1126assert(skippableSize <= srcSize);11271128src = (const BYTE *)src + skippableSize;1129srcSize -= skippableSize;1130continue; /* check next frame */1131} }11321133if (ddict) {1134/* we were called from ZSTD_decompress_usingDDict */1135FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict), "");1136} else {1137/* this will initialize correctly with no dict if dict == NULL, so1138* use this in all cases but ddict */1139FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), "");1140}1141ZSTD_checkContinuity(dctx, dst, dstCapacity);11421143{ const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,1144&src, &srcSize);1145RETURN_ERROR_IF(1146(ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown)1147&& (moreThan1Frame==1),1148srcSize_wrong,1149"At least one frame successfully completed, "1150"but following bytes are garbage: "1151"it's more likely to be a srcSize error, "1152"specifying more input bytes than size of frame(s). "1153"Note: one could be unlucky, it might be a corruption error instead, "1154"happening right at the place where we expect zstd magic bytes. "1155"But this is _much_ less likely than a srcSize field error.");1156if (ZSTD_isError(res)) return res;1157assert(res <= dstCapacity);1158if (res != 0)1159dst = (BYTE*)dst + res;1160dstCapacity -= res;1161}1162moreThan1Frame = 1;1163} /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */11641165RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed");11661167return (size_t)((BYTE*)dst - (BYTE*)dststart);1168}11691170size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,1171void* dst, size_t dstCapacity,1172const void* src, size_t srcSize,1173const void* dict, size_t dictSize)1174{1175return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL);1176}117711781179static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx)1180{1181switch (dctx->dictUses) {1182default:1183assert(0 /* Impossible */);1184ZSTD_FALLTHROUGH;1185case ZSTD_dont_use:1186ZSTD_clearDict(dctx);1187return NULL;1188case ZSTD_use_indefinitely:1189return dctx->ddict;1190case ZSTD_use_once:1191dctx->dictUses = ZSTD_dont_use;1192return dctx->ddict;1193}1194}11951196size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)1197{1198return ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ZSTD_getDDict(dctx));1199}120012011202size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize)1203{1204#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1)1205size_t regenSize;1206ZSTD_DCtx* const dctx = ZSTD_createDCtx_internal(ZSTD_defaultCMem);1207RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!");1208regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);1209ZSTD_freeDCtx(dctx);1210return regenSize;1211#else /* stack mode */1212ZSTD_DCtx dctx;1213ZSTD_initDCtx_internal(&dctx);1214return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize);1215#endif1216}121712181219/*-**************************************1220* Advanced Streaming Decompression API1221* Bufferless and synchronous1222****************************************/1223size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }12241225/**1226* Similar to ZSTD_nextSrcSizeToDecompress(), but when a block input can be streamed, we1227* allow taking a partial block as the input. Currently only raw uncompressed blocks can1228* be streamed.1229*1230* For blocks that can be streamed, this allows us to reduce the latency until we produce1231* output, and avoid copying the input.1232*1233* @param inputSize - The total amount of input that the caller currently has.1234*/1235static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t inputSize) {1236if (!(dctx->stage == ZSTDds_decompressBlock || dctx->stage == ZSTDds_decompressLastBlock))1237return dctx->expected;1238if (dctx->bType != bt_raw)1239return dctx->expected;1240return BOUNDED(1, inputSize, dctx->expected);1241}12421243ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {1244switch(dctx->stage)1245{1246default: /* should not happen */1247assert(0);1248ZSTD_FALLTHROUGH;1249case ZSTDds_getFrameHeaderSize:1250ZSTD_FALLTHROUGH;1251case ZSTDds_decodeFrameHeader:1252return ZSTDnit_frameHeader;1253case ZSTDds_decodeBlockHeader:1254return ZSTDnit_blockHeader;1255case ZSTDds_decompressBlock:1256return ZSTDnit_block;1257case ZSTDds_decompressLastBlock:1258return ZSTDnit_lastBlock;1259case ZSTDds_checkChecksum:1260return ZSTDnit_checksum;1261case ZSTDds_decodeSkippableHeader:1262ZSTD_FALLTHROUGH;1263case ZSTDds_skipFrame:1264return ZSTDnit_skippableFrame;1265}1266}12671268static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; }12691270/** ZSTD_decompressContinue() :1271* srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress())1272* @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)1273* or an error code, which can be tested using ZSTD_isError() */1274size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)1275{1276DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);1277/* Sanity check */1278RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed");1279ZSTD_checkContinuity(dctx, dst, dstCapacity);12801281dctx->processedCSize += srcSize;12821283switch (dctx->stage)1284{1285case ZSTDds_getFrameHeaderSize :1286assert(src != NULL);1287if (dctx->format == ZSTD_f_zstd1) { /* allows header */1288assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */1289if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */1290ZSTD_memcpy(dctx->headerBuffer, src, srcSize);1291dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */1292dctx->stage = ZSTDds_decodeSkippableHeader;1293return 0;1294} }1295dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);1296if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;1297ZSTD_memcpy(dctx->headerBuffer, src, srcSize);1298dctx->expected = dctx->headerSize - srcSize;1299dctx->stage = ZSTDds_decodeFrameHeader;1300return 0;13011302case ZSTDds_decodeFrameHeader:1303assert(src != NULL);1304ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);1305FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), "");1306dctx->expected = ZSTD_blockHeaderSize;1307dctx->stage = ZSTDds_decodeBlockHeader;1308return 0;13091310case ZSTDds_decodeBlockHeader:1311{ blockProperties_t bp;1312size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);1313if (ZSTD_isError(cBlockSize)) return cBlockSize;1314RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum");1315dctx->expected = cBlockSize;1316dctx->bType = bp.blockType;1317dctx->rleSize = bp.origSize;1318if (cBlockSize) {1319dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;1320return 0;1321}1322/* empty block */1323if (bp.lastBlock) {1324if (dctx->fParams.checksumFlag) {1325dctx->expected = 4;1326dctx->stage = ZSTDds_checkChecksum;1327} else {1328dctx->expected = 0; /* end of frame */1329dctx->stage = ZSTDds_getFrameHeaderSize;1330}1331} else {1332dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */1333dctx->stage = ZSTDds_decodeBlockHeader;1334}1335return 0;1336}13371338case ZSTDds_decompressLastBlock:1339case ZSTDds_decompressBlock:1340DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock");1341{ size_t rSize;1342switch(dctx->bType)1343{1344case bt_compressed:1345DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");1346assert(dctx->isFrameDecompression == 1);1347rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, is_streaming);1348dctx->expected = 0; /* Streaming not supported */1349break;1350case bt_raw :1351assert(srcSize <= dctx->expected);1352rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);1353FORWARD_IF_ERROR(rSize, "ZSTD_copyRawBlock failed");1354assert(rSize == srcSize);1355dctx->expected -= rSize;1356break;1357case bt_rle :1358rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize);1359dctx->expected = 0; /* Streaming not supported */1360break;1361case bt_reserved : /* should never happen */1362default:1363RETURN_ERROR(corruption_detected, "invalid block type");1364}1365FORWARD_IF_ERROR(rSize, "");1366RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum");1367DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);1368dctx->decodedSize += rSize;1369if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize);1370dctx->previousDstEnd = (char*)dst + rSize;13711372/* Stay on the same stage until we are finished streaming the block. */1373if (dctx->expected > 0) {1374return rSize;1375}13761377if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */1378DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize);1379RETURN_ERROR_IF(1380dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN1381&& dctx->decodedSize != dctx->fParams.frameContentSize,1382corruption_detected, "");1383if (dctx->fParams.checksumFlag) { /* another round for frame checksum */1384dctx->expected = 4;1385dctx->stage = ZSTDds_checkChecksum;1386} else {1387ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);1388dctx->expected = 0; /* ends here */1389dctx->stage = ZSTDds_getFrameHeaderSize;1390}1391} else {1392dctx->stage = ZSTDds_decodeBlockHeader;1393dctx->expected = ZSTD_blockHeaderSize;1394}1395return rSize;1396}13971398case ZSTDds_checkChecksum:1399assert(srcSize == 4); /* guaranteed by dctx->expected */1400{1401if (dctx->validateChecksum) {1402U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);1403U32 const check32 = MEM_readLE32(src);1404DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);1405RETURN_ERROR_IF(check32 != h32, checksum_wrong, "");1406}1407ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);1408dctx->expected = 0;1409dctx->stage = ZSTDds_getFrameHeaderSize;1410return 0;1411}14121413case ZSTDds_decodeSkippableHeader:1414assert(src != NULL);1415assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);1416assert(dctx->format != ZSTD_f_zstd1_magicless);1417ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */1418dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */1419dctx->stage = ZSTDds_skipFrame;1420return 0;14211422case ZSTDds_skipFrame:1423dctx->expected = 0;1424dctx->stage = ZSTDds_getFrameHeaderSize;1425return 0;14261427default:1428assert(0); /* impossible */1429RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */1430}1431}143214331434static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1435{1436dctx->dictEnd = dctx->previousDstEnd;1437dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));1438dctx->prefixStart = dict;1439dctx->previousDstEnd = (const char*)dict + dictSize;1440#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION1441dctx->dictContentBeginForFuzzing = dctx->prefixStart;1442dctx->dictContentEndForFuzzing = dctx->previousDstEnd;1443#endif1444return 0;1445}14461447/*! ZSTD_loadDEntropy() :1448* dict : must point at beginning of a valid zstd dictionary.1449* @return : size of entropy tables read */1450size_t1451ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,1452const void* const dict, size_t const dictSize)1453{1454const BYTE* dictPtr = (const BYTE*)dict;1455const BYTE* const dictEnd = dictPtr + dictSize;14561457RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted, "dict is too small");1458assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */1459dictPtr += 8; /* skip header = magic + dictID */14601461ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, OFTable) == offsetof(ZSTD_entropyDTables_t, LLTable) + sizeof(entropy->LLTable));1462ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, MLTable) == offsetof(ZSTD_entropyDTables_t, OFTable) + sizeof(entropy->OFTable));1463ZSTD_STATIC_ASSERT(sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable) >= HUF_DECOMPRESS_WORKSPACE_SIZE);1464{ void* const workspace = &entropy->LLTable; /* use fse tables as temporary workspace; implies fse tables are grouped together */1465size_t const workspaceSize = sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable);1466#ifdef HUF_FORCE_DECOMPRESS_X11467/* in minimal huffman, we always use X1 variants */1468size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable,1469dictPtr, dictEnd - dictPtr,1470workspace, workspaceSize, /* flags */ 0);1471#else1472size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,1473dictPtr, (size_t)(dictEnd - dictPtr),1474workspace, workspaceSize, /* flags */ 0);1475#endif1476RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, "");1477dictPtr += hSize;1478}14791480{ short offcodeNCount[MaxOff+1];1481unsigned offcodeMaxValue = MaxOff, offcodeLog;1482size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr));1483RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");1484RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, "");1485RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");1486ZSTD_buildFSETable( entropy->OFTable,1487offcodeNCount, offcodeMaxValue,1488OF_base, OF_bits,1489offcodeLog,1490entropy->workspace, sizeof(entropy->workspace),1491/* bmi2 */0);1492dictPtr += offcodeHeaderSize;1493}14941495{ short matchlengthNCount[MaxML+1];1496unsigned matchlengthMaxValue = MaxML, matchlengthLog;1497size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr));1498RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");1499RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, "");1500RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");1501ZSTD_buildFSETable( entropy->MLTable,1502matchlengthNCount, matchlengthMaxValue,1503ML_base, ML_bits,1504matchlengthLog,1505entropy->workspace, sizeof(entropy->workspace),1506/* bmi2 */ 0);1507dictPtr += matchlengthHeaderSize;1508}15091510{ short litlengthNCount[MaxLL+1];1511unsigned litlengthMaxValue = MaxLL, litlengthLog;1512size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr));1513RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");1514RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, "");1515RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");1516ZSTD_buildFSETable( entropy->LLTable,1517litlengthNCount, litlengthMaxValue,1518LL_base, LL_bits,1519litlengthLog,1520entropy->workspace, sizeof(entropy->workspace),1521/* bmi2 */ 0);1522dictPtr += litlengthHeaderSize;1523}15241525RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, "");1526{ int i;1527size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12));1528for (i=0; i<3; i++) {1529U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4;1530RETURN_ERROR_IF(rep==0 || rep > dictContentSize,1531dictionary_corrupted, "");1532entropy->rep[i] = rep;1533} }15341535return (size_t)(dictPtr - (const BYTE*)dict);1536}15371538static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1539{1540if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize);1541{ U32 const magic = MEM_readLE32(dict);1542if (magic != ZSTD_MAGIC_DICTIONARY) {1543return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */1544} }1545dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);15461547/* load entropy tables */1548{ size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize);1549RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted, "");1550dict = (const char*)dict + eSize;1551dictSize -= eSize;1552}1553dctx->litEntropy = dctx->fseEntropy = 1;15541555/* reference dictionary content */1556return ZSTD_refDictContent(dctx, dict, dictSize);1557}15581559size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)1560{1561assert(dctx != NULL);1562#if ZSTD_TRACE1563dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0;1564#endif1565dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */1566dctx->stage = ZSTDds_getFrameHeaderSize;1567dctx->processedCSize = 0;1568dctx->decodedSize = 0;1569dctx->previousDstEnd = NULL;1570dctx->prefixStart = NULL;1571dctx->virtualStart = NULL;1572dctx->dictEnd = NULL;1573dctx->entropy.hufTable[0] = (HUF_DTable)((ZSTD_HUFFDTABLE_CAPACITY_LOG)*0x1000001); /* cover both little and big endian */1574dctx->litEntropy = dctx->fseEntropy = 0;1575dctx->dictID = 0;1576dctx->bType = bt_reserved;1577dctx->isFrameDecompression = 1;1578ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));1579ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */1580dctx->LLTptr = dctx->entropy.LLTable;1581dctx->MLTptr = dctx->entropy.MLTable;1582dctx->OFTptr = dctx->entropy.OFTable;1583dctx->HUFptr = dctx->entropy.hufTable;1584return 0;1585}15861587size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1588{1589FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");1590if (dict && dictSize)1591RETURN_ERROR_IF(1592ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)),1593dictionary_corrupted, "");1594return 0;1595}159615971598/* ====== ZSTD_DDict ====== */15991600size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)1601{1602DEBUGLOG(4, "ZSTD_decompressBegin_usingDDict");1603assert(dctx != NULL);1604if (ddict) {1605const char* const dictStart = (const char*)ZSTD_DDict_dictContent(ddict);1606size_t const dictSize = ZSTD_DDict_dictSize(ddict);1607const void* const dictEnd = dictStart + dictSize;1608dctx->ddictIsCold = (dctx->dictEnd != dictEnd);1609DEBUGLOG(4, "DDict is %s",1610dctx->ddictIsCold ? "~cold~" : "hot!");1611}1612FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");1613if (ddict) { /* NULL ddict is equivalent to no dictionary */1614ZSTD_copyDDictParameters(dctx, ddict);1615}1616return 0;1617}16181619/*! ZSTD_getDictID_fromDict() :1620* Provides the dictID stored within dictionary.1621* if @return == 0, the dictionary is not conformant with Zstandard specification.1622* It can still be loaded, but as a content-only dictionary. */1623unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)1624{1625if (dictSize < 8) return 0;1626if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0;1627return MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);1628}16291630/*! ZSTD_getDictID_fromFrame() :1631* Provides the dictID required to decompress frame stored within `src`.1632* If @return == 0, the dictID could not be decoded.1633* This could for one of the following reasons :1634* - The frame does not require a dictionary (most common case).1635* - The frame was built with dictID intentionally removed.1636* Needed dictionary is a hidden piece of information.1637* Note : this use case also happens when using a non-conformant dictionary.1638* - `srcSize` is too small, and as a result, frame header could not be decoded.1639* Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`.1640* - This is not a Zstandard frame.1641* When identifying the exact failure cause, it's possible to use1642* ZSTD_getFrameHeader(), which will provide a more precise error code. */1643unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)1644{1645ZSTD_FrameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0, 0, 0 };1646size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);1647if (ZSTD_isError(hError)) return 0;1648return zfp.dictID;1649}165016511652/*! ZSTD_decompress_usingDDict() :1653* Decompression using a pre-digested Dictionary1654* Use dictionary without significant overhead. */1655size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,1656void* dst, size_t dstCapacity,1657const void* src, size_t srcSize,1658const ZSTD_DDict* ddict)1659{1660/* pass content and size in case legacy frames are encountered */1661return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize,1662NULL, 0,1663ddict);1664}166516661667/*=====================================1668* Streaming decompression1669*====================================*/16701671ZSTD_DStream* ZSTD_createDStream(void)1672{1673DEBUGLOG(3, "ZSTD_createDStream");1674return ZSTD_createDCtx_internal(ZSTD_defaultCMem);1675}16761677ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize)1678{1679return ZSTD_initStaticDCtx(workspace, workspaceSize);1680}16811682ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem)1683{1684return ZSTD_createDCtx_internal(customMem);1685}16861687size_t ZSTD_freeDStream(ZSTD_DStream* zds)1688{1689return ZSTD_freeDCtx(zds);1690}169116921693/* *** Initialization *** */16941695size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; }1696size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }16971698size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx,1699const void* dict, size_t dictSize,1700ZSTD_dictLoadMethod_e dictLoadMethod,1701ZSTD_dictContentType_e dictContentType)1702{1703RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1704ZSTD_clearDict(dctx);1705if (dict && dictSize != 0) {1706dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem);1707RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation, "NULL pointer!");1708dctx->ddict = dctx->ddictLocal;1709dctx->dictUses = ZSTD_use_indefinitely;1710}1711return 0;1712}17131714size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1715{1716return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);1717}17181719size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1720{1721return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);1722}17231724size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)1725{1726FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType), "");1727dctx->dictUses = ZSTD_use_once;1728return 0;1729}17301731size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize)1732{1733return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent);1734}173517361737/* ZSTD_initDStream_usingDict() :1738* return : expected size, aka ZSTD_startingInputLength().1739* this function cannot fail */1740size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)1741{1742DEBUGLOG(4, "ZSTD_initDStream_usingDict");1743FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) , "");1744FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) , "");1745return ZSTD_startingInputLength(zds->format);1746}17471748/* note : this variant can't fail */1749size_t ZSTD_initDStream(ZSTD_DStream* zds)1750{1751DEBUGLOG(4, "ZSTD_initDStream");1752FORWARD_IF_ERROR(ZSTD_DCtx_reset(zds, ZSTD_reset_session_only), "");1753FORWARD_IF_ERROR(ZSTD_DCtx_refDDict(zds, NULL), "");1754return ZSTD_startingInputLength(zds->format);1755}17561757/* ZSTD_initDStream_usingDDict() :1758* ddict will just be referenced, and must outlive decompression session1759* this function cannot fail */1760size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)1761{1762DEBUGLOG(4, "ZSTD_initDStream_usingDDict");1763FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , "");1764FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , "");1765return ZSTD_startingInputLength(dctx->format);1766}17671768/* ZSTD_resetDStream() :1769* return : expected size, aka ZSTD_startingInputLength().1770* this function cannot fail */1771size_t ZSTD_resetDStream(ZSTD_DStream* dctx)1772{1773DEBUGLOG(4, "ZSTD_resetDStream");1774FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), "");1775return ZSTD_startingInputLength(dctx->format);1776}177717781779size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)1780{1781RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1782ZSTD_clearDict(dctx);1783if (ddict) {1784dctx->ddict = ddict;1785dctx->dictUses = ZSTD_use_indefinitely;1786if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) {1787if (dctx->ddictSet == NULL) {1788dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem);1789if (!dctx->ddictSet) {1790RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!");1791}1792}1793assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */1794FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), "");1795}1796}1797return 0;1798}17991800/* ZSTD_DCtx_setMaxWindowSize() :1801* note : no direct equivalence in ZSTD_DCtx_setParameter,1802* since this version sets windowSize, and the other sets windowLog */1803size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)1804{1805ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax);1806size_t const min = (size_t)1 << bounds.lowerBound;1807size_t const max = (size_t)1 << bounds.upperBound;1808RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1809RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound, "");1810RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound, "");1811dctx->maxWindowSize = maxWindowSize;1812return 0;1813}18141815size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)1816{1817return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format);1818}18191820ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)1821{1822ZSTD_bounds bounds = { 0, 0, 0 };1823switch(dParam) {1824case ZSTD_d_windowLogMax:1825bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN;1826bounds.upperBound = ZSTD_WINDOWLOG_MAX;1827return bounds;1828case ZSTD_d_format:1829bounds.lowerBound = (int)ZSTD_f_zstd1;1830bounds.upperBound = (int)ZSTD_f_zstd1_magicless;1831ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);1832return bounds;1833case ZSTD_d_stableOutBuffer:1834bounds.lowerBound = (int)ZSTD_bm_buffered;1835bounds.upperBound = (int)ZSTD_bm_stable;1836return bounds;1837case ZSTD_d_forceIgnoreChecksum:1838bounds.lowerBound = (int)ZSTD_d_validateChecksum;1839bounds.upperBound = (int)ZSTD_d_ignoreChecksum;1840return bounds;1841case ZSTD_d_refMultipleDDicts:1842bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict;1843bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts;1844return bounds;1845case ZSTD_d_disableHuffmanAssembly:1846bounds.lowerBound = 0;1847bounds.upperBound = 1;1848return bounds;1849case ZSTD_d_maxBlockSize:1850bounds.lowerBound = ZSTD_BLOCKSIZE_MAX_MIN;1851bounds.upperBound = ZSTD_BLOCKSIZE_MAX;1852return bounds;18531854default:;1855}1856bounds.error = ERROR(parameter_unsupported);1857return bounds;1858}18591860/* ZSTD_dParam_withinBounds:1861* @return 1 if value is within dParam bounds,1862* 0 otherwise */1863static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value)1864{1865ZSTD_bounds const bounds = ZSTD_dParam_getBounds(dParam);1866if (ZSTD_isError(bounds.error)) return 0;1867if (value < bounds.lowerBound) return 0;1868if (value > bounds.upperBound) return 0;1869return 1;1870}18711872#define CHECK_DBOUNDS(p,v) { \1873RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \1874}18751876size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value)1877{1878switch (param) {1879case ZSTD_d_windowLogMax:1880*value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize);1881return 0;1882case ZSTD_d_format:1883*value = (int)dctx->format;1884return 0;1885case ZSTD_d_stableOutBuffer:1886*value = (int)dctx->outBufferMode;1887return 0;1888case ZSTD_d_forceIgnoreChecksum:1889*value = (int)dctx->forceIgnoreChecksum;1890return 0;1891case ZSTD_d_refMultipleDDicts:1892*value = (int)dctx->refMultipleDDicts;1893return 0;1894case ZSTD_d_disableHuffmanAssembly:1895*value = (int)dctx->disableHufAsm;1896return 0;1897case ZSTD_d_maxBlockSize:1898*value = dctx->maxBlockSizeParam;1899return 0;1900default:;1901}1902RETURN_ERROR(parameter_unsupported, "");1903}19041905size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value)1906{1907RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1908switch(dParam) {1909case ZSTD_d_windowLogMax:1910if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT;1911CHECK_DBOUNDS(ZSTD_d_windowLogMax, value);1912dctx->maxWindowSize = ((size_t)1) << value;1913return 0;1914case ZSTD_d_format:1915CHECK_DBOUNDS(ZSTD_d_format, value);1916dctx->format = (ZSTD_format_e)value;1917return 0;1918case ZSTD_d_stableOutBuffer:1919CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value);1920dctx->outBufferMode = (ZSTD_bufferMode_e)value;1921return 0;1922case ZSTD_d_forceIgnoreChecksum:1923CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value);1924dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value;1925return 0;1926case ZSTD_d_refMultipleDDicts:1927CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value);1928if (dctx->staticSize != 0) {1929RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!");1930}1931dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value;1932return 0;1933case ZSTD_d_disableHuffmanAssembly:1934CHECK_DBOUNDS(ZSTD_d_disableHuffmanAssembly, value);1935dctx->disableHufAsm = value != 0;1936return 0;1937case ZSTD_d_maxBlockSize:1938if (value != 0) CHECK_DBOUNDS(ZSTD_d_maxBlockSize, value);1939dctx->maxBlockSizeParam = value;1940return 0;1941default:;1942}1943RETURN_ERROR(parameter_unsupported, "");1944}19451946size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)1947{1948if ( (reset == ZSTD_reset_session_only)1949|| (reset == ZSTD_reset_session_and_parameters) ) {1950dctx->streamStage = zdss_init;1951dctx->noForwardProgress = 0;1952dctx->isFrameDecompression = 1;1953}1954if ( (reset == ZSTD_reset_parameters)1955|| (reset == ZSTD_reset_session_and_parameters) ) {1956RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1957ZSTD_clearDict(dctx);1958ZSTD_DCtx_resetParameters(dctx);1959}1960return 0;1961}196219631964size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)1965{1966return ZSTD_sizeof_DCtx(dctx);1967}19681969static size_t ZSTD_decodingBufferSize_internal(unsigned long long windowSize, unsigned long long frameContentSize, size_t blockSizeMax)1970{1971size_t const blockSize = MIN((size_t)MIN(windowSize, ZSTD_BLOCKSIZE_MAX), blockSizeMax);1972/* We need blockSize + WILDCOPY_OVERLENGTH worth of buffer so that if a block1973* ends at windowSize + WILDCOPY_OVERLENGTH + 1 bytes, we can start writing1974* the block at the beginning of the output buffer, and maintain a full window.1975*1976* We need another blockSize worth of buffer so that we can store split1977* literals at the end of the block without overwriting the extDict window.1978*/1979unsigned long long const neededRBSize = windowSize + (blockSize * 2) + (WILDCOPY_OVERLENGTH * 2);1980unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);1981size_t const minRBSize = (size_t) neededSize;1982RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize,1983frameParameter_windowTooLarge, "");1984return minRBSize;1985}19861987size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)1988{1989return ZSTD_decodingBufferSize_internal(windowSize, frameContentSize, ZSTD_BLOCKSIZE_MAX);1990}19911992size_t ZSTD_estimateDStreamSize(size_t windowSize)1993{1994size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);1995size_t const inBuffSize = blockSize; /* no block can be larger */1996size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN);1997return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;1998}19992000size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)2001{2002U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */2003ZSTD_FrameHeader zfh;2004size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);2005if (ZSTD_isError(err)) return err;2006RETURN_ERROR_IF(err>0, srcSize_wrong, "");2007RETURN_ERROR_IF(zfh.windowSize > windowSizeMax,2008frameParameter_windowTooLarge, "");2009return ZSTD_estimateDStreamSize((size_t)zfh.windowSize);2010}201120122013/* ***** Decompression ***** */20142015static int ZSTD_DCtx_isOverflow(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)2016{2017return (zds->inBuffSize + zds->outBuffSize) >= (neededInBuffSize + neededOutBuffSize) * ZSTD_WORKSPACETOOLARGE_FACTOR;2018}20192020static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)2021{2022if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize))2023zds->oversizedDuration++;2024else2025zds->oversizedDuration = 0;2026}20272028static int ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream* zds)2029{2030return zds->oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION;2031}20322033/* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */2034static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* output)2035{2036ZSTD_outBuffer const expect = zds->expectedOutBuffer;2037/* No requirement when ZSTD_obm_stable is not enabled. */2038if (zds->outBufferMode != ZSTD_bm_stable)2039return 0;2040/* Any buffer is allowed in zdss_init, this must be the same for every other call until2041* the context is reset.2042*/2043if (zds->streamStage == zdss_init)2044return 0;2045/* The buffer must match our expectation exactly. */2046if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size)2047return 0;2048RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!");2049}20502051/* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream()2052* and updates the stage and the output buffer state. This call is extracted so it can be2053* used both when reading directly from the ZSTD_inBuffer, and in buffered input mode.2054* NOTE: You must break after calling this function since the streamStage is modified.2055*/2056static size_t ZSTD_decompressContinueStream(2057ZSTD_DStream* zds, char** op, char* oend,2058void const* src, size_t srcSize) {2059int const isSkipFrame = ZSTD_isSkipFrame(zds);2060if (zds->outBufferMode == ZSTD_bm_buffered) {2061size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart;2062size_t const decodedSize = ZSTD_decompressContinue(zds,2063zds->outBuff + zds->outStart, dstSize, src, srcSize);2064FORWARD_IF_ERROR(decodedSize, "");2065if (!decodedSize && !isSkipFrame) {2066zds->streamStage = zdss_read;2067} else {2068zds->outEnd = zds->outStart + decodedSize;2069zds->streamStage = zdss_flush;2070}2071} else {2072/* Write directly into the output buffer */2073size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op);2074size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize);2075FORWARD_IF_ERROR(decodedSize, "");2076*op += decodedSize;2077/* Flushing is not needed. */2078zds->streamStage = zdss_read;2079assert(*op <= oend);2080assert(zds->outBufferMode == ZSTD_bm_stable);2081}2082return 0;2083}20842085size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input)2086{2087const char* const src = (const char*)input->src;2088const char* const istart = input->pos != 0 ? src + input->pos : src;2089const char* const iend = input->size != 0 ? src + input->size : src;2090const char* ip = istart;2091char* const dst = (char*)output->dst;2092char* const ostart = output->pos != 0 ? dst + output->pos : dst;2093char* const oend = output->size != 0 ? dst + output->size : dst;2094char* op = ostart;2095U32 someMoreWork = 1;20962097DEBUGLOG(5, "ZSTD_decompressStream");2098assert(zds != NULL);2099RETURN_ERROR_IF(2100input->pos > input->size,2101srcSize_wrong,2102"forbidden. in: pos: %u vs size: %u",2103(U32)input->pos, (U32)input->size);2104RETURN_ERROR_IF(2105output->pos > output->size,2106dstSize_tooSmall,2107"forbidden. out: pos: %u vs size: %u",2108(U32)output->pos, (U32)output->size);2109DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));2110FORWARD_IF_ERROR(ZSTD_checkOutBuffer(zds, output), "");21112112while (someMoreWork) {2113switch(zds->streamStage)2114{2115case zdss_init :2116DEBUGLOG(5, "stage zdss_init => transparent reset ");2117zds->streamStage = zdss_loadHeader;2118zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;2119#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)2120zds->legacyVersion = 0;2121#endif2122zds->hostageByte = 0;2123zds->expectedOutBuffer = *output;2124ZSTD_FALLTHROUGH;21252126case zdss_loadHeader :2127DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));2128#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)2129if (zds->legacyVersion) {2130RETURN_ERROR_IF(zds->staticSize, memory_allocation,2131"legacy support is incompatible with static dctx");2132{ size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);2133if (hint==0) zds->streamStage = zdss_init;2134return hint;2135} }2136#endif2137{ size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);2138if (zds->refMultipleDDicts && zds->ddictSet) {2139ZSTD_DCtx_selectFrameDDict(zds);2140}2141if (ZSTD_isError(hSize)) {2142#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)2143U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);2144if (legacyVersion) {2145ZSTD_DDict const* const ddict = ZSTD_getDDict(zds);2146const void* const dict = ddict ? ZSTD_DDict_dictContent(ddict) : NULL;2147size_t const dictSize = ddict ? ZSTD_DDict_dictSize(ddict) : 0;2148DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion);2149RETURN_ERROR_IF(zds->staticSize, memory_allocation,2150"legacy support is incompatible with static dctx");2151FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext,2152zds->previousLegacyVersion, legacyVersion,2153dict, dictSize), "");2154zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;2155{ size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);2156if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */2157return hint;2158} }2159#endif2160return hSize; /* error */2161}2162if (hSize != 0) { /* need more input */2163size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */2164size_t const remainingInput = (size_t)(iend-ip);2165assert(iend >= ip);2166if (toLoad > remainingInput) { /* not enough input to load full header */2167if (remainingInput > 0) {2168ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);2169zds->lhSize += remainingInput;2170}2171input->pos = input->size;2172/* check first few bytes */2173FORWARD_IF_ERROR(2174ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format),2175"First few bytes detected incorrect" );2176/* return hint input size */2177return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */2178}2179assert(ip != NULL);2180ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;2181break;2182} }21832184/* check for single-pass mode opportunity */2185if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN2186&& zds->fParams.frameType != ZSTD_skippableFrame2187&& (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {2188size_t const cSize = ZSTD_findFrameCompressedSize_advanced(istart, (size_t)(iend-istart), zds->format);2189if (cSize <= (size_t)(iend-istart)) {2190/* shortcut : using single-pass mode */2191size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds));2192if (ZSTD_isError(decompressedSize)) return decompressedSize;2193DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()");2194assert(istart != NULL);2195ip = istart + cSize;2196op = op ? op + decompressedSize : op; /* can occur if frameContentSize = 0 (empty frame) */2197zds->expected = 0;2198zds->streamStage = zdss_init;2199someMoreWork = 0;2200break;2201} }22022203/* Check output buffer is large enough for ZSTD_odm_stable. */2204if (zds->outBufferMode == ZSTD_bm_stable2205&& zds->fParams.frameType != ZSTD_skippableFrame2206&& zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN2207&& (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) {2208RETURN_ERROR(dstSize_tooSmall, "ZSTD_obm_stable passed but ZSTD_outBuffer is too small");2209}22102211/* Consume header (see ZSTDds_decodeFrameHeader) */2212DEBUGLOG(4, "Consume header");2213FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), "");22142215if (zds->format == ZSTD_f_zstd12216&& (MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */2217zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);2218zds->stage = ZSTDds_skipFrame;2219} else {2220FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), "");2221zds->expected = ZSTD_blockHeaderSize;2222zds->stage = ZSTDds_decodeBlockHeader;2223}22242225/* control buffer memory usage */2226DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)",2227(U32)(zds->fParams.windowSize >>10),2228(U32)(zds->maxWindowSize >> 10) );2229zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);2230RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize,2231frameParameter_windowTooLarge, "");2232if (zds->maxBlockSizeParam != 0)2233zds->fParams.blockSizeMax = MIN(zds->fParams.blockSizeMax, (unsigned)zds->maxBlockSizeParam);22342235/* Adapt buffer sizes to frame header instructions */2236{ size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);2237size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered2238? ZSTD_decodingBufferSize_internal(zds->fParams.windowSize, zds->fParams.frameContentSize, zds->fParams.blockSizeMax)2239: 0;22402241ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize);22422243{ int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize);2244int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds);22452246if (tooSmall || tooLarge) {2247size_t const bufferSize = neededInBuffSize + neededOutBuffSize;2248DEBUGLOG(4, "inBuff : from %u to %u",2249(U32)zds->inBuffSize, (U32)neededInBuffSize);2250DEBUGLOG(4, "outBuff : from %u to %u",2251(U32)zds->outBuffSize, (U32)neededOutBuffSize);2252if (zds->staticSize) { /* static DCtx */2253DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize);2254assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */2255RETURN_ERROR_IF(2256bufferSize > zds->staticSize - sizeof(ZSTD_DCtx),2257memory_allocation, "");2258} else {2259ZSTD_customFree(zds->inBuff, zds->customMem);2260zds->inBuffSize = 0;2261zds->outBuffSize = 0;2262zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem);2263RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, "");2264}2265zds->inBuffSize = neededInBuffSize;2266zds->outBuff = zds->inBuff + zds->inBuffSize;2267zds->outBuffSize = neededOutBuffSize;2268} } }2269zds->streamStage = zdss_read;2270ZSTD_FALLTHROUGH;22712272case zdss_read:2273DEBUGLOG(5, "stage zdss_read");2274{ size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip));2275DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize);2276if (neededInSize==0) { /* end of frame */2277zds->streamStage = zdss_init;2278someMoreWork = 0;2279break;2280}2281if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */2282FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), "");2283assert(ip != NULL);2284ip += neededInSize;2285/* Function modifies the stage so we must break */2286break;2287} }2288if (ip==iend) { someMoreWork = 0; break; } /* no more input */2289zds->streamStage = zdss_load;2290ZSTD_FALLTHROUGH;22912292case zdss_load:2293{ size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);2294size_t const toLoad = neededInSize - zds->inPos;2295int const isSkipFrame = ZSTD_isSkipFrame(zds);2296size_t loadedSize;2297/* At this point we shouldn't be decompressing a block that we can stream. */2298assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip)));2299if (isSkipFrame) {2300loadedSize = MIN(toLoad, (size_t)(iend-ip));2301} else {2302RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos,2303corruption_detected,2304"should never happen");2305loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip));2306}2307if (loadedSize != 0) {2308/* ip may be NULL */2309ip += loadedSize;2310zds->inPos += loadedSize;2311}2312if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */23132314/* decode loaded input */2315zds->inPos = 0; /* input is consumed */2316FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, zds->inBuff, neededInSize), "");2317/* Function modifies the stage so we must break */2318break;2319}2320case zdss_flush:2321{2322size_t const toFlushSize = zds->outEnd - zds->outStart;2323size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize);23242325op = op ? op + flushedSize : op;23262327zds->outStart += flushedSize;2328if (flushedSize == toFlushSize) { /* flush completed */2329zds->streamStage = zdss_read;2330if ( (zds->outBuffSize < zds->fParams.frameContentSize)2331&& (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) {2332DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)",2333(int)(zds->outBuffSize - zds->outStart),2334(U32)zds->fParams.blockSizeMax);2335zds->outStart = zds->outEnd = 0;2336}2337break;2338} }2339/* cannot complete flush */2340someMoreWork = 0;2341break;23422343default:2344assert(0); /* impossible */2345RETURN_ERROR(GENERIC, "impossible to reach"); /* some compilers require default to do something */2346} }23472348/* result */2349input->pos = (size_t)(ip - (const char*)(input->src));2350output->pos = (size_t)(op - (char*)(output->dst));23512352/* Update the expected output buffer for ZSTD_obm_stable. */2353zds->expectedOutBuffer = *output;23542355if ((ip==istart) && (op==ostart)) { /* no forward progress */2356zds->noForwardProgress ++;2357if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {2358RETURN_ERROR_IF(op==oend, noForwardProgress_destFull, "");2359RETURN_ERROR_IF(ip==iend, noForwardProgress_inputEmpty, "");2360assert(0);2361}2362} else {2363zds->noForwardProgress = 0;2364}2365{ size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds);2366if (!nextSrcSizeHint) { /* frame fully decoded */2367if (zds->outEnd == zds->outStart) { /* output fully flushed */2368if (zds->hostageByte) {2369if (input->pos >= input->size) {2370/* can't release hostage (not present) */2371zds->streamStage = zdss_read;2372return 1;2373}2374input->pos++; /* release hostage */2375} /* zds->hostageByte */2376return 0;2377} /* zds->outEnd == zds->outStart */2378if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */2379input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */2380zds->hostageByte=1;2381}2382return 1;2383} /* nextSrcSizeHint==0 */2384nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */2385assert(zds->inPos <= nextSrcSizeHint);2386nextSrcSizeHint -= zds->inPos; /* part already loaded*/2387return nextSrcSizeHint;2388}2389}23902391size_t ZSTD_decompressStream_simpleArgs (2392ZSTD_DCtx* dctx,2393void* dst, size_t dstCapacity, size_t* dstPos,2394const void* src, size_t srcSize, size_t* srcPos)2395{2396ZSTD_outBuffer output;2397ZSTD_inBuffer input;2398output.dst = dst;2399output.size = dstCapacity;2400output.pos = *dstPos;2401input.src = src;2402input.size = srcSize;2403input.pos = *srcPos;2404{ size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);2405*dstPos = output.pos;2406*srcPos = input.pos;2407return cErr;2408}2409}241024112412