Path: blob/main/sys/contrib/zstd/lib/decompress/zstd_decompress.c
48378 views
/*1* Copyright (c) Yann Collet, Facebook, Inc.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/mem.h" /* low level memory routines */59#define FSE_STATIC_LINKING_ONLY60#include "../common/fse.h"61#define HUF_STATIC_LINKING_ONLY62#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 */6869#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)70# include "../legacy/zstd_legacy.h"71#endif72737475/*************************************76* Multiple DDicts Hashset internals *77*************************************/7879#define DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT 480#define DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT 3 /* These two constants represent SIZE_MULT/COUNT_MULT load factor without using a float.81* Currently, that means a 0.75 load factor.82* So, if count * COUNT_MULT / size * SIZE_MULT != 0, then we've exceeded83* the load factor of the ddict hash set.84*/8586#define DDICT_HASHSET_TABLE_BASE_SIZE 6487#define DDICT_HASHSET_RESIZE_FACTOR 28889/* Hash function to determine starting position of dict insertion within the table90* Returns an index between [0, hashSet->ddictPtrTableSize]91*/92static size_t ZSTD_DDictHashSet_getIndex(const ZSTD_DDictHashSet* hashSet, U32 dictID) {93const U64 hash = XXH64(&dictID, sizeof(U32), 0);94/* DDict ptr table size is a multiple of 2, use size - 1 as mask to get index within [0, hashSet->ddictPtrTableSize) */95return hash & (hashSet->ddictPtrTableSize - 1);96}9798/* Adds DDict to a hashset without resizing it.99* If inserting a DDict with a dictID that already exists in the set, replaces the one in the set.100* Returns 0 if successful, or a zstd error code if something went wrong.101*/102static size_t ZSTD_DDictHashSet_emplaceDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict) {103const U32 dictID = ZSTD_getDictID_fromDDict(ddict);104size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);105const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;106RETURN_ERROR_IF(hashSet->ddictPtrCount == hashSet->ddictPtrTableSize, GENERIC, "Hash set is full!");107DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);108while (hashSet->ddictPtrTable[idx] != NULL) {109/* Replace existing ddict if inserting ddict with same dictID */110if (ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]) == dictID) {111DEBUGLOG(4, "DictID already exists, replacing rather than adding");112hashSet->ddictPtrTable[idx] = ddict;113return 0;114}115idx &= idxRangeMask;116idx++;117}118DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);119hashSet->ddictPtrTable[idx] = ddict;120hashSet->ddictPtrCount++;121return 0;122}123124/* Expands hash table by factor of DDICT_HASHSET_RESIZE_FACTOR and125* rehashes all values, allocates new table, frees old table.126* Returns 0 on success, otherwise a zstd error code.127*/128static size_t ZSTD_DDictHashSet_expand(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {129size_t newTableSize = hashSet->ddictPtrTableSize * DDICT_HASHSET_RESIZE_FACTOR;130const ZSTD_DDict** newTable = (const ZSTD_DDict**)ZSTD_customCalloc(sizeof(ZSTD_DDict*) * newTableSize, customMem);131const ZSTD_DDict** oldTable = hashSet->ddictPtrTable;132size_t oldTableSize = hashSet->ddictPtrTableSize;133size_t i;134135DEBUGLOG(4, "Expanding DDict hash table! Old size: %zu new size: %zu", oldTableSize, newTableSize);136RETURN_ERROR_IF(!newTable, memory_allocation, "Expanded hashset allocation failed!");137hashSet->ddictPtrTable = newTable;138hashSet->ddictPtrTableSize = newTableSize;139hashSet->ddictPtrCount = 0;140for (i = 0; i < oldTableSize; ++i) {141if (oldTable[i] != NULL) {142FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, oldTable[i]), "");143}144}145ZSTD_customFree((void*)oldTable, customMem);146DEBUGLOG(4, "Finished re-hash");147return 0;148}149150/* Fetches a DDict with the given dictID151* Returns the ZSTD_DDict* with the requested dictID. If it doesn't exist, then returns NULL.152*/153static const ZSTD_DDict* ZSTD_DDictHashSet_getDDict(ZSTD_DDictHashSet* hashSet, U32 dictID) {154size_t idx = ZSTD_DDictHashSet_getIndex(hashSet, dictID);155const size_t idxRangeMask = hashSet->ddictPtrTableSize - 1;156DEBUGLOG(4, "Hashed index: for dictID: %u is %zu", dictID, idx);157for (;;) {158size_t currDictID = ZSTD_getDictID_fromDDict(hashSet->ddictPtrTable[idx]);159if (currDictID == dictID || currDictID == 0) {160/* currDictID == 0 implies a NULL ddict entry */161break;162} else {163idx &= idxRangeMask; /* Goes to start of table when we reach the end */164idx++;165}166}167DEBUGLOG(4, "Final idx after probing for dictID %u is: %zu", dictID, idx);168return hashSet->ddictPtrTable[idx];169}170171/* Allocates space for and returns a ddict hash set172* The hash set's ZSTD_DDict* table has all values automatically set to NULL to begin with.173* Returns NULL if allocation failed.174*/175static ZSTD_DDictHashSet* ZSTD_createDDictHashSet(ZSTD_customMem customMem) {176ZSTD_DDictHashSet* ret = (ZSTD_DDictHashSet*)ZSTD_customMalloc(sizeof(ZSTD_DDictHashSet), customMem);177DEBUGLOG(4, "Allocating new hash set");178if (!ret)179return NULL;180ret->ddictPtrTable = (const ZSTD_DDict**)ZSTD_customCalloc(DDICT_HASHSET_TABLE_BASE_SIZE * sizeof(ZSTD_DDict*), customMem);181if (!ret->ddictPtrTable) {182ZSTD_customFree(ret, customMem);183return NULL;184}185ret->ddictPtrTableSize = DDICT_HASHSET_TABLE_BASE_SIZE;186ret->ddictPtrCount = 0;187return ret;188}189190/* Frees the table of ZSTD_DDict* within a hashset, then frees the hashset itself.191* Note: The ZSTD_DDict* within the table are NOT freed.192*/193static void ZSTD_freeDDictHashSet(ZSTD_DDictHashSet* hashSet, ZSTD_customMem customMem) {194DEBUGLOG(4, "Freeing ddict hash set");195if (hashSet && hashSet->ddictPtrTable) {196ZSTD_customFree((void*)hashSet->ddictPtrTable, customMem);197}198if (hashSet) {199ZSTD_customFree(hashSet, customMem);200}201}202203/* Public function: Adds a DDict into the ZSTD_DDictHashSet, possibly triggering a resize of the hash set.204* Returns 0 on success, or a ZSTD error.205*/206static size_t ZSTD_DDictHashSet_addDDict(ZSTD_DDictHashSet* hashSet, const ZSTD_DDict* ddict, ZSTD_customMem customMem) {207DEBUGLOG(4, "Adding dict ID: %u to hashset with - Count: %zu Tablesize: %zu", ZSTD_getDictID_fromDDict(ddict), hashSet->ddictPtrCount, hashSet->ddictPtrTableSize);208if (hashSet->ddictPtrCount * DDICT_HASHSET_MAX_LOAD_FACTOR_COUNT_MULT / hashSet->ddictPtrTableSize * DDICT_HASHSET_MAX_LOAD_FACTOR_SIZE_MULT != 0) {209FORWARD_IF_ERROR(ZSTD_DDictHashSet_expand(hashSet, customMem), "");210}211FORWARD_IF_ERROR(ZSTD_DDictHashSet_emplaceDDict(hashSet, ddict), "");212return 0;213}214215/*-*************************************************************216* Context management217***************************************************************/218size_t ZSTD_sizeof_DCtx (const ZSTD_DCtx* dctx)219{220if (dctx==NULL) return 0; /* support sizeof NULL */221return sizeof(*dctx)222+ ZSTD_sizeof_DDict(dctx->ddictLocal)223+ dctx->inBuffSize + dctx->outBuffSize;224}225226size_t ZSTD_estimateDCtxSize(void) { return sizeof(ZSTD_DCtx); }227228229static size_t ZSTD_startingInputLength(ZSTD_format_e format)230{231size_t const startingInputLength = ZSTD_FRAMEHEADERSIZE_PREFIX(format);232/* only supports formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless */233assert( (format == ZSTD_f_zstd1) || (format == ZSTD_f_zstd1_magicless) );234return startingInputLength;235}236237static void ZSTD_DCtx_resetParameters(ZSTD_DCtx* dctx)238{239assert(dctx->streamStage == zdss_init);240dctx->format = ZSTD_f_zstd1;241dctx->maxWindowSize = ZSTD_MAXWINDOWSIZE_DEFAULT;242dctx->outBufferMode = ZSTD_bm_buffered;243dctx->forceIgnoreChecksum = ZSTD_d_validateChecksum;244dctx->refMultipleDDicts = ZSTD_rmd_refSingleDDict;245}246247static void ZSTD_initDCtx_internal(ZSTD_DCtx* dctx)248{249dctx->staticSize = 0;250dctx->ddict = NULL;251dctx->ddictLocal = NULL;252dctx->dictEnd = NULL;253dctx->ddictIsCold = 0;254dctx->dictUses = ZSTD_dont_use;255dctx->inBuff = NULL;256dctx->inBuffSize = 0;257dctx->outBuffSize = 0;258dctx->streamStage = zdss_init;259#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)260dctx->legacyContext = NULL;261dctx->previousLegacyVersion = 0;262#endif263dctx->noForwardProgress = 0;264dctx->oversizedDuration = 0;265#if DYNAMIC_BMI2266dctx->bmi2 = ZSTD_cpuSupportsBmi2();267#endif268dctx->ddictSet = NULL;269ZSTD_DCtx_resetParameters(dctx);270#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION271dctx->dictContentEndForFuzzing = NULL;272#endif273}274275ZSTD_DCtx* ZSTD_initStaticDCtx(void *workspace, size_t workspaceSize)276{277ZSTD_DCtx* const dctx = (ZSTD_DCtx*) workspace;278279if ((size_t)workspace & 7) return NULL; /* 8-aligned */280if (workspaceSize < sizeof(ZSTD_DCtx)) return NULL; /* minimum size */281282ZSTD_initDCtx_internal(dctx);283dctx->staticSize = workspaceSize;284dctx->inBuff = (char*)(dctx+1);285return dctx;286}287288static ZSTD_DCtx* ZSTD_createDCtx_internal(ZSTD_customMem customMem) {289if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;290291{ ZSTD_DCtx* const dctx = (ZSTD_DCtx*)ZSTD_customMalloc(sizeof(*dctx), customMem);292if (!dctx) return NULL;293dctx->customMem = customMem;294ZSTD_initDCtx_internal(dctx);295return dctx;296}297}298299ZSTD_DCtx* ZSTD_createDCtx_advanced(ZSTD_customMem customMem)300{301return ZSTD_createDCtx_internal(customMem);302}303304ZSTD_DCtx* ZSTD_createDCtx(void)305{306DEBUGLOG(3, "ZSTD_createDCtx");307return ZSTD_createDCtx_internal(ZSTD_defaultCMem);308}309310static void ZSTD_clearDict(ZSTD_DCtx* dctx)311{312ZSTD_freeDDict(dctx->ddictLocal);313dctx->ddictLocal = NULL;314dctx->ddict = NULL;315dctx->dictUses = ZSTD_dont_use;316}317318size_t ZSTD_freeDCtx(ZSTD_DCtx* dctx)319{320if (dctx==NULL) return 0; /* support free on NULL */321RETURN_ERROR_IF(dctx->staticSize, memory_allocation, "not compatible with static DCtx");322{ ZSTD_customMem const cMem = dctx->customMem;323ZSTD_clearDict(dctx);324ZSTD_customFree(dctx->inBuff, cMem);325dctx->inBuff = NULL;326#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)327if (dctx->legacyContext)328ZSTD_freeLegacyStreamContext(dctx->legacyContext, dctx->previousLegacyVersion);329#endif330if (dctx->ddictSet) {331ZSTD_freeDDictHashSet(dctx->ddictSet, cMem);332dctx->ddictSet = NULL;333}334ZSTD_customFree(dctx, cMem);335return 0;336}337}338339/* no longer useful */340void ZSTD_copyDCtx(ZSTD_DCtx* dstDCtx, const ZSTD_DCtx* srcDCtx)341{342size_t const toCopy = (size_t)((char*)(&dstDCtx->inBuff) - (char*)dstDCtx);343ZSTD_memcpy(dstDCtx, srcDCtx, toCopy); /* no need to copy workspace */344}345346/* Given a dctx with a digested frame params, re-selects the correct ZSTD_DDict based on347* the requested dict ID from the frame. If there exists a reference to the correct ZSTD_DDict, then348* accordingly sets the ddict to be used to decompress the frame.349*350* If no DDict is found, then no action is taken, and the ZSTD_DCtx::ddict remains as-is.351*352* ZSTD_d_refMultipleDDicts must be enabled for this function to be called.353*/354static void ZSTD_DCtx_selectFrameDDict(ZSTD_DCtx* dctx) {355assert(dctx->refMultipleDDicts && dctx->ddictSet);356DEBUGLOG(4, "Adjusting DDict based on requested dict ID from frame");357if (dctx->ddict) {358const ZSTD_DDict* frameDDict = ZSTD_DDictHashSet_getDDict(dctx->ddictSet, dctx->fParams.dictID);359if (frameDDict) {360DEBUGLOG(4, "DDict found!");361ZSTD_clearDict(dctx);362dctx->dictID = dctx->fParams.dictID;363dctx->ddict = frameDDict;364dctx->dictUses = ZSTD_use_indefinitely;365}366}367}368369370/*-*************************************************************371* Frame header decoding372***************************************************************/373374/*! ZSTD_isFrame() :375* Tells if the content of `buffer` starts with a valid Frame Identifier.376* Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.377* Note 2 : Legacy Frame Identifiers are considered valid only if Legacy Support is enabled.378* Note 3 : Skippable Frame Identifiers are considered valid. */379unsigned ZSTD_isFrame(const void* buffer, size_t size)380{381if (size < ZSTD_FRAMEIDSIZE) return 0;382{ U32 const magic = MEM_readLE32(buffer);383if (magic == ZSTD_MAGICNUMBER) return 1;384if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;385}386#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)387if (ZSTD_isLegacy(buffer, size)) return 1;388#endif389return 0;390}391392/*! ZSTD_isSkippableFrame() :393* Tells if the content of `buffer` starts with a valid Frame Identifier for a skippable frame.394* Note : Frame Identifier is 4 bytes. If `size < 4`, @return will always be 0.395*/396unsigned ZSTD_isSkippableFrame(const void* buffer, size_t size)397{398if (size < ZSTD_FRAMEIDSIZE) return 0;399{ U32 const magic = MEM_readLE32(buffer);400if ((magic & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) return 1;401}402return 0;403}404405/** ZSTD_frameHeaderSize_internal() :406* srcSize must be large enough to reach header size fields.407* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless.408* @return : size of the Frame Header409* or an error code, which can be tested with ZSTD_isError() */410static size_t ZSTD_frameHeaderSize_internal(const void* src, size_t srcSize, ZSTD_format_e format)411{412size_t const minInputSize = ZSTD_startingInputLength(format);413RETURN_ERROR_IF(srcSize < minInputSize, srcSize_wrong, "");414415{ BYTE const fhd = ((const BYTE*)src)[minInputSize-1];416U32 const dictID= fhd & 3;417U32 const singleSegment = (fhd >> 5) & 1;418U32 const fcsId = fhd >> 6;419return minInputSize + !singleSegment420+ ZSTD_did_fieldSize[dictID] + ZSTD_fcs_fieldSize[fcsId]421+ (singleSegment && !fcsId);422}423}424425/** ZSTD_frameHeaderSize() :426* srcSize must be >= ZSTD_frameHeaderSize_prefix.427* @return : size of the Frame Header,428* or an error code (if srcSize is too small) */429size_t ZSTD_frameHeaderSize(const void* src, size_t srcSize)430{431return ZSTD_frameHeaderSize_internal(src, srcSize, ZSTD_f_zstd1);432}433434435/** ZSTD_getFrameHeader_advanced() :436* decode Frame Header, or require larger `srcSize`.437* note : only works for formats ZSTD_f_zstd1 and ZSTD_f_zstd1_magicless438* @return : 0, `zfhPtr` is correctly filled,439* >0, `srcSize` is too small, value is wanted `srcSize` amount,440* or an error code, which can be tested using ZSTD_isError() */441size_t ZSTD_getFrameHeader_advanced(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize, ZSTD_format_e format)442{443const BYTE* ip = (const BYTE*)src;444size_t const minInputSize = ZSTD_startingInputLength(format);445446ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr)); /* not strictly necessary, but static analyzer do not understand that zfhPtr is only going to be read only if return value is zero, since they are 2 different signals */447if (srcSize < minInputSize) return minInputSize;448RETURN_ERROR_IF(src==NULL, GENERIC, "invalid parameter");449450if ( (format != ZSTD_f_zstd1_magicless)451&& (MEM_readLE32(src) != ZSTD_MAGICNUMBER) ) {452if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {453/* skippable frame */454if (srcSize < ZSTD_SKIPPABLEHEADERSIZE)455return ZSTD_SKIPPABLEHEADERSIZE; /* magic number + frame length */456ZSTD_memset(zfhPtr, 0, sizeof(*zfhPtr));457zfhPtr->frameContentSize = MEM_readLE32((const char *)src + ZSTD_FRAMEIDSIZE);458zfhPtr->frameType = ZSTD_skippableFrame;459return 0;460}461RETURN_ERROR(prefix_unknown, "");462}463464/* ensure there is enough `srcSize` to fully read/decode frame header */465{ size_t const fhsize = ZSTD_frameHeaderSize_internal(src, srcSize, format);466if (srcSize < fhsize) return fhsize;467zfhPtr->headerSize = (U32)fhsize;468}469470{ BYTE const fhdByte = ip[minInputSize-1];471size_t pos = minInputSize;472U32 const dictIDSizeCode = fhdByte&3;473U32 const checksumFlag = (fhdByte>>2)&1;474U32 const singleSegment = (fhdByte>>5)&1;475U32 const fcsID = fhdByte>>6;476U64 windowSize = 0;477U32 dictID = 0;478U64 frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN;479RETURN_ERROR_IF((fhdByte & 0x08) != 0, frameParameter_unsupported,480"reserved bits, must be zero");481482if (!singleSegment) {483BYTE const wlByte = ip[pos++];484U32 const windowLog = (wlByte >> 3) + ZSTD_WINDOWLOG_ABSOLUTEMIN;485RETURN_ERROR_IF(windowLog > ZSTD_WINDOWLOG_MAX, frameParameter_windowTooLarge, "");486windowSize = (1ULL << windowLog);487windowSize += (windowSize >> 3) * (wlByte&7);488}489switch(dictIDSizeCode)490{491default:492assert(0); /* impossible */493ZSTD_FALLTHROUGH;494case 0 : break;495case 1 : dictID = ip[pos]; pos++; break;496case 2 : dictID = MEM_readLE16(ip+pos); pos+=2; break;497case 3 : dictID = MEM_readLE32(ip+pos); pos+=4; break;498}499switch(fcsID)500{501default:502assert(0); /* impossible */503ZSTD_FALLTHROUGH;504case 0 : if (singleSegment) frameContentSize = ip[pos]; break;505case 1 : frameContentSize = MEM_readLE16(ip+pos)+256; break;506case 2 : frameContentSize = MEM_readLE32(ip+pos); break;507case 3 : frameContentSize = MEM_readLE64(ip+pos); break;508}509if (singleSegment) windowSize = frameContentSize;510511zfhPtr->frameType = ZSTD_frame;512zfhPtr->frameContentSize = frameContentSize;513zfhPtr->windowSize = windowSize;514zfhPtr->blockSizeMax = (unsigned) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);515zfhPtr->dictID = dictID;516zfhPtr->checksumFlag = checksumFlag;517}518return 0;519}520521/** ZSTD_getFrameHeader() :522* decode Frame Header, or require larger `srcSize`.523* note : this function does not consume input, it only reads it.524* @return : 0, `zfhPtr` is correctly filled,525* >0, `srcSize` is too small, value is wanted `srcSize` amount,526* or an error code, which can be tested using ZSTD_isError() */527size_t ZSTD_getFrameHeader(ZSTD_frameHeader* zfhPtr, const void* src, size_t srcSize)528{529return ZSTD_getFrameHeader_advanced(zfhPtr, src, srcSize, ZSTD_f_zstd1);530}531532/** ZSTD_getFrameContentSize() :533* compatible with legacy mode534* @return : decompressed size of the single frame pointed to be `src` if known, otherwise535* - ZSTD_CONTENTSIZE_UNKNOWN if the size cannot be determined536* - ZSTD_CONTENTSIZE_ERROR if an error occurred (e.g. invalid magic number, srcSize too small) */537unsigned long long ZSTD_getFrameContentSize(const void *src, size_t srcSize)538{539#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)540if (ZSTD_isLegacy(src, srcSize)) {541unsigned long long const ret = ZSTD_getDecompressedSize_legacy(src, srcSize);542return ret == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : ret;543}544#endif545{ ZSTD_frameHeader zfh;546if (ZSTD_getFrameHeader(&zfh, src, srcSize) != 0)547return ZSTD_CONTENTSIZE_ERROR;548if (zfh.frameType == ZSTD_skippableFrame) {549return 0;550} else {551return zfh.frameContentSize;552} }553}554555static size_t readSkippableFrameSize(void const* src, size_t srcSize)556{557size_t const skippableHeaderSize = ZSTD_SKIPPABLEHEADERSIZE;558U32 sizeU32;559560RETURN_ERROR_IF(srcSize < ZSTD_SKIPPABLEHEADERSIZE, srcSize_wrong, "");561562sizeU32 = MEM_readLE32((BYTE const*)src + ZSTD_FRAMEIDSIZE);563RETURN_ERROR_IF((U32)(sizeU32 + ZSTD_SKIPPABLEHEADERSIZE) < sizeU32,564frameParameter_unsupported, "");565{566size_t const skippableSize = skippableHeaderSize + sizeU32;567RETURN_ERROR_IF(skippableSize > srcSize, srcSize_wrong, "");568return skippableSize;569}570}571572/*! ZSTD_readSkippableFrame() :573* Retrieves a zstd skippable frame containing data given by src, and writes it to dst buffer.574*575* The parameter magicVariant will receive the magicVariant that was supplied when the frame was written,576* i.e. magicNumber - ZSTD_MAGIC_SKIPPABLE_START. This can be NULL if the caller is not interested577* in the magicVariant.578*579* Returns an error if destination buffer is not large enough, or if the frame is not skippable.580*581* @return : number of bytes written or a ZSTD error.582*/583ZSTDLIB_API size_t ZSTD_readSkippableFrame(void* dst, size_t dstCapacity, unsigned* magicVariant,584const void* src, size_t srcSize)585{586U32 const magicNumber = MEM_readLE32(src);587size_t skippableFrameSize = readSkippableFrameSize(src, srcSize);588size_t skippableContentSize = skippableFrameSize - ZSTD_SKIPPABLEHEADERSIZE;589590/* check input validity */591RETURN_ERROR_IF(!ZSTD_isSkippableFrame(src, srcSize), frameParameter_unsupported, "");592RETURN_ERROR_IF(skippableFrameSize < ZSTD_SKIPPABLEHEADERSIZE || skippableFrameSize > srcSize, srcSize_wrong, "");593RETURN_ERROR_IF(skippableContentSize > dstCapacity, dstSize_tooSmall, "");594595/* deliver payload */596if (skippableContentSize > 0 && dst != NULL)597ZSTD_memcpy(dst, (const BYTE *)src + ZSTD_SKIPPABLEHEADERSIZE, skippableContentSize);598if (magicVariant != NULL)599*magicVariant = magicNumber - ZSTD_MAGIC_SKIPPABLE_START;600return skippableContentSize;601}602603/** ZSTD_findDecompressedSize() :604* compatible with legacy mode605* `srcSize` must be the exact length of some number of ZSTD compressed and/or606* skippable frames607* @return : decompressed size of the frames contained */608unsigned long long ZSTD_findDecompressedSize(const void* src, size_t srcSize)609{610unsigned long long totalDstSize = 0;611612while (srcSize >= ZSTD_startingInputLength(ZSTD_f_zstd1)) {613U32 const magicNumber = MEM_readLE32(src);614615if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {616size_t const skippableSize = readSkippableFrameSize(src, srcSize);617if (ZSTD_isError(skippableSize)) {618return ZSTD_CONTENTSIZE_ERROR;619}620assert(skippableSize <= srcSize);621622src = (const BYTE *)src + skippableSize;623srcSize -= skippableSize;624continue;625}626627{ unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);628if (ret >= ZSTD_CONTENTSIZE_ERROR) return ret;629630/* check for overflow */631if (totalDstSize + ret < totalDstSize) return ZSTD_CONTENTSIZE_ERROR;632totalDstSize += ret;633}634{ size_t const frameSrcSize = ZSTD_findFrameCompressedSize(src, srcSize);635if (ZSTD_isError(frameSrcSize)) {636return ZSTD_CONTENTSIZE_ERROR;637}638639src = (const BYTE *)src + frameSrcSize;640srcSize -= frameSrcSize;641}642} /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */643644if (srcSize) return ZSTD_CONTENTSIZE_ERROR;645646return totalDstSize;647}648649/** ZSTD_getDecompressedSize() :650* compatible with legacy mode651* @return : decompressed size if known, 0 otherwise652note : 0 can mean any of the following :653- frame content is empty654- decompressed size field is not present in frame header655- frame header unknown / not supported656- frame header not complete (`srcSize` too small) */657unsigned long long ZSTD_getDecompressedSize(const void* src, size_t srcSize)658{659unsigned long long const ret = ZSTD_getFrameContentSize(src, srcSize);660ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_ERROR < ZSTD_CONTENTSIZE_UNKNOWN);661return (ret >= ZSTD_CONTENTSIZE_ERROR) ? 0 : ret;662}663664665/** ZSTD_decodeFrameHeader() :666* `headerSize` must be the size provided by ZSTD_frameHeaderSize().667* If multiple DDict references are enabled, also will choose the correct DDict to use.668* @return : 0 if success, or an error code, which can be tested using ZSTD_isError() */669static size_t ZSTD_decodeFrameHeader(ZSTD_DCtx* dctx, const void* src, size_t headerSize)670{671size_t const result = ZSTD_getFrameHeader_advanced(&(dctx->fParams), src, headerSize, dctx->format);672if (ZSTD_isError(result)) return result; /* invalid header */673RETURN_ERROR_IF(result>0, srcSize_wrong, "headerSize too small");674675/* Reference DDict requested by frame if dctx references multiple ddicts */676if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts && dctx->ddictSet) {677ZSTD_DCtx_selectFrameDDict(dctx);678}679680#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION681/* Skip the dictID check in fuzzing mode, because it makes the search682* harder.683*/684RETURN_ERROR_IF(dctx->fParams.dictID && (dctx->dictID != dctx->fParams.dictID),685dictionary_wrong, "");686#endif687dctx->validateChecksum = (dctx->fParams.checksumFlag && !dctx->forceIgnoreChecksum) ? 1 : 0;688if (dctx->validateChecksum) XXH64_reset(&dctx->xxhState, 0);689dctx->processedCSize += headerSize;690return 0;691}692693static ZSTD_frameSizeInfo ZSTD_errorFrameSizeInfo(size_t ret)694{695ZSTD_frameSizeInfo frameSizeInfo;696frameSizeInfo.compressedSize = ret;697frameSizeInfo.decompressedBound = ZSTD_CONTENTSIZE_ERROR;698return frameSizeInfo;699}700701static ZSTD_frameSizeInfo ZSTD_findFrameSizeInfo(const void* src, size_t srcSize)702{703ZSTD_frameSizeInfo frameSizeInfo;704ZSTD_memset(&frameSizeInfo, 0, sizeof(ZSTD_frameSizeInfo));705706#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)707if (ZSTD_isLegacy(src, srcSize))708return ZSTD_findFrameSizeInfoLegacy(src, srcSize);709#endif710711if ((srcSize >= ZSTD_SKIPPABLEHEADERSIZE)712&& (MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {713frameSizeInfo.compressedSize = readSkippableFrameSize(src, srcSize);714assert(ZSTD_isError(frameSizeInfo.compressedSize) ||715frameSizeInfo.compressedSize <= srcSize);716return frameSizeInfo;717} else {718const BYTE* ip = (const BYTE*)src;719const BYTE* const ipstart = ip;720size_t remainingSize = srcSize;721size_t nbBlocks = 0;722ZSTD_frameHeader zfh;723724/* Extract Frame Header */725{ size_t const ret = ZSTD_getFrameHeader(&zfh, src, srcSize);726if (ZSTD_isError(ret))727return ZSTD_errorFrameSizeInfo(ret);728if (ret > 0)729return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));730}731732ip += zfh.headerSize;733remainingSize -= zfh.headerSize;734735/* Iterate over each block */736while (1) {737blockProperties_t blockProperties;738size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSize, &blockProperties);739if (ZSTD_isError(cBlockSize))740return ZSTD_errorFrameSizeInfo(cBlockSize);741742if (ZSTD_blockHeaderSize + cBlockSize > remainingSize)743return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));744745ip += ZSTD_blockHeaderSize + cBlockSize;746remainingSize -= ZSTD_blockHeaderSize + cBlockSize;747nbBlocks++;748749if (blockProperties.lastBlock) break;750}751752/* Final frame content checksum */753if (zfh.checksumFlag) {754if (remainingSize < 4)755return ZSTD_errorFrameSizeInfo(ERROR(srcSize_wrong));756ip += 4;757}758759frameSizeInfo.compressedSize = (size_t)(ip - ipstart);760frameSizeInfo.decompressedBound = (zfh.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN)761? zfh.frameContentSize762: nbBlocks * zfh.blockSizeMax;763return frameSizeInfo;764}765}766767/** ZSTD_findFrameCompressedSize() :768* compatible with legacy mode769* `src` must point to the start of a ZSTD frame, ZSTD legacy frame, or skippable frame770* `srcSize` must be at least as large as the frame contained771* @return : the compressed size of the frame starting at `src` */772size_t ZSTD_findFrameCompressedSize(const void *src, size_t srcSize)773{774ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);775return frameSizeInfo.compressedSize;776}777778/** ZSTD_decompressBound() :779* compatible with legacy mode780* `src` must point to the start of a ZSTD frame or a skippeable frame781* `srcSize` must be at least as large as the frame contained782* @return : the maximum decompressed size of the compressed source783*/784unsigned long long ZSTD_decompressBound(const void* src, size_t srcSize)785{786unsigned long long bound = 0;787/* Iterate over each frame */788while (srcSize > 0) {789ZSTD_frameSizeInfo const frameSizeInfo = ZSTD_findFrameSizeInfo(src, srcSize);790size_t const compressedSize = frameSizeInfo.compressedSize;791unsigned long long const decompressedBound = frameSizeInfo.decompressedBound;792if (ZSTD_isError(compressedSize) || decompressedBound == ZSTD_CONTENTSIZE_ERROR)793return ZSTD_CONTENTSIZE_ERROR;794assert(srcSize >= compressedSize);795src = (const BYTE*)src + compressedSize;796srcSize -= compressedSize;797bound += decompressedBound;798}799return bound;800}801802803/*-*************************************************************804* Frame decoding805***************************************************************/806807/** ZSTD_insertBlock() :808* insert `src` block into `dctx` history. Useful to track uncompressed blocks. */809size_t ZSTD_insertBlock(ZSTD_DCtx* dctx, const void* blockStart, size_t blockSize)810{811DEBUGLOG(5, "ZSTD_insertBlock: %u bytes", (unsigned)blockSize);812ZSTD_checkContinuity(dctx, blockStart, blockSize);813dctx->previousDstEnd = (const char*)blockStart + blockSize;814return blockSize;815}816817818static size_t ZSTD_copyRawBlock(void* dst, size_t dstCapacity,819const void* src, size_t srcSize)820{821DEBUGLOG(5, "ZSTD_copyRawBlock");822RETURN_ERROR_IF(srcSize > dstCapacity, dstSize_tooSmall, "");823if (dst == NULL) {824if (srcSize == 0) return 0;825RETURN_ERROR(dstBuffer_null, "");826}827ZSTD_memcpy(dst, src, srcSize);828return srcSize;829}830831static size_t ZSTD_setRleBlock(void* dst, size_t dstCapacity,832BYTE b,833size_t regenSize)834{835RETURN_ERROR_IF(regenSize > dstCapacity, dstSize_tooSmall, "");836if (dst == NULL) {837if (regenSize == 0) return 0;838RETURN_ERROR(dstBuffer_null, "");839}840ZSTD_memset(dst, b, regenSize);841return regenSize;842}843844static void ZSTD_DCtx_trace_end(ZSTD_DCtx const* dctx, U64 uncompressedSize, U64 compressedSize, unsigned streaming)845{846#if ZSTD_TRACE847if (dctx->traceCtx && ZSTD_trace_decompress_end != NULL) {848ZSTD_Trace trace;849ZSTD_memset(&trace, 0, sizeof(trace));850trace.version = ZSTD_VERSION_NUMBER;851trace.streaming = streaming;852if (dctx->ddict) {853trace.dictionaryID = ZSTD_getDictID_fromDDict(dctx->ddict);854trace.dictionarySize = ZSTD_DDict_dictSize(dctx->ddict);855trace.dictionaryIsCold = dctx->ddictIsCold;856}857trace.uncompressedSize = (size_t)uncompressedSize;858trace.compressedSize = (size_t)compressedSize;859trace.dctx = dctx;860ZSTD_trace_decompress_end(dctx->traceCtx, &trace);861}862#else863(void)dctx;864(void)uncompressedSize;865(void)compressedSize;866(void)streaming;867#endif868}869870871/*! ZSTD_decompressFrame() :872* @dctx must be properly initialized873* will update *srcPtr and *srcSizePtr,874* to make *srcPtr progress by one frame. */875static size_t ZSTD_decompressFrame(ZSTD_DCtx* dctx,876void* dst, size_t dstCapacity,877const void** srcPtr, size_t *srcSizePtr)878{879const BYTE* const istart = (const BYTE*)(*srcPtr);880const BYTE* ip = istart;881BYTE* const ostart = (BYTE*)dst;882BYTE* const oend = dstCapacity != 0 ? ostart + dstCapacity : ostart;883BYTE* op = ostart;884size_t remainingSrcSize = *srcSizePtr;885886DEBUGLOG(4, "ZSTD_decompressFrame (srcSize:%i)", (int)*srcSizePtr);887888/* check */889RETURN_ERROR_IF(890remainingSrcSize < ZSTD_FRAMEHEADERSIZE_MIN(dctx->format)+ZSTD_blockHeaderSize,891srcSize_wrong, "");892893/* Frame Header */894{ size_t const frameHeaderSize = ZSTD_frameHeaderSize_internal(895ip, ZSTD_FRAMEHEADERSIZE_PREFIX(dctx->format), dctx->format);896if (ZSTD_isError(frameHeaderSize)) return frameHeaderSize;897RETURN_ERROR_IF(remainingSrcSize < frameHeaderSize+ZSTD_blockHeaderSize,898srcSize_wrong, "");899FORWARD_IF_ERROR( ZSTD_decodeFrameHeader(dctx, ip, frameHeaderSize) , "");900ip += frameHeaderSize; remainingSrcSize -= frameHeaderSize;901}902903/* Loop on each block */904while (1) {905size_t decodedSize;906blockProperties_t blockProperties;907size_t const cBlockSize = ZSTD_getcBlockSize(ip, remainingSrcSize, &blockProperties);908if (ZSTD_isError(cBlockSize)) return cBlockSize;909910ip += ZSTD_blockHeaderSize;911remainingSrcSize -= ZSTD_blockHeaderSize;912RETURN_ERROR_IF(cBlockSize > remainingSrcSize, srcSize_wrong, "");913914switch(blockProperties.blockType)915{916case bt_compressed:917decodedSize = ZSTD_decompressBlock_internal(dctx, op, (size_t)(oend-op), ip, cBlockSize, /* frame */ 1, not_streaming);918break;919case bt_raw :920decodedSize = ZSTD_copyRawBlock(op, (size_t)(oend-op), ip, cBlockSize);921break;922case bt_rle :923decodedSize = ZSTD_setRleBlock(op, (size_t)(oend-op), *ip, blockProperties.origSize);924break;925case bt_reserved :926default:927RETURN_ERROR(corruption_detected, "invalid block type");928}929930if (ZSTD_isError(decodedSize)) return decodedSize;931if (dctx->validateChecksum)932XXH64_update(&dctx->xxhState, op, decodedSize);933if (decodedSize != 0)934op += decodedSize;935assert(ip != NULL);936ip += cBlockSize;937remainingSrcSize -= cBlockSize;938if (blockProperties.lastBlock) break;939}940941if (dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN) {942RETURN_ERROR_IF((U64)(op-ostart) != dctx->fParams.frameContentSize,943corruption_detected, "");944}945if (dctx->fParams.checksumFlag) { /* Frame content checksum verification */946RETURN_ERROR_IF(remainingSrcSize<4, checksum_wrong, "");947if (!dctx->forceIgnoreChecksum) {948U32 const checkCalc = (U32)XXH64_digest(&dctx->xxhState);949U32 checkRead;950checkRead = MEM_readLE32(ip);951RETURN_ERROR_IF(checkRead != checkCalc, checksum_wrong, "");952}953ip += 4;954remainingSrcSize -= 4;955}956ZSTD_DCtx_trace_end(dctx, (U64)(op-ostart), (U64)(ip-istart), /* streaming */ 0);957/* Allow caller to get size read */958*srcPtr = ip;959*srcSizePtr = remainingSrcSize;960return (size_t)(op-ostart);961}962963static size_t ZSTD_decompressMultiFrame(ZSTD_DCtx* dctx,964void* dst, size_t dstCapacity,965const void* src, size_t srcSize,966const void* dict, size_t dictSize,967const ZSTD_DDict* ddict)968{969void* const dststart = dst;970int moreThan1Frame = 0;971972DEBUGLOG(5, "ZSTD_decompressMultiFrame");973assert(dict==NULL || ddict==NULL); /* either dict or ddict set, not both */974975if (ddict) {976dict = ZSTD_DDict_dictContent(ddict);977dictSize = ZSTD_DDict_dictSize(ddict);978}979980while (srcSize >= ZSTD_startingInputLength(dctx->format)) {981982#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT >= 1)983if (ZSTD_isLegacy(src, srcSize)) {984size_t decodedSize;985size_t const frameSize = ZSTD_findFrameCompressedSizeLegacy(src, srcSize);986if (ZSTD_isError(frameSize)) return frameSize;987RETURN_ERROR_IF(dctx->staticSize, memory_allocation,988"legacy support is not compatible with static dctx");989990decodedSize = ZSTD_decompressLegacy(dst, dstCapacity, src, frameSize, dict, dictSize);991if (ZSTD_isError(decodedSize)) return decodedSize;992993assert(decodedSize <= dstCapacity);994dst = (BYTE*)dst + decodedSize;995dstCapacity -= decodedSize;996997src = (const BYTE*)src + frameSize;998srcSize -= frameSize;9991000continue;1001}1002#endif10031004{ U32 const magicNumber = MEM_readLE32(src);1005DEBUGLOG(4, "reading magic number %08X (expecting %08X)",1006(unsigned)magicNumber, ZSTD_MAGICNUMBER);1007if ((magicNumber & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) {1008size_t const skippableSize = readSkippableFrameSize(src, srcSize);1009FORWARD_IF_ERROR(skippableSize, "readSkippableFrameSize failed");1010assert(skippableSize <= srcSize);10111012src = (const BYTE *)src + skippableSize;1013srcSize -= skippableSize;1014continue;1015} }10161017if (ddict) {1018/* we were called from ZSTD_decompress_usingDDict */1019FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(dctx, ddict), "");1020} else {1021/* this will initialize correctly with no dict if dict == NULL, so1022* use this in all cases but ddict */1023FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDict(dctx, dict, dictSize), "");1024}1025ZSTD_checkContinuity(dctx, dst, dstCapacity);10261027{ const size_t res = ZSTD_decompressFrame(dctx, dst, dstCapacity,1028&src, &srcSize);1029RETURN_ERROR_IF(1030(ZSTD_getErrorCode(res) == ZSTD_error_prefix_unknown)1031&& (moreThan1Frame==1),1032srcSize_wrong,1033"At least one frame successfully completed, "1034"but following bytes are garbage: "1035"it's more likely to be a srcSize error, "1036"specifying more input bytes than size of frame(s). "1037"Note: one could be unlucky, it might be a corruption error instead, "1038"happening right at the place where we expect zstd magic bytes. "1039"But this is _much_ less likely than a srcSize field error.");1040if (ZSTD_isError(res)) return res;1041assert(res <= dstCapacity);1042if (res != 0)1043dst = (BYTE*)dst + res;1044dstCapacity -= res;1045}1046moreThan1Frame = 1;1047} /* while (srcSize >= ZSTD_frameHeaderSize_prefix) */10481049RETURN_ERROR_IF(srcSize, srcSize_wrong, "input not entirely consumed");10501051return (size_t)((BYTE*)dst - (BYTE*)dststart);1052}10531054size_t ZSTD_decompress_usingDict(ZSTD_DCtx* dctx,1055void* dst, size_t dstCapacity,1056const void* src, size_t srcSize,1057const void* dict, size_t dictSize)1058{1059return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize, dict, dictSize, NULL);1060}106110621063static ZSTD_DDict const* ZSTD_getDDict(ZSTD_DCtx* dctx)1064{1065switch (dctx->dictUses) {1066default:1067assert(0 /* Impossible */);1068ZSTD_FALLTHROUGH;1069case ZSTD_dont_use:1070ZSTD_clearDict(dctx);1071return NULL;1072case ZSTD_use_indefinitely:1073return dctx->ddict;1074case ZSTD_use_once:1075dctx->dictUses = ZSTD_dont_use;1076return dctx->ddict;1077}1078}10791080size_t ZSTD_decompressDCtx(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)1081{1082return ZSTD_decompress_usingDDict(dctx, dst, dstCapacity, src, srcSize, ZSTD_getDDict(dctx));1083}108410851086size_t ZSTD_decompress(void* dst, size_t dstCapacity, const void* src, size_t srcSize)1087{1088#if defined(ZSTD_HEAPMODE) && (ZSTD_HEAPMODE>=1)1089size_t regenSize;1090ZSTD_DCtx* const dctx = ZSTD_createDCtx_internal(ZSTD_defaultCMem);1091RETURN_ERROR_IF(dctx==NULL, memory_allocation, "NULL pointer!");1092regenSize = ZSTD_decompressDCtx(dctx, dst, dstCapacity, src, srcSize);1093ZSTD_freeDCtx(dctx);1094return regenSize;1095#else /* stack mode */1096ZSTD_DCtx dctx;1097ZSTD_initDCtx_internal(&dctx);1098return ZSTD_decompressDCtx(&dctx, dst, dstCapacity, src, srcSize);1099#endif1100}110111021103/*-**************************************1104* Advanced Streaming Decompression API1105* Bufferless and synchronous1106****************************************/1107size_t ZSTD_nextSrcSizeToDecompress(ZSTD_DCtx* dctx) { return dctx->expected; }11081109/**1110* Similar to ZSTD_nextSrcSizeToDecompress(), but when when a block input can be streamed,1111* we allow taking a partial block as the input. Currently only raw uncompressed blocks can1112* be streamed.1113*1114* For blocks that can be streamed, this allows us to reduce the latency until we produce1115* output, and avoid copying the input.1116*1117* @param inputSize - The total amount of input that the caller currently has.1118*/1119static size_t ZSTD_nextSrcSizeToDecompressWithInputSize(ZSTD_DCtx* dctx, size_t inputSize) {1120if (!(dctx->stage == ZSTDds_decompressBlock || dctx->stage == ZSTDds_decompressLastBlock))1121return dctx->expected;1122if (dctx->bType != bt_raw)1123return dctx->expected;1124return BOUNDED(1, inputSize, dctx->expected);1125}11261127ZSTD_nextInputType_e ZSTD_nextInputType(ZSTD_DCtx* dctx) {1128switch(dctx->stage)1129{1130default: /* should not happen */1131assert(0);1132ZSTD_FALLTHROUGH;1133case ZSTDds_getFrameHeaderSize:1134ZSTD_FALLTHROUGH;1135case ZSTDds_decodeFrameHeader:1136return ZSTDnit_frameHeader;1137case ZSTDds_decodeBlockHeader:1138return ZSTDnit_blockHeader;1139case ZSTDds_decompressBlock:1140return ZSTDnit_block;1141case ZSTDds_decompressLastBlock:1142return ZSTDnit_lastBlock;1143case ZSTDds_checkChecksum:1144return ZSTDnit_checksum;1145case ZSTDds_decodeSkippableHeader:1146ZSTD_FALLTHROUGH;1147case ZSTDds_skipFrame:1148return ZSTDnit_skippableFrame;1149}1150}11511152static int ZSTD_isSkipFrame(ZSTD_DCtx* dctx) { return dctx->stage == ZSTDds_skipFrame; }11531154/** ZSTD_decompressContinue() :1155* srcSize : must be the exact nb of bytes expected (see ZSTD_nextSrcSizeToDecompress())1156* @return : nb of bytes generated into `dst` (necessarily <= `dstCapacity)1157* or an error code, which can be tested using ZSTD_isError() */1158size_t ZSTD_decompressContinue(ZSTD_DCtx* dctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)1159{1160DEBUGLOG(5, "ZSTD_decompressContinue (srcSize:%u)", (unsigned)srcSize);1161/* Sanity check */1162RETURN_ERROR_IF(srcSize != ZSTD_nextSrcSizeToDecompressWithInputSize(dctx, srcSize), srcSize_wrong, "not allowed");1163ZSTD_checkContinuity(dctx, dst, dstCapacity);11641165dctx->processedCSize += srcSize;11661167switch (dctx->stage)1168{1169case ZSTDds_getFrameHeaderSize :1170assert(src != NULL);1171if (dctx->format == ZSTD_f_zstd1) { /* allows header */1172assert(srcSize >= ZSTD_FRAMEIDSIZE); /* to read skippable magic number */1173if ((MEM_readLE32(src) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */1174ZSTD_memcpy(dctx->headerBuffer, src, srcSize);1175dctx->expected = ZSTD_SKIPPABLEHEADERSIZE - srcSize; /* remaining to load to get full skippable frame header */1176dctx->stage = ZSTDds_decodeSkippableHeader;1177return 0;1178} }1179dctx->headerSize = ZSTD_frameHeaderSize_internal(src, srcSize, dctx->format);1180if (ZSTD_isError(dctx->headerSize)) return dctx->headerSize;1181ZSTD_memcpy(dctx->headerBuffer, src, srcSize);1182dctx->expected = dctx->headerSize - srcSize;1183dctx->stage = ZSTDds_decodeFrameHeader;1184return 0;11851186case ZSTDds_decodeFrameHeader:1187assert(src != NULL);1188ZSTD_memcpy(dctx->headerBuffer + (dctx->headerSize - srcSize), src, srcSize);1189FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(dctx, dctx->headerBuffer, dctx->headerSize), "");1190dctx->expected = ZSTD_blockHeaderSize;1191dctx->stage = ZSTDds_decodeBlockHeader;1192return 0;11931194case ZSTDds_decodeBlockHeader:1195{ blockProperties_t bp;1196size_t const cBlockSize = ZSTD_getcBlockSize(src, ZSTD_blockHeaderSize, &bp);1197if (ZSTD_isError(cBlockSize)) return cBlockSize;1198RETURN_ERROR_IF(cBlockSize > dctx->fParams.blockSizeMax, corruption_detected, "Block Size Exceeds Maximum");1199dctx->expected = cBlockSize;1200dctx->bType = bp.blockType;1201dctx->rleSize = bp.origSize;1202if (cBlockSize) {1203dctx->stage = bp.lastBlock ? ZSTDds_decompressLastBlock : ZSTDds_decompressBlock;1204return 0;1205}1206/* empty block */1207if (bp.lastBlock) {1208if (dctx->fParams.checksumFlag) {1209dctx->expected = 4;1210dctx->stage = ZSTDds_checkChecksum;1211} else {1212dctx->expected = 0; /* end of frame */1213dctx->stage = ZSTDds_getFrameHeaderSize;1214}1215} else {1216dctx->expected = ZSTD_blockHeaderSize; /* jump to next header */1217dctx->stage = ZSTDds_decodeBlockHeader;1218}1219return 0;1220}12211222case ZSTDds_decompressLastBlock:1223case ZSTDds_decompressBlock:1224DEBUGLOG(5, "ZSTD_decompressContinue: case ZSTDds_decompressBlock");1225{ size_t rSize;1226switch(dctx->bType)1227{1228case bt_compressed:1229DEBUGLOG(5, "ZSTD_decompressContinue: case bt_compressed");1230rSize = ZSTD_decompressBlock_internal(dctx, dst, dstCapacity, src, srcSize, /* frame */ 1, is_streaming);1231dctx->expected = 0; /* Streaming not supported */1232break;1233case bt_raw :1234assert(srcSize <= dctx->expected);1235rSize = ZSTD_copyRawBlock(dst, dstCapacity, src, srcSize);1236FORWARD_IF_ERROR(rSize, "ZSTD_copyRawBlock failed");1237assert(rSize == srcSize);1238dctx->expected -= rSize;1239break;1240case bt_rle :1241rSize = ZSTD_setRleBlock(dst, dstCapacity, *(const BYTE*)src, dctx->rleSize);1242dctx->expected = 0; /* Streaming not supported */1243break;1244case bt_reserved : /* should never happen */1245default:1246RETURN_ERROR(corruption_detected, "invalid block type");1247}1248FORWARD_IF_ERROR(rSize, "");1249RETURN_ERROR_IF(rSize > dctx->fParams.blockSizeMax, corruption_detected, "Decompressed Block Size Exceeds Maximum");1250DEBUGLOG(5, "ZSTD_decompressContinue: decoded size from block : %u", (unsigned)rSize);1251dctx->decodedSize += rSize;1252if (dctx->validateChecksum) XXH64_update(&dctx->xxhState, dst, rSize);1253dctx->previousDstEnd = (char*)dst + rSize;12541255/* Stay on the same stage until we are finished streaming the block. */1256if (dctx->expected > 0) {1257return rSize;1258}12591260if (dctx->stage == ZSTDds_decompressLastBlock) { /* end of frame */1261DEBUGLOG(4, "ZSTD_decompressContinue: decoded size from frame : %u", (unsigned)dctx->decodedSize);1262RETURN_ERROR_IF(1263dctx->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN1264&& dctx->decodedSize != dctx->fParams.frameContentSize,1265corruption_detected, "");1266if (dctx->fParams.checksumFlag) { /* another round for frame checksum */1267dctx->expected = 4;1268dctx->stage = ZSTDds_checkChecksum;1269} else {1270ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);1271dctx->expected = 0; /* ends here */1272dctx->stage = ZSTDds_getFrameHeaderSize;1273}1274} else {1275dctx->stage = ZSTDds_decodeBlockHeader;1276dctx->expected = ZSTD_blockHeaderSize;1277}1278return rSize;1279}12801281case ZSTDds_checkChecksum:1282assert(srcSize == 4); /* guaranteed by dctx->expected */1283{1284if (dctx->validateChecksum) {1285U32 const h32 = (U32)XXH64_digest(&dctx->xxhState);1286U32 const check32 = MEM_readLE32(src);1287DEBUGLOG(4, "ZSTD_decompressContinue: checksum : calculated %08X :: %08X read", (unsigned)h32, (unsigned)check32);1288RETURN_ERROR_IF(check32 != h32, checksum_wrong, "");1289}1290ZSTD_DCtx_trace_end(dctx, dctx->decodedSize, dctx->processedCSize, /* streaming */ 1);1291dctx->expected = 0;1292dctx->stage = ZSTDds_getFrameHeaderSize;1293return 0;1294}12951296case ZSTDds_decodeSkippableHeader:1297assert(src != NULL);1298assert(srcSize <= ZSTD_SKIPPABLEHEADERSIZE);1299ZSTD_memcpy(dctx->headerBuffer + (ZSTD_SKIPPABLEHEADERSIZE - srcSize), src, srcSize); /* complete skippable header */1300dctx->expected = MEM_readLE32(dctx->headerBuffer + ZSTD_FRAMEIDSIZE); /* note : dctx->expected can grow seriously large, beyond local buffer size */1301dctx->stage = ZSTDds_skipFrame;1302return 0;13031304case ZSTDds_skipFrame:1305dctx->expected = 0;1306dctx->stage = ZSTDds_getFrameHeaderSize;1307return 0;13081309default:1310assert(0); /* impossible */1311RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */1312}1313}131413151316static size_t ZSTD_refDictContent(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1317{1318dctx->dictEnd = dctx->previousDstEnd;1319dctx->virtualStart = (const char*)dict - ((const char*)(dctx->previousDstEnd) - (const char*)(dctx->prefixStart));1320dctx->prefixStart = dict;1321dctx->previousDstEnd = (const char*)dict + dictSize;1322#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION1323dctx->dictContentBeginForFuzzing = dctx->prefixStart;1324dctx->dictContentEndForFuzzing = dctx->previousDstEnd;1325#endif1326return 0;1327}13281329/*! ZSTD_loadDEntropy() :1330* dict : must point at beginning of a valid zstd dictionary.1331* @return : size of entropy tables read */1332size_t1333ZSTD_loadDEntropy(ZSTD_entropyDTables_t* entropy,1334const void* const dict, size_t const dictSize)1335{1336const BYTE* dictPtr = (const BYTE*)dict;1337const BYTE* const dictEnd = dictPtr + dictSize;13381339RETURN_ERROR_IF(dictSize <= 8, dictionary_corrupted, "dict is too small");1340assert(MEM_readLE32(dict) == ZSTD_MAGIC_DICTIONARY); /* dict must be valid */1341dictPtr += 8; /* skip header = magic + dictID */13421343ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, OFTable) == offsetof(ZSTD_entropyDTables_t, LLTable) + sizeof(entropy->LLTable));1344ZSTD_STATIC_ASSERT(offsetof(ZSTD_entropyDTables_t, MLTable) == offsetof(ZSTD_entropyDTables_t, OFTable) + sizeof(entropy->OFTable));1345ZSTD_STATIC_ASSERT(sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable) >= HUF_DECOMPRESS_WORKSPACE_SIZE);1346{ void* const workspace = &entropy->LLTable; /* use fse tables as temporary workspace; implies fse tables are grouped together */1347size_t const workspaceSize = sizeof(entropy->LLTable) + sizeof(entropy->OFTable) + sizeof(entropy->MLTable);1348#ifdef HUF_FORCE_DECOMPRESS_X11349/* in minimal huffman, we always use X1 variants */1350size_t const hSize = HUF_readDTableX1_wksp(entropy->hufTable,1351dictPtr, dictEnd - dictPtr,1352workspace, workspaceSize);1353#else1354size_t const hSize = HUF_readDTableX2_wksp(entropy->hufTable,1355dictPtr, (size_t)(dictEnd - dictPtr),1356workspace, workspaceSize);1357#endif1358RETURN_ERROR_IF(HUF_isError(hSize), dictionary_corrupted, "");1359dictPtr += hSize;1360}13611362{ short offcodeNCount[MaxOff+1];1363unsigned offcodeMaxValue = MaxOff, offcodeLog;1364size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, (size_t)(dictEnd-dictPtr));1365RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");1366RETURN_ERROR_IF(offcodeMaxValue > MaxOff, dictionary_corrupted, "");1367RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");1368ZSTD_buildFSETable( entropy->OFTable,1369offcodeNCount, offcodeMaxValue,1370OF_base, OF_bits,1371offcodeLog,1372entropy->workspace, sizeof(entropy->workspace),1373/* bmi2 */0);1374dictPtr += offcodeHeaderSize;1375}13761377{ short matchlengthNCount[MaxML+1];1378unsigned matchlengthMaxValue = MaxML, matchlengthLog;1379size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, (size_t)(dictEnd-dictPtr));1380RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");1381RETURN_ERROR_IF(matchlengthMaxValue > MaxML, dictionary_corrupted, "");1382RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");1383ZSTD_buildFSETable( entropy->MLTable,1384matchlengthNCount, matchlengthMaxValue,1385ML_base, ML_bits,1386matchlengthLog,1387entropy->workspace, sizeof(entropy->workspace),1388/* bmi2 */ 0);1389dictPtr += matchlengthHeaderSize;1390}13911392{ short litlengthNCount[MaxLL+1];1393unsigned litlengthMaxValue = MaxLL, litlengthLog;1394size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, (size_t)(dictEnd-dictPtr));1395RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");1396RETURN_ERROR_IF(litlengthMaxValue > MaxLL, dictionary_corrupted, "");1397RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");1398ZSTD_buildFSETable( entropy->LLTable,1399litlengthNCount, litlengthMaxValue,1400LL_base, LL_bits,1401litlengthLog,1402entropy->workspace, sizeof(entropy->workspace),1403/* bmi2 */ 0);1404dictPtr += litlengthHeaderSize;1405}14061407RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, "");1408{ int i;1409size_t const dictContentSize = (size_t)(dictEnd - (dictPtr+12));1410for (i=0; i<3; i++) {1411U32 const rep = MEM_readLE32(dictPtr); dictPtr += 4;1412RETURN_ERROR_IF(rep==0 || rep > dictContentSize,1413dictionary_corrupted, "");1414entropy->rep[i] = rep;1415} }14161417return (size_t)(dictPtr - (const BYTE*)dict);1418}14191420static size_t ZSTD_decompress_insertDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1421{1422if (dictSize < 8) return ZSTD_refDictContent(dctx, dict, dictSize);1423{ U32 const magic = MEM_readLE32(dict);1424if (magic != ZSTD_MAGIC_DICTIONARY) {1425return ZSTD_refDictContent(dctx, dict, dictSize); /* pure content mode */1426} }1427dctx->dictID = MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);14281429/* load entropy tables */1430{ size_t const eSize = ZSTD_loadDEntropy(&dctx->entropy, dict, dictSize);1431RETURN_ERROR_IF(ZSTD_isError(eSize), dictionary_corrupted, "");1432dict = (const char*)dict + eSize;1433dictSize -= eSize;1434}1435dctx->litEntropy = dctx->fseEntropy = 1;14361437/* reference dictionary content */1438return ZSTD_refDictContent(dctx, dict, dictSize);1439}14401441size_t ZSTD_decompressBegin(ZSTD_DCtx* dctx)1442{1443assert(dctx != NULL);1444#if ZSTD_TRACE1445dctx->traceCtx = (ZSTD_trace_decompress_begin != NULL) ? ZSTD_trace_decompress_begin(dctx) : 0;1446#endif1447dctx->expected = ZSTD_startingInputLength(dctx->format); /* dctx->format must be properly set */1448dctx->stage = ZSTDds_getFrameHeaderSize;1449dctx->processedCSize = 0;1450dctx->decodedSize = 0;1451dctx->previousDstEnd = NULL;1452dctx->prefixStart = NULL;1453dctx->virtualStart = NULL;1454dctx->dictEnd = NULL;1455dctx->entropy.hufTable[0] = (HUF_DTable)((HufLog)*0x1000001); /* cover both little and big endian */1456dctx->litEntropy = dctx->fseEntropy = 0;1457dctx->dictID = 0;1458dctx->bType = bt_reserved;1459ZSTD_STATIC_ASSERT(sizeof(dctx->entropy.rep) == sizeof(repStartValue));1460ZSTD_memcpy(dctx->entropy.rep, repStartValue, sizeof(repStartValue)); /* initial repcodes */1461dctx->LLTptr = dctx->entropy.LLTable;1462dctx->MLTptr = dctx->entropy.MLTable;1463dctx->OFTptr = dctx->entropy.OFTable;1464dctx->HUFptr = dctx->entropy.hufTable;1465return 0;1466}14671468size_t ZSTD_decompressBegin_usingDict(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1469{1470FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");1471if (dict && dictSize)1472RETURN_ERROR_IF(1473ZSTD_isError(ZSTD_decompress_insertDictionary(dctx, dict, dictSize)),1474dictionary_corrupted, "");1475return 0;1476}147714781479/* ====== ZSTD_DDict ====== */14801481size_t ZSTD_decompressBegin_usingDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)1482{1483DEBUGLOG(4, "ZSTD_decompressBegin_usingDDict");1484assert(dctx != NULL);1485if (ddict) {1486const char* const dictStart = (const char*)ZSTD_DDict_dictContent(ddict);1487size_t const dictSize = ZSTD_DDict_dictSize(ddict);1488const void* const dictEnd = dictStart + dictSize;1489dctx->ddictIsCold = (dctx->dictEnd != dictEnd);1490DEBUGLOG(4, "DDict is %s",1491dctx->ddictIsCold ? "~cold~" : "hot!");1492}1493FORWARD_IF_ERROR( ZSTD_decompressBegin(dctx) , "");1494if (ddict) { /* NULL ddict is equivalent to no dictionary */1495ZSTD_copyDDictParameters(dctx, ddict);1496}1497return 0;1498}14991500/*! ZSTD_getDictID_fromDict() :1501* Provides the dictID stored within dictionary.1502* if @return == 0, the dictionary is not conformant with Zstandard specification.1503* It can still be loaded, but as a content-only dictionary. */1504unsigned ZSTD_getDictID_fromDict(const void* dict, size_t dictSize)1505{1506if (dictSize < 8) return 0;1507if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) return 0;1508return MEM_readLE32((const char*)dict + ZSTD_FRAMEIDSIZE);1509}15101511/*! ZSTD_getDictID_fromFrame() :1512* Provides the dictID required to decompress frame stored within `src`.1513* If @return == 0, the dictID could not be decoded.1514* This could for one of the following reasons :1515* - The frame does not require a dictionary (most common case).1516* - The frame was built with dictID intentionally removed.1517* Needed dictionary is a hidden information.1518* Note : this use case also happens when using a non-conformant dictionary.1519* - `srcSize` is too small, and as a result, frame header could not be decoded.1520* Note : possible if `srcSize < ZSTD_FRAMEHEADERSIZE_MAX`.1521* - This is not a Zstandard frame.1522* When identifying the exact failure cause, it's possible to use1523* ZSTD_getFrameHeader(), which will provide a more precise error code. */1524unsigned ZSTD_getDictID_fromFrame(const void* src, size_t srcSize)1525{1526ZSTD_frameHeader zfp = { 0, 0, 0, ZSTD_frame, 0, 0, 0 };1527size_t const hError = ZSTD_getFrameHeader(&zfp, src, srcSize);1528if (ZSTD_isError(hError)) return 0;1529return zfp.dictID;1530}153115321533/*! ZSTD_decompress_usingDDict() :1534* Decompression using a pre-digested Dictionary1535* Use dictionary without significant overhead. */1536size_t ZSTD_decompress_usingDDict(ZSTD_DCtx* dctx,1537void* dst, size_t dstCapacity,1538const void* src, size_t srcSize,1539const ZSTD_DDict* ddict)1540{1541/* pass content and size in case legacy frames are encountered */1542return ZSTD_decompressMultiFrame(dctx, dst, dstCapacity, src, srcSize,1543NULL, 0,1544ddict);1545}154615471548/*=====================================1549* Streaming decompression1550*====================================*/15511552ZSTD_DStream* ZSTD_createDStream(void)1553{1554DEBUGLOG(3, "ZSTD_createDStream");1555return ZSTD_createDCtx_internal(ZSTD_defaultCMem);1556}15571558ZSTD_DStream* ZSTD_initStaticDStream(void *workspace, size_t workspaceSize)1559{1560return ZSTD_initStaticDCtx(workspace, workspaceSize);1561}15621563ZSTD_DStream* ZSTD_createDStream_advanced(ZSTD_customMem customMem)1564{1565return ZSTD_createDCtx_internal(customMem);1566}15671568size_t ZSTD_freeDStream(ZSTD_DStream* zds)1569{1570return ZSTD_freeDCtx(zds);1571}157215731574/* *** Initialization *** */15751576size_t ZSTD_DStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX + ZSTD_blockHeaderSize; }1577size_t ZSTD_DStreamOutSize(void) { return ZSTD_BLOCKSIZE_MAX; }15781579size_t ZSTD_DCtx_loadDictionary_advanced(ZSTD_DCtx* dctx,1580const void* dict, size_t dictSize,1581ZSTD_dictLoadMethod_e dictLoadMethod,1582ZSTD_dictContentType_e dictContentType)1583{1584RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1585ZSTD_clearDict(dctx);1586if (dict && dictSize != 0) {1587dctx->ddictLocal = ZSTD_createDDict_advanced(dict, dictSize, dictLoadMethod, dictContentType, dctx->customMem);1588RETURN_ERROR_IF(dctx->ddictLocal == NULL, memory_allocation, "NULL pointer!");1589dctx->ddict = dctx->ddictLocal;1590dctx->dictUses = ZSTD_use_indefinitely;1591}1592return 0;1593}15941595size_t ZSTD_DCtx_loadDictionary_byReference(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1596{1597return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);1598}15991600size_t ZSTD_DCtx_loadDictionary(ZSTD_DCtx* dctx, const void* dict, size_t dictSize)1601{1602return ZSTD_DCtx_loadDictionary_advanced(dctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);1603}16041605size_t ZSTD_DCtx_refPrefix_advanced(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)1606{1607FORWARD_IF_ERROR(ZSTD_DCtx_loadDictionary_advanced(dctx, prefix, prefixSize, ZSTD_dlm_byRef, dictContentType), "");1608dctx->dictUses = ZSTD_use_once;1609return 0;1610}16111612size_t ZSTD_DCtx_refPrefix(ZSTD_DCtx* dctx, const void* prefix, size_t prefixSize)1613{1614return ZSTD_DCtx_refPrefix_advanced(dctx, prefix, prefixSize, ZSTD_dct_rawContent);1615}161616171618/* ZSTD_initDStream_usingDict() :1619* return : expected size, aka ZSTD_startingInputLength().1620* this function cannot fail */1621size_t ZSTD_initDStream_usingDict(ZSTD_DStream* zds, const void* dict, size_t dictSize)1622{1623DEBUGLOG(4, "ZSTD_initDStream_usingDict");1624FORWARD_IF_ERROR( ZSTD_DCtx_reset(zds, ZSTD_reset_session_only) , "");1625FORWARD_IF_ERROR( ZSTD_DCtx_loadDictionary(zds, dict, dictSize) , "");1626return ZSTD_startingInputLength(zds->format);1627}16281629/* note : this variant can't fail */1630size_t ZSTD_initDStream(ZSTD_DStream* zds)1631{1632DEBUGLOG(4, "ZSTD_initDStream");1633return ZSTD_initDStream_usingDDict(zds, NULL);1634}16351636/* ZSTD_initDStream_usingDDict() :1637* ddict will just be referenced, and must outlive decompression session1638* this function cannot fail */1639size_t ZSTD_initDStream_usingDDict(ZSTD_DStream* dctx, const ZSTD_DDict* ddict)1640{1641FORWARD_IF_ERROR( ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only) , "");1642FORWARD_IF_ERROR( ZSTD_DCtx_refDDict(dctx, ddict) , "");1643return ZSTD_startingInputLength(dctx->format);1644}16451646/* ZSTD_resetDStream() :1647* return : expected size, aka ZSTD_startingInputLength().1648* this function cannot fail */1649size_t ZSTD_resetDStream(ZSTD_DStream* dctx)1650{1651FORWARD_IF_ERROR(ZSTD_DCtx_reset(dctx, ZSTD_reset_session_only), "");1652return ZSTD_startingInputLength(dctx->format);1653}165416551656size_t ZSTD_DCtx_refDDict(ZSTD_DCtx* dctx, const ZSTD_DDict* ddict)1657{1658RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1659ZSTD_clearDict(dctx);1660if (ddict) {1661dctx->ddict = ddict;1662dctx->dictUses = ZSTD_use_indefinitely;1663if (dctx->refMultipleDDicts == ZSTD_rmd_refMultipleDDicts) {1664if (dctx->ddictSet == NULL) {1665dctx->ddictSet = ZSTD_createDDictHashSet(dctx->customMem);1666if (!dctx->ddictSet) {1667RETURN_ERROR(memory_allocation, "Failed to allocate memory for hash set!");1668}1669}1670assert(!dctx->staticSize); /* Impossible: ddictSet cannot have been allocated if static dctx */1671FORWARD_IF_ERROR(ZSTD_DDictHashSet_addDDict(dctx->ddictSet, ddict, dctx->customMem), "");1672}1673}1674return 0;1675}16761677/* ZSTD_DCtx_setMaxWindowSize() :1678* note : no direct equivalence in ZSTD_DCtx_setParameter,1679* since this version sets windowSize, and the other sets windowLog */1680size_t ZSTD_DCtx_setMaxWindowSize(ZSTD_DCtx* dctx, size_t maxWindowSize)1681{1682ZSTD_bounds const bounds = ZSTD_dParam_getBounds(ZSTD_d_windowLogMax);1683size_t const min = (size_t)1 << bounds.lowerBound;1684size_t const max = (size_t)1 << bounds.upperBound;1685RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1686RETURN_ERROR_IF(maxWindowSize < min, parameter_outOfBound, "");1687RETURN_ERROR_IF(maxWindowSize > max, parameter_outOfBound, "");1688dctx->maxWindowSize = maxWindowSize;1689return 0;1690}16911692size_t ZSTD_DCtx_setFormat(ZSTD_DCtx* dctx, ZSTD_format_e format)1693{1694return ZSTD_DCtx_setParameter(dctx, ZSTD_d_format, (int)format);1695}16961697ZSTD_bounds ZSTD_dParam_getBounds(ZSTD_dParameter dParam)1698{1699ZSTD_bounds bounds = { 0, 0, 0 };1700switch(dParam) {1701case ZSTD_d_windowLogMax:1702bounds.lowerBound = ZSTD_WINDOWLOG_ABSOLUTEMIN;1703bounds.upperBound = ZSTD_WINDOWLOG_MAX;1704return bounds;1705case ZSTD_d_format:1706bounds.lowerBound = (int)ZSTD_f_zstd1;1707bounds.upperBound = (int)ZSTD_f_zstd1_magicless;1708ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);1709return bounds;1710case ZSTD_d_stableOutBuffer:1711bounds.lowerBound = (int)ZSTD_bm_buffered;1712bounds.upperBound = (int)ZSTD_bm_stable;1713return bounds;1714case ZSTD_d_forceIgnoreChecksum:1715bounds.lowerBound = (int)ZSTD_d_validateChecksum;1716bounds.upperBound = (int)ZSTD_d_ignoreChecksum;1717return bounds;1718case ZSTD_d_refMultipleDDicts:1719bounds.lowerBound = (int)ZSTD_rmd_refSingleDDict;1720bounds.upperBound = (int)ZSTD_rmd_refMultipleDDicts;1721return bounds;1722default:;1723}1724bounds.error = ERROR(parameter_unsupported);1725return bounds;1726}17271728/* ZSTD_dParam_withinBounds:1729* @return 1 if value is within dParam bounds,1730* 0 otherwise */1731static int ZSTD_dParam_withinBounds(ZSTD_dParameter dParam, int value)1732{1733ZSTD_bounds const bounds = ZSTD_dParam_getBounds(dParam);1734if (ZSTD_isError(bounds.error)) return 0;1735if (value < bounds.lowerBound) return 0;1736if (value > bounds.upperBound) return 0;1737return 1;1738}17391740#define CHECK_DBOUNDS(p,v) { \1741RETURN_ERROR_IF(!ZSTD_dParam_withinBounds(p, v), parameter_outOfBound, ""); \1742}17431744size_t ZSTD_DCtx_getParameter(ZSTD_DCtx* dctx, ZSTD_dParameter param, int* value)1745{1746switch (param) {1747case ZSTD_d_windowLogMax:1748*value = (int)ZSTD_highbit32((U32)dctx->maxWindowSize);1749return 0;1750case ZSTD_d_format:1751*value = (int)dctx->format;1752return 0;1753case ZSTD_d_stableOutBuffer:1754*value = (int)dctx->outBufferMode;1755return 0;1756case ZSTD_d_forceIgnoreChecksum:1757*value = (int)dctx->forceIgnoreChecksum;1758return 0;1759case ZSTD_d_refMultipleDDicts:1760*value = (int)dctx->refMultipleDDicts;1761return 0;1762default:;1763}1764RETURN_ERROR(parameter_unsupported, "");1765}17661767size_t ZSTD_DCtx_setParameter(ZSTD_DCtx* dctx, ZSTD_dParameter dParam, int value)1768{1769RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1770switch(dParam) {1771case ZSTD_d_windowLogMax:1772if (value == 0) value = ZSTD_WINDOWLOG_LIMIT_DEFAULT;1773CHECK_DBOUNDS(ZSTD_d_windowLogMax, value);1774dctx->maxWindowSize = ((size_t)1) << value;1775return 0;1776case ZSTD_d_format:1777CHECK_DBOUNDS(ZSTD_d_format, value);1778dctx->format = (ZSTD_format_e)value;1779return 0;1780case ZSTD_d_stableOutBuffer:1781CHECK_DBOUNDS(ZSTD_d_stableOutBuffer, value);1782dctx->outBufferMode = (ZSTD_bufferMode_e)value;1783return 0;1784case ZSTD_d_forceIgnoreChecksum:1785CHECK_DBOUNDS(ZSTD_d_forceIgnoreChecksum, value);1786dctx->forceIgnoreChecksum = (ZSTD_forceIgnoreChecksum_e)value;1787return 0;1788case ZSTD_d_refMultipleDDicts:1789CHECK_DBOUNDS(ZSTD_d_refMultipleDDicts, value);1790if (dctx->staticSize != 0) {1791RETURN_ERROR(parameter_unsupported, "Static dctx does not support multiple DDicts!");1792}1793dctx->refMultipleDDicts = (ZSTD_refMultipleDDicts_e)value;1794return 0;1795default:;1796}1797RETURN_ERROR(parameter_unsupported, "");1798}17991800size_t ZSTD_DCtx_reset(ZSTD_DCtx* dctx, ZSTD_ResetDirective reset)1801{1802if ( (reset == ZSTD_reset_session_only)1803|| (reset == ZSTD_reset_session_and_parameters) ) {1804dctx->streamStage = zdss_init;1805dctx->noForwardProgress = 0;1806}1807if ( (reset == ZSTD_reset_parameters)1808|| (reset == ZSTD_reset_session_and_parameters) ) {1809RETURN_ERROR_IF(dctx->streamStage != zdss_init, stage_wrong, "");1810ZSTD_clearDict(dctx);1811ZSTD_DCtx_resetParameters(dctx);1812}1813return 0;1814}181518161817size_t ZSTD_sizeof_DStream(const ZSTD_DStream* dctx)1818{1819return ZSTD_sizeof_DCtx(dctx);1820}18211822size_t ZSTD_decodingBufferSize_min(unsigned long long windowSize, unsigned long long frameContentSize)1823{1824size_t const blockSize = (size_t) MIN(windowSize, ZSTD_BLOCKSIZE_MAX);1825/* 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*/1826unsigned long long const neededRBSize = windowSize + blockSize + ZSTD_BLOCKSIZE_MAX + (WILDCOPY_OVERLENGTH * 2);1827unsigned long long const neededSize = MIN(frameContentSize, neededRBSize);1828size_t const minRBSize = (size_t) neededSize;1829RETURN_ERROR_IF((unsigned long long)minRBSize != neededSize,1830frameParameter_windowTooLarge, "");1831return minRBSize;1832}18331834size_t ZSTD_estimateDStreamSize(size_t windowSize)1835{1836size_t const blockSize = MIN(windowSize, ZSTD_BLOCKSIZE_MAX);1837size_t const inBuffSize = blockSize; /* no block can be larger */1838size_t const outBuffSize = ZSTD_decodingBufferSize_min(windowSize, ZSTD_CONTENTSIZE_UNKNOWN);1839return ZSTD_estimateDCtxSize() + inBuffSize + outBuffSize;1840}18411842size_t ZSTD_estimateDStreamSize_fromFrame(const void* src, size_t srcSize)1843{1844U32 const windowSizeMax = 1U << ZSTD_WINDOWLOG_MAX; /* note : should be user-selectable, but requires an additional parameter (or a dctx) */1845ZSTD_frameHeader zfh;1846size_t const err = ZSTD_getFrameHeader(&zfh, src, srcSize);1847if (ZSTD_isError(err)) return err;1848RETURN_ERROR_IF(err>0, srcSize_wrong, "");1849RETURN_ERROR_IF(zfh.windowSize > windowSizeMax,1850frameParameter_windowTooLarge, "");1851return ZSTD_estimateDStreamSize((size_t)zfh.windowSize);1852}185318541855/* ***** Decompression ***** */18561857static int ZSTD_DCtx_isOverflow(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)1858{1859return (zds->inBuffSize + zds->outBuffSize) >= (neededInBuffSize + neededOutBuffSize) * ZSTD_WORKSPACETOOLARGE_FACTOR;1860}18611862static void ZSTD_DCtx_updateOversizedDuration(ZSTD_DStream* zds, size_t const neededInBuffSize, size_t const neededOutBuffSize)1863{1864if (ZSTD_DCtx_isOverflow(zds, neededInBuffSize, neededOutBuffSize))1865zds->oversizedDuration++;1866else1867zds->oversizedDuration = 0;1868}18691870static int ZSTD_DCtx_isOversizedTooLong(ZSTD_DStream* zds)1871{1872return zds->oversizedDuration >= ZSTD_WORKSPACETOOLARGE_MAXDURATION;1873}18741875/* Checks that the output buffer hasn't changed if ZSTD_obm_stable is used. */1876static size_t ZSTD_checkOutBuffer(ZSTD_DStream const* zds, ZSTD_outBuffer const* output)1877{1878ZSTD_outBuffer const expect = zds->expectedOutBuffer;1879/* No requirement when ZSTD_obm_stable is not enabled. */1880if (zds->outBufferMode != ZSTD_bm_stable)1881return 0;1882/* Any buffer is allowed in zdss_init, this must be the same for every other call until1883* the context is reset.1884*/1885if (zds->streamStage == zdss_init)1886return 0;1887/* The buffer must match our expectation exactly. */1888if (expect.dst == output->dst && expect.pos == output->pos && expect.size == output->size)1889return 0;1890RETURN_ERROR(dstBuffer_wrong, "ZSTD_d_stableOutBuffer enabled but output differs!");1891}18921893/* Calls ZSTD_decompressContinue() with the right parameters for ZSTD_decompressStream()1894* and updates the stage and the output buffer state. This call is extracted so it can be1895* used both when reading directly from the ZSTD_inBuffer, and in buffered input mode.1896* NOTE: You must break after calling this function since the streamStage is modified.1897*/1898static size_t ZSTD_decompressContinueStream(1899ZSTD_DStream* zds, char** op, char* oend,1900void const* src, size_t srcSize) {1901int const isSkipFrame = ZSTD_isSkipFrame(zds);1902if (zds->outBufferMode == ZSTD_bm_buffered) {1903size_t const dstSize = isSkipFrame ? 0 : zds->outBuffSize - zds->outStart;1904size_t const decodedSize = ZSTD_decompressContinue(zds,1905zds->outBuff + zds->outStart, dstSize, src, srcSize);1906FORWARD_IF_ERROR(decodedSize, "");1907if (!decodedSize && !isSkipFrame) {1908zds->streamStage = zdss_read;1909} else {1910zds->outEnd = zds->outStart + decodedSize;1911zds->streamStage = zdss_flush;1912}1913} else {1914/* Write directly into the output buffer */1915size_t const dstSize = isSkipFrame ? 0 : (size_t)(oend - *op);1916size_t const decodedSize = ZSTD_decompressContinue(zds, *op, dstSize, src, srcSize);1917FORWARD_IF_ERROR(decodedSize, "");1918*op += decodedSize;1919/* Flushing is not needed. */1920zds->streamStage = zdss_read;1921assert(*op <= oend);1922assert(zds->outBufferMode == ZSTD_bm_stable);1923}1924return 0;1925}19261927size_t ZSTD_decompressStream(ZSTD_DStream* zds, ZSTD_outBuffer* output, ZSTD_inBuffer* input)1928{1929const char* const src = (const char*)input->src;1930const char* const istart = input->pos != 0 ? src + input->pos : src;1931const char* const iend = input->size != 0 ? src + input->size : src;1932const char* ip = istart;1933char* const dst = (char*)output->dst;1934char* const ostart = output->pos != 0 ? dst + output->pos : dst;1935char* const oend = output->size != 0 ? dst + output->size : dst;1936char* op = ostart;1937U32 someMoreWork = 1;19381939DEBUGLOG(5, "ZSTD_decompressStream");1940RETURN_ERROR_IF(1941input->pos > input->size,1942srcSize_wrong,1943"forbidden. in: pos: %u vs size: %u",1944(U32)input->pos, (U32)input->size);1945RETURN_ERROR_IF(1946output->pos > output->size,1947dstSize_tooSmall,1948"forbidden. out: pos: %u vs size: %u",1949(U32)output->pos, (U32)output->size);1950DEBUGLOG(5, "input size : %u", (U32)(input->size - input->pos));1951FORWARD_IF_ERROR(ZSTD_checkOutBuffer(zds, output), "");19521953while (someMoreWork) {1954switch(zds->streamStage)1955{1956case zdss_init :1957DEBUGLOG(5, "stage zdss_init => transparent reset ");1958zds->streamStage = zdss_loadHeader;1959zds->lhSize = zds->inPos = zds->outStart = zds->outEnd = 0;1960#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)1961zds->legacyVersion = 0;1962#endif1963zds->hostageByte = 0;1964zds->expectedOutBuffer = *output;1965ZSTD_FALLTHROUGH;19661967case zdss_loadHeader :1968DEBUGLOG(5, "stage zdss_loadHeader (srcSize : %u)", (U32)(iend - ip));1969#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)1970if (zds->legacyVersion) {1971RETURN_ERROR_IF(zds->staticSize, memory_allocation,1972"legacy support is incompatible with static dctx");1973{ size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, zds->legacyVersion, output, input);1974if (hint==0) zds->streamStage = zdss_init;1975return hint;1976} }1977#endif1978{ size_t const hSize = ZSTD_getFrameHeader_advanced(&zds->fParams, zds->headerBuffer, zds->lhSize, zds->format);1979if (zds->refMultipleDDicts && zds->ddictSet) {1980ZSTD_DCtx_selectFrameDDict(zds);1981}1982DEBUGLOG(5, "header size : %u", (U32)hSize);1983if (ZSTD_isError(hSize)) {1984#if defined(ZSTD_LEGACY_SUPPORT) && (ZSTD_LEGACY_SUPPORT>=1)1985U32 const legacyVersion = ZSTD_isLegacy(istart, iend-istart);1986if (legacyVersion) {1987ZSTD_DDict const* const ddict = ZSTD_getDDict(zds);1988const void* const dict = ddict ? ZSTD_DDict_dictContent(ddict) : NULL;1989size_t const dictSize = ddict ? ZSTD_DDict_dictSize(ddict) : 0;1990DEBUGLOG(5, "ZSTD_decompressStream: detected legacy version v0.%u", legacyVersion);1991RETURN_ERROR_IF(zds->staticSize, memory_allocation,1992"legacy support is incompatible with static dctx");1993FORWARD_IF_ERROR(ZSTD_initLegacyStream(&zds->legacyContext,1994zds->previousLegacyVersion, legacyVersion,1995dict, dictSize), "");1996zds->legacyVersion = zds->previousLegacyVersion = legacyVersion;1997{ size_t const hint = ZSTD_decompressLegacyStream(zds->legacyContext, legacyVersion, output, input);1998if (hint==0) zds->streamStage = zdss_init; /* or stay in stage zdss_loadHeader */1999return hint;2000} }2001#endif2002return hSize; /* error */2003}2004if (hSize != 0) { /* need more input */2005size_t const toLoad = hSize - zds->lhSize; /* if hSize!=0, hSize > zds->lhSize */2006size_t const remainingInput = (size_t)(iend-ip);2007assert(iend >= ip);2008if (toLoad > remainingInput) { /* not enough input to load full header */2009if (remainingInput > 0) {2010ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, remainingInput);2011zds->lhSize += remainingInput;2012}2013input->pos = input->size;2014return (MAX((size_t)ZSTD_FRAMEHEADERSIZE_MIN(zds->format), hSize) - zds->lhSize) + ZSTD_blockHeaderSize; /* remaining header bytes + next block header */2015}2016assert(ip != NULL);2017ZSTD_memcpy(zds->headerBuffer + zds->lhSize, ip, toLoad); zds->lhSize = hSize; ip += toLoad;2018break;2019} }20202021/* check for single-pass mode opportunity */2022if (zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN2023&& zds->fParams.frameType != ZSTD_skippableFrame2024&& (U64)(size_t)(oend-op) >= zds->fParams.frameContentSize) {2025size_t const cSize = ZSTD_findFrameCompressedSize(istart, (size_t)(iend-istart));2026if (cSize <= (size_t)(iend-istart)) {2027/* shortcut : using single-pass mode */2028size_t const decompressedSize = ZSTD_decompress_usingDDict(zds, op, (size_t)(oend-op), istart, cSize, ZSTD_getDDict(zds));2029if (ZSTD_isError(decompressedSize)) return decompressedSize;2030DEBUGLOG(4, "shortcut to single-pass ZSTD_decompress_usingDDict()")2031ip = istart + cSize;2032op += decompressedSize;2033zds->expected = 0;2034zds->streamStage = zdss_init;2035someMoreWork = 0;2036break;2037} }20382039/* Check output buffer is large enough for ZSTD_odm_stable. */2040if (zds->outBufferMode == ZSTD_bm_stable2041&& zds->fParams.frameType != ZSTD_skippableFrame2042&& zds->fParams.frameContentSize != ZSTD_CONTENTSIZE_UNKNOWN2043&& (U64)(size_t)(oend-op) < zds->fParams.frameContentSize) {2044RETURN_ERROR(dstSize_tooSmall, "ZSTD_obm_stable passed but ZSTD_outBuffer is too small");2045}20462047/* Consume header (see ZSTDds_decodeFrameHeader) */2048DEBUGLOG(4, "Consume header");2049FORWARD_IF_ERROR(ZSTD_decompressBegin_usingDDict(zds, ZSTD_getDDict(zds)), "");20502051if ((MEM_readLE32(zds->headerBuffer) & ZSTD_MAGIC_SKIPPABLE_MASK) == ZSTD_MAGIC_SKIPPABLE_START) { /* skippable frame */2052zds->expected = MEM_readLE32(zds->headerBuffer + ZSTD_FRAMEIDSIZE);2053zds->stage = ZSTDds_skipFrame;2054} else {2055FORWARD_IF_ERROR(ZSTD_decodeFrameHeader(zds, zds->headerBuffer, zds->lhSize), "");2056zds->expected = ZSTD_blockHeaderSize;2057zds->stage = ZSTDds_decodeBlockHeader;2058}20592060/* control buffer memory usage */2061DEBUGLOG(4, "Control max memory usage (%u KB <= max %u KB)",2062(U32)(zds->fParams.windowSize >>10),2063(U32)(zds->maxWindowSize >> 10) );2064zds->fParams.windowSize = MAX(zds->fParams.windowSize, 1U << ZSTD_WINDOWLOG_ABSOLUTEMIN);2065RETURN_ERROR_IF(zds->fParams.windowSize > zds->maxWindowSize,2066frameParameter_windowTooLarge, "");20672068/* Adapt buffer sizes to frame header instructions */2069{ size_t const neededInBuffSize = MAX(zds->fParams.blockSizeMax, 4 /* frame checksum */);2070size_t const neededOutBuffSize = zds->outBufferMode == ZSTD_bm_buffered2071? ZSTD_decodingBufferSize_min(zds->fParams.windowSize, zds->fParams.frameContentSize)2072: 0;20732074ZSTD_DCtx_updateOversizedDuration(zds, neededInBuffSize, neededOutBuffSize);20752076{ int const tooSmall = (zds->inBuffSize < neededInBuffSize) || (zds->outBuffSize < neededOutBuffSize);2077int const tooLarge = ZSTD_DCtx_isOversizedTooLong(zds);20782079if (tooSmall || tooLarge) {2080size_t const bufferSize = neededInBuffSize + neededOutBuffSize;2081DEBUGLOG(4, "inBuff : from %u to %u",2082(U32)zds->inBuffSize, (U32)neededInBuffSize);2083DEBUGLOG(4, "outBuff : from %u to %u",2084(U32)zds->outBuffSize, (U32)neededOutBuffSize);2085if (zds->staticSize) { /* static DCtx */2086DEBUGLOG(4, "staticSize : %u", (U32)zds->staticSize);2087assert(zds->staticSize >= sizeof(ZSTD_DCtx)); /* controlled at init */2088RETURN_ERROR_IF(2089bufferSize > zds->staticSize - sizeof(ZSTD_DCtx),2090memory_allocation, "");2091} else {2092ZSTD_customFree(zds->inBuff, zds->customMem);2093zds->inBuffSize = 0;2094zds->outBuffSize = 0;2095zds->inBuff = (char*)ZSTD_customMalloc(bufferSize, zds->customMem);2096RETURN_ERROR_IF(zds->inBuff == NULL, memory_allocation, "");2097}2098zds->inBuffSize = neededInBuffSize;2099zds->outBuff = zds->inBuff + zds->inBuffSize;2100zds->outBuffSize = neededOutBuffSize;2101} } }2102zds->streamStage = zdss_read;2103ZSTD_FALLTHROUGH;21042105case zdss_read:2106DEBUGLOG(5, "stage zdss_read");2107{ size_t const neededInSize = ZSTD_nextSrcSizeToDecompressWithInputSize(zds, (size_t)(iend - ip));2108DEBUGLOG(5, "neededInSize = %u", (U32)neededInSize);2109if (neededInSize==0) { /* end of frame */2110zds->streamStage = zdss_init;2111someMoreWork = 0;2112break;2113}2114if ((size_t)(iend-ip) >= neededInSize) { /* decode directly from src */2115FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, ip, neededInSize), "");2116ip += neededInSize;2117/* Function modifies the stage so we must break */2118break;2119} }2120if (ip==iend) { someMoreWork = 0; break; } /* no more input */2121zds->streamStage = zdss_load;2122ZSTD_FALLTHROUGH;21232124case zdss_load:2125{ size_t const neededInSize = ZSTD_nextSrcSizeToDecompress(zds);2126size_t const toLoad = neededInSize - zds->inPos;2127int const isSkipFrame = ZSTD_isSkipFrame(zds);2128size_t loadedSize;2129/* At this point we shouldn't be decompressing a block that we can stream. */2130assert(neededInSize == ZSTD_nextSrcSizeToDecompressWithInputSize(zds, iend - ip));2131if (isSkipFrame) {2132loadedSize = MIN(toLoad, (size_t)(iend-ip));2133} else {2134RETURN_ERROR_IF(toLoad > zds->inBuffSize - zds->inPos,2135corruption_detected,2136"should never happen");2137loadedSize = ZSTD_limitCopy(zds->inBuff + zds->inPos, toLoad, ip, (size_t)(iend-ip));2138}2139ip += loadedSize;2140zds->inPos += loadedSize;2141if (loadedSize < toLoad) { someMoreWork = 0; break; } /* not enough input, wait for more */21422143/* decode loaded input */2144zds->inPos = 0; /* input is consumed */2145FORWARD_IF_ERROR(ZSTD_decompressContinueStream(zds, &op, oend, zds->inBuff, neededInSize), "");2146/* Function modifies the stage so we must break */2147break;2148}2149case zdss_flush:2150{ size_t const toFlushSize = zds->outEnd - zds->outStart;2151size_t const flushedSize = ZSTD_limitCopy(op, (size_t)(oend-op), zds->outBuff + zds->outStart, toFlushSize);2152op += flushedSize;2153zds->outStart += flushedSize;2154if (flushedSize == toFlushSize) { /* flush completed */2155zds->streamStage = zdss_read;2156if ( (zds->outBuffSize < zds->fParams.frameContentSize)2157&& (zds->outStart + zds->fParams.blockSizeMax > zds->outBuffSize) ) {2158DEBUGLOG(5, "restart filling outBuff from beginning (left:%i, needed:%u)",2159(int)(zds->outBuffSize - zds->outStart),2160(U32)zds->fParams.blockSizeMax);2161zds->outStart = zds->outEnd = 0;2162}2163break;2164} }2165/* cannot complete flush */2166someMoreWork = 0;2167break;21682169default:2170assert(0); /* impossible */2171RETURN_ERROR(GENERIC, "impossible to reach"); /* some compiler require default to do something */2172} }21732174/* result */2175input->pos = (size_t)(ip - (const char*)(input->src));2176output->pos = (size_t)(op - (char*)(output->dst));21772178/* Update the expected output buffer for ZSTD_obm_stable. */2179zds->expectedOutBuffer = *output;21802181if ((ip==istart) && (op==ostart)) { /* no forward progress */2182zds->noForwardProgress ++;2183if (zds->noForwardProgress >= ZSTD_NO_FORWARD_PROGRESS_MAX) {2184RETURN_ERROR_IF(op==oend, dstSize_tooSmall, "");2185RETURN_ERROR_IF(ip==iend, srcSize_wrong, "");2186assert(0);2187}2188} else {2189zds->noForwardProgress = 0;2190}2191{ size_t nextSrcSizeHint = ZSTD_nextSrcSizeToDecompress(zds);2192if (!nextSrcSizeHint) { /* frame fully decoded */2193if (zds->outEnd == zds->outStart) { /* output fully flushed */2194if (zds->hostageByte) {2195if (input->pos >= input->size) {2196/* can't release hostage (not present) */2197zds->streamStage = zdss_read;2198return 1;2199}2200input->pos++; /* release hostage */2201} /* zds->hostageByte */2202return 0;2203} /* zds->outEnd == zds->outStart */2204if (!zds->hostageByte) { /* output not fully flushed; keep last byte as hostage; will be released when all output is flushed */2205input->pos--; /* note : pos > 0, otherwise, impossible to finish reading last block */2206zds->hostageByte=1;2207}2208return 1;2209} /* nextSrcSizeHint==0 */2210nextSrcSizeHint += ZSTD_blockHeaderSize * (ZSTD_nextInputType(zds) == ZSTDnit_block); /* preload header of next block */2211assert(zds->inPos <= nextSrcSizeHint);2212nextSrcSizeHint -= zds->inPos; /* part already loaded*/2213return nextSrcSizeHint;2214}2215}22162217size_t ZSTD_decompressStream_simpleArgs (2218ZSTD_DCtx* dctx,2219void* dst, size_t dstCapacity, size_t* dstPos,2220const void* src, size_t srcSize, size_t* srcPos)2221{2222ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };2223ZSTD_inBuffer input = { src, srcSize, *srcPos };2224/* ZSTD_compress_generic() will check validity of dstPos and srcPos */2225size_t const cErr = ZSTD_decompressStream(dctx, &output, &input);2226*dstPos = output.pos;2227*srcPos = input.pos;2228return cErr;2229}223022312232