1*3117ece4Schristos /* 2*3117ece4Schristos * Copyright (c) Meta Platforms, Inc. and affiliates. 3*3117ece4Schristos * All rights reserved. 4*3117ece4Schristos * 5*3117ece4Schristos * This source code is licensed under both the BSD-style license (found in the 6*3117ece4Schristos * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7*3117ece4Schristos * in the COPYING file in the root directory of this source tree). 8*3117ece4Schristos * You may select, at your option, one of the above-listed licenses. 9*3117ece4Schristos */ 10*3117ece4Schristos 11*3117ece4Schristos /*-************************************* 12*3117ece4Schristos * Dependencies 13*3117ece4Schristos ***************************************/ 14*3117ece4Schristos #include "../common/allocations.h" /* ZSTD_customMalloc, ZSTD_customCalloc, ZSTD_customFree */ 15*3117ece4Schristos #include "../common/zstd_deps.h" /* INT_MAX, ZSTD_memset, ZSTD_memcpy */ 16*3117ece4Schristos #include "../common/mem.h" 17*3117ece4Schristos #include "hist.h" /* HIST_countFast_wksp */ 18*3117ece4Schristos #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */ 19*3117ece4Schristos #include "../common/fse.h" 20*3117ece4Schristos #include "../common/huf.h" 21*3117ece4Schristos #include "zstd_compress_internal.h" 22*3117ece4Schristos #include "zstd_compress_sequences.h" 23*3117ece4Schristos #include "zstd_compress_literals.h" 24*3117ece4Schristos #include "zstd_fast.h" 25*3117ece4Schristos #include "zstd_double_fast.h" 26*3117ece4Schristos #include "zstd_lazy.h" 27*3117ece4Schristos #include "zstd_opt.h" 28*3117ece4Schristos #include "zstd_ldm.h" 29*3117ece4Schristos #include "zstd_compress_superblock.h" 30*3117ece4Schristos #include "../common/bits.h" /* ZSTD_highbit32, ZSTD_rotateRight_U64 */ 31*3117ece4Schristos 32*3117ece4Schristos /* *************************************************************** 33*3117ece4Schristos * Tuning parameters 34*3117ece4Schristos *****************************************************************/ 35*3117ece4Schristos /*! 36*3117ece4Schristos * COMPRESS_HEAPMODE : 37*3117ece4Schristos * Select how default decompression function ZSTD_compress() allocates its context, 38*3117ece4Schristos * on stack (0, default), or into heap (1). 39*3117ece4Schristos * Note that functions with explicit context such as ZSTD_compressCCtx() are unaffected. 40*3117ece4Schristos */ 41*3117ece4Schristos #ifndef ZSTD_COMPRESS_HEAPMODE 42*3117ece4Schristos # define ZSTD_COMPRESS_HEAPMODE 0 43*3117ece4Schristos #endif 44*3117ece4Schristos 45*3117ece4Schristos /*! 46*3117ece4Schristos * ZSTD_HASHLOG3_MAX : 47*3117ece4Schristos * Maximum size of the hash table dedicated to find 3-bytes matches, 48*3117ece4Schristos * in log format, aka 17 => 1 << 17 == 128Ki positions. 49*3117ece4Schristos * This structure is only used in zstd_opt. 50*3117ece4Schristos * Since allocation is centralized for all strategies, it has to be known here. 51*3117ece4Schristos * The actual (selected) size of the hash table is then stored in ZSTD_matchState_t.hashLog3, 52*3117ece4Schristos * so that zstd_opt.c doesn't need to know about this constant. 53*3117ece4Schristos */ 54*3117ece4Schristos #ifndef ZSTD_HASHLOG3_MAX 55*3117ece4Schristos # define ZSTD_HASHLOG3_MAX 17 56*3117ece4Schristos #endif 57*3117ece4Schristos 58*3117ece4Schristos /*-************************************* 59*3117ece4Schristos * Helper functions 60*3117ece4Schristos ***************************************/ 61*3117ece4Schristos /* ZSTD_compressBound() 62*3117ece4Schristos * Note that the result from this function is only valid for 63*3117ece4Schristos * the one-pass compression functions. 64*3117ece4Schristos * When employing the streaming mode, 65*3117ece4Schristos * if flushes are frequently altering the size of blocks, 66*3117ece4Schristos * the overhead from block headers can make the compressed data larger 67*3117ece4Schristos * than the return value of ZSTD_compressBound(). 68*3117ece4Schristos */ 69*3117ece4Schristos size_t ZSTD_compressBound(size_t srcSize) { 70*3117ece4Schristos size_t const r = ZSTD_COMPRESSBOUND(srcSize); 71*3117ece4Schristos if (r==0) return ERROR(srcSize_wrong); 72*3117ece4Schristos return r; 73*3117ece4Schristos } 74*3117ece4Schristos 75*3117ece4Schristos 76*3117ece4Schristos /*-************************************* 77*3117ece4Schristos * Context memory management 78*3117ece4Schristos ***************************************/ 79*3117ece4Schristos struct ZSTD_CDict_s { 80*3117ece4Schristos const void* dictContent; 81*3117ece4Schristos size_t dictContentSize; 82*3117ece4Schristos ZSTD_dictContentType_e dictContentType; /* The dictContentType the CDict was created with */ 83*3117ece4Schristos U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */ 84*3117ece4Schristos ZSTD_cwksp workspace; 85*3117ece4Schristos ZSTD_matchState_t matchState; 86*3117ece4Schristos ZSTD_compressedBlockState_t cBlockState; 87*3117ece4Schristos ZSTD_customMem customMem; 88*3117ece4Schristos U32 dictID; 89*3117ece4Schristos int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */ 90*3117ece4Schristos ZSTD_paramSwitch_e useRowMatchFinder; /* Indicates whether the CDict was created with params that would use 91*3117ece4Schristos * row-based matchfinder. Unless the cdict is reloaded, we will use 92*3117ece4Schristos * the same greedy/lazy matchfinder at compression time. 93*3117ece4Schristos */ 94*3117ece4Schristos }; /* typedef'd to ZSTD_CDict within "zstd.h" */ 95*3117ece4Schristos 96*3117ece4Schristos ZSTD_CCtx* ZSTD_createCCtx(void) 97*3117ece4Schristos { 98*3117ece4Schristos return ZSTD_createCCtx_advanced(ZSTD_defaultCMem); 99*3117ece4Schristos } 100*3117ece4Schristos 101*3117ece4Schristos static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager) 102*3117ece4Schristos { 103*3117ece4Schristos assert(cctx != NULL); 104*3117ece4Schristos ZSTD_memset(cctx, 0, sizeof(*cctx)); 105*3117ece4Schristos cctx->customMem = memManager; 106*3117ece4Schristos cctx->bmi2 = ZSTD_cpuSupportsBmi2(); 107*3117ece4Schristos { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters); 108*3117ece4Schristos assert(!ZSTD_isError(err)); 109*3117ece4Schristos (void)err; 110*3117ece4Schristos } 111*3117ece4Schristos } 112*3117ece4Schristos 113*3117ece4Schristos ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) 114*3117ece4Schristos { 115*3117ece4Schristos ZSTD_STATIC_ASSERT(zcss_init==0); 116*3117ece4Schristos ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); 117*3117ece4Schristos if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; 118*3117ece4Schristos { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_customMalloc(sizeof(ZSTD_CCtx), customMem); 119*3117ece4Schristos if (!cctx) return NULL; 120*3117ece4Schristos ZSTD_initCCtx(cctx, customMem); 121*3117ece4Schristos return cctx; 122*3117ece4Schristos } 123*3117ece4Schristos } 124*3117ece4Schristos 125*3117ece4Schristos ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize) 126*3117ece4Schristos { 127*3117ece4Schristos ZSTD_cwksp ws; 128*3117ece4Schristos ZSTD_CCtx* cctx; 129*3117ece4Schristos if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */ 130*3117ece4Schristos if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */ 131*3117ece4Schristos ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc); 132*3117ece4Schristos 133*3117ece4Schristos cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx)); 134*3117ece4Schristos if (cctx == NULL) return NULL; 135*3117ece4Schristos 136*3117ece4Schristos ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx)); 137*3117ece4Schristos ZSTD_cwksp_move(&cctx->workspace, &ws); 138*3117ece4Schristos cctx->staticSize = workspaceSize; 139*3117ece4Schristos 140*3117ece4Schristos /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ 141*3117ece4Schristos if (!ZSTD_cwksp_check_available(&cctx->workspace, ENTROPY_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL; 142*3117ece4Schristos cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); 143*3117ece4Schristos cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); 144*3117ece4Schristos cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, ENTROPY_WORKSPACE_SIZE); 145*3117ece4Schristos cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); 146*3117ece4Schristos return cctx; 147*3117ece4Schristos } 148*3117ece4Schristos 149*3117ece4Schristos /** 150*3117ece4Schristos * Clears and frees all of the dictionaries in the CCtx. 151*3117ece4Schristos */ 152*3117ece4Schristos static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx) 153*3117ece4Schristos { 154*3117ece4Schristos ZSTD_customFree(cctx->localDict.dictBuffer, cctx->customMem); 155*3117ece4Schristos ZSTD_freeCDict(cctx->localDict.cdict); 156*3117ece4Schristos ZSTD_memset(&cctx->localDict, 0, sizeof(cctx->localDict)); 157*3117ece4Schristos ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); 158*3117ece4Schristos cctx->cdict = NULL; 159*3117ece4Schristos } 160*3117ece4Schristos 161*3117ece4Schristos static size_t ZSTD_sizeof_localDict(ZSTD_localDict dict) 162*3117ece4Schristos { 163*3117ece4Schristos size_t const bufferSize = dict.dictBuffer != NULL ? dict.dictSize : 0; 164*3117ece4Schristos size_t const cdictSize = ZSTD_sizeof_CDict(dict.cdict); 165*3117ece4Schristos return bufferSize + cdictSize; 166*3117ece4Schristos } 167*3117ece4Schristos 168*3117ece4Schristos static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx) 169*3117ece4Schristos { 170*3117ece4Schristos assert(cctx != NULL); 171*3117ece4Schristos assert(cctx->staticSize == 0); 172*3117ece4Schristos ZSTD_clearAllDicts(cctx); 173*3117ece4Schristos #ifdef ZSTD_MULTITHREAD 174*3117ece4Schristos ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL; 175*3117ece4Schristos #endif 176*3117ece4Schristos ZSTD_cwksp_free(&cctx->workspace, cctx->customMem); 177*3117ece4Schristos } 178*3117ece4Schristos 179*3117ece4Schristos size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) 180*3117ece4Schristos { 181*3117ece4Schristos DEBUGLOG(3, "ZSTD_freeCCtx (address: %p)", (void*)cctx); 182*3117ece4Schristos if (cctx==NULL) return 0; /* support free on NULL */ 183*3117ece4Schristos RETURN_ERROR_IF(cctx->staticSize, memory_allocation, 184*3117ece4Schristos "not compatible with static CCtx"); 185*3117ece4Schristos { int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx); 186*3117ece4Schristos ZSTD_freeCCtxContent(cctx); 187*3117ece4Schristos if (!cctxInWorkspace) ZSTD_customFree(cctx, cctx->customMem); 188*3117ece4Schristos } 189*3117ece4Schristos return 0; 190*3117ece4Schristos } 191*3117ece4Schristos 192*3117ece4Schristos 193*3117ece4Schristos static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx) 194*3117ece4Schristos { 195*3117ece4Schristos #ifdef ZSTD_MULTITHREAD 196*3117ece4Schristos return ZSTDMT_sizeof_CCtx(cctx->mtctx); 197*3117ece4Schristos #else 198*3117ece4Schristos (void)cctx; 199*3117ece4Schristos return 0; 200*3117ece4Schristos #endif 201*3117ece4Schristos } 202*3117ece4Schristos 203*3117ece4Schristos 204*3117ece4Schristos size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) 205*3117ece4Schristos { 206*3117ece4Schristos if (cctx==NULL) return 0; /* support sizeof on NULL */ 207*3117ece4Schristos /* cctx may be in the workspace */ 208*3117ece4Schristos return (cctx->workspace.workspace == cctx ? 0 : sizeof(*cctx)) 209*3117ece4Schristos + ZSTD_cwksp_sizeof(&cctx->workspace) 210*3117ece4Schristos + ZSTD_sizeof_localDict(cctx->localDict) 211*3117ece4Schristos + ZSTD_sizeof_mtctx(cctx); 212*3117ece4Schristos } 213*3117ece4Schristos 214*3117ece4Schristos size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) 215*3117ece4Schristos { 216*3117ece4Schristos return ZSTD_sizeof_CCtx(zcs); /* same object */ 217*3117ece4Schristos } 218*3117ece4Schristos 219*3117ece4Schristos /* private API call, for dictBuilder only */ 220*3117ece4Schristos const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } 221*3117ece4Schristos 222*3117ece4Schristos /* Returns true if the strategy supports using a row based matchfinder */ 223*3117ece4Schristos static int ZSTD_rowMatchFinderSupported(const ZSTD_strategy strategy) { 224*3117ece4Schristos return (strategy >= ZSTD_greedy && strategy <= ZSTD_lazy2); 225*3117ece4Schristos } 226*3117ece4Schristos 227*3117ece4Schristos /* Returns true if the strategy and useRowMatchFinder mode indicate that we will use the row based matchfinder 228*3117ece4Schristos * for this compression. 229*3117ece4Schristos */ 230*3117ece4Schristos static int ZSTD_rowMatchFinderUsed(const ZSTD_strategy strategy, const ZSTD_paramSwitch_e mode) { 231*3117ece4Schristos assert(mode != ZSTD_ps_auto); 232*3117ece4Schristos return ZSTD_rowMatchFinderSupported(strategy) && (mode == ZSTD_ps_enable); 233*3117ece4Schristos } 234*3117ece4Schristos 235*3117ece4Schristos /* Returns row matchfinder usage given an initial mode and cParams */ 236*3117ece4Schristos static ZSTD_paramSwitch_e ZSTD_resolveRowMatchFinderMode(ZSTD_paramSwitch_e mode, 237*3117ece4Schristos const ZSTD_compressionParameters* const cParams) { 238*3117ece4Schristos #if defined(ZSTD_ARCH_X86_SSE2) || defined(ZSTD_ARCH_ARM_NEON) 239*3117ece4Schristos int const kHasSIMD128 = 1; 240*3117ece4Schristos #else 241*3117ece4Schristos int const kHasSIMD128 = 0; 242*3117ece4Schristos #endif 243*3117ece4Schristos if (mode != ZSTD_ps_auto) return mode; /* if requested enabled, but no SIMD, we still will use row matchfinder */ 244*3117ece4Schristos mode = ZSTD_ps_disable; 245*3117ece4Schristos if (!ZSTD_rowMatchFinderSupported(cParams->strategy)) return mode; 246*3117ece4Schristos if (kHasSIMD128) { 247*3117ece4Schristos if (cParams->windowLog > 14) mode = ZSTD_ps_enable; 248*3117ece4Schristos } else { 249*3117ece4Schristos if (cParams->windowLog > 17) mode = ZSTD_ps_enable; 250*3117ece4Schristos } 251*3117ece4Schristos return mode; 252*3117ece4Schristos } 253*3117ece4Schristos 254*3117ece4Schristos /* Returns block splitter usage (generally speaking, when using slower/stronger compression modes) */ 255*3117ece4Schristos static ZSTD_paramSwitch_e ZSTD_resolveBlockSplitterMode(ZSTD_paramSwitch_e mode, 256*3117ece4Schristos const ZSTD_compressionParameters* const cParams) { 257*3117ece4Schristos if (mode != ZSTD_ps_auto) return mode; 258*3117ece4Schristos return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 17) ? ZSTD_ps_enable : ZSTD_ps_disable; 259*3117ece4Schristos } 260*3117ece4Schristos 261*3117ece4Schristos /* Returns 1 if the arguments indicate that we should allocate a chainTable, 0 otherwise */ 262*3117ece4Schristos static int ZSTD_allocateChainTable(const ZSTD_strategy strategy, 263*3117ece4Schristos const ZSTD_paramSwitch_e useRowMatchFinder, 264*3117ece4Schristos const U32 forDDSDict) { 265*3117ece4Schristos assert(useRowMatchFinder != ZSTD_ps_auto); 266*3117ece4Schristos /* We always should allocate a chaintable if we are allocating a matchstate for a DDS dictionary matchstate. 267*3117ece4Schristos * We do not allocate a chaintable if we are using ZSTD_fast, or are using the row-based matchfinder. 268*3117ece4Schristos */ 269*3117ece4Schristos return forDDSDict || ((strategy != ZSTD_fast) && !ZSTD_rowMatchFinderUsed(strategy, useRowMatchFinder)); 270*3117ece4Schristos } 271*3117ece4Schristos 272*3117ece4Schristos /* Returns ZSTD_ps_enable if compression parameters are such that we should 273*3117ece4Schristos * enable long distance matching (wlog >= 27, strategy >= btopt). 274*3117ece4Schristos * Returns ZSTD_ps_disable otherwise. 275*3117ece4Schristos */ 276*3117ece4Schristos static ZSTD_paramSwitch_e ZSTD_resolveEnableLdm(ZSTD_paramSwitch_e mode, 277*3117ece4Schristos const ZSTD_compressionParameters* const cParams) { 278*3117ece4Schristos if (mode != ZSTD_ps_auto) return mode; 279*3117ece4Schristos return (cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27) ? ZSTD_ps_enable : ZSTD_ps_disable; 280*3117ece4Schristos } 281*3117ece4Schristos 282*3117ece4Schristos static int ZSTD_resolveExternalSequenceValidation(int mode) { 283*3117ece4Schristos return mode; 284*3117ece4Schristos } 285*3117ece4Schristos 286*3117ece4Schristos /* Resolves maxBlockSize to the default if no value is present. */ 287*3117ece4Schristos static size_t ZSTD_resolveMaxBlockSize(size_t maxBlockSize) { 288*3117ece4Schristos if (maxBlockSize == 0) { 289*3117ece4Schristos return ZSTD_BLOCKSIZE_MAX; 290*3117ece4Schristos } else { 291*3117ece4Schristos return maxBlockSize; 292*3117ece4Schristos } 293*3117ece4Schristos } 294*3117ece4Schristos 295*3117ece4Schristos static ZSTD_paramSwitch_e ZSTD_resolveExternalRepcodeSearch(ZSTD_paramSwitch_e value, int cLevel) { 296*3117ece4Schristos if (value != ZSTD_ps_auto) return value; 297*3117ece4Schristos if (cLevel < 10) { 298*3117ece4Schristos return ZSTD_ps_disable; 299*3117ece4Schristos } else { 300*3117ece4Schristos return ZSTD_ps_enable; 301*3117ece4Schristos } 302*3117ece4Schristos } 303*3117ece4Schristos 304*3117ece4Schristos /* Returns 1 if compression parameters are such that CDict hashtable and chaintable indices are tagged. 305*3117ece4Schristos * If so, the tags need to be removed in ZSTD_resetCCtx_byCopyingCDict. */ 306*3117ece4Schristos static int ZSTD_CDictIndicesAreTagged(const ZSTD_compressionParameters* const cParams) { 307*3117ece4Schristos return cParams->strategy == ZSTD_fast || cParams->strategy == ZSTD_dfast; 308*3117ece4Schristos } 309*3117ece4Schristos 310*3117ece4Schristos static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( 311*3117ece4Schristos ZSTD_compressionParameters cParams) 312*3117ece4Schristos { 313*3117ece4Schristos ZSTD_CCtx_params cctxParams; 314*3117ece4Schristos /* should not matter, as all cParams are presumed properly defined */ 315*3117ece4Schristos ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT); 316*3117ece4Schristos cctxParams.cParams = cParams; 317*3117ece4Schristos 318*3117ece4Schristos /* Adjust advanced params according to cParams */ 319*3117ece4Schristos cctxParams.ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams.ldmParams.enableLdm, &cParams); 320*3117ece4Schristos if (cctxParams.ldmParams.enableLdm == ZSTD_ps_enable) { 321*3117ece4Schristos ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cParams); 322*3117ece4Schristos assert(cctxParams.ldmParams.hashLog >= cctxParams.ldmParams.bucketSizeLog); 323*3117ece4Schristos assert(cctxParams.ldmParams.hashRateLog < 32); 324*3117ece4Schristos } 325*3117ece4Schristos cctxParams.useBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams.useBlockSplitter, &cParams); 326*3117ece4Schristos cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams); 327*3117ece4Schristos cctxParams.validateSequences = ZSTD_resolveExternalSequenceValidation(cctxParams.validateSequences); 328*3117ece4Schristos cctxParams.maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams.maxBlockSize); 329*3117ece4Schristos cctxParams.searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams.searchForExternalRepcodes, 330*3117ece4Schristos cctxParams.compressionLevel); 331*3117ece4Schristos assert(!ZSTD_checkCParams(cParams)); 332*3117ece4Schristos return cctxParams; 333*3117ece4Schristos } 334*3117ece4Schristos 335*3117ece4Schristos static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced( 336*3117ece4Schristos ZSTD_customMem customMem) 337*3117ece4Schristos { 338*3117ece4Schristos ZSTD_CCtx_params* params; 339*3117ece4Schristos if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; 340*3117ece4Schristos params = (ZSTD_CCtx_params*)ZSTD_customCalloc( 341*3117ece4Schristos sizeof(ZSTD_CCtx_params), customMem); 342*3117ece4Schristos if (!params) { return NULL; } 343*3117ece4Schristos ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); 344*3117ece4Schristos params->customMem = customMem; 345*3117ece4Schristos return params; 346*3117ece4Schristos } 347*3117ece4Schristos 348*3117ece4Schristos ZSTD_CCtx_params* ZSTD_createCCtxParams(void) 349*3117ece4Schristos { 350*3117ece4Schristos return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem); 351*3117ece4Schristos } 352*3117ece4Schristos 353*3117ece4Schristos size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) 354*3117ece4Schristos { 355*3117ece4Schristos if (params == NULL) { return 0; } 356*3117ece4Schristos ZSTD_customFree(params, params->customMem); 357*3117ece4Schristos return 0; 358*3117ece4Schristos } 359*3117ece4Schristos 360*3117ece4Schristos size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params) 361*3117ece4Schristos { 362*3117ece4Schristos return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); 363*3117ece4Schristos } 364*3117ece4Schristos 365*3117ece4Schristos size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) { 366*3117ece4Schristos RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); 367*3117ece4Schristos ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); 368*3117ece4Schristos cctxParams->compressionLevel = compressionLevel; 369*3117ece4Schristos cctxParams->fParams.contentSizeFlag = 1; 370*3117ece4Schristos return 0; 371*3117ece4Schristos } 372*3117ece4Schristos 373*3117ece4Schristos #define ZSTD_NO_CLEVEL 0 374*3117ece4Schristos 375*3117ece4Schristos /** 376*3117ece4Schristos * Initializes `cctxParams` from `params` and `compressionLevel`. 377*3117ece4Schristos * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL. 378*3117ece4Schristos */ 379*3117ece4Schristos static void 380*3117ece4Schristos ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, 381*3117ece4Schristos const ZSTD_parameters* params, 382*3117ece4Schristos int compressionLevel) 383*3117ece4Schristos { 384*3117ece4Schristos assert(!ZSTD_checkCParams(params->cParams)); 385*3117ece4Schristos ZSTD_memset(cctxParams, 0, sizeof(*cctxParams)); 386*3117ece4Schristos cctxParams->cParams = params->cParams; 387*3117ece4Schristos cctxParams->fParams = params->fParams; 388*3117ece4Schristos /* Should not matter, as all cParams are presumed properly defined. 389*3117ece4Schristos * But, set it for tracing anyway. 390*3117ece4Schristos */ 391*3117ece4Schristos cctxParams->compressionLevel = compressionLevel; 392*3117ece4Schristos cctxParams->useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams->useRowMatchFinder, ¶ms->cParams); 393*3117ece4Schristos cctxParams->useBlockSplitter = ZSTD_resolveBlockSplitterMode(cctxParams->useBlockSplitter, ¶ms->cParams); 394*3117ece4Schristos cctxParams->ldmParams.enableLdm = ZSTD_resolveEnableLdm(cctxParams->ldmParams.enableLdm, ¶ms->cParams); 395*3117ece4Schristos cctxParams->validateSequences = ZSTD_resolveExternalSequenceValidation(cctxParams->validateSequences); 396*3117ece4Schristos cctxParams->maxBlockSize = ZSTD_resolveMaxBlockSize(cctxParams->maxBlockSize); 397*3117ece4Schristos cctxParams->searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(cctxParams->searchForExternalRepcodes, compressionLevel); 398*3117ece4Schristos DEBUGLOG(4, "ZSTD_CCtxParams_init_internal: useRowMatchFinder=%d, useBlockSplitter=%d ldm=%d", 399*3117ece4Schristos cctxParams->useRowMatchFinder, cctxParams->useBlockSplitter, cctxParams->ldmParams.enableLdm); 400*3117ece4Schristos } 401*3117ece4Schristos 402*3117ece4Schristos size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) 403*3117ece4Schristos { 404*3117ece4Schristos RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!"); 405*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , ""); 406*3117ece4Schristos ZSTD_CCtxParams_init_internal(cctxParams, ¶ms, ZSTD_NO_CLEVEL); 407*3117ece4Schristos return 0; 408*3117ece4Schristos } 409*3117ece4Schristos 410*3117ece4Schristos /** 411*3117ece4Schristos * Sets cctxParams' cParams and fParams from params, but otherwise leaves them alone. 412*3117ece4Schristos * @param params Validated zstd parameters. 413*3117ece4Schristos */ 414*3117ece4Schristos static void ZSTD_CCtxParams_setZstdParams( 415*3117ece4Schristos ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params) 416*3117ece4Schristos { 417*3117ece4Schristos assert(!ZSTD_checkCParams(params->cParams)); 418*3117ece4Schristos cctxParams->cParams = params->cParams; 419*3117ece4Schristos cctxParams->fParams = params->fParams; 420*3117ece4Schristos /* Should not matter, as all cParams are presumed properly defined. 421*3117ece4Schristos * But, set it for tracing anyway. 422*3117ece4Schristos */ 423*3117ece4Schristos cctxParams->compressionLevel = ZSTD_NO_CLEVEL; 424*3117ece4Schristos } 425*3117ece4Schristos 426*3117ece4Schristos ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) 427*3117ece4Schristos { 428*3117ece4Schristos ZSTD_bounds bounds = { 0, 0, 0 }; 429*3117ece4Schristos 430*3117ece4Schristos switch(param) 431*3117ece4Schristos { 432*3117ece4Schristos case ZSTD_c_compressionLevel: 433*3117ece4Schristos bounds.lowerBound = ZSTD_minCLevel(); 434*3117ece4Schristos bounds.upperBound = ZSTD_maxCLevel(); 435*3117ece4Schristos return bounds; 436*3117ece4Schristos 437*3117ece4Schristos case ZSTD_c_windowLog: 438*3117ece4Schristos bounds.lowerBound = ZSTD_WINDOWLOG_MIN; 439*3117ece4Schristos bounds.upperBound = ZSTD_WINDOWLOG_MAX; 440*3117ece4Schristos return bounds; 441*3117ece4Schristos 442*3117ece4Schristos case ZSTD_c_hashLog: 443*3117ece4Schristos bounds.lowerBound = ZSTD_HASHLOG_MIN; 444*3117ece4Schristos bounds.upperBound = ZSTD_HASHLOG_MAX; 445*3117ece4Schristos return bounds; 446*3117ece4Schristos 447*3117ece4Schristos case ZSTD_c_chainLog: 448*3117ece4Schristos bounds.lowerBound = ZSTD_CHAINLOG_MIN; 449*3117ece4Schristos bounds.upperBound = ZSTD_CHAINLOG_MAX; 450*3117ece4Schristos return bounds; 451*3117ece4Schristos 452*3117ece4Schristos case ZSTD_c_searchLog: 453*3117ece4Schristos bounds.lowerBound = ZSTD_SEARCHLOG_MIN; 454*3117ece4Schristos bounds.upperBound = ZSTD_SEARCHLOG_MAX; 455*3117ece4Schristos return bounds; 456*3117ece4Schristos 457*3117ece4Schristos case ZSTD_c_minMatch: 458*3117ece4Schristos bounds.lowerBound = ZSTD_MINMATCH_MIN; 459*3117ece4Schristos bounds.upperBound = ZSTD_MINMATCH_MAX; 460*3117ece4Schristos return bounds; 461*3117ece4Schristos 462*3117ece4Schristos case ZSTD_c_targetLength: 463*3117ece4Schristos bounds.lowerBound = ZSTD_TARGETLENGTH_MIN; 464*3117ece4Schristos bounds.upperBound = ZSTD_TARGETLENGTH_MAX; 465*3117ece4Schristos return bounds; 466*3117ece4Schristos 467*3117ece4Schristos case ZSTD_c_strategy: 468*3117ece4Schristos bounds.lowerBound = ZSTD_STRATEGY_MIN; 469*3117ece4Schristos bounds.upperBound = ZSTD_STRATEGY_MAX; 470*3117ece4Schristos return bounds; 471*3117ece4Schristos 472*3117ece4Schristos case ZSTD_c_contentSizeFlag: 473*3117ece4Schristos bounds.lowerBound = 0; 474*3117ece4Schristos bounds.upperBound = 1; 475*3117ece4Schristos return bounds; 476*3117ece4Schristos 477*3117ece4Schristos case ZSTD_c_checksumFlag: 478*3117ece4Schristos bounds.lowerBound = 0; 479*3117ece4Schristos bounds.upperBound = 1; 480*3117ece4Schristos return bounds; 481*3117ece4Schristos 482*3117ece4Schristos case ZSTD_c_dictIDFlag: 483*3117ece4Schristos bounds.lowerBound = 0; 484*3117ece4Schristos bounds.upperBound = 1; 485*3117ece4Schristos return bounds; 486*3117ece4Schristos 487*3117ece4Schristos case ZSTD_c_nbWorkers: 488*3117ece4Schristos bounds.lowerBound = 0; 489*3117ece4Schristos #ifdef ZSTD_MULTITHREAD 490*3117ece4Schristos bounds.upperBound = ZSTDMT_NBWORKERS_MAX; 491*3117ece4Schristos #else 492*3117ece4Schristos bounds.upperBound = 0; 493*3117ece4Schristos #endif 494*3117ece4Schristos return bounds; 495*3117ece4Schristos 496*3117ece4Schristos case ZSTD_c_jobSize: 497*3117ece4Schristos bounds.lowerBound = 0; 498*3117ece4Schristos #ifdef ZSTD_MULTITHREAD 499*3117ece4Schristos bounds.upperBound = ZSTDMT_JOBSIZE_MAX; 500*3117ece4Schristos #else 501*3117ece4Schristos bounds.upperBound = 0; 502*3117ece4Schristos #endif 503*3117ece4Schristos return bounds; 504*3117ece4Schristos 505*3117ece4Schristos case ZSTD_c_overlapLog: 506*3117ece4Schristos #ifdef ZSTD_MULTITHREAD 507*3117ece4Schristos bounds.lowerBound = ZSTD_OVERLAPLOG_MIN; 508*3117ece4Schristos bounds.upperBound = ZSTD_OVERLAPLOG_MAX; 509*3117ece4Schristos #else 510*3117ece4Schristos bounds.lowerBound = 0; 511*3117ece4Schristos bounds.upperBound = 0; 512*3117ece4Schristos #endif 513*3117ece4Schristos return bounds; 514*3117ece4Schristos 515*3117ece4Schristos case ZSTD_c_enableDedicatedDictSearch: 516*3117ece4Schristos bounds.lowerBound = 0; 517*3117ece4Schristos bounds.upperBound = 1; 518*3117ece4Schristos return bounds; 519*3117ece4Schristos 520*3117ece4Schristos case ZSTD_c_enableLongDistanceMatching: 521*3117ece4Schristos bounds.lowerBound = (int)ZSTD_ps_auto; 522*3117ece4Schristos bounds.upperBound = (int)ZSTD_ps_disable; 523*3117ece4Schristos return bounds; 524*3117ece4Schristos 525*3117ece4Schristos case ZSTD_c_ldmHashLog: 526*3117ece4Schristos bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN; 527*3117ece4Schristos bounds.upperBound = ZSTD_LDM_HASHLOG_MAX; 528*3117ece4Schristos return bounds; 529*3117ece4Schristos 530*3117ece4Schristos case ZSTD_c_ldmMinMatch: 531*3117ece4Schristos bounds.lowerBound = ZSTD_LDM_MINMATCH_MIN; 532*3117ece4Schristos bounds.upperBound = ZSTD_LDM_MINMATCH_MAX; 533*3117ece4Schristos return bounds; 534*3117ece4Schristos 535*3117ece4Schristos case ZSTD_c_ldmBucketSizeLog: 536*3117ece4Schristos bounds.lowerBound = ZSTD_LDM_BUCKETSIZELOG_MIN; 537*3117ece4Schristos bounds.upperBound = ZSTD_LDM_BUCKETSIZELOG_MAX; 538*3117ece4Schristos return bounds; 539*3117ece4Schristos 540*3117ece4Schristos case ZSTD_c_ldmHashRateLog: 541*3117ece4Schristos bounds.lowerBound = ZSTD_LDM_HASHRATELOG_MIN; 542*3117ece4Schristos bounds.upperBound = ZSTD_LDM_HASHRATELOG_MAX; 543*3117ece4Schristos return bounds; 544*3117ece4Schristos 545*3117ece4Schristos /* experimental parameters */ 546*3117ece4Schristos case ZSTD_c_rsyncable: 547*3117ece4Schristos bounds.lowerBound = 0; 548*3117ece4Schristos bounds.upperBound = 1; 549*3117ece4Schristos return bounds; 550*3117ece4Schristos 551*3117ece4Schristos case ZSTD_c_forceMaxWindow : 552*3117ece4Schristos bounds.lowerBound = 0; 553*3117ece4Schristos bounds.upperBound = 1; 554*3117ece4Schristos return bounds; 555*3117ece4Schristos 556*3117ece4Schristos case ZSTD_c_format: 557*3117ece4Schristos ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless); 558*3117ece4Schristos bounds.lowerBound = ZSTD_f_zstd1; 559*3117ece4Schristos bounds.upperBound = ZSTD_f_zstd1_magicless; /* note : how to ensure at compile time that this is the highest value enum ? */ 560*3117ece4Schristos return bounds; 561*3117ece4Schristos 562*3117ece4Schristos case ZSTD_c_forceAttachDict: 563*3117ece4Schristos ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceLoad); 564*3117ece4Schristos bounds.lowerBound = ZSTD_dictDefaultAttach; 565*3117ece4Schristos bounds.upperBound = ZSTD_dictForceLoad; /* note : how to ensure at compile time that this is the highest value enum ? */ 566*3117ece4Schristos return bounds; 567*3117ece4Schristos 568*3117ece4Schristos case ZSTD_c_literalCompressionMode: 569*3117ece4Schristos ZSTD_STATIC_ASSERT(ZSTD_ps_auto < ZSTD_ps_enable && ZSTD_ps_enable < ZSTD_ps_disable); 570*3117ece4Schristos bounds.lowerBound = (int)ZSTD_ps_auto; 571*3117ece4Schristos bounds.upperBound = (int)ZSTD_ps_disable; 572*3117ece4Schristos return bounds; 573*3117ece4Schristos 574*3117ece4Schristos case ZSTD_c_targetCBlockSize: 575*3117ece4Schristos bounds.lowerBound = ZSTD_TARGETCBLOCKSIZE_MIN; 576*3117ece4Schristos bounds.upperBound = ZSTD_TARGETCBLOCKSIZE_MAX; 577*3117ece4Schristos return bounds; 578*3117ece4Schristos 579*3117ece4Schristos case ZSTD_c_srcSizeHint: 580*3117ece4Schristos bounds.lowerBound = ZSTD_SRCSIZEHINT_MIN; 581*3117ece4Schristos bounds.upperBound = ZSTD_SRCSIZEHINT_MAX; 582*3117ece4Schristos return bounds; 583*3117ece4Schristos 584*3117ece4Schristos case ZSTD_c_stableInBuffer: 585*3117ece4Schristos case ZSTD_c_stableOutBuffer: 586*3117ece4Schristos bounds.lowerBound = (int)ZSTD_bm_buffered; 587*3117ece4Schristos bounds.upperBound = (int)ZSTD_bm_stable; 588*3117ece4Schristos return bounds; 589*3117ece4Schristos 590*3117ece4Schristos case ZSTD_c_blockDelimiters: 591*3117ece4Schristos bounds.lowerBound = (int)ZSTD_sf_noBlockDelimiters; 592*3117ece4Schristos bounds.upperBound = (int)ZSTD_sf_explicitBlockDelimiters; 593*3117ece4Schristos return bounds; 594*3117ece4Schristos 595*3117ece4Schristos case ZSTD_c_validateSequences: 596*3117ece4Schristos bounds.lowerBound = 0; 597*3117ece4Schristos bounds.upperBound = 1; 598*3117ece4Schristos return bounds; 599*3117ece4Schristos 600*3117ece4Schristos case ZSTD_c_useBlockSplitter: 601*3117ece4Schristos bounds.lowerBound = (int)ZSTD_ps_auto; 602*3117ece4Schristos bounds.upperBound = (int)ZSTD_ps_disable; 603*3117ece4Schristos return bounds; 604*3117ece4Schristos 605*3117ece4Schristos case ZSTD_c_useRowMatchFinder: 606*3117ece4Schristos bounds.lowerBound = (int)ZSTD_ps_auto; 607*3117ece4Schristos bounds.upperBound = (int)ZSTD_ps_disable; 608*3117ece4Schristos return bounds; 609*3117ece4Schristos 610*3117ece4Schristos case ZSTD_c_deterministicRefPrefix: 611*3117ece4Schristos bounds.lowerBound = 0; 612*3117ece4Schristos bounds.upperBound = 1; 613*3117ece4Schristos return bounds; 614*3117ece4Schristos 615*3117ece4Schristos case ZSTD_c_prefetchCDictTables: 616*3117ece4Schristos bounds.lowerBound = (int)ZSTD_ps_auto; 617*3117ece4Schristos bounds.upperBound = (int)ZSTD_ps_disable; 618*3117ece4Schristos return bounds; 619*3117ece4Schristos 620*3117ece4Schristos case ZSTD_c_enableSeqProducerFallback: 621*3117ece4Schristos bounds.lowerBound = 0; 622*3117ece4Schristos bounds.upperBound = 1; 623*3117ece4Schristos return bounds; 624*3117ece4Schristos 625*3117ece4Schristos case ZSTD_c_maxBlockSize: 626*3117ece4Schristos bounds.lowerBound = ZSTD_BLOCKSIZE_MAX_MIN; 627*3117ece4Schristos bounds.upperBound = ZSTD_BLOCKSIZE_MAX; 628*3117ece4Schristos return bounds; 629*3117ece4Schristos 630*3117ece4Schristos case ZSTD_c_searchForExternalRepcodes: 631*3117ece4Schristos bounds.lowerBound = (int)ZSTD_ps_auto; 632*3117ece4Schristos bounds.upperBound = (int)ZSTD_ps_disable; 633*3117ece4Schristos return bounds; 634*3117ece4Schristos 635*3117ece4Schristos default: 636*3117ece4Schristos bounds.error = ERROR(parameter_unsupported); 637*3117ece4Schristos return bounds; 638*3117ece4Schristos } 639*3117ece4Schristos } 640*3117ece4Schristos 641*3117ece4Schristos /* ZSTD_cParam_clampBounds: 642*3117ece4Schristos * Clamps the value into the bounded range. 643*3117ece4Schristos */ 644*3117ece4Schristos static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value) 645*3117ece4Schristos { 646*3117ece4Schristos ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); 647*3117ece4Schristos if (ZSTD_isError(bounds.error)) return bounds.error; 648*3117ece4Schristos if (*value < bounds.lowerBound) *value = bounds.lowerBound; 649*3117ece4Schristos if (*value > bounds.upperBound) *value = bounds.upperBound; 650*3117ece4Schristos return 0; 651*3117ece4Schristos } 652*3117ece4Schristos 653*3117ece4Schristos #define BOUNDCHECK(cParam, val) \ 654*3117ece4Schristos do { \ 655*3117ece4Schristos RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \ 656*3117ece4Schristos parameter_outOfBound, "Param out of bounds"); \ 657*3117ece4Schristos } while (0) 658*3117ece4Schristos 659*3117ece4Schristos 660*3117ece4Schristos static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) 661*3117ece4Schristos { 662*3117ece4Schristos switch(param) 663*3117ece4Schristos { 664*3117ece4Schristos case ZSTD_c_compressionLevel: 665*3117ece4Schristos case ZSTD_c_hashLog: 666*3117ece4Schristos case ZSTD_c_chainLog: 667*3117ece4Schristos case ZSTD_c_searchLog: 668*3117ece4Schristos case ZSTD_c_minMatch: 669*3117ece4Schristos case ZSTD_c_targetLength: 670*3117ece4Schristos case ZSTD_c_strategy: 671*3117ece4Schristos return 1; 672*3117ece4Schristos 673*3117ece4Schristos case ZSTD_c_format: 674*3117ece4Schristos case ZSTD_c_windowLog: 675*3117ece4Schristos case ZSTD_c_contentSizeFlag: 676*3117ece4Schristos case ZSTD_c_checksumFlag: 677*3117ece4Schristos case ZSTD_c_dictIDFlag: 678*3117ece4Schristos case ZSTD_c_forceMaxWindow : 679*3117ece4Schristos case ZSTD_c_nbWorkers: 680*3117ece4Schristos case ZSTD_c_jobSize: 681*3117ece4Schristos case ZSTD_c_overlapLog: 682*3117ece4Schristos case ZSTD_c_rsyncable: 683*3117ece4Schristos case ZSTD_c_enableDedicatedDictSearch: 684*3117ece4Schristos case ZSTD_c_enableLongDistanceMatching: 685*3117ece4Schristos case ZSTD_c_ldmHashLog: 686*3117ece4Schristos case ZSTD_c_ldmMinMatch: 687*3117ece4Schristos case ZSTD_c_ldmBucketSizeLog: 688*3117ece4Schristos case ZSTD_c_ldmHashRateLog: 689*3117ece4Schristos case ZSTD_c_forceAttachDict: 690*3117ece4Schristos case ZSTD_c_literalCompressionMode: 691*3117ece4Schristos case ZSTD_c_targetCBlockSize: 692*3117ece4Schristos case ZSTD_c_srcSizeHint: 693*3117ece4Schristos case ZSTD_c_stableInBuffer: 694*3117ece4Schristos case ZSTD_c_stableOutBuffer: 695*3117ece4Schristos case ZSTD_c_blockDelimiters: 696*3117ece4Schristos case ZSTD_c_validateSequences: 697*3117ece4Schristos case ZSTD_c_useBlockSplitter: 698*3117ece4Schristos case ZSTD_c_useRowMatchFinder: 699*3117ece4Schristos case ZSTD_c_deterministicRefPrefix: 700*3117ece4Schristos case ZSTD_c_prefetchCDictTables: 701*3117ece4Schristos case ZSTD_c_enableSeqProducerFallback: 702*3117ece4Schristos case ZSTD_c_maxBlockSize: 703*3117ece4Schristos case ZSTD_c_searchForExternalRepcodes: 704*3117ece4Schristos default: 705*3117ece4Schristos return 0; 706*3117ece4Schristos } 707*3117ece4Schristos } 708*3117ece4Schristos 709*3117ece4Schristos size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) 710*3117ece4Schristos { 711*3117ece4Schristos DEBUGLOG(4, "ZSTD_CCtx_setParameter (%i, %i)", (int)param, value); 712*3117ece4Schristos if (cctx->streamStage != zcss_init) { 713*3117ece4Schristos if (ZSTD_isUpdateAuthorized(param)) { 714*3117ece4Schristos cctx->cParamsChanged = 1; 715*3117ece4Schristos } else { 716*3117ece4Schristos RETURN_ERROR(stage_wrong, "can only set params in cctx init stage"); 717*3117ece4Schristos } } 718*3117ece4Schristos 719*3117ece4Schristos switch(param) 720*3117ece4Schristos { 721*3117ece4Schristos case ZSTD_c_nbWorkers: 722*3117ece4Schristos RETURN_ERROR_IF((value!=0) && cctx->staticSize, parameter_unsupported, 723*3117ece4Schristos "MT not compatible with static alloc"); 724*3117ece4Schristos break; 725*3117ece4Schristos 726*3117ece4Schristos case ZSTD_c_compressionLevel: 727*3117ece4Schristos case ZSTD_c_windowLog: 728*3117ece4Schristos case ZSTD_c_hashLog: 729*3117ece4Schristos case ZSTD_c_chainLog: 730*3117ece4Schristos case ZSTD_c_searchLog: 731*3117ece4Schristos case ZSTD_c_minMatch: 732*3117ece4Schristos case ZSTD_c_targetLength: 733*3117ece4Schristos case ZSTD_c_strategy: 734*3117ece4Schristos case ZSTD_c_ldmHashRateLog: 735*3117ece4Schristos case ZSTD_c_format: 736*3117ece4Schristos case ZSTD_c_contentSizeFlag: 737*3117ece4Schristos case ZSTD_c_checksumFlag: 738*3117ece4Schristos case ZSTD_c_dictIDFlag: 739*3117ece4Schristos case ZSTD_c_forceMaxWindow: 740*3117ece4Schristos case ZSTD_c_forceAttachDict: 741*3117ece4Schristos case ZSTD_c_literalCompressionMode: 742*3117ece4Schristos case ZSTD_c_jobSize: 743*3117ece4Schristos case ZSTD_c_overlapLog: 744*3117ece4Schristos case ZSTD_c_rsyncable: 745*3117ece4Schristos case ZSTD_c_enableDedicatedDictSearch: 746*3117ece4Schristos case ZSTD_c_enableLongDistanceMatching: 747*3117ece4Schristos case ZSTD_c_ldmHashLog: 748*3117ece4Schristos case ZSTD_c_ldmMinMatch: 749*3117ece4Schristos case ZSTD_c_ldmBucketSizeLog: 750*3117ece4Schristos case ZSTD_c_targetCBlockSize: 751*3117ece4Schristos case ZSTD_c_srcSizeHint: 752*3117ece4Schristos case ZSTD_c_stableInBuffer: 753*3117ece4Schristos case ZSTD_c_stableOutBuffer: 754*3117ece4Schristos case ZSTD_c_blockDelimiters: 755*3117ece4Schristos case ZSTD_c_validateSequences: 756*3117ece4Schristos case ZSTD_c_useBlockSplitter: 757*3117ece4Schristos case ZSTD_c_useRowMatchFinder: 758*3117ece4Schristos case ZSTD_c_deterministicRefPrefix: 759*3117ece4Schristos case ZSTD_c_prefetchCDictTables: 760*3117ece4Schristos case ZSTD_c_enableSeqProducerFallback: 761*3117ece4Schristos case ZSTD_c_maxBlockSize: 762*3117ece4Schristos case ZSTD_c_searchForExternalRepcodes: 763*3117ece4Schristos break; 764*3117ece4Schristos 765*3117ece4Schristos default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); 766*3117ece4Schristos } 767*3117ece4Schristos return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value); 768*3117ece4Schristos } 769*3117ece4Schristos 770*3117ece4Schristos size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, 771*3117ece4Schristos ZSTD_cParameter param, int value) 772*3117ece4Schristos { 773*3117ece4Schristos DEBUGLOG(4, "ZSTD_CCtxParams_setParameter (%i, %i)", (int)param, value); 774*3117ece4Schristos switch(param) 775*3117ece4Schristos { 776*3117ece4Schristos case ZSTD_c_format : 777*3117ece4Schristos BOUNDCHECK(ZSTD_c_format, value); 778*3117ece4Schristos CCtxParams->format = (ZSTD_format_e)value; 779*3117ece4Schristos return (size_t)CCtxParams->format; 780*3117ece4Schristos 781*3117ece4Schristos case ZSTD_c_compressionLevel : { 782*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); 783*3117ece4Schristos if (value == 0) 784*3117ece4Schristos CCtxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ 785*3117ece4Schristos else 786*3117ece4Schristos CCtxParams->compressionLevel = value; 787*3117ece4Schristos if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel; 788*3117ece4Schristos return 0; /* return type (size_t) cannot represent negative values */ 789*3117ece4Schristos } 790*3117ece4Schristos 791*3117ece4Schristos case ZSTD_c_windowLog : 792*3117ece4Schristos if (value!=0) /* 0 => use default */ 793*3117ece4Schristos BOUNDCHECK(ZSTD_c_windowLog, value); 794*3117ece4Schristos CCtxParams->cParams.windowLog = (U32)value; 795*3117ece4Schristos return CCtxParams->cParams.windowLog; 796*3117ece4Schristos 797*3117ece4Schristos case ZSTD_c_hashLog : 798*3117ece4Schristos if (value!=0) /* 0 => use default */ 799*3117ece4Schristos BOUNDCHECK(ZSTD_c_hashLog, value); 800*3117ece4Schristos CCtxParams->cParams.hashLog = (U32)value; 801*3117ece4Schristos return CCtxParams->cParams.hashLog; 802*3117ece4Schristos 803*3117ece4Schristos case ZSTD_c_chainLog : 804*3117ece4Schristos if (value!=0) /* 0 => use default */ 805*3117ece4Schristos BOUNDCHECK(ZSTD_c_chainLog, value); 806*3117ece4Schristos CCtxParams->cParams.chainLog = (U32)value; 807*3117ece4Schristos return CCtxParams->cParams.chainLog; 808*3117ece4Schristos 809*3117ece4Schristos case ZSTD_c_searchLog : 810*3117ece4Schristos if (value!=0) /* 0 => use default */ 811*3117ece4Schristos BOUNDCHECK(ZSTD_c_searchLog, value); 812*3117ece4Schristos CCtxParams->cParams.searchLog = (U32)value; 813*3117ece4Schristos return (size_t)value; 814*3117ece4Schristos 815*3117ece4Schristos case ZSTD_c_minMatch : 816*3117ece4Schristos if (value!=0) /* 0 => use default */ 817*3117ece4Schristos BOUNDCHECK(ZSTD_c_minMatch, value); 818*3117ece4Schristos CCtxParams->cParams.minMatch = (U32)value; 819*3117ece4Schristos return CCtxParams->cParams.minMatch; 820*3117ece4Schristos 821*3117ece4Schristos case ZSTD_c_targetLength : 822*3117ece4Schristos BOUNDCHECK(ZSTD_c_targetLength, value); 823*3117ece4Schristos CCtxParams->cParams.targetLength = (U32)value; 824*3117ece4Schristos return CCtxParams->cParams.targetLength; 825*3117ece4Schristos 826*3117ece4Schristos case ZSTD_c_strategy : 827*3117ece4Schristos if (value!=0) /* 0 => use default */ 828*3117ece4Schristos BOUNDCHECK(ZSTD_c_strategy, value); 829*3117ece4Schristos CCtxParams->cParams.strategy = (ZSTD_strategy)value; 830*3117ece4Schristos return (size_t)CCtxParams->cParams.strategy; 831*3117ece4Schristos 832*3117ece4Schristos case ZSTD_c_contentSizeFlag : 833*3117ece4Schristos /* Content size written in frame header _when known_ (default:1) */ 834*3117ece4Schristos DEBUGLOG(4, "set content size flag = %u", (value!=0)); 835*3117ece4Schristos CCtxParams->fParams.contentSizeFlag = value != 0; 836*3117ece4Schristos return (size_t)CCtxParams->fParams.contentSizeFlag; 837*3117ece4Schristos 838*3117ece4Schristos case ZSTD_c_checksumFlag : 839*3117ece4Schristos /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ 840*3117ece4Schristos CCtxParams->fParams.checksumFlag = value != 0; 841*3117ece4Schristos return (size_t)CCtxParams->fParams.checksumFlag; 842*3117ece4Schristos 843*3117ece4Schristos case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ 844*3117ece4Schristos DEBUGLOG(4, "set dictIDFlag = %u", (value!=0)); 845*3117ece4Schristos CCtxParams->fParams.noDictIDFlag = !value; 846*3117ece4Schristos return !CCtxParams->fParams.noDictIDFlag; 847*3117ece4Schristos 848*3117ece4Schristos case ZSTD_c_forceMaxWindow : 849*3117ece4Schristos CCtxParams->forceWindow = (value != 0); 850*3117ece4Schristos return (size_t)CCtxParams->forceWindow; 851*3117ece4Schristos 852*3117ece4Schristos case ZSTD_c_forceAttachDict : { 853*3117ece4Schristos const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value; 854*3117ece4Schristos BOUNDCHECK(ZSTD_c_forceAttachDict, (int)pref); 855*3117ece4Schristos CCtxParams->attachDictPref = pref; 856*3117ece4Schristos return CCtxParams->attachDictPref; 857*3117ece4Schristos } 858*3117ece4Schristos 859*3117ece4Schristos case ZSTD_c_literalCompressionMode : { 860*3117ece4Schristos const ZSTD_paramSwitch_e lcm = (ZSTD_paramSwitch_e)value; 861*3117ece4Schristos BOUNDCHECK(ZSTD_c_literalCompressionMode, (int)lcm); 862*3117ece4Schristos CCtxParams->literalCompressionMode = lcm; 863*3117ece4Schristos return CCtxParams->literalCompressionMode; 864*3117ece4Schristos } 865*3117ece4Schristos 866*3117ece4Schristos case ZSTD_c_nbWorkers : 867*3117ece4Schristos #ifndef ZSTD_MULTITHREAD 868*3117ece4Schristos RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 869*3117ece4Schristos return 0; 870*3117ece4Schristos #else 871*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); 872*3117ece4Schristos CCtxParams->nbWorkers = value; 873*3117ece4Schristos return (size_t)(CCtxParams->nbWorkers); 874*3117ece4Schristos #endif 875*3117ece4Schristos 876*3117ece4Schristos case ZSTD_c_jobSize : 877*3117ece4Schristos #ifndef ZSTD_MULTITHREAD 878*3117ece4Schristos RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 879*3117ece4Schristos return 0; 880*3117ece4Schristos #else 881*3117ece4Schristos /* Adjust to the minimum non-default value. */ 882*3117ece4Schristos if (value != 0 && value < ZSTDMT_JOBSIZE_MIN) 883*3117ece4Schristos value = ZSTDMT_JOBSIZE_MIN; 884*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), ""); 885*3117ece4Schristos assert(value >= 0); 886*3117ece4Schristos CCtxParams->jobSize = value; 887*3117ece4Schristos return CCtxParams->jobSize; 888*3117ece4Schristos #endif 889*3117ece4Schristos 890*3117ece4Schristos case ZSTD_c_overlapLog : 891*3117ece4Schristos #ifndef ZSTD_MULTITHREAD 892*3117ece4Schristos RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 893*3117ece4Schristos return 0; 894*3117ece4Schristos #else 895*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), ""); 896*3117ece4Schristos CCtxParams->overlapLog = value; 897*3117ece4Schristos return (size_t)CCtxParams->overlapLog; 898*3117ece4Schristos #endif 899*3117ece4Schristos 900*3117ece4Schristos case ZSTD_c_rsyncable : 901*3117ece4Schristos #ifndef ZSTD_MULTITHREAD 902*3117ece4Schristos RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 903*3117ece4Schristos return 0; 904*3117ece4Schristos #else 905*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value), ""); 906*3117ece4Schristos CCtxParams->rsyncable = value; 907*3117ece4Schristos return (size_t)CCtxParams->rsyncable; 908*3117ece4Schristos #endif 909*3117ece4Schristos 910*3117ece4Schristos case ZSTD_c_enableDedicatedDictSearch : 911*3117ece4Schristos CCtxParams->enableDedicatedDictSearch = (value!=0); 912*3117ece4Schristos return (size_t)CCtxParams->enableDedicatedDictSearch; 913*3117ece4Schristos 914*3117ece4Schristos case ZSTD_c_enableLongDistanceMatching : 915*3117ece4Schristos BOUNDCHECK(ZSTD_c_enableLongDistanceMatching, value); 916*3117ece4Schristos CCtxParams->ldmParams.enableLdm = (ZSTD_paramSwitch_e)value; 917*3117ece4Schristos return CCtxParams->ldmParams.enableLdm; 918*3117ece4Schristos 919*3117ece4Schristos case ZSTD_c_ldmHashLog : 920*3117ece4Schristos if (value!=0) /* 0 ==> auto */ 921*3117ece4Schristos BOUNDCHECK(ZSTD_c_ldmHashLog, value); 922*3117ece4Schristos CCtxParams->ldmParams.hashLog = (U32)value; 923*3117ece4Schristos return CCtxParams->ldmParams.hashLog; 924*3117ece4Schristos 925*3117ece4Schristos case ZSTD_c_ldmMinMatch : 926*3117ece4Schristos if (value!=0) /* 0 ==> default */ 927*3117ece4Schristos BOUNDCHECK(ZSTD_c_ldmMinMatch, value); 928*3117ece4Schristos CCtxParams->ldmParams.minMatchLength = (U32)value; 929*3117ece4Schristos return CCtxParams->ldmParams.minMatchLength; 930*3117ece4Schristos 931*3117ece4Schristos case ZSTD_c_ldmBucketSizeLog : 932*3117ece4Schristos if (value!=0) /* 0 ==> default */ 933*3117ece4Schristos BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value); 934*3117ece4Schristos CCtxParams->ldmParams.bucketSizeLog = (U32)value; 935*3117ece4Schristos return CCtxParams->ldmParams.bucketSizeLog; 936*3117ece4Schristos 937*3117ece4Schristos case ZSTD_c_ldmHashRateLog : 938*3117ece4Schristos if (value!=0) /* 0 ==> default */ 939*3117ece4Schristos BOUNDCHECK(ZSTD_c_ldmHashRateLog, value); 940*3117ece4Schristos CCtxParams->ldmParams.hashRateLog = (U32)value; 941*3117ece4Schristos return CCtxParams->ldmParams.hashRateLog; 942*3117ece4Schristos 943*3117ece4Schristos case ZSTD_c_targetCBlockSize : 944*3117ece4Schristos if (value!=0) { /* 0 ==> default */ 945*3117ece4Schristos value = MAX(value, ZSTD_TARGETCBLOCKSIZE_MIN); 946*3117ece4Schristos BOUNDCHECK(ZSTD_c_targetCBlockSize, value); 947*3117ece4Schristos } 948*3117ece4Schristos CCtxParams->targetCBlockSize = (U32)value; 949*3117ece4Schristos return CCtxParams->targetCBlockSize; 950*3117ece4Schristos 951*3117ece4Schristos case ZSTD_c_srcSizeHint : 952*3117ece4Schristos if (value!=0) /* 0 ==> default */ 953*3117ece4Schristos BOUNDCHECK(ZSTD_c_srcSizeHint, value); 954*3117ece4Schristos CCtxParams->srcSizeHint = value; 955*3117ece4Schristos return (size_t)CCtxParams->srcSizeHint; 956*3117ece4Schristos 957*3117ece4Schristos case ZSTD_c_stableInBuffer: 958*3117ece4Schristos BOUNDCHECK(ZSTD_c_stableInBuffer, value); 959*3117ece4Schristos CCtxParams->inBufferMode = (ZSTD_bufferMode_e)value; 960*3117ece4Schristos return CCtxParams->inBufferMode; 961*3117ece4Schristos 962*3117ece4Schristos case ZSTD_c_stableOutBuffer: 963*3117ece4Schristos BOUNDCHECK(ZSTD_c_stableOutBuffer, value); 964*3117ece4Schristos CCtxParams->outBufferMode = (ZSTD_bufferMode_e)value; 965*3117ece4Schristos return CCtxParams->outBufferMode; 966*3117ece4Schristos 967*3117ece4Schristos case ZSTD_c_blockDelimiters: 968*3117ece4Schristos BOUNDCHECK(ZSTD_c_blockDelimiters, value); 969*3117ece4Schristos CCtxParams->blockDelimiters = (ZSTD_sequenceFormat_e)value; 970*3117ece4Schristos return CCtxParams->blockDelimiters; 971*3117ece4Schristos 972*3117ece4Schristos case ZSTD_c_validateSequences: 973*3117ece4Schristos BOUNDCHECK(ZSTD_c_validateSequences, value); 974*3117ece4Schristos CCtxParams->validateSequences = value; 975*3117ece4Schristos return (size_t)CCtxParams->validateSequences; 976*3117ece4Schristos 977*3117ece4Schristos case ZSTD_c_useBlockSplitter: 978*3117ece4Schristos BOUNDCHECK(ZSTD_c_useBlockSplitter, value); 979*3117ece4Schristos CCtxParams->useBlockSplitter = (ZSTD_paramSwitch_e)value; 980*3117ece4Schristos return CCtxParams->useBlockSplitter; 981*3117ece4Schristos 982*3117ece4Schristos case ZSTD_c_useRowMatchFinder: 983*3117ece4Schristos BOUNDCHECK(ZSTD_c_useRowMatchFinder, value); 984*3117ece4Schristos CCtxParams->useRowMatchFinder = (ZSTD_paramSwitch_e)value; 985*3117ece4Schristos return CCtxParams->useRowMatchFinder; 986*3117ece4Schristos 987*3117ece4Schristos case ZSTD_c_deterministicRefPrefix: 988*3117ece4Schristos BOUNDCHECK(ZSTD_c_deterministicRefPrefix, value); 989*3117ece4Schristos CCtxParams->deterministicRefPrefix = !!value; 990*3117ece4Schristos return (size_t)CCtxParams->deterministicRefPrefix; 991*3117ece4Schristos 992*3117ece4Schristos case ZSTD_c_prefetchCDictTables: 993*3117ece4Schristos BOUNDCHECK(ZSTD_c_prefetchCDictTables, value); 994*3117ece4Schristos CCtxParams->prefetchCDictTables = (ZSTD_paramSwitch_e)value; 995*3117ece4Schristos return CCtxParams->prefetchCDictTables; 996*3117ece4Schristos 997*3117ece4Schristos case ZSTD_c_enableSeqProducerFallback: 998*3117ece4Schristos BOUNDCHECK(ZSTD_c_enableSeqProducerFallback, value); 999*3117ece4Schristos CCtxParams->enableMatchFinderFallback = value; 1000*3117ece4Schristos return (size_t)CCtxParams->enableMatchFinderFallback; 1001*3117ece4Schristos 1002*3117ece4Schristos case ZSTD_c_maxBlockSize: 1003*3117ece4Schristos if (value!=0) /* 0 ==> default */ 1004*3117ece4Schristos BOUNDCHECK(ZSTD_c_maxBlockSize, value); 1005*3117ece4Schristos CCtxParams->maxBlockSize = value; 1006*3117ece4Schristos return CCtxParams->maxBlockSize; 1007*3117ece4Schristos 1008*3117ece4Schristos case ZSTD_c_searchForExternalRepcodes: 1009*3117ece4Schristos BOUNDCHECK(ZSTD_c_searchForExternalRepcodes, value); 1010*3117ece4Schristos CCtxParams->searchForExternalRepcodes = (ZSTD_paramSwitch_e)value; 1011*3117ece4Schristos return CCtxParams->searchForExternalRepcodes; 1012*3117ece4Schristos 1013*3117ece4Schristos default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); 1014*3117ece4Schristos } 1015*3117ece4Schristos } 1016*3117ece4Schristos 1017*3117ece4Schristos size_t ZSTD_CCtx_getParameter(ZSTD_CCtx const* cctx, ZSTD_cParameter param, int* value) 1018*3117ece4Schristos { 1019*3117ece4Schristos return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value); 1020*3117ece4Schristos } 1021*3117ece4Schristos 1022*3117ece4Schristos size_t ZSTD_CCtxParams_getParameter( 1023*3117ece4Schristos ZSTD_CCtx_params const* CCtxParams, ZSTD_cParameter param, int* value) 1024*3117ece4Schristos { 1025*3117ece4Schristos switch(param) 1026*3117ece4Schristos { 1027*3117ece4Schristos case ZSTD_c_format : 1028*3117ece4Schristos *value = CCtxParams->format; 1029*3117ece4Schristos break; 1030*3117ece4Schristos case ZSTD_c_compressionLevel : 1031*3117ece4Schristos *value = CCtxParams->compressionLevel; 1032*3117ece4Schristos break; 1033*3117ece4Schristos case ZSTD_c_windowLog : 1034*3117ece4Schristos *value = (int)CCtxParams->cParams.windowLog; 1035*3117ece4Schristos break; 1036*3117ece4Schristos case ZSTD_c_hashLog : 1037*3117ece4Schristos *value = (int)CCtxParams->cParams.hashLog; 1038*3117ece4Schristos break; 1039*3117ece4Schristos case ZSTD_c_chainLog : 1040*3117ece4Schristos *value = (int)CCtxParams->cParams.chainLog; 1041*3117ece4Schristos break; 1042*3117ece4Schristos case ZSTD_c_searchLog : 1043*3117ece4Schristos *value = CCtxParams->cParams.searchLog; 1044*3117ece4Schristos break; 1045*3117ece4Schristos case ZSTD_c_minMatch : 1046*3117ece4Schristos *value = CCtxParams->cParams.minMatch; 1047*3117ece4Schristos break; 1048*3117ece4Schristos case ZSTD_c_targetLength : 1049*3117ece4Schristos *value = CCtxParams->cParams.targetLength; 1050*3117ece4Schristos break; 1051*3117ece4Schristos case ZSTD_c_strategy : 1052*3117ece4Schristos *value = (unsigned)CCtxParams->cParams.strategy; 1053*3117ece4Schristos break; 1054*3117ece4Schristos case ZSTD_c_contentSizeFlag : 1055*3117ece4Schristos *value = CCtxParams->fParams.contentSizeFlag; 1056*3117ece4Schristos break; 1057*3117ece4Schristos case ZSTD_c_checksumFlag : 1058*3117ece4Schristos *value = CCtxParams->fParams.checksumFlag; 1059*3117ece4Schristos break; 1060*3117ece4Schristos case ZSTD_c_dictIDFlag : 1061*3117ece4Schristos *value = !CCtxParams->fParams.noDictIDFlag; 1062*3117ece4Schristos break; 1063*3117ece4Schristos case ZSTD_c_forceMaxWindow : 1064*3117ece4Schristos *value = CCtxParams->forceWindow; 1065*3117ece4Schristos break; 1066*3117ece4Schristos case ZSTD_c_forceAttachDict : 1067*3117ece4Schristos *value = CCtxParams->attachDictPref; 1068*3117ece4Schristos break; 1069*3117ece4Schristos case ZSTD_c_literalCompressionMode : 1070*3117ece4Schristos *value = CCtxParams->literalCompressionMode; 1071*3117ece4Schristos break; 1072*3117ece4Schristos case ZSTD_c_nbWorkers : 1073*3117ece4Schristos #ifndef ZSTD_MULTITHREAD 1074*3117ece4Schristos assert(CCtxParams->nbWorkers == 0); 1075*3117ece4Schristos #endif 1076*3117ece4Schristos *value = CCtxParams->nbWorkers; 1077*3117ece4Schristos break; 1078*3117ece4Schristos case ZSTD_c_jobSize : 1079*3117ece4Schristos #ifndef ZSTD_MULTITHREAD 1080*3117ece4Schristos RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 1081*3117ece4Schristos #else 1082*3117ece4Schristos assert(CCtxParams->jobSize <= INT_MAX); 1083*3117ece4Schristos *value = (int)CCtxParams->jobSize; 1084*3117ece4Schristos break; 1085*3117ece4Schristos #endif 1086*3117ece4Schristos case ZSTD_c_overlapLog : 1087*3117ece4Schristos #ifndef ZSTD_MULTITHREAD 1088*3117ece4Schristos RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 1089*3117ece4Schristos #else 1090*3117ece4Schristos *value = CCtxParams->overlapLog; 1091*3117ece4Schristos break; 1092*3117ece4Schristos #endif 1093*3117ece4Schristos case ZSTD_c_rsyncable : 1094*3117ece4Schristos #ifndef ZSTD_MULTITHREAD 1095*3117ece4Schristos RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 1096*3117ece4Schristos #else 1097*3117ece4Schristos *value = CCtxParams->rsyncable; 1098*3117ece4Schristos break; 1099*3117ece4Schristos #endif 1100*3117ece4Schristos case ZSTD_c_enableDedicatedDictSearch : 1101*3117ece4Schristos *value = CCtxParams->enableDedicatedDictSearch; 1102*3117ece4Schristos break; 1103*3117ece4Schristos case ZSTD_c_enableLongDistanceMatching : 1104*3117ece4Schristos *value = CCtxParams->ldmParams.enableLdm; 1105*3117ece4Schristos break; 1106*3117ece4Schristos case ZSTD_c_ldmHashLog : 1107*3117ece4Schristos *value = CCtxParams->ldmParams.hashLog; 1108*3117ece4Schristos break; 1109*3117ece4Schristos case ZSTD_c_ldmMinMatch : 1110*3117ece4Schristos *value = CCtxParams->ldmParams.minMatchLength; 1111*3117ece4Schristos break; 1112*3117ece4Schristos case ZSTD_c_ldmBucketSizeLog : 1113*3117ece4Schristos *value = CCtxParams->ldmParams.bucketSizeLog; 1114*3117ece4Schristos break; 1115*3117ece4Schristos case ZSTD_c_ldmHashRateLog : 1116*3117ece4Schristos *value = CCtxParams->ldmParams.hashRateLog; 1117*3117ece4Schristos break; 1118*3117ece4Schristos case ZSTD_c_targetCBlockSize : 1119*3117ece4Schristos *value = (int)CCtxParams->targetCBlockSize; 1120*3117ece4Schristos break; 1121*3117ece4Schristos case ZSTD_c_srcSizeHint : 1122*3117ece4Schristos *value = (int)CCtxParams->srcSizeHint; 1123*3117ece4Schristos break; 1124*3117ece4Schristos case ZSTD_c_stableInBuffer : 1125*3117ece4Schristos *value = (int)CCtxParams->inBufferMode; 1126*3117ece4Schristos break; 1127*3117ece4Schristos case ZSTD_c_stableOutBuffer : 1128*3117ece4Schristos *value = (int)CCtxParams->outBufferMode; 1129*3117ece4Schristos break; 1130*3117ece4Schristos case ZSTD_c_blockDelimiters : 1131*3117ece4Schristos *value = (int)CCtxParams->blockDelimiters; 1132*3117ece4Schristos break; 1133*3117ece4Schristos case ZSTD_c_validateSequences : 1134*3117ece4Schristos *value = (int)CCtxParams->validateSequences; 1135*3117ece4Schristos break; 1136*3117ece4Schristos case ZSTD_c_useBlockSplitter : 1137*3117ece4Schristos *value = (int)CCtxParams->useBlockSplitter; 1138*3117ece4Schristos break; 1139*3117ece4Schristos case ZSTD_c_useRowMatchFinder : 1140*3117ece4Schristos *value = (int)CCtxParams->useRowMatchFinder; 1141*3117ece4Schristos break; 1142*3117ece4Schristos case ZSTD_c_deterministicRefPrefix: 1143*3117ece4Schristos *value = (int)CCtxParams->deterministicRefPrefix; 1144*3117ece4Schristos break; 1145*3117ece4Schristos case ZSTD_c_prefetchCDictTables: 1146*3117ece4Schristos *value = (int)CCtxParams->prefetchCDictTables; 1147*3117ece4Schristos break; 1148*3117ece4Schristos case ZSTD_c_enableSeqProducerFallback: 1149*3117ece4Schristos *value = CCtxParams->enableMatchFinderFallback; 1150*3117ece4Schristos break; 1151*3117ece4Schristos case ZSTD_c_maxBlockSize: 1152*3117ece4Schristos *value = (int)CCtxParams->maxBlockSize; 1153*3117ece4Schristos break; 1154*3117ece4Schristos case ZSTD_c_searchForExternalRepcodes: 1155*3117ece4Schristos *value = (int)CCtxParams->searchForExternalRepcodes; 1156*3117ece4Schristos break; 1157*3117ece4Schristos default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); 1158*3117ece4Schristos } 1159*3117ece4Schristos return 0; 1160*3117ece4Schristos } 1161*3117ece4Schristos 1162*3117ece4Schristos /** ZSTD_CCtx_setParametersUsingCCtxParams() : 1163*3117ece4Schristos * just applies `params` into `cctx` 1164*3117ece4Schristos * no action is performed, parameters are merely stored. 1165*3117ece4Schristos * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx. 1166*3117ece4Schristos * This is possible even if a compression is ongoing. 1167*3117ece4Schristos * In which case, new parameters will be applied on the fly, starting with next compression job. 1168*3117ece4Schristos */ 1169*3117ece4Schristos size_t ZSTD_CCtx_setParametersUsingCCtxParams( 1170*3117ece4Schristos ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) 1171*3117ece4Schristos { 1172*3117ece4Schristos DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams"); 1173*3117ece4Schristos RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 1174*3117ece4Schristos "The context is in the wrong stage!"); 1175*3117ece4Schristos RETURN_ERROR_IF(cctx->cdict, stage_wrong, 1176*3117ece4Schristos "Can't override parameters with cdict attached (some must " 1177*3117ece4Schristos "be inherited from the cdict)."); 1178*3117ece4Schristos 1179*3117ece4Schristos cctx->requestedParams = *params; 1180*3117ece4Schristos return 0; 1181*3117ece4Schristos } 1182*3117ece4Schristos 1183*3117ece4Schristos size_t ZSTD_CCtx_setCParams(ZSTD_CCtx* cctx, ZSTD_compressionParameters cparams) 1184*3117ece4Schristos { 1185*3117ece4Schristos ZSTD_STATIC_ASSERT(sizeof(cparams) == 7 * 4 /* all params are listed below */); 1186*3117ece4Schristos DEBUGLOG(4, "ZSTD_CCtx_setCParams"); 1187*3117ece4Schristos /* only update if all parameters are valid */ 1188*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_checkCParams(cparams), ""); 1189*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_windowLog, cparams.windowLog), ""); 1190*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_chainLog, cparams.chainLog), ""); 1191*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_hashLog, cparams.hashLog), ""); 1192*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_searchLog, cparams.searchLog), ""); 1193*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_minMatch, cparams.minMatch), ""); 1194*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_targetLength, cparams.targetLength), ""); 1195*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_strategy, cparams.strategy), ""); 1196*3117ece4Schristos return 0; 1197*3117ece4Schristos } 1198*3117ece4Schristos 1199*3117ece4Schristos size_t ZSTD_CCtx_setFParams(ZSTD_CCtx* cctx, ZSTD_frameParameters fparams) 1200*3117ece4Schristos { 1201*3117ece4Schristos ZSTD_STATIC_ASSERT(sizeof(fparams) == 3 * 4 /* all params are listed below */); 1202*3117ece4Schristos DEBUGLOG(4, "ZSTD_CCtx_setFParams"); 1203*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_contentSizeFlag, fparams.contentSizeFlag != 0), ""); 1204*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_checksumFlag, fparams.checksumFlag != 0), ""); 1205*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_setParameter(cctx, ZSTD_c_dictIDFlag, fparams.noDictIDFlag == 0), ""); 1206*3117ece4Schristos return 0; 1207*3117ece4Schristos } 1208*3117ece4Schristos 1209*3117ece4Schristos size_t ZSTD_CCtx_setParams(ZSTD_CCtx* cctx, ZSTD_parameters params) 1210*3117ece4Schristos { 1211*3117ece4Schristos DEBUGLOG(4, "ZSTD_CCtx_setParams"); 1212*3117ece4Schristos /* First check cParams, because we want to update all or none. */ 1213*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); 1214*3117ece4Schristos /* Next set fParams, because this could fail if the cctx isn't in init stage. */ 1215*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_setFParams(cctx, params.fParams), ""); 1216*3117ece4Schristos /* Finally set cParams, which should succeed. */ 1217*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_setCParams(cctx, params.cParams), ""); 1218*3117ece4Schristos return 0; 1219*3117ece4Schristos } 1220*3117ece4Schristos 1221*3117ece4Schristos size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) 1222*3117ece4Schristos { 1223*3117ece4Schristos DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %llu bytes", pledgedSrcSize); 1224*3117ece4Schristos RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 1225*3117ece4Schristos "Can't set pledgedSrcSize when not in init stage."); 1226*3117ece4Schristos cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; 1227*3117ece4Schristos return 0; 1228*3117ece4Schristos } 1229*3117ece4Schristos 1230*3117ece4Schristos static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams( 1231*3117ece4Schristos int const compressionLevel, 1232*3117ece4Schristos size_t const dictSize); 1233*3117ece4Schristos static int ZSTD_dedicatedDictSearch_isSupported( 1234*3117ece4Schristos const ZSTD_compressionParameters* cParams); 1235*3117ece4Schristos static void ZSTD_dedicatedDictSearch_revertCParams( 1236*3117ece4Schristos ZSTD_compressionParameters* cParams); 1237*3117ece4Schristos 1238*3117ece4Schristos /** 1239*3117ece4Schristos * Initializes the local dictionary using requested parameters. 1240*3117ece4Schristos * NOTE: Initialization does not employ the pledged src size, 1241*3117ece4Schristos * because the dictionary may be used for multiple compressions. 1242*3117ece4Schristos */ 1243*3117ece4Schristos static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) 1244*3117ece4Schristos { 1245*3117ece4Schristos ZSTD_localDict* const dl = &cctx->localDict; 1246*3117ece4Schristos if (dl->dict == NULL) { 1247*3117ece4Schristos /* No local dictionary. */ 1248*3117ece4Schristos assert(dl->dictBuffer == NULL); 1249*3117ece4Schristos assert(dl->cdict == NULL); 1250*3117ece4Schristos assert(dl->dictSize == 0); 1251*3117ece4Schristos return 0; 1252*3117ece4Schristos } 1253*3117ece4Schristos if (dl->cdict != NULL) { 1254*3117ece4Schristos /* Local dictionary already initialized. */ 1255*3117ece4Schristos assert(cctx->cdict == dl->cdict); 1256*3117ece4Schristos return 0; 1257*3117ece4Schristos } 1258*3117ece4Schristos assert(dl->dictSize > 0); 1259*3117ece4Schristos assert(cctx->cdict == NULL); 1260*3117ece4Schristos assert(cctx->prefixDict.dict == NULL); 1261*3117ece4Schristos 1262*3117ece4Schristos dl->cdict = ZSTD_createCDict_advanced2( 1263*3117ece4Schristos dl->dict, 1264*3117ece4Schristos dl->dictSize, 1265*3117ece4Schristos ZSTD_dlm_byRef, 1266*3117ece4Schristos dl->dictContentType, 1267*3117ece4Schristos &cctx->requestedParams, 1268*3117ece4Schristos cctx->customMem); 1269*3117ece4Schristos RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed"); 1270*3117ece4Schristos cctx->cdict = dl->cdict; 1271*3117ece4Schristos return 0; 1272*3117ece4Schristos } 1273*3117ece4Schristos 1274*3117ece4Schristos size_t ZSTD_CCtx_loadDictionary_advanced( 1275*3117ece4Schristos ZSTD_CCtx* cctx, 1276*3117ece4Schristos const void* dict, size_t dictSize, 1277*3117ece4Schristos ZSTD_dictLoadMethod_e dictLoadMethod, 1278*3117ece4Schristos ZSTD_dictContentType_e dictContentType) 1279*3117ece4Schristos { 1280*3117ece4Schristos DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); 1281*3117ece4Schristos RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 1282*3117ece4Schristos "Can't load a dictionary when cctx is not in init stage."); 1283*3117ece4Schristos ZSTD_clearAllDicts(cctx); /* erase any previously set dictionary */ 1284*3117ece4Schristos if (dict == NULL || dictSize == 0) /* no dictionary */ 1285*3117ece4Schristos return 0; 1286*3117ece4Schristos if (dictLoadMethod == ZSTD_dlm_byRef) { 1287*3117ece4Schristos cctx->localDict.dict = dict; 1288*3117ece4Schristos } else { 1289*3117ece4Schristos /* copy dictionary content inside CCtx to own its lifetime */ 1290*3117ece4Schristos void* dictBuffer; 1291*3117ece4Schristos RETURN_ERROR_IF(cctx->staticSize, memory_allocation, 1292*3117ece4Schristos "static CCtx can't allocate for an internal copy of dictionary"); 1293*3117ece4Schristos dictBuffer = ZSTD_customMalloc(dictSize, cctx->customMem); 1294*3117ece4Schristos RETURN_ERROR_IF(dictBuffer==NULL, memory_allocation, 1295*3117ece4Schristos "allocation failed for dictionary content"); 1296*3117ece4Schristos ZSTD_memcpy(dictBuffer, dict, dictSize); 1297*3117ece4Schristos cctx->localDict.dictBuffer = dictBuffer; /* owned ptr to free */ 1298*3117ece4Schristos cctx->localDict.dict = dictBuffer; /* read-only reference */ 1299*3117ece4Schristos } 1300*3117ece4Schristos cctx->localDict.dictSize = dictSize; 1301*3117ece4Schristos cctx->localDict.dictContentType = dictContentType; 1302*3117ece4Schristos return 0; 1303*3117ece4Schristos } 1304*3117ece4Schristos 1305*3117ece4Schristos size_t ZSTD_CCtx_loadDictionary_byReference( 1306*3117ece4Schristos ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 1307*3117ece4Schristos { 1308*3117ece4Schristos return ZSTD_CCtx_loadDictionary_advanced( 1309*3117ece4Schristos cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); 1310*3117ece4Schristos } 1311*3117ece4Schristos 1312*3117ece4Schristos size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 1313*3117ece4Schristos { 1314*3117ece4Schristos return ZSTD_CCtx_loadDictionary_advanced( 1315*3117ece4Schristos cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); 1316*3117ece4Schristos } 1317*3117ece4Schristos 1318*3117ece4Schristos 1319*3117ece4Schristos size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 1320*3117ece4Schristos { 1321*3117ece4Schristos RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 1322*3117ece4Schristos "Can't ref a dict when ctx not in init stage."); 1323*3117ece4Schristos /* Free the existing local cdict (if any) to save memory. */ 1324*3117ece4Schristos ZSTD_clearAllDicts(cctx); 1325*3117ece4Schristos cctx->cdict = cdict; 1326*3117ece4Schristos return 0; 1327*3117ece4Schristos } 1328*3117ece4Schristos 1329*3117ece4Schristos size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool) 1330*3117ece4Schristos { 1331*3117ece4Schristos RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 1332*3117ece4Schristos "Can't ref a pool when ctx not in init stage."); 1333*3117ece4Schristos cctx->pool = pool; 1334*3117ece4Schristos return 0; 1335*3117ece4Schristos } 1336*3117ece4Schristos 1337*3117ece4Schristos size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) 1338*3117ece4Schristos { 1339*3117ece4Schristos return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent); 1340*3117ece4Schristos } 1341*3117ece4Schristos 1342*3117ece4Schristos size_t ZSTD_CCtx_refPrefix_advanced( 1343*3117ece4Schristos ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) 1344*3117ece4Schristos { 1345*3117ece4Schristos RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 1346*3117ece4Schristos "Can't ref a prefix when ctx not in init stage."); 1347*3117ece4Schristos ZSTD_clearAllDicts(cctx); 1348*3117ece4Schristos if (prefix != NULL && prefixSize > 0) { 1349*3117ece4Schristos cctx->prefixDict.dict = prefix; 1350*3117ece4Schristos cctx->prefixDict.dictSize = prefixSize; 1351*3117ece4Schristos cctx->prefixDict.dictContentType = dictContentType; 1352*3117ece4Schristos } 1353*3117ece4Schristos return 0; 1354*3117ece4Schristos } 1355*3117ece4Schristos 1356*3117ece4Schristos /*! ZSTD_CCtx_reset() : 1357*3117ece4Schristos * Also dumps dictionary */ 1358*3117ece4Schristos size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset) 1359*3117ece4Schristos { 1360*3117ece4Schristos if ( (reset == ZSTD_reset_session_only) 1361*3117ece4Schristos || (reset == ZSTD_reset_session_and_parameters) ) { 1362*3117ece4Schristos cctx->streamStage = zcss_init; 1363*3117ece4Schristos cctx->pledgedSrcSizePlusOne = 0; 1364*3117ece4Schristos } 1365*3117ece4Schristos if ( (reset == ZSTD_reset_parameters) 1366*3117ece4Schristos || (reset == ZSTD_reset_session_and_parameters) ) { 1367*3117ece4Schristos RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong, 1368*3117ece4Schristos "Reset parameters is only possible during init stage."); 1369*3117ece4Schristos ZSTD_clearAllDicts(cctx); 1370*3117ece4Schristos return ZSTD_CCtxParams_reset(&cctx->requestedParams); 1371*3117ece4Schristos } 1372*3117ece4Schristos return 0; 1373*3117ece4Schristos } 1374*3117ece4Schristos 1375*3117ece4Schristos 1376*3117ece4Schristos /** ZSTD_checkCParams() : 1377*3117ece4Schristos control CParam values remain within authorized range. 1378*3117ece4Schristos @return : 0, or an error code if one value is beyond authorized range */ 1379*3117ece4Schristos size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) 1380*3117ece4Schristos { 1381*3117ece4Schristos BOUNDCHECK(ZSTD_c_windowLog, (int)cParams.windowLog); 1382*3117ece4Schristos BOUNDCHECK(ZSTD_c_chainLog, (int)cParams.chainLog); 1383*3117ece4Schristos BOUNDCHECK(ZSTD_c_hashLog, (int)cParams.hashLog); 1384*3117ece4Schristos BOUNDCHECK(ZSTD_c_searchLog, (int)cParams.searchLog); 1385*3117ece4Schristos BOUNDCHECK(ZSTD_c_minMatch, (int)cParams.minMatch); 1386*3117ece4Schristos BOUNDCHECK(ZSTD_c_targetLength,(int)cParams.targetLength); 1387*3117ece4Schristos BOUNDCHECK(ZSTD_c_strategy, cParams.strategy); 1388*3117ece4Schristos return 0; 1389*3117ece4Schristos } 1390*3117ece4Schristos 1391*3117ece4Schristos /** ZSTD_clampCParams() : 1392*3117ece4Schristos * make CParam values within valid range. 1393*3117ece4Schristos * @return : valid CParams */ 1394*3117ece4Schristos static ZSTD_compressionParameters 1395*3117ece4Schristos ZSTD_clampCParams(ZSTD_compressionParameters cParams) 1396*3117ece4Schristos { 1397*3117ece4Schristos # define CLAMP_TYPE(cParam, val, type) \ 1398*3117ece4Schristos do { \ 1399*3117ece4Schristos ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \ 1400*3117ece4Schristos if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \ 1401*3117ece4Schristos else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \ 1402*3117ece4Schristos } while (0) 1403*3117ece4Schristos # define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned) 1404*3117ece4Schristos CLAMP(ZSTD_c_windowLog, cParams.windowLog); 1405*3117ece4Schristos CLAMP(ZSTD_c_chainLog, cParams.chainLog); 1406*3117ece4Schristos CLAMP(ZSTD_c_hashLog, cParams.hashLog); 1407*3117ece4Schristos CLAMP(ZSTD_c_searchLog, cParams.searchLog); 1408*3117ece4Schristos CLAMP(ZSTD_c_minMatch, cParams.minMatch); 1409*3117ece4Schristos CLAMP(ZSTD_c_targetLength,cParams.targetLength); 1410*3117ece4Schristos CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy); 1411*3117ece4Schristos return cParams; 1412*3117ece4Schristos } 1413*3117ece4Schristos 1414*3117ece4Schristos /** ZSTD_cycleLog() : 1415*3117ece4Schristos * condition for correct operation : hashLog > 1 */ 1416*3117ece4Schristos U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) 1417*3117ece4Schristos { 1418*3117ece4Schristos U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2); 1419*3117ece4Schristos return hashLog - btScale; 1420*3117ece4Schristos } 1421*3117ece4Schristos 1422*3117ece4Schristos /** ZSTD_dictAndWindowLog() : 1423*3117ece4Schristos * Returns an adjusted window log that is large enough to fit the source and the dictionary. 1424*3117ece4Schristos * The zstd format says that the entire dictionary is valid if one byte of the dictionary 1425*3117ece4Schristos * is within the window. So the hashLog and chainLog should be large enough to reference both 1426*3117ece4Schristos * the dictionary and the window. So we must use this adjusted dictAndWindowLog when downsizing 1427*3117ece4Schristos * the hashLog and windowLog. 1428*3117ece4Schristos * NOTE: srcSize must not be ZSTD_CONTENTSIZE_UNKNOWN. 1429*3117ece4Schristos */ 1430*3117ece4Schristos static U32 ZSTD_dictAndWindowLog(U32 windowLog, U64 srcSize, U64 dictSize) 1431*3117ece4Schristos { 1432*3117ece4Schristos const U64 maxWindowSize = 1ULL << ZSTD_WINDOWLOG_MAX; 1433*3117ece4Schristos /* No dictionary ==> No change */ 1434*3117ece4Schristos if (dictSize == 0) { 1435*3117ece4Schristos return windowLog; 1436*3117ece4Schristos } 1437*3117ece4Schristos assert(windowLog <= ZSTD_WINDOWLOG_MAX); 1438*3117ece4Schristos assert(srcSize != ZSTD_CONTENTSIZE_UNKNOWN); /* Handled in ZSTD_adjustCParams_internal() */ 1439*3117ece4Schristos { 1440*3117ece4Schristos U64 const windowSize = 1ULL << windowLog; 1441*3117ece4Schristos U64 const dictAndWindowSize = dictSize + windowSize; 1442*3117ece4Schristos /* If the window size is already large enough to fit both the source and the dictionary 1443*3117ece4Schristos * then just use the window size. Otherwise adjust so that it fits the dictionary and 1444*3117ece4Schristos * the window. 1445*3117ece4Schristos */ 1446*3117ece4Schristos if (windowSize >= dictSize + srcSize) { 1447*3117ece4Schristos return windowLog; /* Window size large enough already */ 1448*3117ece4Schristos } else if (dictAndWindowSize >= maxWindowSize) { 1449*3117ece4Schristos return ZSTD_WINDOWLOG_MAX; /* Larger than max window log */ 1450*3117ece4Schristos } else { 1451*3117ece4Schristos return ZSTD_highbit32((U32)dictAndWindowSize - 1) + 1; 1452*3117ece4Schristos } 1453*3117ece4Schristos } 1454*3117ece4Schristos } 1455*3117ece4Schristos 1456*3117ece4Schristos /** ZSTD_adjustCParams_internal() : 1457*3117ece4Schristos * optimize `cPar` for a specified input (`srcSize` and `dictSize`). 1458*3117ece4Schristos * mostly downsize to reduce memory consumption and initialization latency. 1459*3117ece4Schristos * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known. 1460*3117ece4Schristos * `mode` is the mode for parameter adjustment. See docs for `ZSTD_cParamMode_e`. 1461*3117ece4Schristos * note : `srcSize==0` means 0! 1462*3117ece4Schristos * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */ 1463*3117ece4Schristos static ZSTD_compressionParameters 1464*3117ece4Schristos ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, 1465*3117ece4Schristos unsigned long long srcSize, 1466*3117ece4Schristos size_t dictSize, 1467*3117ece4Schristos ZSTD_cParamMode_e mode, 1468*3117ece4Schristos ZSTD_paramSwitch_e useRowMatchFinder) 1469*3117ece4Schristos { 1470*3117ece4Schristos const U64 minSrcSize = 513; /* (1<<9) + 1 */ 1471*3117ece4Schristos const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); 1472*3117ece4Schristos assert(ZSTD_checkCParams(cPar)==0); 1473*3117ece4Schristos 1474*3117ece4Schristos /* Cascade the selected strategy down to the next-highest one built into 1475*3117ece4Schristos * this binary. */ 1476*3117ece4Schristos #ifdef ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR 1477*3117ece4Schristos if (cPar.strategy == ZSTD_btultra2) { 1478*3117ece4Schristos cPar.strategy = ZSTD_btultra; 1479*3117ece4Schristos } 1480*3117ece4Schristos if (cPar.strategy == ZSTD_btultra) { 1481*3117ece4Schristos cPar.strategy = ZSTD_btopt; 1482*3117ece4Schristos } 1483*3117ece4Schristos #endif 1484*3117ece4Schristos #ifdef ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR 1485*3117ece4Schristos if (cPar.strategy == ZSTD_btopt) { 1486*3117ece4Schristos cPar.strategy = ZSTD_btlazy2; 1487*3117ece4Schristos } 1488*3117ece4Schristos #endif 1489*3117ece4Schristos #ifdef ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR 1490*3117ece4Schristos if (cPar.strategy == ZSTD_btlazy2) { 1491*3117ece4Schristos cPar.strategy = ZSTD_lazy2; 1492*3117ece4Schristos } 1493*3117ece4Schristos #endif 1494*3117ece4Schristos #ifdef ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR 1495*3117ece4Schristos if (cPar.strategy == ZSTD_lazy2) { 1496*3117ece4Schristos cPar.strategy = ZSTD_lazy; 1497*3117ece4Schristos } 1498*3117ece4Schristos #endif 1499*3117ece4Schristos #ifdef ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR 1500*3117ece4Schristos if (cPar.strategy == ZSTD_lazy) { 1501*3117ece4Schristos cPar.strategy = ZSTD_greedy; 1502*3117ece4Schristos } 1503*3117ece4Schristos #endif 1504*3117ece4Schristos #ifdef ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR 1505*3117ece4Schristos if (cPar.strategy == ZSTD_greedy) { 1506*3117ece4Schristos cPar.strategy = ZSTD_dfast; 1507*3117ece4Schristos } 1508*3117ece4Schristos #endif 1509*3117ece4Schristos #ifdef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR 1510*3117ece4Schristos if (cPar.strategy == ZSTD_dfast) { 1511*3117ece4Schristos cPar.strategy = ZSTD_fast; 1512*3117ece4Schristos cPar.targetLength = 0; 1513*3117ece4Schristos } 1514*3117ece4Schristos #endif 1515*3117ece4Schristos 1516*3117ece4Schristos switch (mode) { 1517*3117ece4Schristos case ZSTD_cpm_unknown: 1518*3117ece4Schristos case ZSTD_cpm_noAttachDict: 1519*3117ece4Schristos /* If we don't know the source size, don't make any 1520*3117ece4Schristos * assumptions about it. We will already have selected 1521*3117ece4Schristos * smaller parameters if a dictionary is in use. 1522*3117ece4Schristos */ 1523*3117ece4Schristos break; 1524*3117ece4Schristos case ZSTD_cpm_createCDict: 1525*3117ece4Schristos /* Assume a small source size when creating a dictionary 1526*3117ece4Schristos * with an unknown source size. 1527*3117ece4Schristos */ 1528*3117ece4Schristos if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN) 1529*3117ece4Schristos srcSize = minSrcSize; 1530*3117ece4Schristos break; 1531*3117ece4Schristos case ZSTD_cpm_attachDict: 1532*3117ece4Schristos /* Dictionary has its own dedicated parameters which have 1533*3117ece4Schristos * already been selected. We are selecting parameters 1534*3117ece4Schristos * for only the source. 1535*3117ece4Schristos */ 1536*3117ece4Schristos dictSize = 0; 1537*3117ece4Schristos break; 1538*3117ece4Schristos default: 1539*3117ece4Schristos assert(0); 1540*3117ece4Schristos break; 1541*3117ece4Schristos } 1542*3117ece4Schristos 1543*3117ece4Schristos /* resize windowLog if input is small enough, to use less memory */ 1544*3117ece4Schristos if ( (srcSize <= maxWindowResize) 1545*3117ece4Schristos && (dictSize <= maxWindowResize) ) { 1546*3117ece4Schristos U32 const tSize = (U32)(srcSize + dictSize); 1547*3117ece4Schristos static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN; 1548*3117ece4Schristos U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN : 1549*3117ece4Schristos ZSTD_highbit32(tSize-1) + 1; 1550*3117ece4Schristos if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; 1551*3117ece4Schristos } 1552*3117ece4Schristos if (srcSize != ZSTD_CONTENTSIZE_UNKNOWN) { 1553*3117ece4Schristos U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize); 1554*3117ece4Schristos U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); 1555*3117ece4Schristos if (cPar.hashLog > dictAndWindowLog+1) cPar.hashLog = dictAndWindowLog+1; 1556*3117ece4Schristos if (cycleLog > dictAndWindowLog) 1557*3117ece4Schristos cPar.chainLog -= (cycleLog - dictAndWindowLog); 1558*3117ece4Schristos } 1559*3117ece4Schristos 1560*3117ece4Schristos if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) 1561*3117ece4Schristos cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */ 1562*3117ece4Schristos 1563*3117ece4Schristos /* We can't use more than 32 bits of hash in total, so that means that we require: 1564*3117ece4Schristos * (hashLog + 8) <= 32 && (chainLog + 8) <= 32 1565*3117ece4Schristos */ 1566*3117ece4Schristos if (mode == ZSTD_cpm_createCDict && ZSTD_CDictIndicesAreTagged(&cPar)) { 1567*3117ece4Schristos U32 const maxShortCacheHashLog = 32 - ZSTD_SHORT_CACHE_TAG_BITS; 1568*3117ece4Schristos if (cPar.hashLog > maxShortCacheHashLog) { 1569*3117ece4Schristos cPar.hashLog = maxShortCacheHashLog; 1570*3117ece4Schristos } 1571*3117ece4Schristos if (cPar.chainLog > maxShortCacheHashLog) { 1572*3117ece4Schristos cPar.chainLog = maxShortCacheHashLog; 1573*3117ece4Schristos } 1574*3117ece4Schristos } 1575*3117ece4Schristos 1576*3117ece4Schristos 1577*3117ece4Schristos /* At this point, we aren't 100% sure if we are using the row match finder. 1578*3117ece4Schristos * Unless it is explicitly disabled, conservatively assume that it is enabled. 1579*3117ece4Schristos * In this case it will only be disabled for small sources, so shrinking the 1580*3117ece4Schristos * hash log a little bit shouldn't result in any ratio loss. 1581*3117ece4Schristos */ 1582*3117ece4Schristos if (useRowMatchFinder == ZSTD_ps_auto) 1583*3117ece4Schristos useRowMatchFinder = ZSTD_ps_enable; 1584*3117ece4Schristos 1585*3117ece4Schristos /* We can't hash more than 32-bits in total. So that means that we require: 1586*3117ece4Schristos * (hashLog - rowLog + 8) <= 32 1587*3117ece4Schristos */ 1588*3117ece4Schristos if (ZSTD_rowMatchFinderUsed(cPar.strategy, useRowMatchFinder)) { 1589*3117ece4Schristos /* Switch to 32-entry rows if searchLog is 5 (or more) */ 1590*3117ece4Schristos U32 const rowLog = BOUNDED(4, cPar.searchLog, 6); 1591*3117ece4Schristos U32 const maxRowHashLog = 32 - ZSTD_ROW_HASH_TAG_BITS; 1592*3117ece4Schristos U32 const maxHashLog = maxRowHashLog + rowLog; 1593*3117ece4Schristos assert(cPar.hashLog >= rowLog); 1594*3117ece4Schristos if (cPar.hashLog > maxHashLog) { 1595*3117ece4Schristos cPar.hashLog = maxHashLog; 1596*3117ece4Schristos } 1597*3117ece4Schristos } 1598*3117ece4Schristos 1599*3117ece4Schristos return cPar; 1600*3117ece4Schristos } 1601*3117ece4Schristos 1602*3117ece4Schristos ZSTD_compressionParameters 1603*3117ece4Schristos ZSTD_adjustCParams(ZSTD_compressionParameters cPar, 1604*3117ece4Schristos unsigned long long srcSize, 1605*3117ece4Schristos size_t dictSize) 1606*3117ece4Schristos { 1607*3117ece4Schristos cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */ 1608*3117ece4Schristos if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN; 1609*3117ece4Schristos return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize, ZSTD_cpm_unknown, ZSTD_ps_auto); 1610*3117ece4Schristos } 1611*3117ece4Schristos 1612*3117ece4Schristos static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); 1613*3117ece4Schristos static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode); 1614*3117ece4Schristos 1615*3117ece4Schristos static void ZSTD_overrideCParams( 1616*3117ece4Schristos ZSTD_compressionParameters* cParams, 1617*3117ece4Schristos const ZSTD_compressionParameters* overrides) 1618*3117ece4Schristos { 1619*3117ece4Schristos if (overrides->windowLog) cParams->windowLog = overrides->windowLog; 1620*3117ece4Schristos if (overrides->hashLog) cParams->hashLog = overrides->hashLog; 1621*3117ece4Schristos if (overrides->chainLog) cParams->chainLog = overrides->chainLog; 1622*3117ece4Schristos if (overrides->searchLog) cParams->searchLog = overrides->searchLog; 1623*3117ece4Schristos if (overrides->minMatch) cParams->minMatch = overrides->minMatch; 1624*3117ece4Schristos if (overrides->targetLength) cParams->targetLength = overrides->targetLength; 1625*3117ece4Schristos if (overrides->strategy) cParams->strategy = overrides->strategy; 1626*3117ece4Schristos } 1627*3117ece4Schristos 1628*3117ece4Schristos ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( 1629*3117ece4Schristos const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) 1630*3117ece4Schristos { 1631*3117ece4Schristos ZSTD_compressionParameters cParams; 1632*3117ece4Schristos if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) { 1633*3117ece4Schristos srcSizeHint = CCtxParams->srcSizeHint; 1634*3117ece4Schristos } 1635*3117ece4Schristos cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize, mode); 1636*3117ece4Schristos if (CCtxParams->ldmParams.enableLdm == ZSTD_ps_enable) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; 1637*3117ece4Schristos ZSTD_overrideCParams(&cParams, &CCtxParams->cParams); 1638*3117ece4Schristos assert(!ZSTD_checkCParams(cParams)); 1639*3117ece4Schristos /* srcSizeHint == 0 means 0 */ 1640*3117ece4Schristos return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize, mode, CCtxParams->useRowMatchFinder); 1641*3117ece4Schristos } 1642*3117ece4Schristos 1643*3117ece4Schristos static size_t 1644*3117ece4Schristos ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, 1645*3117ece4Schristos const ZSTD_paramSwitch_e useRowMatchFinder, 1646*3117ece4Schristos const U32 enableDedicatedDictSearch, 1647*3117ece4Schristos const U32 forCCtx) 1648*3117ece4Schristos { 1649*3117ece4Schristos /* chain table size should be 0 for fast or row-hash strategies */ 1650*3117ece4Schristos size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, enableDedicatedDictSearch && !forCCtx) 1651*3117ece4Schristos ? ((size_t)1 << cParams->chainLog) 1652*3117ece4Schristos : 0; 1653*3117ece4Schristos size_t const hSize = ((size_t)1) << cParams->hashLog; 1654*3117ece4Schristos U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 1655*3117ece4Schristos size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; 1656*3117ece4Schristos /* We don't use ZSTD_cwksp_alloc_size() here because the tables aren't 1657*3117ece4Schristos * surrounded by redzones in ASAN. */ 1658*3117ece4Schristos size_t const tableSpace = chainSize * sizeof(U32) 1659*3117ece4Schristos + hSize * sizeof(U32) 1660*3117ece4Schristos + h3Size * sizeof(U32); 1661*3117ece4Schristos size_t const optPotentialSpace = 1662*3117ece4Schristos ZSTD_cwksp_aligned_alloc_size((MaxML+1) * sizeof(U32)) 1663*3117ece4Schristos + ZSTD_cwksp_aligned_alloc_size((MaxLL+1) * sizeof(U32)) 1664*3117ece4Schristos + ZSTD_cwksp_aligned_alloc_size((MaxOff+1) * sizeof(U32)) 1665*3117ece4Schristos + ZSTD_cwksp_aligned_alloc_size((1<<Litbits) * sizeof(U32)) 1666*3117ece4Schristos + ZSTD_cwksp_aligned_alloc_size(ZSTD_OPT_SIZE * sizeof(ZSTD_match_t)) 1667*3117ece4Schristos + ZSTD_cwksp_aligned_alloc_size(ZSTD_OPT_SIZE * sizeof(ZSTD_optimal_t)); 1668*3117ece4Schristos size_t const lazyAdditionalSpace = ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder) 1669*3117ece4Schristos ? ZSTD_cwksp_aligned_alloc_size(hSize) 1670*3117ece4Schristos : 0; 1671*3117ece4Schristos size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt)) 1672*3117ece4Schristos ? optPotentialSpace 1673*3117ece4Schristos : 0; 1674*3117ece4Schristos size_t const slackSpace = ZSTD_cwksp_slack_space_required(); 1675*3117ece4Schristos 1676*3117ece4Schristos /* tables are guaranteed to be sized in multiples of 64 bytes (or 16 uint32_t) */ 1677*3117ece4Schristos ZSTD_STATIC_ASSERT(ZSTD_HASHLOG_MIN >= 4 && ZSTD_WINDOWLOG_MIN >= 4 && ZSTD_CHAINLOG_MIN >= 4); 1678*3117ece4Schristos assert(useRowMatchFinder != ZSTD_ps_auto); 1679*3117ece4Schristos 1680*3117ece4Schristos DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u", 1681*3117ece4Schristos (U32)chainSize, (U32)hSize, (U32)h3Size); 1682*3117ece4Schristos return tableSpace + optSpace + slackSpace + lazyAdditionalSpace; 1683*3117ece4Schristos } 1684*3117ece4Schristos 1685*3117ece4Schristos /* Helper function for calculating memory requirements. 1686*3117ece4Schristos * Gives a tighter bound than ZSTD_sequenceBound() by taking minMatch into account. */ 1687*3117ece4Schristos static size_t ZSTD_maxNbSeq(size_t blockSize, unsigned minMatch, int useSequenceProducer) { 1688*3117ece4Schristos U32 const divider = (minMatch==3 || useSequenceProducer) ? 3 : 4; 1689*3117ece4Schristos return blockSize / divider; 1690*3117ece4Schristos } 1691*3117ece4Schristos 1692*3117ece4Schristos static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal( 1693*3117ece4Schristos const ZSTD_compressionParameters* cParams, 1694*3117ece4Schristos const ldmParams_t* ldmParams, 1695*3117ece4Schristos const int isStatic, 1696*3117ece4Schristos const ZSTD_paramSwitch_e useRowMatchFinder, 1697*3117ece4Schristos const size_t buffInSize, 1698*3117ece4Schristos const size_t buffOutSize, 1699*3117ece4Schristos const U64 pledgedSrcSize, 1700*3117ece4Schristos int useSequenceProducer, 1701*3117ece4Schristos size_t maxBlockSize) 1702*3117ece4Schristos { 1703*3117ece4Schristos size_t const windowSize = (size_t) BOUNDED(1ULL, 1ULL << cParams->windowLog, pledgedSrcSize); 1704*3117ece4Schristos size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(maxBlockSize), windowSize); 1705*3117ece4Schristos size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, cParams->minMatch, useSequenceProducer); 1706*3117ece4Schristos size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) 1707*3117ece4Schristos + ZSTD_cwksp_aligned_alloc_size(maxNbSeq * sizeof(seqDef)) 1708*3117ece4Schristos + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); 1709*3117ece4Schristos size_t const entropySpace = ZSTD_cwksp_alloc_size(ENTROPY_WORKSPACE_SIZE); 1710*3117ece4Schristos size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); 1711*3117ece4Schristos size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 0, /* forCCtx */ 1); 1712*3117ece4Schristos 1713*3117ece4Schristos size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams); 1714*3117ece4Schristos size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize); 1715*3117ece4Schristos size_t const ldmSeqSpace = ldmParams->enableLdm == ZSTD_ps_enable ? 1716*3117ece4Schristos ZSTD_cwksp_aligned_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0; 1717*3117ece4Schristos 1718*3117ece4Schristos 1719*3117ece4Schristos size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) 1720*3117ece4Schristos + ZSTD_cwksp_alloc_size(buffOutSize); 1721*3117ece4Schristos 1722*3117ece4Schristos size_t const cctxSpace = isStatic ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0; 1723*3117ece4Schristos 1724*3117ece4Schristos size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize); 1725*3117ece4Schristos size_t const externalSeqSpace = useSequenceProducer 1726*3117ece4Schristos ? ZSTD_cwksp_aligned_alloc_size(maxNbExternalSeq * sizeof(ZSTD_Sequence)) 1727*3117ece4Schristos : 0; 1728*3117ece4Schristos 1729*3117ece4Schristos size_t const neededSpace = 1730*3117ece4Schristos cctxSpace + 1731*3117ece4Schristos entropySpace + 1732*3117ece4Schristos blockStateSpace + 1733*3117ece4Schristos ldmSpace + 1734*3117ece4Schristos ldmSeqSpace + 1735*3117ece4Schristos matchStateSize + 1736*3117ece4Schristos tokenSpace + 1737*3117ece4Schristos bufferSpace + 1738*3117ece4Schristos externalSeqSpace; 1739*3117ece4Schristos 1740*3117ece4Schristos DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace); 1741*3117ece4Schristos return neededSpace; 1742*3117ece4Schristos } 1743*3117ece4Schristos 1744*3117ece4Schristos size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) 1745*3117ece4Schristos { 1746*3117ece4Schristos ZSTD_compressionParameters const cParams = 1747*3117ece4Schristos ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); 1748*3117ece4Schristos ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, 1749*3117ece4Schristos &cParams); 1750*3117ece4Schristos 1751*3117ece4Schristos RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); 1752*3117ece4Schristos /* estimateCCtxSize is for one-shot compression. So no buffers should 1753*3117ece4Schristos * be needed. However, we still allocate two 0-sized buffers, which can 1754*3117ece4Schristos * take space under ASAN. */ 1755*3117ece4Schristos return ZSTD_estimateCCtxSize_usingCCtxParams_internal( 1756*3117ece4Schristos &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize); 1757*3117ece4Schristos } 1758*3117ece4Schristos 1759*3117ece4Schristos size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) 1760*3117ece4Schristos { 1761*3117ece4Schristos ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); 1762*3117ece4Schristos if (ZSTD_rowMatchFinderSupported(cParams.strategy)) { 1763*3117ece4Schristos /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */ 1764*3117ece4Schristos size_t noRowCCtxSize; 1765*3117ece4Schristos size_t rowCCtxSize; 1766*3117ece4Schristos initialParams.useRowMatchFinder = ZSTD_ps_disable; 1767*3117ece4Schristos noRowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); 1768*3117ece4Schristos initialParams.useRowMatchFinder = ZSTD_ps_enable; 1769*3117ece4Schristos rowCCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); 1770*3117ece4Schristos return MAX(noRowCCtxSize, rowCCtxSize); 1771*3117ece4Schristos } else { 1772*3117ece4Schristos return ZSTD_estimateCCtxSize_usingCCtxParams(&initialParams); 1773*3117ece4Schristos } 1774*3117ece4Schristos } 1775*3117ece4Schristos 1776*3117ece4Schristos static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) 1777*3117ece4Schristos { 1778*3117ece4Schristos int tier = 0; 1779*3117ece4Schristos size_t largestSize = 0; 1780*3117ece4Schristos static const unsigned long long srcSizeTiers[4] = {16 KB, 128 KB, 256 KB, ZSTD_CONTENTSIZE_UNKNOWN}; 1781*3117ece4Schristos for (; tier < 4; ++tier) { 1782*3117ece4Schristos /* Choose the set of cParams for a given level across all srcSizes that give the largest cctxSize */ 1783*3117ece4Schristos ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeTiers[tier], 0, ZSTD_cpm_noAttachDict); 1784*3117ece4Schristos largestSize = MAX(ZSTD_estimateCCtxSize_usingCParams(cParams), largestSize); 1785*3117ece4Schristos } 1786*3117ece4Schristos return largestSize; 1787*3117ece4Schristos } 1788*3117ece4Schristos 1789*3117ece4Schristos size_t ZSTD_estimateCCtxSize(int compressionLevel) 1790*3117ece4Schristos { 1791*3117ece4Schristos int level; 1792*3117ece4Schristos size_t memBudget = 0; 1793*3117ece4Schristos for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { 1794*3117ece4Schristos /* Ensure monotonically increasing memory usage as compression level increases */ 1795*3117ece4Schristos size_t const newMB = ZSTD_estimateCCtxSize_internal(level); 1796*3117ece4Schristos if (newMB > memBudget) memBudget = newMB; 1797*3117ece4Schristos } 1798*3117ece4Schristos return memBudget; 1799*3117ece4Schristos } 1800*3117ece4Schristos 1801*3117ece4Schristos size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) 1802*3117ece4Schristos { 1803*3117ece4Schristos RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); 1804*3117ece4Schristos { ZSTD_compressionParameters const cParams = 1805*3117ece4Schristos ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); 1806*3117ece4Schristos size_t const blockSize = MIN(ZSTD_resolveMaxBlockSize(params->maxBlockSize), (size_t)1 << cParams.windowLog); 1807*3117ece4Schristos size_t const inBuffSize = (params->inBufferMode == ZSTD_bm_buffered) 1808*3117ece4Schristos ? ((size_t)1 << cParams.windowLog) + blockSize 1809*3117ece4Schristos : 0; 1810*3117ece4Schristos size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered) 1811*3117ece4Schristos ? ZSTD_compressBound(blockSize) + 1 1812*3117ece4Schristos : 0; 1813*3117ece4Schristos ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params->useRowMatchFinder, ¶ms->cParams); 1814*3117ece4Schristos 1815*3117ece4Schristos return ZSTD_estimateCCtxSize_usingCCtxParams_internal( 1816*3117ece4Schristos &cParams, ¶ms->ldmParams, 1, useRowMatchFinder, inBuffSize, outBuffSize, 1817*3117ece4Schristos ZSTD_CONTENTSIZE_UNKNOWN, ZSTD_hasExtSeqProd(params), params->maxBlockSize); 1818*3117ece4Schristos } 1819*3117ece4Schristos } 1820*3117ece4Schristos 1821*3117ece4Schristos size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) 1822*3117ece4Schristos { 1823*3117ece4Schristos ZSTD_CCtx_params initialParams = ZSTD_makeCCtxParamsFromCParams(cParams); 1824*3117ece4Schristos if (ZSTD_rowMatchFinderSupported(cParams.strategy)) { 1825*3117ece4Schristos /* Pick bigger of not using and using row-based matchfinder for greedy and lazy strategies */ 1826*3117ece4Schristos size_t noRowCCtxSize; 1827*3117ece4Schristos size_t rowCCtxSize; 1828*3117ece4Schristos initialParams.useRowMatchFinder = ZSTD_ps_disable; 1829*3117ece4Schristos noRowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); 1830*3117ece4Schristos initialParams.useRowMatchFinder = ZSTD_ps_enable; 1831*3117ece4Schristos rowCCtxSize = ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); 1832*3117ece4Schristos return MAX(noRowCCtxSize, rowCCtxSize); 1833*3117ece4Schristos } else { 1834*3117ece4Schristos return ZSTD_estimateCStreamSize_usingCCtxParams(&initialParams); 1835*3117ece4Schristos } 1836*3117ece4Schristos } 1837*3117ece4Schristos 1838*3117ece4Schristos static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) 1839*3117ece4Schristos { 1840*3117ece4Schristos ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict); 1841*3117ece4Schristos return ZSTD_estimateCStreamSize_usingCParams(cParams); 1842*3117ece4Schristos } 1843*3117ece4Schristos 1844*3117ece4Schristos size_t ZSTD_estimateCStreamSize(int compressionLevel) 1845*3117ece4Schristos { 1846*3117ece4Schristos int level; 1847*3117ece4Schristos size_t memBudget = 0; 1848*3117ece4Schristos for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { 1849*3117ece4Schristos size_t const newMB = ZSTD_estimateCStreamSize_internal(level); 1850*3117ece4Schristos if (newMB > memBudget) memBudget = newMB; 1851*3117ece4Schristos } 1852*3117ece4Schristos return memBudget; 1853*3117ece4Schristos } 1854*3117ece4Schristos 1855*3117ece4Schristos /* ZSTD_getFrameProgression(): 1856*3117ece4Schristos * tells how much data has been consumed (input) and produced (output) for current frame. 1857*3117ece4Schristos * able to count progression inside worker threads (non-blocking mode). 1858*3117ece4Schristos */ 1859*3117ece4Schristos ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx) 1860*3117ece4Schristos { 1861*3117ece4Schristos #ifdef ZSTD_MULTITHREAD 1862*3117ece4Schristos if (cctx->appliedParams.nbWorkers > 0) { 1863*3117ece4Schristos return ZSTDMT_getFrameProgression(cctx->mtctx); 1864*3117ece4Schristos } 1865*3117ece4Schristos #endif 1866*3117ece4Schristos { ZSTD_frameProgression fp; 1867*3117ece4Schristos size_t const buffered = (cctx->inBuff == NULL) ? 0 : 1868*3117ece4Schristos cctx->inBuffPos - cctx->inToCompress; 1869*3117ece4Schristos if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress); 1870*3117ece4Schristos assert(buffered <= ZSTD_BLOCKSIZE_MAX); 1871*3117ece4Schristos fp.ingested = cctx->consumedSrcSize + buffered; 1872*3117ece4Schristos fp.consumed = cctx->consumedSrcSize; 1873*3117ece4Schristos fp.produced = cctx->producedCSize; 1874*3117ece4Schristos fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */ 1875*3117ece4Schristos fp.currentJobID = 0; 1876*3117ece4Schristos fp.nbActiveWorkers = 0; 1877*3117ece4Schristos return fp; 1878*3117ece4Schristos } } 1879*3117ece4Schristos 1880*3117ece4Schristos /*! ZSTD_toFlushNow() 1881*3117ece4Schristos * Only useful for multithreading scenarios currently (nbWorkers >= 1). 1882*3117ece4Schristos */ 1883*3117ece4Schristos size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx) 1884*3117ece4Schristos { 1885*3117ece4Schristos #ifdef ZSTD_MULTITHREAD 1886*3117ece4Schristos if (cctx->appliedParams.nbWorkers > 0) { 1887*3117ece4Schristos return ZSTDMT_toFlushNow(cctx->mtctx); 1888*3117ece4Schristos } 1889*3117ece4Schristos #endif 1890*3117ece4Schristos (void)cctx; 1891*3117ece4Schristos return 0; /* over-simplification; could also check if context is currently running in streaming mode, and in which case, report how many bytes are left to be flushed within output buffer */ 1892*3117ece4Schristos } 1893*3117ece4Schristos 1894*3117ece4Schristos static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1, 1895*3117ece4Schristos ZSTD_compressionParameters cParams2) 1896*3117ece4Schristos { 1897*3117ece4Schristos (void)cParams1; 1898*3117ece4Schristos (void)cParams2; 1899*3117ece4Schristos assert(cParams1.windowLog == cParams2.windowLog); 1900*3117ece4Schristos assert(cParams1.chainLog == cParams2.chainLog); 1901*3117ece4Schristos assert(cParams1.hashLog == cParams2.hashLog); 1902*3117ece4Schristos assert(cParams1.searchLog == cParams2.searchLog); 1903*3117ece4Schristos assert(cParams1.minMatch == cParams2.minMatch); 1904*3117ece4Schristos assert(cParams1.targetLength == cParams2.targetLength); 1905*3117ece4Schristos assert(cParams1.strategy == cParams2.strategy); 1906*3117ece4Schristos } 1907*3117ece4Schristos 1908*3117ece4Schristos void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) 1909*3117ece4Schristos { 1910*3117ece4Schristos int i; 1911*3117ece4Schristos for (i = 0; i < ZSTD_REP_NUM; ++i) 1912*3117ece4Schristos bs->rep[i] = repStartValue[i]; 1913*3117ece4Schristos bs->entropy.huf.repeatMode = HUF_repeat_none; 1914*3117ece4Schristos bs->entropy.fse.offcode_repeatMode = FSE_repeat_none; 1915*3117ece4Schristos bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none; 1916*3117ece4Schristos bs->entropy.fse.litlength_repeatMode = FSE_repeat_none; 1917*3117ece4Schristos } 1918*3117ece4Schristos 1919*3117ece4Schristos /*! ZSTD_invalidateMatchState() 1920*3117ece4Schristos * Invalidate all the matches in the match finder tables. 1921*3117ece4Schristos * Requires nextSrc and base to be set (can be NULL). 1922*3117ece4Schristos */ 1923*3117ece4Schristos static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms) 1924*3117ece4Schristos { 1925*3117ece4Schristos ZSTD_window_clear(&ms->window); 1926*3117ece4Schristos 1927*3117ece4Schristos ms->nextToUpdate = ms->window.dictLimit; 1928*3117ece4Schristos ms->loadedDictEnd = 0; 1929*3117ece4Schristos ms->opt.litLengthSum = 0; /* force reset of btopt stats */ 1930*3117ece4Schristos ms->dictMatchState = NULL; 1931*3117ece4Schristos } 1932*3117ece4Schristos 1933*3117ece4Schristos /** 1934*3117ece4Schristos * Controls, for this matchState reset, whether the tables need to be cleared / 1935*3117ece4Schristos * prepared for the coming compression (ZSTDcrp_makeClean), or whether the 1936*3117ece4Schristos * tables can be left unclean (ZSTDcrp_leaveDirty), because we know that a 1937*3117ece4Schristos * subsequent operation will overwrite the table space anyways (e.g., copying 1938*3117ece4Schristos * the matchState contents in from a CDict). 1939*3117ece4Schristos */ 1940*3117ece4Schristos typedef enum { 1941*3117ece4Schristos ZSTDcrp_makeClean, 1942*3117ece4Schristos ZSTDcrp_leaveDirty 1943*3117ece4Schristos } ZSTD_compResetPolicy_e; 1944*3117ece4Schristos 1945*3117ece4Schristos /** 1946*3117ece4Schristos * Controls, for this matchState reset, whether indexing can continue where it 1947*3117ece4Schristos * left off (ZSTDirp_continue), or whether it needs to be restarted from zero 1948*3117ece4Schristos * (ZSTDirp_reset). 1949*3117ece4Schristos */ 1950*3117ece4Schristos typedef enum { 1951*3117ece4Schristos ZSTDirp_continue, 1952*3117ece4Schristos ZSTDirp_reset 1953*3117ece4Schristos } ZSTD_indexResetPolicy_e; 1954*3117ece4Schristos 1955*3117ece4Schristos typedef enum { 1956*3117ece4Schristos ZSTD_resetTarget_CDict, 1957*3117ece4Schristos ZSTD_resetTarget_CCtx 1958*3117ece4Schristos } ZSTD_resetTarget_e; 1959*3117ece4Schristos 1960*3117ece4Schristos /* Mixes bits in a 64 bits in a value, based on XXH3_rrmxmx */ 1961*3117ece4Schristos static U64 ZSTD_bitmix(U64 val, U64 len) { 1962*3117ece4Schristos val ^= ZSTD_rotateRight_U64(val, 49) ^ ZSTD_rotateRight_U64(val, 24); 1963*3117ece4Schristos val *= 0x9FB21C651E98DF25ULL; 1964*3117ece4Schristos val ^= (val >> 35) + len ; 1965*3117ece4Schristos val *= 0x9FB21C651E98DF25ULL; 1966*3117ece4Schristos return val ^ (val >> 28); 1967*3117ece4Schristos } 1968*3117ece4Schristos 1969*3117ece4Schristos /* Mixes in the hashSalt and hashSaltEntropy to create a new hashSalt */ 1970*3117ece4Schristos static void ZSTD_advanceHashSalt(ZSTD_matchState_t* ms) { 1971*3117ece4Schristos ms->hashSalt = ZSTD_bitmix(ms->hashSalt, 8) ^ ZSTD_bitmix((U64) ms->hashSaltEntropy, 4); 1972*3117ece4Schristos } 1973*3117ece4Schristos 1974*3117ece4Schristos static size_t 1975*3117ece4Schristos ZSTD_reset_matchState(ZSTD_matchState_t* ms, 1976*3117ece4Schristos ZSTD_cwksp* ws, 1977*3117ece4Schristos const ZSTD_compressionParameters* cParams, 1978*3117ece4Schristos const ZSTD_paramSwitch_e useRowMatchFinder, 1979*3117ece4Schristos const ZSTD_compResetPolicy_e crp, 1980*3117ece4Schristos const ZSTD_indexResetPolicy_e forceResetIndex, 1981*3117ece4Schristos const ZSTD_resetTarget_e forWho) 1982*3117ece4Schristos { 1983*3117ece4Schristos /* disable chain table allocation for fast or row-based strategies */ 1984*3117ece4Schristos size_t const chainSize = ZSTD_allocateChainTable(cParams->strategy, useRowMatchFinder, 1985*3117ece4Schristos ms->dedicatedDictSearch && (forWho == ZSTD_resetTarget_CDict)) 1986*3117ece4Schristos ? ((size_t)1 << cParams->chainLog) 1987*3117ece4Schristos : 0; 1988*3117ece4Schristos size_t const hSize = ((size_t)1) << cParams->hashLog; 1989*3117ece4Schristos U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 1990*3117ece4Schristos size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; 1991*3117ece4Schristos 1992*3117ece4Schristos DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset); 1993*3117ece4Schristos assert(useRowMatchFinder != ZSTD_ps_auto); 1994*3117ece4Schristos if (forceResetIndex == ZSTDirp_reset) { 1995*3117ece4Schristos ZSTD_window_init(&ms->window); 1996*3117ece4Schristos ZSTD_cwksp_mark_tables_dirty(ws); 1997*3117ece4Schristos } 1998*3117ece4Schristos 1999*3117ece4Schristos ms->hashLog3 = hashLog3; 2000*3117ece4Schristos ms->lazySkipping = 0; 2001*3117ece4Schristos 2002*3117ece4Schristos ZSTD_invalidateMatchState(ms); 2003*3117ece4Schristos 2004*3117ece4Schristos assert(!ZSTD_cwksp_reserve_failed(ws)); /* check that allocation hasn't already failed */ 2005*3117ece4Schristos 2006*3117ece4Schristos ZSTD_cwksp_clear_tables(ws); 2007*3117ece4Schristos 2008*3117ece4Schristos DEBUGLOG(5, "reserving table space"); 2009*3117ece4Schristos /* table Space */ 2010*3117ece4Schristos ms->hashTable = (U32*)ZSTD_cwksp_reserve_table(ws, hSize * sizeof(U32)); 2011*3117ece4Schristos ms->chainTable = (U32*)ZSTD_cwksp_reserve_table(ws, chainSize * sizeof(U32)); 2012*3117ece4Schristos ms->hashTable3 = (U32*)ZSTD_cwksp_reserve_table(ws, h3Size * sizeof(U32)); 2013*3117ece4Schristos RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation, 2014*3117ece4Schristos "failed a workspace allocation in ZSTD_reset_matchState"); 2015*3117ece4Schristos 2016*3117ece4Schristos DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_leaveDirty); 2017*3117ece4Schristos if (crp!=ZSTDcrp_leaveDirty) { 2018*3117ece4Schristos /* reset tables only */ 2019*3117ece4Schristos ZSTD_cwksp_clean_tables(ws); 2020*3117ece4Schristos } 2021*3117ece4Schristos 2022*3117ece4Schristos if (ZSTD_rowMatchFinderUsed(cParams->strategy, useRowMatchFinder)) { 2023*3117ece4Schristos /* Row match finder needs an additional table of hashes ("tags") */ 2024*3117ece4Schristos size_t const tagTableSize = hSize; 2025*3117ece4Schristos /* We want to generate a new salt in case we reset a Cctx, but we always want to use 2026*3117ece4Schristos * 0 when we reset a Cdict */ 2027*3117ece4Schristos if(forWho == ZSTD_resetTarget_CCtx) { 2028*3117ece4Schristos ms->tagTable = (BYTE*) ZSTD_cwksp_reserve_aligned_init_once(ws, tagTableSize); 2029*3117ece4Schristos ZSTD_advanceHashSalt(ms); 2030*3117ece4Schristos } else { 2031*3117ece4Schristos /* When we are not salting we want to always memset the memory */ 2032*3117ece4Schristos ms->tagTable = (BYTE*) ZSTD_cwksp_reserve_aligned(ws, tagTableSize); 2033*3117ece4Schristos ZSTD_memset(ms->tagTable, 0, tagTableSize); 2034*3117ece4Schristos ms->hashSalt = 0; 2035*3117ece4Schristos } 2036*3117ece4Schristos { /* Switch to 32-entry rows if searchLog is 5 (or more) */ 2037*3117ece4Schristos U32 const rowLog = BOUNDED(4, cParams->searchLog, 6); 2038*3117ece4Schristos assert(cParams->hashLog >= rowLog); 2039*3117ece4Schristos ms->rowHashLog = cParams->hashLog - rowLog; 2040*3117ece4Schristos } 2041*3117ece4Schristos } 2042*3117ece4Schristos 2043*3117ece4Schristos /* opt parser space */ 2044*3117ece4Schristos if ((forWho == ZSTD_resetTarget_CCtx) && (cParams->strategy >= ZSTD_btopt)) { 2045*3117ece4Schristos DEBUGLOG(4, "reserving optimal parser space"); 2046*3117ece4Schristos ms->opt.litFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (1<<Litbits) * sizeof(unsigned)); 2047*3117ece4Schristos ms->opt.litLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxLL+1) * sizeof(unsigned)); 2048*3117ece4Schristos ms->opt.matchLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxML+1) * sizeof(unsigned)); 2049*3117ece4Schristos ms->opt.offCodeFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxOff+1) * sizeof(unsigned)); 2050*3117ece4Schristos ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, ZSTD_OPT_SIZE * sizeof(ZSTD_match_t)); 2051*3117ece4Schristos ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, ZSTD_OPT_SIZE * sizeof(ZSTD_optimal_t)); 2052*3117ece4Schristos } 2053*3117ece4Schristos 2054*3117ece4Schristos ms->cParams = *cParams; 2055*3117ece4Schristos 2056*3117ece4Schristos RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation, 2057*3117ece4Schristos "failed a workspace allocation in ZSTD_reset_matchState"); 2058*3117ece4Schristos return 0; 2059*3117ece4Schristos } 2060*3117ece4Schristos 2061*3117ece4Schristos /* ZSTD_indexTooCloseToMax() : 2062*3117ece4Schristos * minor optimization : prefer memset() rather than reduceIndex() 2063*3117ece4Schristos * which is measurably slow in some circumstances (reported for Visual Studio). 2064*3117ece4Schristos * Works when re-using a context for a lot of smallish inputs : 2065*3117ece4Schristos * if all inputs are smaller than ZSTD_INDEXOVERFLOW_MARGIN, 2066*3117ece4Schristos * memset() will be triggered before reduceIndex(). 2067*3117ece4Schristos */ 2068*3117ece4Schristos #define ZSTD_INDEXOVERFLOW_MARGIN (16 MB) 2069*3117ece4Schristos static int ZSTD_indexTooCloseToMax(ZSTD_window_t w) 2070*3117ece4Schristos { 2071*3117ece4Schristos return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN); 2072*3117ece4Schristos } 2073*3117ece4Schristos 2074*3117ece4Schristos /** ZSTD_dictTooBig(): 2075*3117ece4Schristos * When dictionaries are larger than ZSTD_CHUNKSIZE_MAX they can't be loaded in 2076*3117ece4Schristos * one go generically. So we ensure that in that case we reset the tables to zero, 2077*3117ece4Schristos * so that we can load as much of the dictionary as possible. 2078*3117ece4Schristos */ 2079*3117ece4Schristos static int ZSTD_dictTooBig(size_t const loadedDictSize) 2080*3117ece4Schristos { 2081*3117ece4Schristos return loadedDictSize > ZSTD_CHUNKSIZE_MAX; 2082*3117ece4Schristos } 2083*3117ece4Schristos 2084*3117ece4Schristos /*! ZSTD_resetCCtx_internal() : 2085*3117ece4Schristos * @param loadedDictSize The size of the dictionary to be loaded 2086*3117ece4Schristos * into the context, if any. If no dictionary is used, or the 2087*3117ece4Schristos * dictionary is being attached / copied, then pass 0. 2088*3117ece4Schristos * note : `params` are assumed fully validated at this stage. 2089*3117ece4Schristos */ 2090*3117ece4Schristos static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, 2091*3117ece4Schristos ZSTD_CCtx_params const* params, 2092*3117ece4Schristos U64 const pledgedSrcSize, 2093*3117ece4Schristos size_t const loadedDictSize, 2094*3117ece4Schristos ZSTD_compResetPolicy_e const crp, 2095*3117ece4Schristos ZSTD_buffered_policy_e const zbuff) 2096*3117ece4Schristos { 2097*3117ece4Schristos ZSTD_cwksp* const ws = &zc->workspace; 2098*3117ece4Schristos DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u, useRowMatchFinder=%d useBlockSplitter=%d", 2099*3117ece4Schristos (U32)pledgedSrcSize, params->cParams.windowLog, (int)params->useRowMatchFinder, (int)params->useBlockSplitter); 2100*3117ece4Schristos assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); 2101*3117ece4Schristos 2102*3117ece4Schristos zc->isFirstBlock = 1; 2103*3117ece4Schristos 2104*3117ece4Schristos /* Set applied params early so we can modify them for LDM, 2105*3117ece4Schristos * and point params at the applied params. 2106*3117ece4Schristos */ 2107*3117ece4Schristos zc->appliedParams = *params; 2108*3117ece4Schristos params = &zc->appliedParams; 2109*3117ece4Schristos 2110*3117ece4Schristos assert(params->useRowMatchFinder != ZSTD_ps_auto); 2111*3117ece4Schristos assert(params->useBlockSplitter != ZSTD_ps_auto); 2112*3117ece4Schristos assert(params->ldmParams.enableLdm != ZSTD_ps_auto); 2113*3117ece4Schristos assert(params->maxBlockSize != 0); 2114*3117ece4Schristos if (params->ldmParams.enableLdm == ZSTD_ps_enable) { 2115*3117ece4Schristos /* Adjust long distance matching parameters */ 2116*3117ece4Schristos ZSTD_ldm_adjustParameters(&zc->appliedParams.ldmParams, ¶ms->cParams); 2117*3117ece4Schristos assert(params->ldmParams.hashLog >= params->ldmParams.bucketSizeLog); 2118*3117ece4Schristos assert(params->ldmParams.hashRateLog < 32); 2119*3117ece4Schristos } 2120*3117ece4Schristos 2121*3117ece4Schristos { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params->cParams.windowLog), pledgedSrcSize)); 2122*3117ece4Schristos size_t const blockSize = MIN(params->maxBlockSize, windowSize); 2123*3117ece4Schristos size_t const maxNbSeq = ZSTD_maxNbSeq(blockSize, params->cParams.minMatch, ZSTD_hasExtSeqProd(params)); 2124*3117ece4Schristos size_t const buffOutSize = (zbuff == ZSTDb_buffered && params->outBufferMode == ZSTD_bm_buffered) 2125*3117ece4Schristos ? ZSTD_compressBound(blockSize) + 1 2126*3117ece4Schristos : 0; 2127*3117ece4Schristos size_t const buffInSize = (zbuff == ZSTDb_buffered && params->inBufferMode == ZSTD_bm_buffered) 2128*3117ece4Schristos ? windowSize + blockSize 2129*3117ece4Schristos : 0; 2130*3117ece4Schristos size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize); 2131*3117ece4Schristos 2132*3117ece4Schristos int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window); 2133*3117ece4Schristos int const dictTooBig = ZSTD_dictTooBig(loadedDictSize); 2134*3117ece4Schristos ZSTD_indexResetPolicy_e needsIndexReset = 2135*3117ece4Schristos (indexTooClose || dictTooBig || !zc->initialized) ? ZSTDirp_reset : ZSTDirp_continue; 2136*3117ece4Schristos 2137*3117ece4Schristos size_t const neededSpace = 2138*3117ece4Schristos ZSTD_estimateCCtxSize_usingCCtxParams_internal( 2139*3117ece4Schristos ¶ms->cParams, ¶ms->ldmParams, zc->staticSize != 0, params->useRowMatchFinder, 2140*3117ece4Schristos buffInSize, buffOutSize, pledgedSrcSize, ZSTD_hasExtSeqProd(params), params->maxBlockSize); 2141*3117ece4Schristos 2142*3117ece4Schristos FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!"); 2143*3117ece4Schristos 2144*3117ece4Schristos if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0); 2145*3117ece4Schristos 2146*3117ece4Schristos { /* Check if workspace is large enough, alloc a new one if needed */ 2147*3117ece4Schristos int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace; 2148*3117ece4Schristos int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace); 2149*3117ece4Schristos int resizeWorkspace = workspaceTooSmall || workspaceWasteful; 2150*3117ece4Schristos DEBUGLOG(4, "Need %zu B workspace", neededSpace); 2151*3117ece4Schristos DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); 2152*3117ece4Schristos 2153*3117ece4Schristos if (resizeWorkspace) { 2154*3117ece4Schristos DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB", 2155*3117ece4Schristos ZSTD_cwksp_sizeof(ws) >> 10, 2156*3117ece4Schristos neededSpace >> 10); 2157*3117ece4Schristos 2158*3117ece4Schristos RETURN_ERROR_IF(zc->staticSize, memory_allocation, "static cctx : no resize"); 2159*3117ece4Schristos 2160*3117ece4Schristos needsIndexReset = ZSTDirp_reset; 2161*3117ece4Schristos 2162*3117ece4Schristos ZSTD_cwksp_free(ws, zc->customMem); 2163*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_cwksp_create(ws, neededSpace, zc->customMem), ""); 2164*3117ece4Schristos 2165*3117ece4Schristos DEBUGLOG(5, "reserving object space"); 2166*3117ece4Schristos /* Statically sized space. 2167*3117ece4Schristos * entropyWorkspace never moves, 2168*3117ece4Schristos * though prev/next block swap places */ 2169*3117ece4Schristos assert(ZSTD_cwksp_check_available(ws, 2 * sizeof(ZSTD_compressedBlockState_t))); 2170*3117ece4Schristos zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t)); 2171*3117ece4Schristos RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock"); 2172*3117ece4Schristos zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t)); 2173*3117ece4Schristos RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate nextCBlock"); 2174*3117ece4Schristos zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, ENTROPY_WORKSPACE_SIZE); 2175*3117ece4Schristos RETURN_ERROR_IF(zc->entropyWorkspace == NULL, memory_allocation, "couldn't allocate entropyWorkspace"); 2176*3117ece4Schristos } } 2177*3117ece4Schristos 2178*3117ece4Schristos ZSTD_cwksp_clear(ws); 2179*3117ece4Schristos 2180*3117ece4Schristos /* init params */ 2181*3117ece4Schristos zc->blockState.matchState.cParams = params->cParams; 2182*3117ece4Schristos zc->blockState.matchState.prefetchCDictTables = params->prefetchCDictTables == ZSTD_ps_enable; 2183*3117ece4Schristos zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; 2184*3117ece4Schristos zc->consumedSrcSize = 0; 2185*3117ece4Schristos zc->producedCSize = 0; 2186*3117ece4Schristos if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) 2187*3117ece4Schristos zc->appliedParams.fParams.contentSizeFlag = 0; 2188*3117ece4Schristos DEBUGLOG(4, "pledged content size : %u ; flag : %u", 2189*3117ece4Schristos (unsigned)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag); 2190*3117ece4Schristos zc->blockSize = blockSize; 2191*3117ece4Schristos 2192*3117ece4Schristos XXH64_reset(&zc->xxhState, 0); 2193*3117ece4Schristos zc->stage = ZSTDcs_init; 2194*3117ece4Schristos zc->dictID = 0; 2195*3117ece4Schristos zc->dictContentSize = 0; 2196*3117ece4Schristos 2197*3117ece4Schristos ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock); 2198*3117ece4Schristos 2199*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_reset_matchState( 2200*3117ece4Schristos &zc->blockState.matchState, 2201*3117ece4Schristos ws, 2202*3117ece4Schristos ¶ms->cParams, 2203*3117ece4Schristos params->useRowMatchFinder, 2204*3117ece4Schristos crp, 2205*3117ece4Schristos needsIndexReset, 2206*3117ece4Schristos ZSTD_resetTarget_CCtx), ""); 2207*3117ece4Schristos 2208*3117ece4Schristos zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef)); 2209*3117ece4Schristos 2210*3117ece4Schristos /* ldm hash table */ 2211*3117ece4Schristos if (params->ldmParams.enableLdm == ZSTD_ps_enable) { 2212*3117ece4Schristos /* TODO: avoid memset? */ 2213*3117ece4Schristos size_t const ldmHSize = ((size_t)1) << params->ldmParams.hashLog; 2214*3117ece4Schristos zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t)); 2215*3117ece4Schristos ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t)); 2216*3117ece4Schristos zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq)); 2217*3117ece4Schristos zc->maxNbLdmSequences = maxNbLdmSeq; 2218*3117ece4Schristos 2219*3117ece4Schristos ZSTD_window_init(&zc->ldmState.window); 2220*3117ece4Schristos zc->ldmState.loadedDictEnd = 0; 2221*3117ece4Schristos } 2222*3117ece4Schristos 2223*3117ece4Schristos /* reserve space for block-level external sequences */ 2224*3117ece4Schristos if (ZSTD_hasExtSeqProd(params)) { 2225*3117ece4Schristos size_t const maxNbExternalSeq = ZSTD_sequenceBound(blockSize); 2226*3117ece4Schristos zc->extSeqBufCapacity = maxNbExternalSeq; 2227*3117ece4Schristos zc->extSeqBuf = 2228*3117ece4Schristos (ZSTD_Sequence*)ZSTD_cwksp_reserve_aligned(ws, maxNbExternalSeq * sizeof(ZSTD_Sequence)); 2229*3117ece4Schristos } 2230*3117ece4Schristos 2231*3117ece4Schristos /* buffers */ 2232*3117ece4Schristos 2233*3117ece4Schristos /* ZSTD_wildcopy() is used to copy into the literals buffer, 2234*3117ece4Schristos * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes. 2235*3117ece4Schristos */ 2236*3117ece4Schristos zc->seqStore.litStart = ZSTD_cwksp_reserve_buffer(ws, blockSize + WILDCOPY_OVERLENGTH); 2237*3117ece4Schristos zc->seqStore.maxNbLit = blockSize; 2238*3117ece4Schristos 2239*3117ece4Schristos zc->bufferedPolicy = zbuff; 2240*3117ece4Schristos zc->inBuffSize = buffInSize; 2241*3117ece4Schristos zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize); 2242*3117ece4Schristos zc->outBuffSize = buffOutSize; 2243*3117ece4Schristos zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize); 2244*3117ece4Schristos 2245*3117ece4Schristos /* ldm bucketOffsets table */ 2246*3117ece4Schristos if (params->ldmParams.enableLdm == ZSTD_ps_enable) { 2247*3117ece4Schristos /* TODO: avoid memset? */ 2248*3117ece4Schristos size_t const numBuckets = 2249*3117ece4Schristos ((size_t)1) << (params->ldmParams.hashLog - 2250*3117ece4Schristos params->ldmParams.bucketSizeLog); 2251*3117ece4Schristos zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, numBuckets); 2252*3117ece4Schristos ZSTD_memset(zc->ldmState.bucketOffsets, 0, numBuckets); 2253*3117ece4Schristos } 2254*3117ece4Schristos 2255*3117ece4Schristos /* sequences storage */ 2256*3117ece4Schristos ZSTD_referenceExternalSequences(zc, NULL, 0); 2257*3117ece4Schristos zc->seqStore.maxNbSeq = maxNbSeq; 2258*3117ece4Schristos zc->seqStore.llCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); 2259*3117ece4Schristos zc->seqStore.mlCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); 2260*3117ece4Schristos zc->seqStore.ofCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); 2261*3117ece4Schristos 2262*3117ece4Schristos DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws)); 2263*3117ece4Schristos assert(ZSTD_cwksp_estimated_space_within_bounds(ws, neededSpace)); 2264*3117ece4Schristos 2265*3117ece4Schristos zc->initialized = 1; 2266*3117ece4Schristos 2267*3117ece4Schristos return 0; 2268*3117ece4Schristos } 2269*3117ece4Schristos } 2270*3117ece4Schristos 2271*3117ece4Schristos /* ZSTD_invalidateRepCodes() : 2272*3117ece4Schristos * ensures next compression will not use repcodes from previous block. 2273*3117ece4Schristos * Note : only works with regular variant; 2274*3117ece4Schristos * do not use with extDict variant ! */ 2275*3117ece4Schristos void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) { 2276*3117ece4Schristos int i; 2277*3117ece4Schristos for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0; 2278*3117ece4Schristos assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window)); 2279*3117ece4Schristos } 2280*3117ece4Schristos 2281*3117ece4Schristos /* These are the approximate sizes for each strategy past which copying the 2282*3117ece4Schristos * dictionary tables into the working context is faster than using them 2283*3117ece4Schristos * in-place. 2284*3117ece4Schristos */ 2285*3117ece4Schristos static const size_t attachDictSizeCutoffs[ZSTD_STRATEGY_MAX+1] = { 2286*3117ece4Schristos 8 KB, /* unused */ 2287*3117ece4Schristos 8 KB, /* ZSTD_fast */ 2288*3117ece4Schristos 16 KB, /* ZSTD_dfast */ 2289*3117ece4Schristos 32 KB, /* ZSTD_greedy */ 2290*3117ece4Schristos 32 KB, /* ZSTD_lazy */ 2291*3117ece4Schristos 32 KB, /* ZSTD_lazy2 */ 2292*3117ece4Schristos 32 KB, /* ZSTD_btlazy2 */ 2293*3117ece4Schristos 32 KB, /* ZSTD_btopt */ 2294*3117ece4Schristos 8 KB, /* ZSTD_btultra */ 2295*3117ece4Schristos 8 KB /* ZSTD_btultra2 */ 2296*3117ece4Schristos }; 2297*3117ece4Schristos 2298*3117ece4Schristos static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, 2299*3117ece4Schristos const ZSTD_CCtx_params* params, 2300*3117ece4Schristos U64 pledgedSrcSize) 2301*3117ece4Schristos { 2302*3117ece4Schristos size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy]; 2303*3117ece4Schristos int const dedicatedDictSearch = cdict->matchState.dedicatedDictSearch; 2304*3117ece4Schristos return dedicatedDictSearch 2305*3117ece4Schristos || ( ( pledgedSrcSize <= cutoff 2306*3117ece4Schristos || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN 2307*3117ece4Schristos || params->attachDictPref == ZSTD_dictForceAttach ) 2308*3117ece4Schristos && params->attachDictPref != ZSTD_dictForceCopy 2309*3117ece4Schristos && !params->forceWindow ); /* dictMatchState isn't correctly 2310*3117ece4Schristos * handled in _enforceMaxDist */ 2311*3117ece4Schristos } 2312*3117ece4Schristos 2313*3117ece4Schristos static size_t 2314*3117ece4Schristos ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, 2315*3117ece4Schristos const ZSTD_CDict* cdict, 2316*3117ece4Schristos ZSTD_CCtx_params params, 2317*3117ece4Schristos U64 pledgedSrcSize, 2318*3117ece4Schristos ZSTD_buffered_policy_e zbuff) 2319*3117ece4Schristos { 2320*3117ece4Schristos DEBUGLOG(4, "ZSTD_resetCCtx_byAttachingCDict() pledgedSrcSize=%llu", 2321*3117ece4Schristos (unsigned long long)pledgedSrcSize); 2322*3117ece4Schristos { 2323*3117ece4Schristos ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams; 2324*3117ece4Schristos unsigned const windowLog = params.cParams.windowLog; 2325*3117ece4Schristos assert(windowLog != 0); 2326*3117ece4Schristos /* Resize working context table params for input only, since the dict 2327*3117ece4Schristos * has its own tables. */ 2328*3117ece4Schristos /* pledgedSrcSize == 0 means 0! */ 2329*3117ece4Schristos 2330*3117ece4Schristos if (cdict->matchState.dedicatedDictSearch) { 2331*3117ece4Schristos ZSTD_dedicatedDictSearch_revertCParams(&adjusted_cdict_cParams); 2332*3117ece4Schristos } 2333*3117ece4Schristos 2334*3117ece4Schristos params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize, 2335*3117ece4Schristos cdict->dictContentSize, ZSTD_cpm_attachDict, 2336*3117ece4Schristos params.useRowMatchFinder); 2337*3117ece4Schristos params.cParams.windowLog = windowLog; 2338*3117ece4Schristos params.useRowMatchFinder = cdict->useRowMatchFinder; /* cdict overrides */ 2339*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize, 2340*3117ece4Schristos /* loadedDictSize */ 0, 2341*3117ece4Schristos ZSTDcrp_makeClean, zbuff), ""); 2342*3117ece4Schristos assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy); 2343*3117ece4Schristos } 2344*3117ece4Schristos 2345*3117ece4Schristos { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc 2346*3117ece4Schristos - cdict->matchState.window.base); 2347*3117ece4Schristos const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit; 2348*3117ece4Schristos if (cdictLen == 0) { 2349*3117ece4Schristos /* don't even attach dictionaries with no contents */ 2350*3117ece4Schristos DEBUGLOG(4, "skipping attaching empty dictionary"); 2351*3117ece4Schristos } else { 2352*3117ece4Schristos DEBUGLOG(4, "attaching dictionary into context"); 2353*3117ece4Schristos cctx->blockState.matchState.dictMatchState = &cdict->matchState; 2354*3117ece4Schristos 2355*3117ece4Schristos /* prep working match state so dict matches never have negative indices 2356*3117ece4Schristos * when they are translated to the working context's index space. */ 2357*3117ece4Schristos if (cctx->blockState.matchState.window.dictLimit < cdictEnd) { 2358*3117ece4Schristos cctx->blockState.matchState.window.nextSrc = 2359*3117ece4Schristos cctx->blockState.matchState.window.base + cdictEnd; 2360*3117ece4Schristos ZSTD_window_clear(&cctx->blockState.matchState.window); 2361*3117ece4Schristos } 2362*3117ece4Schristos /* loadedDictEnd is expressed within the referential of the active context */ 2363*3117ece4Schristos cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit; 2364*3117ece4Schristos } } 2365*3117ece4Schristos 2366*3117ece4Schristos cctx->dictID = cdict->dictID; 2367*3117ece4Schristos cctx->dictContentSize = cdict->dictContentSize; 2368*3117ece4Schristos 2369*3117ece4Schristos /* copy block state */ 2370*3117ece4Schristos ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 2371*3117ece4Schristos 2372*3117ece4Schristos return 0; 2373*3117ece4Schristos } 2374*3117ece4Schristos 2375*3117ece4Schristos static void ZSTD_copyCDictTableIntoCCtx(U32* dst, U32 const* src, size_t tableSize, 2376*3117ece4Schristos ZSTD_compressionParameters const* cParams) { 2377*3117ece4Schristos if (ZSTD_CDictIndicesAreTagged(cParams)){ 2378*3117ece4Schristos /* Remove tags from the CDict table if they are present. 2379*3117ece4Schristos * See docs on "short cache" in zstd_compress_internal.h for context. */ 2380*3117ece4Schristos size_t i; 2381*3117ece4Schristos for (i = 0; i < tableSize; i++) { 2382*3117ece4Schristos U32 const taggedIndex = src[i]; 2383*3117ece4Schristos U32 const index = taggedIndex >> ZSTD_SHORT_CACHE_TAG_BITS; 2384*3117ece4Schristos dst[i] = index; 2385*3117ece4Schristos } 2386*3117ece4Schristos } else { 2387*3117ece4Schristos ZSTD_memcpy(dst, src, tableSize * sizeof(U32)); 2388*3117ece4Schristos } 2389*3117ece4Schristos } 2390*3117ece4Schristos 2391*3117ece4Schristos static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, 2392*3117ece4Schristos const ZSTD_CDict* cdict, 2393*3117ece4Schristos ZSTD_CCtx_params params, 2394*3117ece4Schristos U64 pledgedSrcSize, 2395*3117ece4Schristos ZSTD_buffered_policy_e zbuff) 2396*3117ece4Schristos { 2397*3117ece4Schristos const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; 2398*3117ece4Schristos 2399*3117ece4Schristos assert(!cdict->matchState.dedicatedDictSearch); 2400*3117ece4Schristos DEBUGLOG(4, "ZSTD_resetCCtx_byCopyingCDict() pledgedSrcSize=%llu", 2401*3117ece4Schristos (unsigned long long)pledgedSrcSize); 2402*3117ece4Schristos 2403*3117ece4Schristos { unsigned const windowLog = params.cParams.windowLog; 2404*3117ece4Schristos assert(windowLog != 0); 2405*3117ece4Schristos /* Copy only compression parameters related to tables. */ 2406*3117ece4Schristos params.cParams = *cdict_cParams; 2407*3117ece4Schristos params.cParams.windowLog = windowLog; 2408*3117ece4Schristos params.useRowMatchFinder = cdict->useRowMatchFinder; 2409*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, ¶ms, pledgedSrcSize, 2410*3117ece4Schristos /* loadedDictSize */ 0, 2411*3117ece4Schristos ZSTDcrp_leaveDirty, zbuff), ""); 2412*3117ece4Schristos assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); 2413*3117ece4Schristos assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog); 2414*3117ece4Schristos assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog); 2415*3117ece4Schristos } 2416*3117ece4Schristos 2417*3117ece4Schristos ZSTD_cwksp_mark_tables_dirty(&cctx->workspace); 2418*3117ece4Schristos assert(params.useRowMatchFinder != ZSTD_ps_auto); 2419*3117ece4Schristos 2420*3117ece4Schristos /* copy tables */ 2421*3117ece4Schristos { size_t const chainSize = ZSTD_allocateChainTable(cdict_cParams->strategy, cdict->useRowMatchFinder, 0 /* DDS guaranteed disabled */) 2422*3117ece4Schristos ? ((size_t)1 << cdict_cParams->chainLog) 2423*3117ece4Schristos : 0; 2424*3117ece4Schristos size_t const hSize = (size_t)1 << cdict_cParams->hashLog; 2425*3117ece4Schristos 2426*3117ece4Schristos ZSTD_copyCDictTableIntoCCtx(cctx->blockState.matchState.hashTable, 2427*3117ece4Schristos cdict->matchState.hashTable, 2428*3117ece4Schristos hSize, cdict_cParams); 2429*3117ece4Schristos 2430*3117ece4Schristos /* Do not copy cdict's chainTable if cctx has parameters such that it would not use chainTable */ 2431*3117ece4Schristos if (ZSTD_allocateChainTable(cctx->appliedParams.cParams.strategy, cctx->appliedParams.useRowMatchFinder, 0 /* forDDSDict */)) { 2432*3117ece4Schristos ZSTD_copyCDictTableIntoCCtx(cctx->blockState.matchState.chainTable, 2433*3117ece4Schristos cdict->matchState.chainTable, 2434*3117ece4Schristos chainSize, cdict_cParams); 2435*3117ece4Schristos } 2436*3117ece4Schristos /* copy tag table */ 2437*3117ece4Schristos if (ZSTD_rowMatchFinderUsed(cdict_cParams->strategy, cdict->useRowMatchFinder)) { 2438*3117ece4Schristos size_t const tagTableSize = hSize; 2439*3117ece4Schristos ZSTD_memcpy(cctx->blockState.matchState.tagTable, 2440*3117ece4Schristos cdict->matchState.tagTable, 2441*3117ece4Schristos tagTableSize); 2442*3117ece4Schristos cctx->blockState.matchState.hashSalt = cdict->matchState.hashSalt; 2443*3117ece4Schristos } 2444*3117ece4Schristos } 2445*3117ece4Schristos 2446*3117ece4Schristos /* Zero the hashTable3, since the cdict never fills it */ 2447*3117ece4Schristos { int const h3log = cctx->blockState.matchState.hashLog3; 2448*3117ece4Schristos size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; 2449*3117ece4Schristos assert(cdict->matchState.hashLog3 == 0); 2450*3117ece4Schristos ZSTD_memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); 2451*3117ece4Schristos } 2452*3117ece4Schristos 2453*3117ece4Schristos ZSTD_cwksp_mark_tables_clean(&cctx->workspace); 2454*3117ece4Schristos 2455*3117ece4Schristos /* copy dictionary offsets */ 2456*3117ece4Schristos { ZSTD_matchState_t const* srcMatchState = &cdict->matchState; 2457*3117ece4Schristos ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState; 2458*3117ece4Schristos dstMatchState->window = srcMatchState->window; 2459*3117ece4Schristos dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 2460*3117ece4Schristos dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 2461*3117ece4Schristos } 2462*3117ece4Schristos 2463*3117ece4Schristos cctx->dictID = cdict->dictID; 2464*3117ece4Schristos cctx->dictContentSize = cdict->dictContentSize; 2465*3117ece4Schristos 2466*3117ece4Schristos /* copy block state */ 2467*3117ece4Schristos ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 2468*3117ece4Schristos 2469*3117ece4Schristos return 0; 2470*3117ece4Schristos } 2471*3117ece4Schristos 2472*3117ece4Schristos /* We have a choice between copying the dictionary context into the working 2473*3117ece4Schristos * context, or referencing the dictionary context from the working context 2474*3117ece4Schristos * in-place. We decide here which strategy to use. */ 2475*3117ece4Schristos static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx, 2476*3117ece4Schristos const ZSTD_CDict* cdict, 2477*3117ece4Schristos const ZSTD_CCtx_params* params, 2478*3117ece4Schristos U64 pledgedSrcSize, 2479*3117ece4Schristos ZSTD_buffered_policy_e zbuff) 2480*3117ece4Schristos { 2481*3117ece4Schristos 2482*3117ece4Schristos DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)", 2483*3117ece4Schristos (unsigned)pledgedSrcSize); 2484*3117ece4Schristos 2485*3117ece4Schristos if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) { 2486*3117ece4Schristos return ZSTD_resetCCtx_byAttachingCDict( 2487*3117ece4Schristos cctx, cdict, *params, pledgedSrcSize, zbuff); 2488*3117ece4Schristos } else { 2489*3117ece4Schristos return ZSTD_resetCCtx_byCopyingCDict( 2490*3117ece4Schristos cctx, cdict, *params, pledgedSrcSize, zbuff); 2491*3117ece4Schristos } 2492*3117ece4Schristos } 2493*3117ece4Schristos 2494*3117ece4Schristos /*! ZSTD_copyCCtx_internal() : 2495*3117ece4Schristos * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 2496*3117ece4Schristos * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 2497*3117ece4Schristos * The "context", in this case, refers to the hash and chain tables, 2498*3117ece4Schristos * entropy tables, and dictionary references. 2499*3117ece4Schristos * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx. 2500*3117ece4Schristos * @return : 0, or an error code */ 2501*3117ece4Schristos static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, 2502*3117ece4Schristos const ZSTD_CCtx* srcCCtx, 2503*3117ece4Schristos ZSTD_frameParameters fParams, 2504*3117ece4Schristos U64 pledgedSrcSize, 2505*3117ece4Schristos ZSTD_buffered_policy_e zbuff) 2506*3117ece4Schristos { 2507*3117ece4Schristos RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong, 2508*3117ece4Schristos "Can't copy a ctx that's not in init stage."); 2509*3117ece4Schristos DEBUGLOG(5, "ZSTD_copyCCtx_internal"); 2510*3117ece4Schristos ZSTD_memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); 2511*3117ece4Schristos { ZSTD_CCtx_params params = dstCCtx->requestedParams; 2512*3117ece4Schristos /* Copy only compression parameters related to tables. */ 2513*3117ece4Schristos params.cParams = srcCCtx->appliedParams.cParams; 2514*3117ece4Schristos assert(srcCCtx->appliedParams.useRowMatchFinder != ZSTD_ps_auto); 2515*3117ece4Schristos assert(srcCCtx->appliedParams.useBlockSplitter != ZSTD_ps_auto); 2516*3117ece4Schristos assert(srcCCtx->appliedParams.ldmParams.enableLdm != ZSTD_ps_auto); 2517*3117ece4Schristos params.useRowMatchFinder = srcCCtx->appliedParams.useRowMatchFinder; 2518*3117ece4Schristos params.useBlockSplitter = srcCCtx->appliedParams.useBlockSplitter; 2519*3117ece4Schristos params.ldmParams = srcCCtx->appliedParams.ldmParams; 2520*3117ece4Schristos params.fParams = fParams; 2521*3117ece4Schristos params.maxBlockSize = srcCCtx->appliedParams.maxBlockSize; 2522*3117ece4Schristos ZSTD_resetCCtx_internal(dstCCtx, ¶ms, pledgedSrcSize, 2523*3117ece4Schristos /* loadedDictSize */ 0, 2524*3117ece4Schristos ZSTDcrp_leaveDirty, zbuff); 2525*3117ece4Schristos assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog); 2526*3117ece4Schristos assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy); 2527*3117ece4Schristos assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog); 2528*3117ece4Schristos assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog); 2529*3117ece4Schristos assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3); 2530*3117ece4Schristos } 2531*3117ece4Schristos 2532*3117ece4Schristos ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace); 2533*3117ece4Schristos 2534*3117ece4Schristos /* copy tables */ 2535*3117ece4Schristos { size_t const chainSize = ZSTD_allocateChainTable(srcCCtx->appliedParams.cParams.strategy, 2536*3117ece4Schristos srcCCtx->appliedParams.useRowMatchFinder, 2537*3117ece4Schristos 0 /* forDDSDict */) 2538*3117ece4Schristos ? ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog) 2539*3117ece4Schristos : 0; 2540*3117ece4Schristos size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; 2541*3117ece4Schristos int const h3log = srcCCtx->blockState.matchState.hashLog3; 2542*3117ece4Schristos size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; 2543*3117ece4Schristos 2544*3117ece4Schristos ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable, 2545*3117ece4Schristos srcCCtx->blockState.matchState.hashTable, 2546*3117ece4Schristos hSize * sizeof(U32)); 2547*3117ece4Schristos ZSTD_memcpy(dstCCtx->blockState.matchState.chainTable, 2548*3117ece4Schristos srcCCtx->blockState.matchState.chainTable, 2549*3117ece4Schristos chainSize * sizeof(U32)); 2550*3117ece4Schristos ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable3, 2551*3117ece4Schristos srcCCtx->blockState.matchState.hashTable3, 2552*3117ece4Schristos h3Size * sizeof(U32)); 2553*3117ece4Schristos } 2554*3117ece4Schristos 2555*3117ece4Schristos ZSTD_cwksp_mark_tables_clean(&dstCCtx->workspace); 2556*3117ece4Schristos 2557*3117ece4Schristos /* copy dictionary offsets */ 2558*3117ece4Schristos { 2559*3117ece4Schristos const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState; 2560*3117ece4Schristos ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState; 2561*3117ece4Schristos dstMatchState->window = srcMatchState->window; 2562*3117ece4Schristos dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 2563*3117ece4Schristos dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 2564*3117ece4Schristos } 2565*3117ece4Schristos dstCCtx->dictID = srcCCtx->dictID; 2566*3117ece4Schristos dstCCtx->dictContentSize = srcCCtx->dictContentSize; 2567*3117ece4Schristos 2568*3117ece4Schristos /* copy block state */ 2569*3117ece4Schristos ZSTD_memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); 2570*3117ece4Schristos 2571*3117ece4Schristos return 0; 2572*3117ece4Schristos } 2573*3117ece4Schristos 2574*3117ece4Schristos /*! ZSTD_copyCCtx() : 2575*3117ece4Schristos * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 2576*3117ece4Schristos * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 2577*3117ece4Schristos * pledgedSrcSize==0 means "unknown". 2578*3117ece4Schristos * @return : 0, or an error code */ 2579*3117ece4Schristos size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) 2580*3117ece4Schristos { 2581*3117ece4Schristos ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 2582*3117ece4Schristos ZSTD_buffered_policy_e const zbuff = srcCCtx->bufferedPolicy; 2583*3117ece4Schristos ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); 2584*3117ece4Schristos if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; 2585*3117ece4Schristos fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN); 2586*3117ece4Schristos 2587*3117ece4Schristos return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, 2588*3117ece4Schristos fParams, pledgedSrcSize, 2589*3117ece4Schristos zbuff); 2590*3117ece4Schristos } 2591*3117ece4Schristos 2592*3117ece4Schristos 2593*3117ece4Schristos #define ZSTD_ROWSIZE 16 2594*3117ece4Schristos /*! ZSTD_reduceTable() : 2595*3117ece4Schristos * reduce table indexes by `reducerValue`, or squash to zero. 2596*3117ece4Schristos * PreserveMark preserves "unsorted mark" for btlazy2 strategy. 2597*3117ece4Schristos * It must be set to a clear 0/1 value, to remove branch during inlining. 2598*3117ece4Schristos * Presume table size is a multiple of ZSTD_ROWSIZE 2599*3117ece4Schristos * to help auto-vectorization */ 2600*3117ece4Schristos FORCE_INLINE_TEMPLATE void 2601*3117ece4Schristos ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark) 2602*3117ece4Schristos { 2603*3117ece4Schristos int const nbRows = (int)size / ZSTD_ROWSIZE; 2604*3117ece4Schristos int cellNb = 0; 2605*3117ece4Schristos int rowNb; 2606*3117ece4Schristos /* Protect special index values < ZSTD_WINDOW_START_INDEX. */ 2607*3117ece4Schristos U32 const reducerThreshold = reducerValue + ZSTD_WINDOW_START_INDEX; 2608*3117ece4Schristos assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */ 2609*3117ece4Schristos assert(size < (1U<<31)); /* can be casted to int */ 2610*3117ece4Schristos 2611*3117ece4Schristos #if ZSTD_MEMORY_SANITIZER && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) 2612*3117ece4Schristos /* To validate that the table reuse logic is sound, and that we don't 2613*3117ece4Schristos * access table space that we haven't cleaned, we re-"poison" the table 2614*3117ece4Schristos * space every time we mark it dirty. 2615*3117ece4Schristos * 2616*3117ece4Schristos * This function however is intended to operate on those dirty tables and 2617*3117ece4Schristos * re-clean them. So when this function is used correctly, we can unpoison 2618*3117ece4Schristos * the memory it operated on. This introduces a blind spot though, since 2619*3117ece4Schristos * if we now try to operate on __actually__ poisoned memory, we will not 2620*3117ece4Schristos * detect that. */ 2621*3117ece4Schristos __msan_unpoison(table, size * sizeof(U32)); 2622*3117ece4Schristos #endif 2623*3117ece4Schristos 2624*3117ece4Schristos for (rowNb=0 ; rowNb < nbRows ; rowNb++) { 2625*3117ece4Schristos int column; 2626*3117ece4Schristos for (column=0; column<ZSTD_ROWSIZE; column++) { 2627*3117ece4Schristos U32 newVal; 2628*3117ece4Schristos if (preserveMark && table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) { 2629*3117ece4Schristos /* This write is pointless, but is required(?) for the compiler 2630*3117ece4Schristos * to auto-vectorize the loop. */ 2631*3117ece4Schristos newVal = ZSTD_DUBT_UNSORTED_MARK; 2632*3117ece4Schristos } else if (table[cellNb] < reducerThreshold) { 2633*3117ece4Schristos newVal = 0; 2634*3117ece4Schristos } else { 2635*3117ece4Schristos newVal = table[cellNb] - reducerValue; 2636*3117ece4Schristos } 2637*3117ece4Schristos table[cellNb] = newVal; 2638*3117ece4Schristos cellNb++; 2639*3117ece4Schristos } } 2640*3117ece4Schristos } 2641*3117ece4Schristos 2642*3117ece4Schristos static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue) 2643*3117ece4Schristos { 2644*3117ece4Schristos ZSTD_reduceTable_internal(table, size, reducerValue, 0); 2645*3117ece4Schristos } 2646*3117ece4Schristos 2647*3117ece4Schristos static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue) 2648*3117ece4Schristos { 2649*3117ece4Schristos ZSTD_reduceTable_internal(table, size, reducerValue, 1); 2650*3117ece4Schristos } 2651*3117ece4Schristos 2652*3117ece4Schristos /*! ZSTD_reduceIndex() : 2653*3117ece4Schristos * rescale all indexes to avoid future overflow (indexes are U32) */ 2654*3117ece4Schristos static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const U32 reducerValue) 2655*3117ece4Schristos { 2656*3117ece4Schristos { U32 const hSize = (U32)1 << params->cParams.hashLog; 2657*3117ece4Schristos ZSTD_reduceTable(ms->hashTable, hSize, reducerValue); 2658*3117ece4Schristos } 2659*3117ece4Schristos 2660*3117ece4Schristos if (ZSTD_allocateChainTable(params->cParams.strategy, params->useRowMatchFinder, (U32)ms->dedicatedDictSearch)) { 2661*3117ece4Schristos U32 const chainSize = (U32)1 << params->cParams.chainLog; 2662*3117ece4Schristos if (params->cParams.strategy == ZSTD_btlazy2) 2663*3117ece4Schristos ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue); 2664*3117ece4Schristos else 2665*3117ece4Schristos ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue); 2666*3117ece4Schristos } 2667*3117ece4Schristos 2668*3117ece4Schristos if (ms->hashLog3) { 2669*3117ece4Schristos U32 const h3Size = (U32)1 << ms->hashLog3; 2670*3117ece4Schristos ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue); 2671*3117ece4Schristos } 2672*3117ece4Schristos } 2673*3117ece4Schristos 2674*3117ece4Schristos 2675*3117ece4Schristos /*-******************************************************* 2676*3117ece4Schristos * Block entropic compression 2677*3117ece4Schristos *********************************************************/ 2678*3117ece4Schristos 2679*3117ece4Schristos /* See doc/zstd_compression_format.md for detailed format description */ 2680*3117ece4Schristos 2681*3117ece4Schristos int ZSTD_seqToCodes(const seqStore_t* seqStorePtr) 2682*3117ece4Schristos { 2683*3117ece4Schristos const seqDef* const sequences = seqStorePtr->sequencesStart; 2684*3117ece4Schristos BYTE* const llCodeTable = seqStorePtr->llCode; 2685*3117ece4Schristos BYTE* const ofCodeTable = seqStorePtr->ofCode; 2686*3117ece4Schristos BYTE* const mlCodeTable = seqStorePtr->mlCode; 2687*3117ece4Schristos U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 2688*3117ece4Schristos U32 u; 2689*3117ece4Schristos int longOffsets = 0; 2690*3117ece4Schristos assert(nbSeq <= seqStorePtr->maxNbSeq); 2691*3117ece4Schristos for (u=0; u<nbSeq; u++) { 2692*3117ece4Schristos U32 const llv = sequences[u].litLength; 2693*3117ece4Schristos U32 const ofCode = ZSTD_highbit32(sequences[u].offBase); 2694*3117ece4Schristos U32 const mlv = sequences[u].mlBase; 2695*3117ece4Schristos llCodeTable[u] = (BYTE)ZSTD_LLcode(llv); 2696*3117ece4Schristos ofCodeTable[u] = (BYTE)ofCode; 2697*3117ece4Schristos mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv); 2698*3117ece4Schristos assert(!(MEM_64bits() && ofCode >= STREAM_ACCUMULATOR_MIN)); 2699*3117ece4Schristos if (MEM_32bits() && ofCode >= STREAM_ACCUMULATOR_MIN) 2700*3117ece4Schristos longOffsets = 1; 2701*3117ece4Schristos } 2702*3117ece4Schristos if (seqStorePtr->longLengthType==ZSTD_llt_literalLength) 2703*3117ece4Schristos llCodeTable[seqStorePtr->longLengthPos] = MaxLL; 2704*3117ece4Schristos if (seqStorePtr->longLengthType==ZSTD_llt_matchLength) 2705*3117ece4Schristos mlCodeTable[seqStorePtr->longLengthPos] = MaxML; 2706*3117ece4Schristos return longOffsets; 2707*3117ece4Schristos } 2708*3117ece4Schristos 2709*3117ece4Schristos /* ZSTD_useTargetCBlockSize(): 2710*3117ece4Schristos * Returns if target compressed block size param is being used. 2711*3117ece4Schristos * If used, compression will do best effort to make a compressed block size to be around targetCBlockSize. 2712*3117ece4Schristos * Returns 1 if true, 0 otherwise. */ 2713*3117ece4Schristos static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams) 2714*3117ece4Schristos { 2715*3117ece4Schristos DEBUGLOG(5, "ZSTD_useTargetCBlockSize (targetCBlockSize=%zu)", cctxParams->targetCBlockSize); 2716*3117ece4Schristos return (cctxParams->targetCBlockSize != 0); 2717*3117ece4Schristos } 2718*3117ece4Schristos 2719*3117ece4Schristos /* ZSTD_blockSplitterEnabled(): 2720*3117ece4Schristos * Returns if block splitting param is being used 2721*3117ece4Schristos * If used, compression will do best effort to split a block in order to improve compression ratio. 2722*3117ece4Schristos * At the time this function is called, the parameter must be finalized. 2723*3117ece4Schristos * Returns 1 if true, 0 otherwise. */ 2724*3117ece4Schristos static int ZSTD_blockSplitterEnabled(ZSTD_CCtx_params* cctxParams) 2725*3117ece4Schristos { 2726*3117ece4Schristos DEBUGLOG(5, "ZSTD_blockSplitterEnabled (useBlockSplitter=%d)", cctxParams->useBlockSplitter); 2727*3117ece4Schristos assert(cctxParams->useBlockSplitter != ZSTD_ps_auto); 2728*3117ece4Schristos return (cctxParams->useBlockSplitter == ZSTD_ps_enable); 2729*3117ece4Schristos } 2730*3117ece4Schristos 2731*3117ece4Schristos /* Type returned by ZSTD_buildSequencesStatistics containing finalized symbol encoding types 2732*3117ece4Schristos * and size of the sequences statistics 2733*3117ece4Schristos */ 2734*3117ece4Schristos typedef struct { 2735*3117ece4Schristos U32 LLtype; 2736*3117ece4Schristos U32 Offtype; 2737*3117ece4Schristos U32 MLtype; 2738*3117ece4Schristos size_t size; 2739*3117ece4Schristos size_t lastCountSize; /* Accounts for bug in 1.3.4. More detail in ZSTD_entropyCompressSeqStore_internal() */ 2740*3117ece4Schristos int longOffsets; 2741*3117ece4Schristos } ZSTD_symbolEncodingTypeStats_t; 2742*3117ece4Schristos 2743*3117ece4Schristos /* ZSTD_buildSequencesStatistics(): 2744*3117ece4Schristos * Returns a ZSTD_symbolEncodingTypeStats_t, or a zstd error code in the `size` field. 2745*3117ece4Schristos * Modifies `nextEntropy` to have the appropriate values as a side effect. 2746*3117ece4Schristos * nbSeq must be greater than 0. 2747*3117ece4Schristos * 2748*3117ece4Schristos * entropyWkspSize must be of size at least ENTROPY_WORKSPACE_SIZE - (MaxSeq + 1)*sizeof(U32) 2749*3117ece4Schristos */ 2750*3117ece4Schristos static ZSTD_symbolEncodingTypeStats_t 2751*3117ece4Schristos ZSTD_buildSequencesStatistics( 2752*3117ece4Schristos const seqStore_t* seqStorePtr, size_t nbSeq, 2753*3117ece4Schristos const ZSTD_fseCTables_t* prevEntropy, ZSTD_fseCTables_t* nextEntropy, 2754*3117ece4Schristos BYTE* dst, const BYTE* const dstEnd, 2755*3117ece4Schristos ZSTD_strategy strategy, unsigned* countWorkspace, 2756*3117ece4Schristos void* entropyWorkspace, size_t entropyWkspSize) 2757*3117ece4Schristos { 2758*3117ece4Schristos BYTE* const ostart = dst; 2759*3117ece4Schristos const BYTE* const oend = dstEnd; 2760*3117ece4Schristos BYTE* op = ostart; 2761*3117ece4Schristos FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable; 2762*3117ece4Schristos FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable; 2763*3117ece4Schristos FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable; 2764*3117ece4Schristos const BYTE* const ofCodeTable = seqStorePtr->ofCode; 2765*3117ece4Schristos const BYTE* const llCodeTable = seqStorePtr->llCode; 2766*3117ece4Schristos const BYTE* const mlCodeTable = seqStorePtr->mlCode; 2767*3117ece4Schristos ZSTD_symbolEncodingTypeStats_t stats; 2768*3117ece4Schristos 2769*3117ece4Schristos stats.lastCountSize = 0; 2770*3117ece4Schristos /* convert length/distances into codes */ 2771*3117ece4Schristos stats.longOffsets = ZSTD_seqToCodes(seqStorePtr); 2772*3117ece4Schristos assert(op <= oend); 2773*3117ece4Schristos assert(nbSeq != 0); /* ZSTD_selectEncodingType() divides by nbSeq */ 2774*3117ece4Schristos /* build CTable for Literal Lengths */ 2775*3117ece4Schristos { unsigned max = MaxLL; 2776*3117ece4Schristos size_t const mostFrequent = HIST_countFast_wksp(countWorkspace, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ 2777*3117ece4Schristos DEBUGLOG(5, "Building LL table"); 2778*3117ece4Schristos nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode; 2779*3117ece4Schristos stats.LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, 2780*3117ece4Schristos countWorkspace, max, mostFrequent, nbSeq, 2781*3117ece4Schristos LLFSELog, prevEntropy->litlengthCTable, 2782*3117ece4Schristos LL_defaultNorm, LL_defaultNormLog, 2783*3117ece4Schristos ZSTD_defaultAllowed, strategy); 2784*3117ece4Schristos assert(set_basic < set_compressed && set_rle < set_compressed); 2785*3117ece4Schristos assert(!(stats.LLtype < set_compressed && nextEntropy->litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 2786*3117ece4Schristos { size_t const countSize = ZSTD_buildCTable( 2787*3117ece4Schristos op, (size_t)(oend - op), 2788*3117ece4Schristos CTable_LitLength, LLFSELog, (symbolEncodingType_e)stats.LLtype, 2789*3117ece4Schristos countWorkspace, max, llCodeTable, nbSeq, 2790*3117ece4Schristos LL_defaultNorm, LL_defaultNormLog, MaxLL, 2791*3117ece4Schristos prevEntropy->litlengthCTable, 2792*3117ece4Schristos sizeof(prevEntropy->litlengthCTable), 2793*3117ece4Schristos entropyWorkspace, entropyWkspSize); 2794*3117ece4Schristos if (ZSTD_isError(countSize)) { 2795*3117ece4Schristos DEBUGLOG(3, "ZSTD_buildCTable for LitLens failed"); 2796*3117ece4Schristos stats.size = countSize; 2797*3117ece4Schristos return stats; 2798*3117ece4Schristos } 2799*3117ece4Schristos if (stats.LLtype == set_compressed) 2800*3117ece4Schristos stats.lastCountSize = countSize; 2801*3117ece4Schristos op += countSize; 2802*3117ece4Schristos assert(op <= oend); 2803*3117ece4Schristos } } 2804*3117ece4Schristos /* build CTable for Offsets */ 2805*3117ece4Schristos { unsigned max = MaxOff; 2806*3117ece4Schristos size_t const mostFrequent = HIST_countFast_wksp( 2807*3117ece4Schristos countWorkspace, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ 2808*3117ece4Schristos /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ 2809*3117ece4Schristos ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; 2810*3117ece4Schristos DEBUGLOG(5, "Building OF table"); 2811*3117ece4Schristos nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode; 2812*3117ece4Schristos stats.Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, 2813*3117ece4Schristos countWorkspace, max, mostFrequent, nbSeq, 2814*3117ece4Schristos OffFSELog, prevEntropy->offcodeCTable, 2815*3117ece4Schristos OF_defaultNorm, OF_defaultNormLog, 2816*3117ece4Schristos defaultPolicy, strategy); 2817*3117ece4Schristos assert(!(stats.Offtype < set_compressed && nextEntropy->offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 2818*3117ece4Schristos { size_t const countSize = ZSTD_buildCTable( 2819*3117ece4Schristos op, (size_t)(oend - op), 2820*3117ece4Schristos CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)stats.Offtype, 2821*3117ece4Schristos countWorkspace, max, ofCodeTable, nbSeq, 2822*3117ece4Schristos OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, 2823*3117ece4Schristos prevEntropy->offcodeCTable, 2824*3117ece4Schristos sizeof(prevEntropy->offcodeCTable), 2825*3117ece4Schristos entropyWorkspace, entropyWkspSize); 2826*3117ece4Schristos if (ZSTD_isError(countSize)) { 2827*3117ece4Schristos DEBUGLOG(3, "ZSTD_buildCTable for Offsets failed"); 2828*3117ece4Schristos stats.size = countSize; 2829*3117ece4Schristos return stats; 2830*3117ece4Schristos } 2831*3117ece4Schristos if (stats.Offtype == set_compressed) 2832*3117ece4Schristos stats.lastCountSize = countSize; 2833*3117ece4Schristos op += countSize; 2834*3117ece4Schristos assert(op <= oend); 2835*3117ece4Schristos } } 2836*3117ece4Schristos /* build CTable for MatchLengths */ 2837*3117ece4Schristos { unsigned max = MaxML; 2838*3117ece4Schristos size_t const mostFrequent = HIST_countFast_wksp( 2839*3117ece4Schristos countWorkspace, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ 2840*3117ece4Schristos DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); 2841*3117ece4Schristos nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode; 2842*3117ece4Schristos stats.MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, 2843*3117ece4Schristos countWorkspace, max, mostFrequent, nbSeq, 2844*3117ece4Schristos MLFSELog, prevEntropy->matchlengthCTable, 2845*3117ece4Schristos ML_defaultNorm, ML_defaultNormLog, 2846*3117ece4Schristos ZSTD_defaultAllowed, strategy); 2847*3117ece4Schristos assert(!(stats.MLtype < set_compressed && nextEntropy->matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 2848*3117ece4Schristos { size_t const countSize = ZSTD_buildCTable( 2849*3117ece4Schristos op, (size_t)(oend - op), 2850*3117ece4Schristos CTable_MatchLength, MLFSELog, (symbolEncodingType_e)stats.MLtype, 2851*3117ece4Schristos countWorkspace, max, mlCodeTable, nbSeq, 2852*3117ece4Schristos ML_defaultNorm, ML_defaultNormLog, MaxML, 2853*3117ece4Schristos prevEntropy->matchlengthCTable, 2854*3117ece4Schristos sizeof(prevEntropy->matchlengthCTable), 2855*3117ece4Schristos entropyWorkspace, entropyWkspSize); 2856*3117ece4Schristos if (ZSTD_isError(countSize)) { 2857*3117ece4Schristos DEBUGLOG(3, "ZSTD_buildCTable for MatchLengths failed"); 2858*3117ece4Schristos stats.size = countSize; 2859*3117ece4Schristos return stats; 2860*3117ece4Schristos } 2861*3117ece4Schristos if (stats.MLtype == set_compressed) 2862*3117ece4Schristos stats.lastCountSize = countSize; 2863*3117ece4Schristos op += countSize; 2864*3117ece4Schristos assert(op <= oend); 2865*3117ece4Schristos } } 2866*3117ece4Schristos stats.size = (size_t)(op-ostart); 2867*3117ece4Schristos return stats; 2868*3117ece4Schristos } 2869*3117ece4Schristos 2870*3117ece4Schristos /* ZSTD_entropyCompressSeqStore_internal(): 2871*3117ece4Schristos * compresses both literals and sequences 2872*3117ece4Schristos * Returns compressed size of block, or a zstd error. 2873*3117ece4Schristos */ 2874*3117ece4Schristos #define SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO 20 2875*3117ece4Schristos MEM_STATIC size_t 2876*3117ece4Schristos ZSTD_entropyCompressSeqStore_internal( 2877*3117ece4Schristos const seqStore_t* seqStorePtr, 2878*3117ece4Schristos const ZSTD_entropyCTables_t* prevEntropy, 2879*3117ece4Schristos ZSTD_entropyCTables_t* nextEntropy, 2880*3117ece4Schristos const ZSTD_CCtx_params* cctxParams, 2881*3117ece4Schristos void* dst, size_t dstCapacity, 2882*3117ece4Schristos void* entropyWorkspace, size_t entropyWkspSize, 2883*3117ece4Schristos const int bmi2) 2884*3117ece4Schristos { 2885*3117ece4Schristos ZSTD_strategy const strategy = cctxParams->cParams.strategy; 2886*3117ece4Schristos unsigned* count = (unsigned*)entropyWorkspace; 2887*3117ece4Schristos FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable; 2888*3117ece4Schristos FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable; 2889*3117ece4Schristos FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable; 2890*3117ece4Schristos const seqDef* const sequences = seqStorePtr->sequencesStart; 2891*3117ece4Schristos const size_t nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 2892*3117ece4Schristos const BYTE* const ofCodeTable = seqStorePtr->ofCode; 2893*3117ece4Schristos const BYTE* const llCodeTable = seqStorePtr->llCode; 2894*3117ece4Schristos const BYTE* const mlCodeTable = seqStorePtr->mlCode; 2895*3117ece4Schristos BYTE* const ostart = (BYTE*)dst; 2896*3117ece4Schristos BYTE* const oend = ostart + dstCapacity; 2897*3117ece4Schristos BYTE* op = ostart; 2898*3117ece4Schristos size_t lastCountSize; 2899*3117ece4Schristos int longOffsets = 0; 2900*3117ece4Schristos 2901*3117ece4Schristos entropyWorkspace = count + (MaxSeq + 1); 2902*3117ece4Schristos entropyWkspSize -= (MaxSeq + 1) * sizeof(*count); 2903*3117ece4Schristos 2904*3117ece4Schristos DEBUGLOG(5, "ZSTD_entropyCompressSeqStore_internal (nbSeq=%zu, dstCapacity=%zu)", nbSeq, dstCapacity); 2905*3117ece4Schristos ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 2906*3117ece4Schristos assert(entropyWkspSize >= HUF_WORKSPACE_SIZE); 2907*3117ece4Schristos 2908*3117ece4Schristos /* Compress literals */ 2909*3117ece4Schristos { const BYTE* const literals = seqStorePtr->litStart; 2910*3117ece4Schristos size_t const numSequences = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 2911*3117ece4Schristos size_t const numLiterals = (size_t)(seqStorePtr->lit - seqStorePtr->litStart); 2912*3117ece4Schristos /* Base suspicion of uncompressibility on ratio of literals to sequences */ 2913*3117ece4Schristos unsigned const suspectUncompressible = (numSequences == 0) || (numLiterals / numSequences >= SUSPECT_UNCOMPRESSIBLE_LITERAL_RATIO); 2914*3117ece4Schristos size_t const litSize = (size_t)(seqStorePtr->lit - literals); 2915*3117ece4Schristos 2916*3117ece4Schristos size_t const cSize = ZSTD_compressLiterals( 2917*3117ece4Schristos op, dstCapacity, 2918*3117ece4Schristos literals, litSize, 2919*3117ece4Schristos entropyWorkspace, entropyWkspSize, 2920*3117ece4Schristos &prevEntropy->huf, &nextEntropy->huf, 2921*3117ece4Schristos cctxParams->cParams.strategy, 2922*3117ece4Schristos ZSTD_literalsCompressionIsDisabled(cctxParams), 2923*3117ece4Schristos suspectUncompressible, bmi2); 2924*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed"); 2925*3117ece4Schristos assert(cSize <= dstCapacity); 2926*3117ece4Schristos op += cSize; 2927*3117ece4Schristos } 2928*3117ece4Schristos 2929*3117ece4Schristos /* Sequences Header */ 2930*3117ece4Schristos RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, 2931*3117ece4Schristos dstSize_tooSmall, "Can't fit seq hdr in output buf!"); 2932*3117ece4Schristos if (nbSeq < 128) { 2933*3117ece4Schristos *op++ = (BYTE)nbSeq; 2934*3117ece4Schristos } else if (nbSeq < LONGNBSEQ) { 2935*3117ece4Schristos op[0] = (BYTE)((nbSeq>>8) + 0x80); 2936*3117ece4Schristos op[1] = (BYTE)nbSeq; 2937*3117ece4Schristos op+=2; 2938*3117ece4Schristos } else { 2939*3117ece4Schristos op[0]=0xFF; 2940*3117ece4Schristos MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)); 2941*3117ece4Schristos op+=3; 2942*3117ece4Schristos } 2943*3117ece4Schristos assert(op <= oend); 2944*3117ece4Schristos if (nbSeq==0) { 2945*3117ece4Schristos /* Copy the old tables over as if we repeated them */ 2946*3117ece4Schristos ZSTD_memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); 2947*3117ece4Schristos return (size_t)(op - ostart); 2948*3117ece4Schristos } 2949*3117ece4Schristos { BYTE* const seqHead = op++; 2950*3117ece4Schristos /* build stats for sequences */ 2951*3117ece4Schristos const ZSTD_symbolEncodingTypeStats_t stats = 2952*3117ece4Schristos ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq, 2953*3117ece4Schristos &prevEntropy->fse, &nextEntropy->fse, 2954*3117ece4Schristos op, oend, 2955*3117ece4Schristos strategy, count, 2956*3117ece4Schristos entropyWorkspace, entropyWkspSize); 2957*3117ece4Schristos FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!"); 2958*3117ece4Schristos *seqHead = (BYTE)((stats.LLtype<<6) + (stats.Offtype<<4) + (stats.MLtype<<2)); 2959*3117ece4Schristos lastCountSize = stats.lastCountSize; 2960*3117ece4Schristos op += stats.size; 2961*3117ece4Schristos longOffsets = stats.longOffsets; 2962*3117ece4Schristos } 2963*3117ece4Schristos 2964*3117ece4Schristos { size_t const bitstreamSize = ZSTD_encodeSequences( 2965*3117ece4Schristos op, (size_t)(oend - op), 2966*3117ece4Schristos CTable_MatchLength, mlCodeTable, 2967*3117ece4Schristos CTable_OffsetBits, ofCodeTable, 2968*3117ece4Schristos CTable_LitLength, llCodeTable, 2969*3117ece4Schristos sequences, nbSeq, 2970*3117ece4Schristos longOffsets, bmi2); 2971*3117ece4Schristos FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed"); 2972*3117ece4Schristos op += bitstreamSize; 2973*3117ece4Schristos assert(op <= oend); 2974*3117ece4Schristos /* zstd versions <= 1.3.4 mistakenly report corruption when 2975*3117ece4Schristos * FSE_readNCount() receives a buffer < 4 bytes. 2976*3117ece4Schristos * Fixed by https://github.com/facebook/zstd/pull/1146. 2977*3117ece4Schristos * This can happen when the last set_compressed table present is 2 2978*3117ece4Schristos * bytes and the bitstream is only one byte. 2979*3117ece4Schristos * In this exceedingly rare case, we will simply emit an uncompressed 2980*3117ece4Schristos * block, since it isn't worth optimizing. 2981*3117ece4Schristos */ 2982*3117ece4Schristos if (lastCountSize && (lastCountSize + bitstreamSize) < 4) { 2983*3117ece4Schristos /* lastCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ 2984*3117ece4Schristos assert(lastCountSize + bitstreamSize == 3); 2985*3117ece4Schristos DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " 2986*3117ece4Schristos "emitting an uncompressed block."); 2987*3117ece4Schristos return 0; 2988*3117ece4Schristos } 2989*3117ece4Schristos } 2990*3117ece4Schristos 2991*3117ece4Schristos DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart)); 2992*3117ece4Schristos return (size_t)(op - ostart); 2993*3117ece4Schristos } 2994*3117ece4Schristos 2995*3117ece4Schristos MEM_STATIC size_t 2996*3117ece4Schristos ZSTD_entropyCompressSeqStore( 2997*3117ece4Schristos const seqStore_t* seqStorePtr, 2998*3117ece4Schristos const ZSTD_entropyCTables_t* prevEntropy, 2999*3117ece4Schristos ZSTD_entropyCTables_t* nextEntropy, 3000*3117ece4Schristos const ZSTD_CCtx_params* cctxParams, 3001*3117ece4Schristos void* dst, size_t dstCapacity, 3002*3117ece4Schristos size_t srcSize, 3003*3117ece4Schristos void* entropyWorkspace, size_t entropyWkspSize, 3004*3117ece4Schristos int bmi2) 3005*3117ece4Schristos { 3006*3117ece4Schristos size_t const cSize = ZSTD_entropyCompressSeqStore_internal( 3007*3117ece4Schristos seqStorePtr, prevEntropy, nextEntropy, cctxParams, 3008*3117ece4Schristos dst, dstCapacity, 3009*3117ece4Schristos entropyWorkspace, entropyWkspSize, bmi2); 3010*3117ece4Schristos if (cSize == 0) return 0; 3011*3117ece4Schristos /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block. 3012*3117ece4Schristos * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block. 3013*3117ece4Schristos */ 3014*3117ece4Schristos if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) { 3015*3117ece4Schristos DEBUGLOG(4, "not enough dstCapacity (%zu) for ZSTD_entropyCompressSeqStore_internal()=> do not compress block", dstCapacity); 3016*3117ece4Schristos return 0; /* block not compressed */ 3017*3117ece4Schristos } 3018*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSeqStore_internal failed"); 3019*3117ece4Schristos 3020*3117ece4Schristos /* Check compressibility */ 3021*3117ece4Schristos { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy); 3022*3117ece4Schristos if (cSize >= maxCSize) return 0; /* block not compressed */ 3023*3117ece4Schristos } 3024*3117ece4Schristos DEBUGLOG(5, "ZSTD_entropyCompressSeqStore() cSize: %zu", cSize); 3025*3117ece4Schristos /* libzstd decoder before > v1.5.4 is not compatible with compressed blocks of size ZSTD_BLOCKSIZE_MAX exactly. 3026*3117ece4Schristos * This restriction is indirectly already fulfilled by respecting ZSTD_minGain() condition above. 3027*3117ece4Schristos */ 3028*3117ece4Schristos assert(cSize < ZSTD_BLOCKSIZE_MAX); 3029*3117ece4Schristos return cSize; 3030*3117ece4Schristos } 3031*3117ece4Schristos 3032*3117ece4Schristos /* ZSTD_selectBlockCompressor() : 3033*3117ece4Schristos * Not static, but internal use only (used by long distance matcher) 3034*3117ece4Schristos * assumption : strat is a valid strategy */ 3035*3117ece4Schristos ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_paramSwitch_e useRowMatchFinder, ZSTD_dictMode_e dictMode) 3036*3117ece4Schristos { 3037*3117ece4Schristos static const ZSTD_blockCompressor blockCompressor[4][ZSTD_STRATEGY_MAX+1] = { 3038*3117ece4Schristos { ZSTD_compressBlock_fast /* default for 0 */, 3039*3117ece4Schristos ZSTD_compressBlock_fast, 3040*3117ece4Schristos ZSTD_COMPRESSBLOCK_DOUBLEFAST, 3041*3117ece4Schristos ZSTD_COMPRESSBLOCK_GREEDY, 3042*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY, 3043*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY2, 3044*3117ece4Schristos ZSTD_COMPRESSBLOCK_BTLAZY2, 3045*3117ece4Schristos ZSTD_COMPRESSBLOCK_BTOPT, 3046*3117ece4Schristos ZSTD_COMPRESSBLOCK_BTULTRA, 3047*3117ece4Schristos ZSTD_COMPRESSBLOCK_BTULTRA2 3048*3117ece4Schristos }, 3049*3117ece4Schristos { ZSTD_compressBlock_fast_extDict /* default for 0 */, 3050*3117ece4Schristos ZSTD_compressBlock_fast_extDict, 3051*3117ece4Schristos ZSTD_COMPRESSBLOCK_DOUBLEFAST_EXTDICT, 3052*3117ece4Schristos ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT, 3053*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY_EXTDICT, 3054*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT, 3055*3117ece4Schristos ZSTD_COMPRESSBLOCK_BTLAZY2_EXTDICT, 3056*3117ece4Schristos ZSTD_COMPRESSBLOCK_BTOPT_EXTDICT, 3057*3117ece4Schristos ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT, 3058*3117ece4Schristos ZSTD_COMPRESSBLOCK_BTULTRA_EXTDICT 3059*3117ece4Schristos }, 3060*3117ece4Schristos { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */, 3061*3117ece4Schristos ZSTD_compressBlock_fast_dictMatchState, 3062*3117ece4Schristos ZSTD_COMPRESSBLOCK_DOUBLEFAST_DICTMATCHSTATE, 3063*3117ece4Schristos ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE, 3064*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE, 3065*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE, 3066*3117ece4Schristos ZSTD_COMPRESSBLOCK_BTLAZY2_DICTMATCHSTATE, 3067*3117ece4Schristos ZSTD_COMPRESSBLOCK_BTOPT_DICTMATCHSTATE, 3068*3117ece4Schristos ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE, 3069*3117ece4Schristos ZSTD_COMPRESSBLOCK_BTULTRA_DICTMATCHSTATE 3070*3117ece4Schristos }, 3071*3117ece4Schristos { NULL /* default for 0 */, 3072*3117ece4Schristos NULL, 3073*3117ece4Schristos NULL, 3074*3117ece4Schristos ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH, 3075*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH, 3076*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH, 3077*3117ece4Schristos NULL, 3078*3117ece4Schristos NULL, 3079*3117ece4Schristos NULL, 3080*3117ece4Schristos NULL } 3081*3117ece4Schristos }; 3082*3117ece4Schristos ZSTD_blockCompressor selectedCompressor; 3083*3117ece4Schristos ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); 3084*3117ece4Schristos 3085*3117ece4Schristos assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); 3086*3117ece4Schristos DEBUGLOG(4, "Selected block compressor: dictMode=%d strat=%d rowMatchfinder=%d", (int)dictMode, (int)strat, (int)useRowMatchFinder); 3087*3117ece4Schristos if (ZSTD_rowMatchFinderUsed(strat, useRowMatchFinder)) { 3088*3117ece4Schristos static const ZSTD_blockCompressor rowBasedBlockCompressors[4][3] = { 3089*3117ece4Schristos { 3090*3117ece4Schristos ZSTD_COMPRESSBLOCK_GREEDY_ROW, 3091*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY_ROW, 3092*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY2_ROW 3093*3117ece4Schristos }, 3094*3117ece4Schristos { 3095*3117ece4Schristos ZSTD_COMPRESSBLOCK_GREEDY_EXTDICT_ROW, 3096*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY_EXTDICT_ROW, 3097*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY2_EXTDICT_ROW 3098*3117ece4Schristos }, 3099*3117ece4Schristos { 3100*3117ece4Schristos ZSTD_COMPRESSBLOCK_GREEDY_DICTMATCHSTATE_ROW, 3101*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY_DICTMATCHSTATE_ROW, 3102*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY2_DICTMATCHSTATE_ROW 3103*3117ece4Schristos }, 3104*3117ece4Schristos { 3105*3117ece4Schristos ZSTD_COMPRESSBLOCK_GREEDY_DEDICATEDDICTSEARCH_ROW, 3106*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY_DEDICATEDDICTSEARCH_ROW, 3107*3117ece4Schristos ZSTD_COMPRESSBLOCK_LAZY2_DEDICATEDDICTSEARCH_ROW 3108*3117ece4Schristos } 3109*3117ece4Schristos }; 3110*3117ece4Schristos DEBUGLOG(4, "Selecting a row-based matchfinder"); 3111*3117ece4Schristos assert(useRowMatchFinder != ZSTD_ps_auto); 3112*3117ece4Schristos selectedCompressor = rowBasedBlockCompressors[(int)dictMode][(int)strat - (int)ZSTD_greedy]; 3113*3117ece4Schristos } else { 3114*3117ece4Schristos selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; 3115*3117ece4Schristos } 3116*3117ece4Schristos assert(selectedCompressor != NULL); 3117*3117ece4Schristos return selectedCompressor; 3118*3117ece4Schristos } 3119*3117ece4Schristos 3120*3117ece4Schristos static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, 3121*3117ece4Schristos const BYTE* anchor, size_t lastLLSize) 3122*3117ece4Schristos { 3123*3117ece4Schristos ZSTD_memcpy(seqStorePtr->lit, anchor, lastLLSize); 3124*3117ece4Schristos seqStorePtr->lit += lastLLSize; 3125*3117ece4Schristos } 3126*3117ece4Schristos 3127*3117ece4Schristos void ZSTD_resetSeqStore(seqStore_t* ssPtr) 3128*3117ece4Schristos { 3129*3117ece4Schristos ssPtr->lit = ssPtr->litStart; 3130*3117ece4Schristos ssPtr->sequences = ssPtr->sequencesStart; 3131*3117ece4Schristos ssPtr->longLengthType = ZSTD_llt_none; 3132*3117ece4Schristos } 3133*3117ece4Schristos 3134*3117ece4Schristos /* ZSTD_postProcessSequenceProducerResult() : 3135*3117ece4Schristos * Validates and post-processes sequences obtained through the external matchfinder API: 3136*3117ece4Schristos * - Checks whether nbExternalSeqs represents an error condition. 3137*3117ece4Schristos * - Appends a block delimiter to outSeqs if one is not already present. 3138*3117ece4Schristos * See zstd.h for context regarding block delimiters. 3139*3117ece4Schristos * Returns the number of sequences after post-processing, or an error code. */ 3140*3117ece4Schristos static size_t ZSTD_postProcessSequenceProducerResult( 3141*3117ece4Schristos ZSTD_Sequence* outSeqs, size_t nbExternalSeqs, size_t outSeqsCapacity, size_t srcSize 3142*3117ece4Schristos ) { 3143*3117ece4Schristos RETURN_ERROR_IF( 3144*3117ece4Schristos nbExternalSeqs > outSeqsCapacity, 3145*3117ece4Schristos sequenceProducer_failed, 3146*3117ece4Schristos "External sequence producer returned error code %lu", 3147*3117ece4Schristos (unsigned long)nbExternalSeqs 3148*3117ece4Schristos ); 3149*3117ece4Schristos 3150*3117ece4Schristos RETURN_ERROR_IF( 3151*3117ece4Schristos nbExternalSeqs == 0 && srcSize > 0, 3152*3117ece4Schristos sequenceProducer_failed, 3153*3117ece4Schristos "Got zero sequences from external sequence producer for a non-empty src buffer!" 3154*3117ece4Schristos ); 3155*3117ece4Schristos 3156*3117ece4Schristos if (srcSize == 0) { 3157*3117ece4Schristos ZSTD_memset(&outSeqs[0], 0, sizeof(ZSTD_Sequence)); 3158*3117ece4Schristos return 1; 3159*3117ece4Schristos } 3160*3117ece4Schristos 3161*3117ece4Schristos { 3162*3117ece4Schristos ZSTD_Sequence const lastSeq = outSeqs[nbExternalSeqs - 1]; 3163*3117ece4Schristos 3164*3117ece4Schristos /* We can return early if lastSeq is already a block delimiter. */ 3165*3117ece4Schristos if (lastSeq.offset == 0 && lastSeq.matchLength == 0) { 3166*3117ece4Schristos return nbExternalSeqs; 3167*3117ece4Schristos } 3168*3117ece4Schristos 3169*3117ece4Schristos /* This error condition is only possible if the external matchfinder 3170*3117ece4Schristos * produced an invalid parse, by definition of ZSTD_sequenceBound(). */ 3171*3117ece4Schristos RETURN_ERROR_IF( 3172*3117ece4Schristos nbExternalSeqs == outSeqsCapacity, 3173*3117ece4Schristos sequenceProducer_failed, 3174*3117ece4Schristos "nbExternalSeqs == outSeqsCapacity but lastSeq is not a block delimiter!" 3175*3117ece4Schristos ); 3176*3117ece4Schristos 3177*3117ece4Schristos /* lastSeq is not a block delimiter, so we need to append one. */ 3178*3117ece4Schristos ZSTD_memset(&outSeqs[nbExternalSeqs], 0, sizeof(ZSTD_Sequence)); 3179*3117ece4Schristos return nbExternalSeqs + 1; 3180*3117ece4Schristos } 3181*3117ece4Schristos } 3182*3117ece4Schristos 3183*3117ece4Schristos /* ZSTD_fastSequenceLengthSum() : 3184*3117ece4Schristos * Returns sum(litLen) + sum(matchLen) + lastLits for *seqBuf*. 3185*3117ece4Schristos * Similar to another function in zstd_compress.c (determine_blockSize), 3186*3117ece4Schristos * except it doesn't check for a block delimiter to end summation. 3187*3117ece4Schristos * Removing the early exit allows the compiler to auto-vectorize (https://godbolt.org/z/cY1cajz9P). 3188*3117ece4Schristos * This function can be deleted and replaced by determine_blockSize after we resolve issue #3456. */ 3189*3117ece4Schristos static size_t ZSTD_fastSequenceLengthSum(ZSTD_Sequence const* seqBuf, size_t seqBufSize) { 3190*3117ece4Schristos size_t matchLenSum, litLenSum, i; 3191*3117ece4Schristos matchLenSum = 0; 3192*3117ece4Schristos litLenSum = 0; 3193*3117ece4Schristos for (i = 0; i < seqBufSize; i++) { 3194*3117ece4Schristos litLenSum += seqBuf[i].litLength; 3195*3117ece4Schristos matchLenSum += seqBuf[i].matchLength; 3196*3117ece4Schristos } 3197*3117ece4Schristos return litLenSum + matchLenSum; 3198*3117ece4Schristos } 3199*3117ece4Schristos 3200*3117ece4Schristos typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e; 3201*3117ece4Schristos 3202*3117ece4Schristos static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) 3203*3117ece4Schristos { 3204*3117ece4Schristos ZSTD_matchState_t* const ms = &zc->blockState.matchState; 3205*3117ece4Schristos DEBUGLOG(5, "ZSTD_buildSeqStore (srcSize=%zu)", srcSize); 3206*3117ece4Schristos assert(srcSize <= ZSTD_BLOCKSIZE_MAX); 3207*3117ece4Schristos /* Assert that we have correctly flushed the ctx params into the ms's copy */ 3208*3117ece4Schristos ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); 3209*3117ece4Schristos /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding 3210*3117ece4Schristos * additional 1. We need to revisit and change this logic to be more consistent */ 3211*3117ece4Schristos if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1+1) { 3212*3117ece4Schristos if (zc->appliedParams.cParams.strategy >= ZSTD_btopt) { 3213*3117ece4Schristos ZSTD_ldm_skipRawSeqStoreBytes(&zc->externSeqStore, srcSize); 3214*3117ece4Schristos } else { 3215*3117ece4Schristos ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); 3216*3117ece4Schristos } 3217*3117ece4Schristos return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */ 3218*3117ece4Schristos } 3219*3117ece4Schristos ZSTD_resetSeqStore(&(zc->seqStore)); 3220*3117ece4Schristos /* required for optimal parser to read stats from dictionary */ 3221*3117ece4Schristos ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy; 3222*3117ece4Schristos /* tell the optimal parser how we expect to compress literals */ 3223*3117ece4Schristos ms->opt.literalCompressionMode = zc->appliedParams.literalCompressionMode; 3224*3117ece4Schristos /* a gap between an attached dict and the current window is not safe, 3225*3117ece4Schristos * they must remain adjacent, 3226*3117ece4Schristos * and when that stops being the case, the dict must be unset */ 3227*3117ece4Schristos assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit); 3228*3117ece4Schristos 3229*3117ece4Schristos /* limited update after a very long match */ 3230*3117ece4Schristos { const BYTE* const base = ms->window.base; 3231*3117ece4Schristos const BYTE* const istart = (const BYTE*)src; 3232*3117ece4Schristos const U32 curr = (U32)(istart-base); 3233*3117ece4Schristos if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */ 3234*3117ece4Schristos if (curr > ms->nextToUpdate + 384) 3235*3117ece4Schristos ms->nextToUpdate = curr - MIN(192, (U32)(curr - ms->nextToUpdate - 384)); 3236*3117ece4Schristos } 3237*3117ece4Schristos 3238*3117ece4Schristos /* select and store sequences */ 3239*3117ece4Schristos { ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms); 3240*3117ece4Schristos size_t lastLLSize; 3241*3117ece4Schristos { int i; 3242*3117ece4Schristos for (i = 0; i < ZSTD_REP_NUM; ++i) 3243*3117ece4Schristos zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i]; 3244*3117ece4Schristos } 3245*3117ece4Schristos if (zc->externSeqStore.pos < zc->externSeqStore.size) { 3246*3117ece4Schristos assert(zc->appliedParams.ldmParams.enableLdm == ZSTD_ps_disable); 3247*3117ece4Schristos 3248*3117ece4Schristos /* External matchfinder + LDM is technically possible, just not implemented yet. 3249*3117ece4Schristos * We need to revisit soon and implement it. */ 3250*3117ece4Schristos RETURN_ERROR_IF( 3251*3117ece4Schristos ZSTD_hasExtSeqProd(&zc->appliedParams), 3252*3117ece4Schristos parameter_combination_unsupported, 3253*3117ece4Schristos "Long-distance matching with external sequence producer enabled is not currently supported." 3254*3117ece4Schristos ); 3255*3117ece4Schristos 3256*3117ece4Schristos /* Updates ldmSeqStore.pos */ 3257*3117ece4Schristos lastLLSize = 3258*3117ece4Schristos ZSTD_ldm_blockCompress(&zc->externSeqStore, 3259*3117ece4Schristos ms, &zc->seqStore, 3260*3117ece4Schristos zc->blockState.nextCBlock->rep, 3261*3117ece4Schristos zc->appliedParams.useRowMatchFinder, 3262*3117ece4Schristos src, srcSize); 3263*3117ece4Schristos assert(zc->externSeqStore.pos <= zc->externSeqStore.size); 3264*3117ece4Schristos } else if (zc->appliedParams.ldmParams.enableLdm == ZSTD_ps_enable) { 3265*3117ece4Schristos rawSeqStore_t ldmSeqStore = kNullRawSeqStore; 3266*3117ece4Schristos 3267*3117ece4Schristos /* External matchfinder + LDM is technically possible, just not implemented yet. 3268*3117ece4Schristos * We need to revisit soon and implement it. */ 3269*3117ece4Schristos RETURN_ERROR_IF( 3270*3117ece4Schristos ZSTD_hasExtSeqProd(&zc->appliedParams), 3271*3117ece4Schristos parameter_combination_unsupported, 3272*3117ece4Schristos "Long-distance matching with external sequence producer enabled is not currently supported." 3273*3117ece4Schristos ); 3274*3117ece4Schristos 3275*3117ece4Schristos ldmSeqStore.seq = zc->ldmSequences; 3276*3117ece4Schristos ldmSeqStore.capacity = zc->maxNbLdmSequences; 3277*3117ece4Schristos /* Updates ldmSeqStore.size */ 3278*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore, 3279*3117ece4Schristos &zc->appliedParams.ldmParams, 3280*3117ece4Schristos src, srcSize), ""); 3281*3117ece4Schristos /* Updates ldmSeqStore.pos */ 3282*3117ece4Schristos lastLLSize = 3283*3117ece4Schristos ZSTD_ldm_blockCompress(&ldmSeqStore, 3284*3117ece4Schristos ms, &zc->seqStore, 3285*3117ece4Schristos zc->blockState.nextCBlock->rep, 3286*3117ece4Schristos zc->appliedParams.useRowMatchFinder, 3287*3117ece4Schristos src, srcSize); 3288*3117ece4Schristos assert(ldmSeqStore.pos == ldmSeqStore.size); 3289*3117ece4Schristos } else if (ZSTD_hasExtSeqProd(&zc->appliedParams)) { 3290*3117ece4Schristos assert( 3291*3117ece4Schristos zc->extSeqBufCapacity >= ZSTD_sequenceBound(srcSize) 3292*3117ece4Schristos ); 3293*3117ece4Schristos assert(zc->appliedParams.extSeqProdFunc != NULL); 3294*3117ece4Schristos 3295*3117ece4Schristos { U32 const windowSize = (U32)1 << zc->appliedParams.cParams.windowLog; 3296*3117ece4Schristos 3297*3117ece4Schristos size_t const nbExternalSeqs = (zc->appliedParams.extSeqProdFunc)( 3298*3117ece4Schristos zc->appliedParams.extSeqProdState, 3299*3117ece4Schristos zc->extSeqBuf, 3300*3117ece4Schristos zc->extSeqBufCapacity, 3301*3117ece4Schristos src, srcSize, 3302*3117ece4Schristos NULL, 0, /* dict and dictSize, currently not supported */ 3303*3117ece4Schristos zc->appliedParams.compressionLevel, 3304*3117ece4Schristos windowSize 3305*3117ece4Schristos ); 3306*3117ece4Schristos 3307*3117ece4Schristos size_t const nbPostProcessedSeqs = ZSTD_postProcessSequenceProducerResult( 3308*3117ece4Schristos zc->extSeqBuf, 3309*3117ece4Schristos nbExternalSeqs, 3310*3117ece4Schristos zc->extSeqBufCapacity, 3311*3117ece4Schristos srcSize 3312*3117ece4Schristos ); 3313*3117ece4Schristos 3314*3117ece4Schristos /* Return early if there is no error, since we don't need to worry about last literals */ 3315*3117ece4Schristos if (!ZSTD_isError(nbPostProcessedSeqs)) { 3316*3117ece4Schristos ZSTD_sequencePosition seqPos = {0,0,0}; 3317*3117ece4Schristos size_t const seqLenSum = ZSTD_fastSequenceLengthSum(zc->extSeqBuf, nbPostProcessedSeqs); 3318*3117ece4Schristos RETURN_ERROR_IF(seqLenSum > srcSize, externalSequences_invalid, "External sequences imply too large a block!"); 3319*3117ece4Schristos FORWARD_IF_ERROR( 3320*3117ece4Schristos ZSTD_copySequencesToSeqStoreExplicitBlockDelim( 3321*3117ece4Schristos zc, &seqPos, 3322*3117ece4Schristos zc->extSeqBuf, nbPostProcessedSeqs, 3323*3117ece4Schristos src, srcSize, 3324*3117ece4Schristos zc->appliedParams.searchForExternalRepcodes 3325*3117ece4Schristos ), 3326*3117ece4Schristos "Failed to copy external sequences to seqStore!" 3327*3117ece4Schristos ); 3328*3117ece4Schristos ms->ldmSeqStore = NULL; 3329*3117ece4Schristos DEBUGLOG(5, "Copied %lu sequences from external sequence producer to internal seqStore.", (unsigned long)nbExternalSeqs); 3330*3117ece4Schristos return ZSTDbss_compress; 3331*3117ece4Schristos } 3332*3117ece4Schristos 3333*3117ece4Schristos /* Propagate the error if fallback is disabled */ 3334*3117ece4Schristos if (!zc->appliedParams.enableMatchFinderFallback) { 3335*3117ece4Schristos return nbPostProcessedSeqs; 3336*3117ece4Schristos } 3337*3117ece4Schristos 3338*3117ece4Schristos /* Fallback to software matchfinder */ 3339*3117ece4Schristos { ZSTD_blockCompressor const blockCompressor = 3340*3117ece4Schristos ZSTD_selectBlockCompressor( 3341*3117ece4Schristos zc->appliedParams.cParams.strategy, 3342*3117ece4Schristos zc->appliedParams.useRowMatchFinder, 3343*3117ece4Schristos dictMode); 3344*3117ece4Schristos ms->ldmSeqStore = NULL; 3345*3117ece4Schristos DEBUGLOG( 3346*3117ece4Schristos 5, 3347*3117ece4Schristos "External sequence producer returned error code %lu. Falling back to internal parser.", 3348*3117ece4Schristos (unsigned long)nbExternalSeqs 3349*3117ece4Schristos ); 3350*3117ece4Schristos lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); 3351*3117ece4Schristos } } 3352*3117ece4Schristos } else { /* not long range mode and no external matchfinder */ 3353*3117ece4Schristos ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor( 3354*3117ece4Schristos zc->appliedParams.cParams.strategy, 3355*3117ece4Schristos zc->appliedParams.useRowMatchFinder, 3356*3117ece4Schristos dictMode); 3357*3117ece4Schristos ms->ldmSeqStore = NULL; 3358*3117ece4Schristos lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); 3359*3117ece4Schristos } 3360*3117ece4Schristos { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; 3361*3117ece4Schristos ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize); 3362*3117ece4Schristos } } 3363*3117ece4Schristos return ZSTDbss_compress; 3364*3117ece4Schristos } 3365*3117ece4Schristos 3366*3117ece4Schristos static size_t ZSTD_copyBlockSequences(SeqCollector* seqCollector, const seqStore_t* seqStore, const U32 prevRepcodes[ZSTD_REP_NUM]) 3367*3117ece4Schristos { 3368*3117ece4Schristos const seqDef* inSeqs = seqStore->sequencesStart; 3369*3117ece4Schristos const size_t nbInSequences = seqStore->sequences - inSeqs; 3370*3117ece4Schristos const size_t nbInLiterals = (size_t)(seqStore->lit - seqStore->litStart); 3371*3117ece4Schristos 3372*3117ece4Schristos ZSTD_Sequence* outSeqs = seqCollector->seqIndex == 0 ? seqCollector->seqStart : seqCollector->seqStart + seqCollector->seqIndex; 3373*3117ece4Schristos const size_t nbOutSequences = nbInSequences + 1; 3374*3117ece4Schristos size_t nbOutLiterals = 0; 3375*3117ece4Schristos repcodes_t repcodes; 3376*3117ece4Schristos size_t i; 3377*3117ece4Schristos 3378*3117ece4Schristos /* Bounds check that we have enough space for every input sequence 3379*3117ece4Schristos * and the block delimiter 3380*3117ece4Schristos */ 3381*3117ece4Schristos assert(seqCollector->seqIndex <= seqCollector->maxSequences); 3382*3117ece4Schristos RETURN_ERROR_IF( 3383*3117ece4Schristos nbOutSequences > (size_t)(seqCollector->maxSequences - seqCollector->seqIndex), 3384*3117ece4Schristos dstSize_tooSmall, 3385*3117ece4Schristos "Not enough space to copy sequences"); 3386*3117ece4Schristos 3387*3117ece4Schristos ZSTD_memcpy(&repcodes, prevRepcodes, sizeof(repcodes)); 3388*3117ece4Schristos for (i = 0; i < nbInSequences; ++i) { 3389*3117ece4Schristos U32 rawOffset; 3390*3117ece4Schristos outSeqs[i].litLength = inSeqs[i].litLength; 3391*3117ece4Schristos outSeqs[i].matchLength = inSeqs[i].mlBase + MINMATCH; 3392*3117ece4Schristos outSeqs[i].rep = 0; 3393*3117ece4Schristos 3394*3117ece4Schristos /* Handle the possible single length >= 64K 3395*3117ece4Schristos * There can only be one because we add MINMATCH to every match length, 3396*3117ece4Schristos * and blocks are at most 128K. 3397*3117ece4Schristos */ 3398*3117ece4Schristos if (i == seqStore->longLengthPos) { 3399*3117ece4Schristos if (seqStore->longLengthType == ZSTD_llt_literalLength) { 3400*3117ece4Schristos outSeqs[i].litLength += 0x10000; 3401*3117ece4Schristos } else if (seqStore->longLengthType == ZSTD_llt_matchLength) { 3402*3117ece4Schristos outSeqs[i].matchLength += 0x10000; 3403*3117ece4Schristos } 3404*3117ece4Schristos } 3405*3117ece4Schristos 3406*3117ece4Schristos /* Determine the raw offset given the offBase, which may be a repcode. */ 3407*3117ece4Schristos if (OFFBASE_IS_REPCODE(inSeqs[i].offBase)) { 3408*3117ece4Schristos const U32 repcode = OFFBASE_TO_REPCODE(inSeqs[i].offBase); 3409*3117ece4Schristos assert(repcode > 0); 3410*3117ece4Schristos outSeqs[i].rep = repcode; 3411*3117ece4Schristos if (outSeqs[i].litLength != 0) { 3412*3117ece4Schristos rawOffset = repcodes.rep[repcode - 1]; 3413*3117ece4Schristos } else { 3414*3117ece4Schristos if (repcode == 3) { 3415*3117ece4Schristos assert(repcodes.rep[0] > 1); 3416*3117ece4Schristos rawOffset = repcodes.rep[0] - 1; 3417*3117ece4Schristos } else { 3418*3117ece4Schristos rawOffset = repcodes.rep[repcode]; 3419*3117ece4Schristos } 3420*3117ece4Schristos } 3421*3117ece4Schristos } else { 3422*3117ece4Schristos rawOffset = OFFBASE_TO_OFFSET(inSeqs[i].offBase); 3423*3117ece4Schristos } 3424*3117ece4Schristos outSeqs[i].offset = rawOffset; 3425*3117ece4Schristos 3426*3117ece4Schristos /* Update repcode history for the sequence */ 3427*3117ece4Schristos ZSTD_updateRep(repcodes.rep, 3428*3117ece4Schristos inSeqs[i].offBase, 3429*3117ece4Schristos inSeqs[i].litLength == 0); 3430*3117ece4Schristos 3431*3117ece4Schristos nbOutLiterals += outSeqs[i].litLength; 3432*3117ece4Schristos } 3433*3117ece4Schristos /* Insert last literals (if any exist) in the block as a sequence with ml == off == 0. 3434*3117ece4Schristos * If there are no last literals, then we'll emit (of: 0, ml: 0, ll: 0), which is a marker 3435*3117ece4Schristos * for the block boundary, according to the API. 3436*3117ece4Schristos */ 3437*3117ece4Schristos assert(nbInLiterals >= nbOutLiterals); 3438*3117ece4Schristos { 3439*3117ece4Schristos const size_t lastLLSize = nbInLiterals - nbOutLiterals; 3440*3117ece4Schristos outSeqs[nbInSequences].litLength = (U32)lastLLSize; 3441*3117ece4Schristos outSeqs[nbInSequences].matchLength = 0; 3442*3117ece4Schristos outSeqs[nbInSequences].offset = 0; 3443*3117ece4Schristos assert(nbOutSequences == nbInSequences + 1); 3444*3117ece4Schristos } 3445*3117ece4Schristos seqCollector->seqIndex += nbOutSequences; 3446*3117ece4Schristos assert(seqCollector->seqIndex <= seqCollector->maxSequences); 3447*3117ece4Schristos 3448*3117ece4Schristos return 0; 3449*3117ece4Schristos } 3450*3117ece4Schristos 3451*3117ece4Schristos size_t ZSTD_sequenceBound(size_t srcSize) { 3452*3117ece4Schristos const size_t maxNbSeq = (srcSize / ZSTD_MINMATCH_MIN) + 1; 3453*3117ece4Schristos const size_t maxNbDelims = (srcSize / ZSTD_BLOCKSIZE_MAX_MIN) + 1; 3454*3117ece4Schristos return maxNbSeq + maxNbDelims; 3455*3117ece4Schristos } 3456*3117ece4Schristos 3457*3117ece4Schristos size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, 3458*3117ece4Schristos size_t outSeqsSize, const void* src, size_t srcSize) 3459*3117ece4Schristos { 3460*3117ece4Schristos const size_t dstCapacity = ZSTD_compressBound(srcSize); 3461*3117ece4Schristos void* dst = ZSTD_customMalloc(dstCapacity, ZSTD_defaultCMem); 3462*3117ece4Schristos SeqCollector seqCollector; 3463*3117ece4Schristos { 3464*3117ece4Schristos int targetCBlockSize; 3465*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_getParameter(zc, ZSTD_c_targetCBlockSize, &targetCBlockSize), ""); 3466*3117ece4Schristos RETURN_ERROR_IF(targetCBlockSize != 0, parameter_unsupported, "targetCBlockSize != 0"); 3467*3117ece4Schristos } 3468*3117ece4Schristos { 3469*3117ece4Schristos int nbWorkers; 3470*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_getParameter(zc, ZSTD_c_nbWorkers, &nbWorkers), ""); 3471*3117ece4Schristos RETURN_ERROR_IF(nbWorkers != 0, parameter_unsupported, "nbWorkers != 0"); 3472*3117ece4Schristos } 3473*3117ece4Schristos 3474*3117ece4Schristos RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!"); 3475*3117ece4Schristos 3476*3117ece4Schristos seqCollector.collectSequences = 1; 3477*3117ece4Schristos seqCollector.seqStart = outSeqs; 3478*3117ece4Schristos seqCollector.seqIndex = 0; 3479*3117ece4Schristos seqCollector.maxSequences = outSeqsSize; 3480*3117ece4Schristos zc->seqCollector = seqCollector; 3481*3117ece4Schristos 3482*3117ece4Schristos { 3483*3117ece4Schristos const size_t ret = ZSTD_compress2(zc, dst, dstCapacity, src, srcSize); 3484*3117ece4Schristos ZSTD_customFree(dst, ZSTD_defaultCMem); 3485*3117ece4Schristos FORWARD_IF_ERROR(ret, "ZSTD_compress2 failed"); 3486*3117ece4Schristos } 3487*3117ece4Schristos assert(zc->seqCollector.seqIndex <= ZSTD_sequenceBound(srcSize)); 3488*3117ece4Schristos return zc->seqCollector.seqIndex; 3489*3117ece4Schristos } 3490*3117ece4Schristos 3491*3117ece4Schristos size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize) { 3492*3117ece4Schristos size_t in = 0; 3493*3117ece4Schristos size_t out = 0; 3494*3117ece4Schristos for (; in < seqsSize; ++in) { 3495*3117ece4Schristos if (sequences[in].offset == 0 && sequences[in].matchLength == 0) { 3496*3117ece4Schristos if (in != seqsSize - 1) { 3497*3117ece4Schristos sequences[in+1].litLength += sequences[in].litLength; 3498*3117ece4Schristos } 3499*3117ece4Schristos } else { 3500*3117ece4Schristos sequences[out] = sequences[in]; 3501*3117ece4Schristos ++out; 3502*3117ece4Schristos } 3503*3117ece4Schristos } 3504*3117ece4Schristos return out; 3505*3117ece4Schristos } 3506*3117ece4Schristos 3507*3117ece4Schristos /* Unrolled loop to read four size_ts of input at a time. Returns 1 if is RLE, 0 if not. */ 3508*3117ece4Schristos static int ZSTD_isRLE(const BYTE* src, size_t length) { 3509*3117ece4Schristos const BYTE* ip = src; 3510*3117ece4Schristos const BYTE value = ip[0]; 3511*3117ece4Schristos const size_t valueST = (size_t)((U64)value * 0x0101010101010101ULL); 3512*3117ece4Schristos const size_t unrollSize = sizeof(size_t) * 4; 3513*3117ece4Schristos const size_t unrollMask = unrollSize - 1; 3514*3117ece4Schristos const size_t prefixLength = length & unrollMask; 3515*3117ece4Schristos size_t i; 3516*3117ece4Schristos if (length == 1) return 1; 3517*3117ece4Schristos /* Check if prefix is RLE first before using unrolled loop */ 3518*3117ece4Schristos if (prefixLength && ZSTD_count(ip+1, ip, ip+prefixLength) != prefixLength-1) { 3519*3117ece4Schristos return 0; 3520*3117ece4Schristos } 3521*3117ece4Schristos for (i = prefixLength; i != length; i += unrollSize) { 3522*3117ece4Schristos size_t u; 3523*3117ece4Schristos for (u = 0; u < unrollSize; u += sizeof(size_t)) { 3524*3117ece4Schristos if (MEM_readST(ip + i + u) != valueST) { 3525*3117ece4Schristos return 0; 3526*3117ece4Schristos } } } 3527*3117ece4Schristos return 1; 3528*3117ece4Schristos } 3529*3117ece4Schristos 3530*3117ece4Schristos /* Returns true if the given block may be RLE. 3531*3117ece4Schristos * This is just a heuristic based on the compressibility. 3532*3117ece4Schristos * It may return both false positives and false negatives. 3533*3117ece4Schristos */ 3534*3117ece4Schristos static int ZSTD_maybeRLE(seqStore_t const* seqStore) 3535*3117ece4Schristos { 3536*3117ece4Schristos size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart); 3537*3117ece4Schristos size_t const nbLits = (size_t)(seqStore->lit - seqStore->litStart); 3538*3117ece4Schristos 3539*3117ece4Schristos return nbSeqs < 4 && nbLits < 10; 3540*3117ece4Schristos } 3541*3117ece4Schristos 3542*3117ece4Schristos static void 3543*3117ece4Schristos ZSTD_blockState_confirmRepcodesAndEntropyTables(ZSTD_blockState_t* const bs) 3544*3117ece4Schristos { 3545*3117ece4Schristos ZSTD_compressedBlockState_t* const tmp = bs->prevCBlock; 3546*3117ece4Schristos bs->prevCBlock = bs->nextCBlock; 3547*3117ece4Schristos bs->nextCBlock = tmp; 3548*3117ece4Schristos } 3549*3117ece4Schristos 3550*3117ece4Schristos /* Writes the block header */ 3551*3117ece4Schristos static void 3552*3117ece4Schristos writeBlockHeader(void* op, size_t cSize, size_t blockSize, U32 lastBlock) 3553*3117ece4Schristos { 3554*3117ece4Schristos U32 const cBlockHeader = cSize == 1 ? 3555*3117ece4Schristos lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : 3556*3117ece4Schristos lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); 3557*3117ece4Schristos MEM_writeLE24(op, cBlockHeader); 3558*3117ece4Schristos DEBUGLOG(3, "writeBlockHeader: cSize: %zu blockSize: %zu lastBlock: %u", cSize, blockSize, lastBlock); 3559*3117ece4Schristos } 3560*3117ece4Schristos 3561*3117ece4Schristos /** ZSTD_buildBlockEntropyStats_literals() : 3562*3117ece4Schristos * Builds entropy for the literals. 3563*3117ece4Schristos * Stores literals block type (raw, rle, compressed, repeat) and 3564*3117ece4Schristos * huffman description table to hufMetadata. 3565*3117ece4Schristos * Requires ENTROPY_WORKSPACE_SIZE workspace 3566*3117ece4Schristos * @return : size of huffman description table, or an error code 3567*3117ece4Schristos */ 3568*3117ece4Schristos static size_t 3569*3117ece4Schristos ZSTD_buildBlockEntropyStats_literals(void* const src, size_t srcSize, 3570*3117ece4Schristos const ZSTD_hufCTables_t* prevHuf, 3571*3117ece4Schristos ZSTD_hufCTables_t* nextHuf, 3572*3117ece4Schristos ZSTD_hufCTablesMetadata_t* hufMetadata, 3573*3117ece4Schristos const int literalsCompressionIsDisabled, 3574*3117ece4Schristos void* workspace, size_t wkspSize, 3575*3117ece4Schristos int hufFlags) 3576*3117ece4Schristos { 3577*3117ece4Schristos BYTE* const wkspStart = (BYTE*)workspace; 3578*3117ece4Schristos BYTE* const wkspEnd = wkspStart + wkspSize; 3579*3117ece4Schristos BYTE* const countWkspStart = wkspStart; 3580*3117ece4Schristos unsigned* const countWksp = (unsigned*)workspace; 3581*3117ece4Schristos const size_t countWkspSize = (HUF_SYMBOLVALUE_MAX + 1) * sizeof(unsigned); 3582*3117ece4Schristos BYTE* const nodeWksp = countWkspStart + countWkspSize; 3583*3117ece4Schristos const size_t nodeWkspSize = (size_t)(wkspEnd - nodeWksp); 3584*3117ece4Schristos unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX; 3585*3117ece4Schristos unsigned huffLog = LitHufLog; 3586*3117ece4Schristos HUF_repeat repeat = prevHuf->repeatMode; 3587*3117ece4Schristos DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_literals (srcSize=%zu)", srcSize); 3588*3117ece4Schristos 3589*3117ece4Schristos /* Prepare nextEntropy assuming reusing the existing table */ 3590*3117ece4Schristos ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 3591*3117ece4Schristos 3592*3117ece4Schristos if (literalsCompressionIsDisabled) { 3593*3117ece4Schristos DEBUGLOG(5, "set_basic - disabled"); 3594*3117ece4Schristos hufMetadata->hType = set_basic; 3595*3117ece4Schristos return 0; 3596*3117ece4Schristos } 3597*3117ece4Schristos 3598*3117ece4Schristos /* small ? don't even attempt compression (speed opt) */ 3599*3117ece4Schristos #ifndef COMPRESS_LITERALS_SIZE_MIN 3600*3117ece4Schristos # define COMPRESS_LITERALS_SIZE_MIN 63 /* heuristic */ 3601*3117ece4Schristos #endif 3602*3117ece4Schristos { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; 3603*3117ece4Schristos if (srcSize <= minLitSize) { 3604*3117ece4Schristos DEBUGLOG(5, "set_basic - too small"); 3605*3117ece4Schristos hufMetadata->hType = set_basic; 3606*3117ece4Schristos return 0; 3607*3117ece4Schristos } } 3608*3117ece4Schristos 3609*3117ece4Schristos /* Scan input and build symbol stats */ 3610*3117ece4Schristos { size_t const largest = 3611*3117ece4Schristos HIST_count_wksp (countWksp, &maxSymbolValue, 3612*3117ece4Schristos (const BYTE*)src, srcSize, 3613*3117ece4Schristos workspace, wkspSize); 3614*3117ece4Schristos FORWARD_IF_ERROR(largest, "HIST_count_wksp failed"); 3615*3117ece4Schristos if (largest == srcSize) { 3616*3117ece4Schristos /* only one literal symbol */ 3617*3117ece4Schristos DEBUGLOG(5, "set_rle"); 3618*3117ece4Schristos hufMetadata->hType = set_rle; 3619*3117ece4Schristos return 0; 3620*3117ece4Schristos } 3621*3117ece4Schristos if (largest <= (srcSize >> 7)+4) { 3622*3117ece4Schristos /* heuristic: likely not compressible */ 3623*3117ece4Schristos DEBUGLOG(5, "set_basic - no gain"); 3624*3117ece4Schristos hufMetadata->hType = set_basic; 3625*3117ece4Schristos return 0; 3626*3117ece4Schristos } } 3627*3117ece4Schristos 3628*3117ece4Schristos /* Validate the previous Huffman table */ 3629*3117ece4Schristos if (repeat == HUF_repeat_check 3630*3117ece4Schristos && !HUF_validateCTable((HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue)) { 3631*3117ece4Schristos repeat = HUF_repeat_none; 3632*3117ece4Schristos } 3633*3117ece4Schristos 3634*3117ece4Schristos /* Build Huffman Tree */ 3635*3117ece4Schristos ZSTD_memset(nextHuf->CTable, 0, sizeof(nextHuf->CTable)); 3636*3117ece4Schristos huffLog = HUF_optimalTableLog(huffLog, srcSize, maxSymbolValue, nodeWksp, nodeWkspSize, nextHuf->CTable, countWksp, hufFlags); 3637*3117ece4Schristos assert(huffLog <= LitHufLog); 3638*3117ece4Schristos { size_t const maxBits = HUF_buildCTable_wksp((HUF_CElt*)nextHuf->CTable, countWksp, 3639*3117ece4Schristos maxSymbolValue, huffLog, 3640*3117ece4Schristos nodeWksp, nodeWkspSize); 3641*3117ece4Schristos FORWARD_IF_ERROR(maxBits, "HUF_buildCTable_wksp"); 3642*3117ece4Schristos huffLog = (U32)maxBits; 3643*3117ece4Schristos } 3644*3117ece4Schristos { /* Build and write the CTable */ 3645*3117ece4Schristos size_t const newCSize = HUF_estimateCompressedSize( 3646*3117ece4Schristos (HUF_CElt*)nextHuf->CTable, countWksp, maxSymbolValue); 3647*3117ece4Schristos size_t const hSize = HUF_writeCTable_wksp( 3648*3117ece4Schristos hufMetadata->hufDesBuffer, sizeof(hufMetadata->hufDesBuffer), 3649*3117ece4Schristos (HUF_CElt*)nextHuf->CTable, maxSymbolValue, huffLog, 3650*3117ece4Schristos nodeWksp, nodeWkspSize); 3651*3117ece4Schristos /* Check against repeating the previous CTable */ 3652*3117ece4Schristos if (repeat != HUF_repeat_none) { 3653*3117ece4Schristos size_t const oldCSize = HUF_estimateCompressedSize( 3654*3117ece4Schristos (HUF_CElt const*)prevHuf->CTable, countWksp, maxSymbolValue); 3655*3117ece4Schristos if (oldCSize < srcSize && (oldCSize <= hSize + newCSize || hSize + 12 >= srcSize)) { 3656*3117ece4Schristos DEBUGLOG(5, "set_repeat - smaller"); 3657*3117ece4Schristos ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 3658*3117ece4Schristos hufMetadata->hType = set_repeat; 3659*3117ece4Schristos return 0; 3660*3117ece4Schristos } } 3661*3117ece4Schristos if (newCSize + hSize >= srcSize) { 3662*3117ece4Schristos DEBUGLOG(5, "set_basic - no gains"); 3663*3117ece4Schristos ZSTD_memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 3664*3117ece4Schristos hufMetadata->hType = set_basic; 3665*3117ece4Schristos return 0; 3666*3117ece4Schristos } 3667*3117ece4Schristos DEBUGLOG(5, "set_compressed (hSize=%u)", (U32)hSize); 3668*3117ece4Schristos hufMetadata->hType = set_compressed; 3669*3117ece4Schristos nextHuf->repeatMode = HUF_repeat_check; 3670*3117ece4Schristos return hSize; 3671*3117ece4Schristos } 3672*3117ece4Schristos } 3673*3117ece4Schristos 3674*3117ece4Schristos 3675*3117ece4Schristos /* ZSTD_buildDummySequencesStatistics(): 3676*3117ece4Schristos * Returns a ZSTD_symbolEncodingTypeStats_t with all encoding types as set_basic, 3677*3117ece4Schristos * and updates nextEntropy to the appropriate repeatMode. 3678*3117ece4Schristos */ 3679*3117ece4Schristos static ZSTD_symbolEncodingTypeStats_t 3680*3117ece4Schristos ZSTD_buildDummySequencesStatistics(ZSTD_fseCTables_t* nextEntropy) 3681*3117ece4Schristos { 3682*3117ece4Schristos ZSTD_symbolEncodingTypeStats_t stats = {set_basic, set_basic, set_basic, 0, 0, 0}; 3683*3117ece4Schristos nextEntropy->litlength_repeatMode = FSE_repeat_none; 3684*3117ece4Schristos nextEntropy->offcode_repeatMode = FSE_repeat_none; 3685*3117ece4Schristos nextEntropy->matchlength_repeatMode = FSE_repeat_none; 3686*3117ece4Schristos return stats; 3687*3117ece4Schristos } 3688*3117ece4Schristos 3689*3117ece4Schristos /** ZSTD_buildBlockEntropyStats_sequences() : 3690*3117ece4Schristos * Builds entropy for the sequences. 3691*3117ece4Schristos * Stores symbol compression modes and fse table to fseMetadata. 3692*3117ece4Schristos * Requires ENTROPY_WORKSPACE_SIZE wksp. 3693*3117ece4Schristos * @return : size of fse tables or error code */ 3694*3117ece4Schristos static size_t 3695*3117ece4Schristos ZSTD_buildBlockEntropyStats_sequences( 3696*3117ece4Schristos const seqStore_t* seqStorePtr, 3697*3117ece4Schristos const ZSTD_fseCTables_t* prevEntropy, 3698*3117ece4Schristos ZSTD_fseCTables_t* nextEntropy, 3699*3117ece4Schristos const ZSTD_CCtx_params* cctxParams, 3700*3117ece4Schristos ZSTD_fseCTablesMetadata_t* fseMetadata, 3701*3117ece4Schristos void* workspace, size_t wkspSize) 3702*3117ece4Schristos { 3703*3117ece4Schristos ZSTD_strategy const strategy = cctxParams->cParams.strategy; 3704*3117ece4Schristos size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 3705*3117ece4Schristos BYTE* const ostart = fseMetadata->fseTablesBuffer; 3706*3117ece4Schristos BYTE* const oend = ostart + sizeof(fseMetadata->fseTablesBuffer); 3707*3117ece4Schristos BYTE* op = ostart; 3708*3117ece4Schristos unsigned* countWorkspace = (unsigned*)workspace; 3709*3117ece4Schristos unsigned* entropyWorkspace = countWorkspace + (MaxSeq + 1); 3710*3117ece4Schristos size_t entropyWorkspaceSize = wkspSize - (MaxSeq + 1) * sizeof(*countWorkspace); 3711*3117ece4Schristos ZSTD_symbolEncodingTypeStats_t stats; 3712*3117ece4Schristos 3713*3117ece4Schristos DEBUGLOG(5, "ZSTD_buildBlockEntropyStats_sequences (nbSeq=%zu)", nbSeq); 3714*3117ece4Schristos stats = nbSeq != 0 ? ZSTD_buildSequencesStatistics(seqStorePtr, nbSeq, 3715*3117ece4Schristos prevEntropy, nextEntropy, op, oend, 3716*3117ece4Schristos strategy, countWorkspace, 3717*3117ece4Schristos entropyWorkspace, entropyWorkspaceSize) 3718*3117ece4Schristos : ZSTD_buildDummySequencesStatistics(nextEntropy); 3719*3117ece4Schristos FORWARD_IF_ERROR(stats.size, "ZSTD_buildSequencesStatistics failed!"); 3720*3117ece4Schristos fseMetadata->llType = (symbolEncodingType_e) stats.LLtype; 3721*3117ece4Schristos fseMetadata->ofType = (symbolEncodingType_e) stats.Offtype; 3722*3117ece4Schristos fseMetadata->mlType = (symbolEncodingType_e) stats.MLtype; 3723*3117ece4Schristos fseMetadata->lastCountSize = stats.lastCountSize; 3724*3117ece4Schristos return stats.size; 3725*3117ece4Schristos } 3726*3117ece4Schristos 3727*3117ece4Schristos 3728*3117ece4Schristos /** ZSTD_buildBlockEntropyStats() : 3729*3117ece4Schristos * Builds entropy for the block. 3730*3117ece4Schristos * Requires workspace size ENTROPY_WORKSPACE_SIZE 3731*3117ece4Schristos * @return : 0 on success, or an error code 3732*3117ece4Schristos * Note : also employed in superblock 3733*3117ece4Schristos */ 3734*3117ece4Schristos size_t ZSTD_buildBlockEntropyStats( 3735*3117ece4Schristos const seqStore_t* seqStorePtr, 3736*3117ece4Schristos const ZSTD_entropyCTables_t* prevEntropy, 3737*3117ece4Schristos ZSTD_entropyCTables_t* nextEntropy, 3738*3117ece4Schristos const ZSTD_CCtx_params* cctxParams, 3739*3117ece4Schristos ZSTD_entropyCTablesMetadata_t* entropyMetadata, 3740*3117ece4Schristos void* workspace, size_t wkspSize) 3741*3117ece4Schristos { 3742*3117ece4Schristos size_t const litSize = (size_t)(seqStorePtr->lit - seqStorePtr->litStart); 3743*3117ece4Schristos int const huf_useOptDepth = (cctxParams->cParams.strategy >= HUF_OPTIMAL_DEPTH_THRESHOLD); 3744*3117ece4Schristos int const hufFlags = huf_useOptDepth ? HUF_flags_optimalDepth : 0; 3745*3117ece4Schristos 3746*3117ece4Schristos entropyMetadata->hufMetadata.hufDesSize = 3747*3117ece4Schristos ZSTD_buildBlockEntropyStats_literals(seqStorePtr->litStart, litSize, 3748*3117ece4Schristos &prevEntropy->huf, &nextEntropy->huf, 3749*3117ece4Schristos &entropyMetadata->hufMetadata, 3750*3117ece4Schristos ZSTD_literalsCompressionIsDisabled(cctxParams), 3751*3117ece4Schristos workspace, wkspSize, hufFlags); 3752*3117ece4Schristos 3753*3117ece4Schristos FORWARD_IF_ERROR(entropyMetadata->hufMetadata.hufDesSize, "ZSTD_buildBlockEntropyStats_literals failed"); 3754*3117ece4Schristos entropyMetadata->fseMetadata.fseTablesSize = 3755*3117ece4Schristos ZSTD_buildBlockEntropyStats_sequences(seqStorePtr, 3756*3117ece4Schristos &prevEntropy->fse, &nextEntropy->fse, 3757*3117ece4Schristos cctxParams, 3758*3117ece4Schristos &entropyMetadata->fseMetadata, 3759*3117ece4Schristos workspace, wkspSize); 3760*3117ece4Schristos FORWARD_IF_ERROR(entropyMetadata->fseMetadata.fseTablesSize, "ZSTD_buildBlockEntropyStats_sequences failed"); 3761*3117ece4Schristos return 0; 3762*3117ece4Schristos } 3763*3117ece4Schristos 3764*3117ece4Schristos /* Returns the size estimate for the literals section (header + content) of a block */ 3765*3117ece4Schristos static size_t 3766*3117ece4Schristos ZSTD_estimateBlockSize_literal(const BYTE* literals, size_t litSize, 3767*3117ece4Schristos const ZSTD_hufCTables_t* huf, 3768*3117ece4Schristos const ZSTD_hufCTablesMetadata_t* hufMetadata, 3769*3117ece4Schristos void* workspace, size_t wkspSize, 3770*3117ece4Schristos int writeEntropy) 3771*3117ece4Schristos { 3772*3117ece4Schristos unsigned* const countWksp = (unsigned*)workspace; 3773*3117ece4Schristos unsigned maxSymbolValue = HUF_SYMBOLVALUE_MAX; 3774*3117ece4Schristos size_t literalSectionHeaderSize = 3 + (litSize >= 1 KB) + (litSize >= 16 KB); 3775*3117ece4Schristos U32 singleStream = litSize < 256; 3776*3117ece4Schristos 3777*3117ece4Schristos if (hufMetadata->hType == set_basic) return litSize; 3778*3117ece4Schristos else if (hufMetadata->hType == set_rle) return 1; 3779*3117ece4Schristos else if (hufMetadata->hType == set_compressed || hufMetadata->hType == set_repeat) { 3780*3117ece4Schristos size_t const largest = HIST_count_wksp (countWksp, &maxSymbolValue, (const BYTE*)literals, litSize, workspace, wkspSize); 3781*3117ece4Schristos if (ZSTD_isError(largest)) return litSize; 3782*3117ece4Schristos { size_t cLitSizeEstimate = HUF_estimateCompressedSize((const HUF_CElt*)huf->CTable, countWksp, maxSymbolValue); 3783*3117ece4Schristos if (writeEntropy) cLitSizeEstimate += hufMetadata->hufDesSize; 3784*3117ece4Schristos if (!singleStream) cLitSizeEstimate += 6; /* multi-stream huffman uses 6-byte jump table */ 3785*3117ece4Schristos return cLitSizeEstimate + literalSectionHeaderSize; 3786*3117ece4Schristos } } 3787*3117ece4Schristos assert(0); /* impossible */ 3788*3117ece4Schristos return 0; 3789*3117ece4Schristos } 3790*3117ece4Schristos 3791*3117ece4Schristos /* Returns the size estimate for the FSE-compressed symbols (of, ml, ll) of a block */ 3792*3117ece4Schristos static size_t 3793*3117ece4Schristos ZSTD_estimateBlockSize_symbolType(symbolEncodingType_e type, 3794*3117ece4Schristos const BYTE* codeTable, size_t nbSeq, unsigned maxCode, 3795*3117ece4Schristos const FSE_CTable* fseCTable, 3796*3117ece4Schristos const U8* additionalBits, 3797*3117ece4Schristos short const* defaultNorm, U32 defaultNormLog, U32 defaultMax, 3798*3117ece4Schristos void* workspace, size_t wkspSize) 3799*3117ece4Schristos { 3800*3117ece4Schristos unsigned* const countWksp = (unsigned*)workspace; 3801*3117ece4Schristos const BYTE* ctp = codeTable; 3802*3117ece4Schristos const BYTE* const ctStart = ctp; 3803*3117ece4Schristos const BYTE* const ctEnd = ctStart + nbSeq; 3804*3117ece4Schristos size_t cSymbolTypeSizeEstimateInBits = 0; 3805*3117ece4Schristos unsigned max = maxCode; 3806*3117ece4Schristos 3807*3117ece4Schristos HIST_countFast_wksp(countWksp, &max, codeTable, nbSeq, workspace, wkspSize); /* can't fail */ 3808*3117ece4Schristos if (type == set_basic) { 3809*3117ece4Schristos /* We selected this encoding type, so it must be valid. */ 3810*3117ece4Schristos assert(max <= defaultMax); 3811*3117ece4Schristos (void)defaultMax; 3812*3117ece4Schristos cSymbolTypeSizeEstimateInBits = ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, countWksp, max); 3813*3117ece4Schristos } else if (type == set_rle) { 3814*3117ece4Schristos cSymbolTypeSizeEstimateInBits = 0; 3815*3117ece4Schristos } else if (type == set_compressed || type == set_repeat) { 3816*3117ece4Schristos cSymbolTypeSizeEstimateInBits = ZSTD_fseBitCost(fseCTable, countWksp, max); 3817*3117ece4Schristos } 3818*3117ece4Schristos if (ZSTD_isError(cSymbolTypeSizeEstimateInBits)) { 3819*3117ece4Schristos return nbSeq * 10; 3820*3117ece4Schristos } 3821*3117ece4Schristos while (ctp < ctEnd) { 3822*3117ece4Schristos if (additionalBits) cSymbolTypeSizeEstimateInBits += additionalBits[*ctp]; 3823*3117ece4Schristos else cSymbolTypeSizeEstimateInBits += *ctp; /* for offset, offset code is also the number of additional bits */ 3824*3117ece4Schristos ctp++; 3825*3117ece4Schristos } 3826*3117ece4Schristos return cSymbolTypeSizeEstimateInBits >> 3; 3827*3117ece4Schristos } 3828*3117ece4Schristos 3829*3117ece4Schristos /* Returns the size estimate for the sequences section (header + content) of a block */ 3830*3117ece4Schristos static size_t 3831*3117ece4Schristos ZSTD_estimateBlockSize_sequences(const BYTE* ofCodeTable, 3832*3117ece4Schristos const BYTE* llCodeTable, 3833*3117ece4Schristos const BYTE* mlCodeTable, 3834*3117ece4Schristos size_t nbSeq, 3835*3117ece4Schristos const ZSTD_fseCTables_t* fseTables, 3836*3117ece4Schristos const ZSTD_fseCTablesMetadata_t* fseMetadata, 3837*3117ece4Schristos void* workspace, size_t wkspSize, 3838*3117ece4Schristos int writeEntropy) 3839*3117ece4Schristos { 3840*3117ece4Schristos size_t sequencesSectionHeaderSize = 1 /* seqHead */ + 1 /* min seqSize size */ + (nbSeq >= 128) + (nbSeq >= LONGNBSEQ); 3841*3117ece4Schristos size_t cSeqSizeEstimate = 0; 3842*3117ece4Schristos cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->ofType, ofCodeTable, nbSeq, MaxOff, 3843*3117ece4Schristos fseTables->offcodeCTable, NULL, 3844*3117ece4Schristos OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, 3845*3117ece4Schristos workspace, wkspSize); 3846*3117ece4Schristos cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->llType, llCodeTable, nbSeq, MaxLL, 3847*3117ece4Schristos fseTables->litlengthCTable, LL_bits, 3848*3117ece4Schristos LL_defaultNorm, LL_defaultNormLog, MaxLL, 3849*3117ece4Schristos workspace, wkspSize); 3850*3117ece4Schristos cSeqSizeEstimate += ZSTD_estimateBlockSize_symbolType(fseMetadata->mlType, mlCodeTable, nbSeq, MaxML, 3851*3117ece4Schristos fseTables->matchlengthCTable, ML_bits, 3852*3117ece4Schristos ML_defaultNorm, ML_defaultNormLog, MaxML, 3853*3117ece4Schristos workspace, wkspSize); 3854*3117ece4Schristos if (writeEntropy) cSeqSizeEstimate += fseMetadata->fseTablesSize; 3855*3117ece4Schristos return cSeqSizeEstimate + sequencesSectionHeaderSize; 3856*3117ece4Schristos } 3857*3117ece4Schristos 3858*3117ece4Schristos /* Returns the size estimate for a given stream of literals, of, ll, ml */ 3859*3117ece4Schristos static size_t 3860*3117ece4Schristos ZSTD_estimateBlockSize(const BYTE* literals, size_t litSize, 3861*3117ece4Schristos const BYTE* ofCodeTable, 3862*3117ece4Schristos const BYTE* llCodeTable, 3863*3117ece4Schristos const BYTE* mlCodeTable, 3864*3117ece4Schristos size_t nbSeq, 3865*3117ece4Schristos const ZSTD_entropyCTables_t* entropy, 3866*3117ece4Schristos const ZSTD_entropyCTablesMetadata_t* entropyMetadata, 3867*3117ece4Schristos void* workspace, size_t wkspSize, 3868*3117ece4Schristos int writeLitEntropy, int writeSeqEntropy) 3869*3117ece4Schristos { 3870*3117ece4Schristos size_t const literalsSize = ZSTD_estimateBlockSize_literal(literals, litSize, 3871*3117ece4Schristos &entropy->huf, &entropyMetadata->hufMetadata, 3872*3117ece4Schristos workspace, wkspSize, writeLitEntropy); 3873*3117ece4Schristos size_t const seqSize = ZSTD_estimateBlockSize_sequences(ofCodeTable, llCodeTable, mlCodeTable, 3874*3117ece4Schristos nbSeq, &entropy->fse, &entropyMetadata->fseMetadata, 3875*3117ece4Schristos workspace, wkspSize, writeSeqEntropy); 3876*3117ece4Schristos return seqSize + literalsSize + ZSTD_blockHeaderSize; 3877*3117ece4Schristos } 3878*3117ece4Schristos 3879*3117ece4Schristos /* Builds entropy statistics and uses them for blocksize estimation. 3880*3117ece4Schristos * 3881*3117ece4Schristos * @return: estimated compressed size of the seqStore, or a zstd error. 3882*3117ece4Schristos */ 3883*3117ece4Schristos static size_t 3884*3117ece4Schristos ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(seqStore_t* seqStore, ZSTD_CCtx* zc) 3885*3117ece4Schristos { 3886*3117ece4Schristos ZSTD_entropyCTablesMetadata_t* const entropyMetadata = &zc->blockSplitCtx.entropyMetadata; 3887*3117ece4Schristos DEBUGLOG(6, "ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize()"); 3888*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_buildBlockEntropyStats(seqStore, 3889*3117ece4Schristos &zc->blockState.prevCBlock->entropy, 3890*3117ece4Schristos &zc->blockState.nextCBlock->entropy, 3891*3117ece4Schristos &zc->appliedParams, 3892*3117ece4Schristos entropyMetadata, 3893*3117ece4Schristos zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE), ""); 3894*3117ece4Schristos return ZSTD_estimateBlockSize( 3895*3117ece4Schristos seqStore->litStart, (size_t)(seqStore->lit - seqStore->litStart), 3896*3117ece4Schristos seqStore->ofCode, seqStore->llCode, seqStore->mlCode, 3897*3117ece4Schristos (size_t)(seqStore->sequences - seqStore->sequencesStart), 3898*3117ece4Schristos &zc->blockState.nextCBlock->entropy, 3899*3117ece4Schristos entropyMetadata, 3900*3117ece4Schristos zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE, 3901*3117ece4Schristos (int)(entropyMetadata->hufMetadata.hType == set_compressed), 1); 3902*3117ece4Schristos } 3903*3117ece4Schristos 3904*3117ece4Schristos /* Returns literals bytes represented in a seqStore */ 3905*3117ece4Schristos static size_t ZSTD_countSeqStoreLiteralsBytes(const seqStore_t* const seqStore) 3906*3117ece4Schristos { 3907*3117ece4Schristos size_t literalsBytes = 0; 3908*3117ece4Schristos size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart); 3909*3117ece4Schristos size_t i; 3910*3117ece4Schristos for (i = 0; i < nbSeqs; ++i) { 3911*3117ece4Schristos seqDef const seq = seqStore->sequencesStart[i]; 3912*3117ece4Schristos literalsBytes += seq.litLength; 3913*3117ece4Schristos if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_literalLength) { 3914*3117ece4Schristos literalsBytes += 0x10000; 3915*3117ece4Schristos } } 3916*3117ece4Schristos return literalsBytes; 3917*3117ece4Schristos } 3918*3117ece4Schristos 3919*3117ece4Schristos /* Returns match bytes represented in a seqStore */ 3920*3117ece4Schristos static size_t ZSTD_countSeqStoreMatchBytes(const seqStore_t* const seqStore) 3921*3117ece4Schristos { 3922*3117ece4Schristos size_t matchBytes = 0; 3923*3117ece4Schristos size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart); 3924*3117ece4Schristos size_t i; 3925*3117ece4Schristos for (i = 0; i < nbSeqs; ++i) { 3926*3117ece4Schristos seqDef seq = seqStore->sequencesStart[i]; 3927*3117ece4Schristos matchBytes += seq.mlBase + MINMATCH; 3928*3117ece4Schristos if (i == seqStore->longLengthPos && seqStore->longLengthType == ZSTD_llt_matchLength) { 3929*3117ece4Schristos matchBytes += 0x10000; 3930*3117ece4Schristos } } 3931*3117ece4Schristos return matchBytes; 3932*3117ece4Schristos } 3933*3117ece4Schristos 3934*3117ece4Schristos /* Derives the seqStore that is a chunk of the originalSeqStore from [startIdx, endIdx). 3935*3117ece4Schristos * Stores the result in resultSeqStore. 3936*3117ece4Schristos */ 3937*3117ece4Schristos static void ZSTD_deriveSeqStoreChunk(seqStore_t* resultSeqStore, 3938*3117ece4Schristos const seqStore_t* originalSeqStore, 3939*3117ece4Schristos size_t startIdx, size_t endIdx) 3940*3117ece4Schristos { 3941*3117ece4Schristos *resultSeqStore = *originalSeqStore; 3942*3117ece4Schristos if (startIdx > 0) { 3943*3117ece4Schristos resultSeqStore->sequences = originalSeqStore->sequencesStart + startIdx; 3944*3117ece4Schristos resultSeqStore->litStart += ZSTD_countSeqStoreLiteralsBytes(resultSeqStore); 3945*3117ece4Schristos } 3946*3117ece4Schristos 3947*3117ece4Schristos /* Move longLengthPos into the correct position if necessary */ 3948*3117ece4Schristos if (originalSeqStore->longLengthType != ZSTD_llt_none) { 3949*3117ece4Schristos if (originalSeqStore->longLengthPos < startIdx || originalSeqStore->longLengthPos > endIdx) { 3950*3117ece4Schristos resultSeqStore->longLengthType = ZSTD_llt_none; 3951*3117ece4Schristos } else { 3952*3117ece4Schristos resultSeqStore->longLengthPos -= (U32)startIdx; 3953*3117ece4Schristos } 3954*3117ece4Schristos } 3955*3117ece4Schristos resultSeqStore->sequencesStart = originalSeqStore->sequencesStart + startIdx; 3956*3117ece4Schristos resultSeqStore->sequences = originalSeqStore->sequencesStart + endIdx; 3957*3117ece4Schristos if (endIdx == (size_t)(originalSeqStore->sequences - originalSeqStore->sequencesStart)) { 3958*3117ece4Schristos /* This accounts for possible last literals if the derived chunk reaches the end of the block */ 3959*3117ece4Schristos assert(resultSeqStore->lit == originalSeqStore->lit); 3960*3117ece4Schristos } else { 3961*3117ece4Schristos size_t const literalsBytes = ZSTD_countSeqStoreLiteralsBytes(resultSeqStore); 3962*3117ece4Schristos resultSeqStore->lit = resultSeqStore->litStart + literalsBytes; 3963*3117ece4Schristos } 3964*3117ece4Schristos resultSeqStore->llCode += startIdx; 3965*3117ece4Schristos resultSeqStore->mlCode += startIdx; 3966*3117ece4Schristos resultSeqStore->ofCode += startIdx; 3967*3117ece4Schristos } 3968*3117ece4Schristos 3969*3117ece4Schristos /** 3970*3117ece4Schristos * Returns the raw offset represented by the combination of offBase, ll0, and repcode history. 3971*3117ece4Schristos * offBase must represent a repcode in the numeric representation of ZSTD_storeSeq(). 3972*3117ece4Schristos */ 3973*3117ece4Schristos static U32 3974*3117ece4Schristos ZSTD_resolveRepcodeToRawOffset(const U32 rep[ZSTD_REP_NUM], const U32 offBase, const U32 ll0) 3975*3117ece4Schristos { 3976*3117ece4Schristos U32 const adjustedRepCode = OFFBASE_TO_REPCODE(offBase) - 1 + ll0; /* [ 0 - 3 ] */ 3977*3117ece4Schristos assert(OFFBASE_IS_REPCODE(offBase)); 3978*3117ece4Schristos if (adjustedRepCode == ZSTD_REP_NUM) { 3979*3117ece4Schristos assert(ll0); 3980*3117ece4Schristos /* litlength == 0 and offCode == 2 implies selection of first repcode - 1 3981*3117ece4Schristos * This is only valid if it results in a valid offset value, aka > 0. 3982*3117ece4Schristos * Note : it may happen that `rep[0]==1` in exceptional circumstances. 3983*3117ece4Schristos * In which case this function will return 0, which is an invalid offset. 3984*3117ece4Schristos * It's not an issue though, since this value will be 3985*3117ece4Schristos * compared and discarded within ZSTD_seqStore_resolveOffCodes(). 3986*3117ece4Schristos */ 3987*3117ece4Schristos return rep[0] - 1; 3988*3117ece4Schristos } 3989*3117ece4Schristos return rep[adjustedRepCode]; 3990*3117ece4Schristos } 3991*3117ece4Schristos 3992*3117ece4Schristos /** 3993*3117ece4Schristos * ZSTD_seqStore_resolveOffCodes() reconciles any possible divergences in offset history that may arise 3994*3117ece4Schristos * due to emission of RLE/raw blocks that disturb the offset history, 3995*3117ece4Schristos * and replaces any repcodes within the seqStore that may be invalid. 3996*3117ece4Schristos * 3997*3117ece4Schristos * dRepcodes are updated as would be on the decompression side. 3998*3117ece4Schristos * cRepcodes are updated exactly in accordance with the seqStore. 3999*3117ece4Schristos * 4000*3117ece4Schristos * Note : this function assumes seq->offBase respects the following numbering scheme : 4001*3117ece4Schristos * 0 : invalid 4002*3117ece4Schristos * 1-3 : repcode 1-3 4003*3117ece4Schristos * 4+ : real_offset+3 4004*3117ece4Schristos */ 4005*3117ece4Schristos static void 4006*3117ece4Schristos ZSTD_seqStore_resolveOffCodes(repcodes_t* const dRepcodes, repcodes_t* const cRepcodes, 4007*3117ece4Schristos const seqStore_t* const seqStore, U32 const nbSeq) 4008*3117ece4Schristos { 4009*3117ece4Schristos U32 idx = 0; 4010*3117ece4Schristos U32 const longLitLenIdx = seqStore->longLengthType == ZSTD_llt_literalLength ? seqStore->longLengthPos : nbSeq; 4011*3117ece4Schristos for (; idx < nbSeq; ++idx) { 4012*3117ece4Schristos seqDef* const seq = seqStore->sequencesStart + idx; 4013*3117ece4Schristos U32 const ll0 = (seq->litLength == 0) && (idx != longLitLenIdx); 4014*3117ece4Schristos U32 const offBase = seq->offBase; 4015*3117ece4Schristos assert(offBase > 0); 4016*3117ece4Schristos if (OFFBASE_IS_REPCODE(offBase)) { 4017*3117ece4Schristos U32 const dRawOffset = ZSTD_resolveRepcodeToRawOffset(dRepcodes->rep, offBase, ll0); 4018*3117ece4Schristos U32 const cRawOffset = ZSTD_resolveRepcodeToRawOffset(cRepcodes->rep, offBase, ll0); 4019*3117ece4Schristos /* Adjust simulated decompression repcode history if we come across a mismatch. Replace 4020*3117ece4Schristos * the repcode with the offset it actually references, determined by the compression 4021*3117ece4Schristos * repcode history. 4022*3117ece4Schristos */ 4023*3117ece4Schristos if (dRawOffset != cRawOffset) { 4024*3117ece4Schristos seq->offBase = OFFSET_TO_OFFBASE(cRawOffset); 4025*3117ece4Schristos } 4026*3117ece4Schristos } 4027*3117ece4Schristos /* Compression repcode history is always updated with values directly from the unmodified seqStore. 4028*3117ece4Schristos * Decompression repcode history may use modified seq->offset value taken from compression repcode history. 4029*3117ece4Schristos */ 4030*3117ece4Schristos ZSTD_updateRep(dRepcodes->rep, seq->offBase, ll0); 4031*3117ece4Schristos ZSTD_updateRep(cRepcodes->rep, offBase, ll0); 4032*3117ece4Schristos } 4033*3117ece4Schristos } 4034*3117ece4Schristos 4035*3117ece4Schristos /* ZSTD_compressSeqStore_singleBlock(): 4036*3117ece4Schristos * Compresses a seqStore into a block with a block header, into the buffer dst. 4037*3117ece4Schristos * 4038*3117ece4Schristos * Returns the total size of that block (including header) or a ZSTD error code. 4039*3117ece4Schristos */ 4040*3117ece4Schristos static size_t 4041*3117ece4Schristos ZSTD_compressSeqStore_singleBlock(ZSTD_CCtx* zc, 4042*3117ece4Schristos const seqStore_t* const seqStore, 4043*3117ece4Schristos repcodes_t* const dRep, repcodes_t* const cRep, 4044*3117ece4Schristos void* dst, size_t dstCapacity, 4045*3117ece4Schristos const void* src, size_t srcSize, 4046*3117ece4Schristos U32 lastBlock, U32 isPartition) 4047*3117ece4Schristos { 4048*3117ece4Schristos const U32 rleMaxLength = 25; 4049*3117ece4Schristos BYTE* op = (BYTE*)dst; 4050*3117ece4Schristos const BYTE* ip = (const BYTE*)src; 4051*3117ece4Schristos size_t cSize; 4052*3117ece4Schristos size_t cSeqsSize; 4053*3117ece4Schristos 4054*3117ece4Schristos /* In case of an RLE or raw block, the simulated decompression repcode history must be reset */ 4055*3117ece4Schristos repcodes_t const dRepOriginal = *dRep; 4056*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressSeqStore_singleBlock"); 4057*3117ece4Schristos if (isPartition) 4058*3117ece4Schristos ZSTD_seqStore_resolveOffCodes(dRep, cRep, seqStore, (U32)(seqStore->sequences - seqStore->sequencesStart)); 4059*3117ece4Schristos 4060*3117ece4Schristos RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, "Block header doesn't fit"); 4061*3117ece4Schristos cSeqsSize = ZSTD_entropyCompressSeqStore(seqStore, 4062*3117ece4Schristos &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, 4063*3117ece4Schristos &zc->appliedParams, 4064*3117ece4Schristos op + ZSTD_blockHeaderSize, dstCapacity - ZSTD_blockHeaderSize, 4065*3117ece4Schristos srcSize, 4066*3117ece4Schristos zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, 4067*3117ece4Schristos zc->bmi2); 4068*3117ece4Schristos FORWARD_IF_ERROR(cSeqsSize, "ZSTD_entropyCompressSeqStore failed!"); 4069*3117ece4Schristos 4070*3117ece4Schristos if (!zc->isFirstBlock && 4071*3117ece4Schristos cSeqsSize < rleMaxLength && 4072*3117ece4Schristos ZSTD_isRLE((BYTE const*)src, srcSize)) { 4073*3117ece4Schristos /* We don't want to emit our first block as a RLE even if it qualifies because 4074*3117ece4Schristos * doing so will cause the decoder (cli only) to throw a "should consume all input error." 4075*3117ece4Schristos * This is only an issue for zstd <= v1.4.3 4076*3117ece4Schristos */ 4077*3117ece4Schristos cSeqsSize = 1; 4078*3117ece4Schristos } 4079*3117ece4Schristos 4080*3117ece4Schristos /* Sequence collection not supported when block splitting */ 4081*3117ece4Schristos if (zc->seqCollector.collectSequences) { 4082*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_copyBlockSequences(&zc->seqCollector, seqStore, dRepOriginal.rep), "copyBlockSequences failed"); 4083*3117ece4Schristos ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); 4084*3117ece4Schristos return 0; 4085*3117ece4Schristos } 4086*3117ece4Schristos 4087*3117ece4Schristos if (cSeqsSize == 0) { 4088*3117ece4Schristos cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, srcSize, lastBlock); 4089*3117ece4Schristos FORWARD_IF_ERROR(cSize, "Nocompress block failed"); 4090*3117ece4Schristos DEBUGLOG(4, "Writing out nocompress block, size: %zu", cSize); 4091*3117ece4Schristos *dRep = dRepOriginal; /* reset simulated decompression repcode history */ 4092*3117ece4Schristos } else if (cSeqsSize == 1) { 4093*3117ece4Schristos cSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, srcSize, lastBlock); 4094*3117ece4Schristos FORWARD_IF_ERROR(cSize, "RLE compress block failed"); 4095*3117ece4Schristos DEBUGLOG(4, "Writing out RLE block, size: %zu", cSize); 4096*3117ece4Schristos *dRep = dRepOriginal; /* reset simulated decompression repcode history */ 4097*3117ece4Schristos } else { 4098*3117ece4Schristos ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); 4099*3117ece4Schristos writeBlockHeader(op, cSeqsSize, srcSize, lastBlock); 4100*3117ece4Schristos cSize = ZSTD_blockHeaderSize + cSeqsSize; 4101*3117ece4Schristos DEBUGLOG(4, "Writing out compressed block, size: %zu", cSize); 4102*3117ece4Schristos } 4103*3117ece4Schristos 4104*3117ece4Schristos if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) 4105*3117ece4Schristos zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; 4106*3117ece4Schristos 4107*3117ece4Schristos return cSize; 4108*3117ece4Schristos } 4109*3117ece4Schristos 4110*3117ece4Schristos /* Struct to keep track of where we are in our recursive calls. */ 4111*3117ece4Schristos typedef struct { 4112*3117ece4Schristos U32* splitLocations; /* Array of split indices */ 4113*3117ece4Schristos size_t idx; /* The current index within splitLocations being worked on */ 4114*3117ece4Schristos } seqStoreSplits; 4115*3117ece4Schristos 4116*3117ece4Schristos #define MIN_SEQUENCES_BLOCK_SPLITTING 300 4117*3117ece4Schristos 4118*3117ece4Schristos /* Helper function to perform the recursive search for block splits. 4119*3117ece4Schristos * Estimates the cost of seqStore prior to split, and estimates the cost of splitting the sequences in half. 4120*3117ece4Schristos * If advantageous to split, then we recurse down the two sub-blocks. 4121*3117ece4Schristos * If not, or if an error occurred in estimation, then we do not recurse. 4122*3117ece4Schristos * 4123*3117ece4Schristos * Note: The recursion depth is capped by a heuristic minimum number of sequences, 4124*3117ece4Schristos * defined by MIN_SEQUENCES_BLOCK_SPLITTING. 4125*3117ece4Schristos * In theory, this means the absolute largest recursion depth is 10 == log2(maxNbSeqInBlock/MIN_SEQUENCES_BLOCK_SPLITTING). 4126*3117ece4Schristos * In practice, recursion depth usually doesn't go beyond 4. 4127*3117ece4Schristos * 4128*3117ece4Schristos * Furthermore, the number of splits is capped by ZSTD_MAX_NB_BLOCK_SPLITS. 4129*3117ece4Schristos * At ZSTD_MAX_NB_BLOCK_SPLITS == 196 with the current existing blockSize 4130*3117ece4Schristos * maximum of 128 KB, this value is actually impossible to reach. 4131*3117ece4Schristos */ 4132*3117ece4Schristos static void 4133*3117ece4Schristos ZSTD_deriveBlockSplitsHelper(seqStoreSplits* splits, size_t startIdx, size_t endIdx, 4134*3117ece4Schristos ZSTD_CCtx* zc, const seqStore_t* origSeqStore) 4135*3117ece4Schristos { 4136*3117ece4Schristos seqStore_t* const fullSeqStoreChunk = &zc->blockSplitCtx.fullSeqStoreChunk; 4137*3117ece4Schristos seqStore_t* const firstHalfSeqStore = &zc->blockSplitCtx.firstHalfSeqStore; 4138*3117ece4Schristos seqStore_t* const secondHalfSeqStore = &zc->blockSplitCtx.secondHalfSeqStore; 4139*3117ece4Schristos size_t estimatedOriginalSize; 4140*3117ece4Schristos size_t estimatedFirstHalfSize; 4141*3117ece4Schristos size_t estimatedSecondHalfSize; 4142*3117ece4Schristos size_t midIdx = (startIdx + endIdx)/2; 4143*3117ece4Schristos 4144*3117ece4Schristos DEBUGLOG(5, "ZSTD_deriveBlockSplitsHelper: startIdx=%zu endIdx=%zu", startIdx, endIdx); 4145*3117ece4Schristos assert(endIdx >= startIdx); 4146*3117ece4Schristos if (endIdx - startIdx < MIN_SEQUENCES_BLOCK_SPLITTING || splits->idx >= ZSTD_MAX_NB_BLOCK_SPLITS) { 4147*3117ece4Schristos DEBUGLOG(6, "ZSTD_deriveBlockSplitsHelper: Too few sequences (%zu)", endIdx - startIdx); 4148*3117ece4Schristos return; 4149*3117ece4Schristos } 4150*3117ece4Schristos ZSTD_deriveSeqStoreChunk(fullSeqStoreChunk, origSeqStore, startIdx, endIdx); 4151*3117ece4Schristos ZSTD_deriveSeqStoreChunk(firstHalfSeqStore, origSeqStore, startIdx, midIdx); 4152*3117ece4Schristos ZSTD_deriveSeqStoreChunk(secondHalfSeqStore, origSeqStore, midIdx, endIdx); 4153*3117ece4Schristos estimatedOriginalSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(fullSeqStoreChunk, zc); 4154*3117ece4Schristos estimatedFirstHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(firstHalfSeqStore, zc); 4155*3117ece4Schristos estimatedSecondHalfSize = ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(secondHalfSeqStore, zc); 4156*3117ece4Schristos DEBUGLOG(5, "Estimated original block size: %zu -- First half split: %zu -- Second half split: %zu", 4157*3117ece4Schristos estimatedOriginalSize, estimatedFirstHalfSize, estimatedSecondHalfSize); 4158*3117ece4Schristos if (ZSTD_isError(estimatedOriginalSize) || ZSTD_isError(estimatedFirstHalfSize) || ZSTD_isError(estimatedSecondHalfSize)) { 4159*3117ece4Schristos return; 4160*3117ece4Schristos } 4161*3117ece4Schristos if (estimatedFirstHalfSize + estimatedSecondHalfSize < estimatedOriginalSize) { 4162*3117ece4Schristos DEBUGLOG(5, "split decided at seqNb:%zu", midIdx); 4163*3117ece4Schristos ZSTD_deriveBlockSplitsHelper(splits, startIdx, midIdx, zc, origSeqStore); 4164*3117ece4Schristos splits->splitLocations[splits->idx] = (U32)midIdx; 4165*3117ece4Schristos splits->idx++; 4166*3117ece4Schristos ZSTD_deriveBlockSplitsHelper(splits, midIdx, endIdx, zc, origSeqStore); 4167*3117ece4Schristos } 4168*3117ece4Schristos } 4169*3117ece4Schristos 4170*3117ece4Schristos /* Base recursive function. 4171*3117ece4Schristos * Populates a table with intra-block partition indices that can improve compression ratio. 4172*3117ece4Schristos * 4173*3117ece4Schristos * @return: number of splits made (which equals the size of the partition table - 1). 4174*3117ece4Schristos */ 4175*3117ece4Schristos static size_t ZSTD_deriveBlockSplits(ZSTD_CCtx* zc, U32 partitions[], U32 nbSeq) 4176*3117ece4Schristos { 4177*3117ece4Schristos seqStoreSplits splits; 4178*3117ece4Schristos splits.splitLocations = partitions; 4179*3117ece4Schristos splits.idx = 0; 4180*3117ece4Schristos if (nbSeq <= 4) { 4181*3117ece4Schristos DEBUGLOG(5, "ZSTD_deriveBlockSplits: Too few sequences to split (%u <= 4)", nbSeq); 4182*3117ece4Schristos /* Refuse to try and split anything with less than 4 sequences */ 4183*3117ece4Schristos return 0; 4184*3117ece4Schristos } 4185*3117ece4Schristos ZSTD_deriveBlockSplitsHelper(&splits, 0, nbSeq, zc, &zc->seqStore); 4186*3117ece4Schristos splits.splitLocations[splits.idx] = nbSeq; 4187*3117ece4Schristos DEBUGLOG(5, "ZSTD_deriveBlockSplits: final nb partitions: %zu", splits.idx+1); 4188*3117ece4Schristos return splits.idx; 4189*3117ece4Schristos } 4190*3117ece4Schristos 4191*3117ece4Schristos /* ZSTD_compressBlock_splitBlock(): 4192*3117ece4Schristos * Attempts to split a given block into multiple blocks to improve compression ratio. 4193*3117ece4Schristos * 4194*3117ece4Schristos * Returns combined size of all blocks (which includes headers), or a ZSTD error code. 4195*3117ece4Schristos */ 4196*3117ece4Schristos static size_t 4197*3117ece4Schristos ZSTD_compressBlock_splitBlock_internal(ZSTD_CCtx* zc, 4198*3117ece4Schristos void* dst, size_t dstCapacity, 4199*3117ece4Schristos const void* src, size_t blockSize, 4200*3117ece4Schristos U32 lastBlock, U32 nbSeq) 4201*3117ece4Schristos { 4202*3117ece4Schristos size_t cSize = 0; 4203*3117ece4Schristos const BYTE* ip = (const BYTE*)src; 4204*3117ece4Schristos BYTE* op = (BYTE*)dst; 4205*3117ece4Schristos size_t i = 0; 4206*3117ece4Schristos size_t srcBytesTotal = 0; 4207*3117ece4Schristos U32* const partitions = zc->blockSplitCtx.partitions; /* size == ZSTD_MAX_NB_BLOCK_SPLITS */ 4208*3117ece4Schristos seqStore_t* const nextSeqStore = &zc->blockSplitCtx.nextSeqStore; 4209*3117ece4Schristos seqStore_t* const currSeqStore = &zc->blockSplitCtx.currSeqStore; 4210*3117ece4Schristos size_t const numSplits = ZSTD_deriveBlockSplits(zc, partitions, nbSeq); 4211*3117ece4Schristos 4212*3117ece4Schristos /* If a block is split and some partitions are emitted as RLE/uncompressed, then repcode history 4213*3117ece4Schristos * may become invalid. In order to reconcile potentially invalid repcodes, we keep track of two 4214*3117ece4Schristos * separate repcode histories that simulate repcode history on compression and decompression side, 4215*3117ece4Schristos * and use the histories to determine whether we must replace a particular repcode with its raw offset. 4216*3117ece4Schristos * 4217*3117ece4Schristos * 1) cRep gets updated for each partition, regardless of whether the block was emitted as uncompressed 4218*3117ece4Schristos * or RLE. This allows us to retrieve the offset value that an invalid repcode references within 4219*3117ece4Schristos * a nocompress/RLE block. 4220*3117ece4Schristos * 2) dRep gets updated only for compressed partitions, and when a repcode gets replaced, will use 4221*3117ece4Schristos * the replacement offset value rather than the original repcode to update the repcode history. 4222*3117ece4Schristos * dRep also will be the final repcode history sent to the next block. 4223*3117ece4Schristos * 4224*3117ece4Schristos * See ZSTD_seqStore_resolveOffCodes() for more details. 4225*3117ece4Schristos */ 4226*3117ece4Schristos repcodes_t dRep; 4227*3117ece4Schristos repcodes_t cRep; 4228*3117ece4Schristos ZSTD_memcpy(dRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); 4229*3117ece4Schristos ZSTD_memcpy(cRep.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t)); 4230*3117ece4Schristos ZSTD_memset(nextSeqStore, 0, sizeof(seqStore_t)); 4231*3117ece4Schristos 4232*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressBlock_splitBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", 4233*3117ece4Schristos (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, 4234*3117ece4Schristos (unsigned)zc->blockState.matchState.nextToUpdate); 4235*3117ece4Schristos 4236*3117ece4Schristos if (numSplits == 0) { 4237*3117ece4Schristos size_t cSizeSingleBlock = 4238*3117ece4Schristos ZSTD_compressSeqStore_singleBlock(zc, &zc->seqStore, 4239*3117ece4Schristos &dRep, &cRep, 4240*3117ece4Schristos op, dstCapacity, 4241*3117ece4Schristos ip, blockSize, 4242*3117ece4Schristos lastBlock, 0 /* isPartition */); 4243*3117ece4Schristos FORWARD_IF_ERROR(cSizeSingleBlock, "Compressing single block from splitBlock_internal() failed!"); 4244*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressBlock_splitBlock_internal: No splits"); 4245*3117ece4Schristos assert(zc->blockSize <= ZSTD_BLOCKSIZE_MAX); 4246*3117ece4Schristos assert(cSizeSingleBlock <= zc->blockSize + ZSTD_blockHeaderSize); 4247*3117ece4Schristos return cSizeSingleBlock; 4248*3117ece4Schristos } 4249*3117ece4Schristos 4250*3117ece4Schristos ZSTD_deriveSeqStoreChunk(currSeqStore, &zc->seqStore, 0, partitions[0]); 4251*3117ece4Schristos for (i = 0; i <= numSplits; ++i) { 4252*3117ece4Schristos size_t cSizeChunk; 4253*3117ece4Schristos U32 const lastPartition = (i == numSplits); 4254*3117ece4Schristos U32 lastBlockEntireSrc = 0; 4255*3117ece4Schristos 4256*3117ece4Schristos size_t srcBytes = ZSTD_countSeqStoreLiteralsBytes(currSeqStore) + ZSTD_countSeqStoreMatchBytes(currSeqStore); 4257*3117ece4Schristos srcBytesTotal += srcBytes; 4258*3117ece4Schristos if (lastPartition) { 4259*3117ece4Schristos /* This is the final partition, need to account for possible last literals */ 4260*3117ece4Schristos srcBytes += blockSize - srcBytesTotal; 4261*3117ece4Schristos lastBlockEntireSrc = lastBlock; 4262*3117ece4Schristos } else { 4263*3117ece4Schristos ZSTD_deriveSeqStoreChunk(nextSeqStore, &zc->seqStore, partitions[i], partitions[i+1]); 4264*3117ece4Schristos } 4265*3117ece4Schristos 4266*3117ece4Schristos cSizeChunk = ZSTD_compressSeqStore_singleBlock(zc, currSeqStore, 4267*3117ece4Schristos &dRep, &cRep, 4268*3117ece4Schristos op, dstCapacity, 4269*3117ece4Schristos ip, srcBytes, 4270*3117ece4Schristos lastBlockEntireSrc, 1 /* isPartition */); 4271*3117ece4Schristos DEBUGLOG(5, "Estimated size: %zu vs %zu : actual size", 4272*3117ece4Schristos ZSTD_buildEntropyStatisticsAndEstimateSubBlockSize(currSeqStore, zc), cSizeChunk); 4273*3117ece4Schristos FORWARD_IF_ERROR(cSizeChunk, "Compressing chunk failed!"); 4274*3117ece4Schristos 4275*3117ece4Schristos ip += srcBytes; 4276*3117ece4Schristos op += cSizeChunk; 4277*3117ece4Schristos dstCapacity -= cSizeChunk; 4278*3117ece4Schristos cSize += cSizeChunk; 4279*3117ece4Schristos *currSeqStore = *nextSeqStore; 4280*3117ece4Schristos assert(cSizeChunk <= zc->blockSize + ZSTD_blockHeaderSize); 4281*3117ece4Schristos } 4282*3117ece4Schristos /* cRep and dRep may have diverged during the compression. 4283*3117ece4Schristos * If so, we use the dRep repcodes for the next block. 4284*3117ece4Schristos */ 4285*3117ece4Schristos ZSTD_memcpy(zc->blockState.prevCBlock->rep, dRep.rep, sizeof(repcodes_t)); 4286*3117ece4Schristos return cSize; 4287*3117ece4Schristos } 4288*3117ece4Schristos 4289*3117ece4Schristos static size_t 4290*3117ece4Schristos ZSTD_compressBlock_splitBlock(ZSTD_CCtx* zc, 4291*3117ece4Schristos void* dst, size_t dstCapacity, 4292*3117ece4Schristos const void* src, size_t srcSize, U32 lastBlock) 4293*3117ece4Schristos { 4294*3117ece4Schristos U32 nbSeq; 4295*3117ece4Schristos size_t cSize; 4296*3117ece4Schristos DEBUGLOG(4, "ZSTD_compressBlock_splitBlock"); 4297*3117ece4Schristos assert(zc->appliedParams.useBlockSplitter == ZSTD_ps_enable); 4298*3117ece4Schristos 4299*3117ece4Schristos { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); 4300*3117ece4Schristos FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); 4301*3117ece4Schristos if (bss == ZSTDbss_noCompress) { 4302*3117ece4Schristos if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) 4303*3117ece4Schristos zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; 4304*3117ece4Schristos RETURN_ERROR_IF(zc->seqCollector.collectSequences, sequenceProducer_failed, "Uncompressible block"); 4305*3117ece4Schristos cSize = ZSTD_noCompressBlock(dst, dstCapacity, src, srcSize, lastBlock); 4306*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); 4307*3117ece4Schristos DEBUGLOG(4, "ZSTD_compressBlock_splitBlock: Nocompress block"); 4308*3117ece4Schristos return cSize; 4309*3117ece4Schristos } 4310*3117ece4Schristos nbSeq = (U32)(zc->seqStore.sequences - zc->seqStore.sequencesStart); 4311*3117ece4Schristos } 4312*3117ece4Schristos 4313*3117ece4Schristos cSize = ZSTD_compressBlock_splitBlock_internal(zc, dst, dstCapacity, src, srcSize, lastBlock, nbSeq); 4314*3117ece4Schristos FORWARD_IF_ERROR(cSize, "Splitting blocks failed!"); 4315*3117ece4Schristos return cSize; 4316*3117ece4Schristos } 4317*3117ece4Schristos 4318*3117ece4Schristos static size_t 4319*3117ece4Schristos ZSTD_compressBlock_internal(ZSTD_CCtx* zc, 4320*3117ece4Schristos void* dst, size_t dstCapacity, 4321*3117ece4Schristos const void* src, size_t srcSize, U32 frame) 4322*3117ece4Schristos { 4323*3117ece4Schristos /* This is an estimated upper bound for the length of an rle block. 4324*3117ece4Schristos * This isn't the actual upper bound. 4325*3117ece4Schristos * Finding the real threshold needs further investigation. 4326*3117ece4Schristos */ 4327*3117ece4Schristos const U32 rleMaxLength = 25; 4328*3117ece4Schristos size_t cSize; 4329*3117ece4Schristos const BYTE* ip = (const BYTE*)src; 4330*3117ece4Schristos BYTE* op = (BYTE*)dst; 4331*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", 4332*3117ece4Schristos (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, 4333*3117ece4Schristos (unsigned)zc->blockState.matchState.nextToUpdate); 4334*3117ece4Schristos 4335*3117ece4Schristos { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); 4336*3117ece4Schristos FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); 4337*3117ece4Schristos if (bss == ZSTDbss_noCompress) { 4338*3117ece4Schristos RETURN_ERROR_IF(zc->seqCollector.collectSequences, sequenceProducer_failed, "Uncompressible block"); 4339*3117ece4Schristos cSize = 0; 4340*3117ece4Schristos goto out; 4341*3117ece4Schristos } 4342*3117ece4Schristos } 4343*3117ece4Schristos 4344*3117ece4Schristos if (zc->seqCollector.collectSequences) { 4345*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_copyBlockSequences(&zc->seqCollector, ZSTD_getSeqStore(zc), zc->blockState.prevCBlock->rep), "copyBlockSequences failed"); 4346*3117ece4Schristos ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); 4347*3117ece4Schristos return 0; 4348*3117ece4Schristos } 4349*3117ece4Schristos 4350*3117ece4Schristos /* encode sequences and literals */ 4351*3117ece4Schristos cSize = ZSTD_entropyCompressSeqStore(&zc->seqStore, 4352*3117ece4Schristos &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, 4353*3117ece4Schristos &zc->appliedParams, 4354*3117ece4Schristos dst, dstCapacity, 4355*3117ece4Schristos srcSize, 4356*3117ece4Schristos zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, 4357*3117ece4Schristos zc->bmi2); 4358*3117ece4Schristos 4359*3117ece4Schristos if (frame && 4360*3117ece4Schristos /* We don't want to emit our first block as a RLE even if it qualifies because 4361*3117ece4Schristos * doing so will cause the decoder (cli only) to throw a "should consume all input error." 4362*3117ece4Schristos * This is only an issue for zstd <= v1.4.3 4363*3117ece4Schristos */ 4364*3117ece4Schristos !zc->isFirstBlock && 4365*3117ece4Schristos cSize < rleMaxLength && 4366*3117ece4Schristos ZSTD_isRLE(ip, srcSize)) 4367*3117ece4Schristos { 4368*3117ece4Schristos cSize = 1; 4369*3117ece4Schristos op[0] = ip[0]; 4370*3117ece4Schristos } 4371*3117ece4Schristos 4372*3117ece4Schristos out: 4373*3117ece4Schristos if (!ZSTD_isError(cSize) && cSize > 1) { 4374*3117ece4Schristos ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); 4375*3117ece4Schristos } 4376*3117ece4Schristos /* We check that dictionaries have offset codes available for the first 4377*3117ece4Schristos * block. After the first block, the offcode table might not have large 4378*3117ece4Schristos * enough codes to represent the offsets in the data. 4379*3117ece4Schristos */ 4380*3117ece4Schristos if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) 4381*3117ece4Schristos zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; 4382*3117ece4Schristos 4383*3117ece4Schristos return cSize; 4384*3117ece4Schristos } 4385*3117ece4Schristos 4386*3117ece4Schristos static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc, 4387*3117ece4Schristos void* dst, size_t dstCapacity, 4388*3117ece4Schristos const void* src, size_t srcSize, 4389*3117ece4Schristos const size_t bss, U32 lastBlock) 4390*3117ece4Schristos { 4391*3117ece4Schristos DEBUGLOG(6, "Attempting ZSTD_compressSuperBlock()"); 4392*3117ece4Schristos if (bss == ZSTDbss_compress) { 4393*3117ece4Schristos if (/* We don't want to emit our first block as a RLE even if it qualifies because 4394*3117ece4Schristos * doing so will cause the decoder (cli only) to throw a "should consume all input error." 4395*3117ece4Schristos * This is only an issue for zstd <= v1.4.3 4396*3117ece4Schristos */ 4397*3117ece4Schristos !zc->isFirstBlock && 4398*3117ece4Schristos ZSTD_maybeRLE(&zc->seqStore) && 4399*3117ece4Schristos ZSTD_isRLE((BYTE const*)src, srcSize)) 4400*3117ece4Schristos { 4401*3117ece4Schristos return ZSTD_rleCompressBlock(dst, dstCapacity, *(BYTE const*)src, srcSize, lastBlock); 4402*3117ece4Schristos } 4403*3117ece4Schristos /* Attempt superblock compression. 4404*3117ece4Schristos * 4405*3117ece4Schristos * Note that compressed size of ZSTD_compressSuperBlock() is not bound by the 4406*3117ece4Schristos * standard ZSTD_compressBound(). This is a problem, because even if we have 4407*3117ece4Schristos * space now, taking an extra byte now could cause us to run out of space later 4408*3117ece4Schristos * and violate ZSTD_compressBound(). 4409*3117ece4Schristos * 4410*3117ece4Schristos * Define blockBound(blockSize) = blockSize + ZSTD_blockHeaderSize. 4411*3117ece4Schristos * 4412*3117ece4Schristos * In order to respect ZSTD_compressBound() we must attempt to emit a raw 4413*3117ece4Schristos * uncompressed block in these cases: 4414*3117ece4Schristos * * cSize == 0: Return code for an uncompressed block. 4415*3117ece4Schristos * * cSize == dstSize_tooSmall: We may have expanded beyond blockBound(srcSize). 4416*3117ece4Schristos * ZSTD_noCompressBlock() will return dstSize_tooSmall if we are really out of 4417*3117ece4Schristos * output space. 4418*3117ece4Schristos * * cSize >= blockBound(srcSize): We have expanded the block too much so 4419*3117ece4Schristos * emit an uncompressed block. 4420*3117ece4Schristos */ 4421*3117ece4Schristos { size_t const cSize = 4422*3117ece4Schristos ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock); 4423*3117ece4Schristos if (cSize != ERROR(dstSize_tooSmall)) { 4424*3117ece4Schristos size_t const maxCSize = 4425*3117ece4Schristos srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy); 4426*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed"); 4427*3117ece4Schristos if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) { 4428*3117ece4Schristos ZSTD_blockState_confirmRepcodesAndEntropyTables(&zc->blockState); 4429*3117ece4Schristos return cSize; 4430*3117ece4Schristos } 4431*3117ece4Schristos } 4432*3117ece4Schristos } 4433*3117ece4Schristos } /* if (bss == ZSTDbss_compress)*/ 4434*3117ece4Schristos 4435*3117ece4Schristos DEBUGLOG(6, "Resorting to ZSTD_noCompressBlock()"); 4436*3117ece4Schristos /* Superblock compression failed, attempt to emit a single no compress block. 4437*3117ece4Schristos * The decoder will be able to stream this block since it is uncompressed. 4438*3117ece4Schristos */ 4439*3117ece4Schristos return ZSTD_noCompressBlock(dst, dstCapacity, src, srcSize, lastBlock); 4440*3117ece4Schristos } 4441*3117ece4Schristos 4442*3117ece4Schristos static size_t ZSTD_compressBlock_targetCBlockSize(ZSTD_CCtx* zc, 4443*3117ece4Schristos void* dst, size_t dstCapacity, 4444*3117ece4Schristos const void* src, size_t srcSize, 4445*3117ece4Schristos U32 lastBlock) 4446*3117ece4Schristos { 4447*3117ece4Schristos size_t cSize = 0; 4448*3117ece4Schristos const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); 4449*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressBlock_targetCBlockSize (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u, srcSize=%zu)", 4450*3117ece4Schristos (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, (unsigned)zc->blockState.matchState.nextToUpdate, srcSize); 4451*3117ece4Schristos FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed"); 4452*3117ece4Schristos 4453*3117ece4Schristos cSize = ZSTD_compressBlock_targetCBlockSize_body(zc, dst, dstCapacity, src, srcSize, bss, lastBlock); 4454*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize_body failed"); 4455*3117ece4Schristos 4456*3117ece4Schristos if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) 4457*3117ece4Schristos zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; 4458*3117ece4Schristos 4459*3117ece4Schristos return cSize; 4460*3117ece4Schristos } 4461*3117ece4Schristos 4462*3117ece4Schristos static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, 4463*3117ece4Schristos ZSTD_cwksp* ws, 4464*3117ece4Schristos ZSTD_CCtx_params const* params, 4465*3117ece4Schristos void const* ip, 4466*3117ece4Schristos void const* iend) 4467*3117ece4Schristos { 4468*3117ece4Schristos U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); 4469*3117ece4Schristos U32 const maxDist = (U32)1 << params->cParams.windowLog; 4470*3117ece4Schristos if (ZSTD_window_needOverflowCorrection(ms->window, cycleLog, maxDist, ms->loadedDictEnd, ip, iend)) { 4471*3117ece4Schristos U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); 4472*3117ece4Schristos ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); 4473*3117ece4Schristos ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); 4474*3117ece4Schristos ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); 4475*3117ece4Schristos ZSTD_cwksp_mark_tables_dirty(ws); 4476*3117ece4Schristos ZSTD_reduceIndex(ms, params, correction); 4477*3117ece4Schristos ZSTD_cwksp_mark_tables_clean(ws); 4478*3117ece4Schristos if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; 4479*3117ece4Schristos else ms->nextToUpdate -= correction; 4480*3117ece4Schristos /* invalidate dictionaries on overflow correction */ 4481*3117ece4Schristos ms->loadedDictEnd = 0; 4482*3117ece4Schristos ms->dictMatchState = NULL; 4483*3117ece4Schristos } 4484*3117ece4Schristos } 4485*3117ece4Schristos 4486*3117ece4Schristos /*! ZSTD_compress_frameChunk() : 4487*3117ece4Schristos * Compress a chunk of data into one or multiple blocks. 4488*3117ece4Schristos * All blocks will be terminated, all input will be consumed. 4489*3117ece4Schristos * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content. 4490*3117ece4Schristos * Frame is supposed already started (header already produced) 4491*3117ece4Schristos * @return : compressed size, or an error code 4492*3117ece4Schristos */ 4493*3117ece4Schristos static size_t ZSTD_compress_frameChunk(ZSTD_CCtx* cctx, 4494*3117ece4Schristos void* dst, size_t dstCapacity, 4495*3117ece4Schristos const void* src, size_t srcSize, 4496*3117ece4Schristos U32 lastFrameChunk) 4497*3117ece4Schristos { 4498*3117ece4Schristos size_t blockSize = cctx->blockSize; 4499*3117ece4Schristos size_t remaining = srcSize; 4500*3117ece4Schristos const BYTE* ip = (const BYTE*)src; 4501*3117ece4Schristos BYTE* const ostart = (BYTE*)dst; 4502*3117ece4Schristos BYTE* op = ostart; 4503*3117ece4Schristos U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; 4504*3117ece4Schristos 4505*3117ece4Schristos assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX); 4506*3117ece4Schristos 4507*3117ece4Schristos DEBUGLOG(4, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); 4508*3117ece4Schristos if (cctx->appliedParams.fParams.checksumFlag && srcSize) 4509*3117ece4Schristos XXH64_update(&cctx->xxhState, src, srcSize); 4510*3117ece4Schristos 4511*3117ece4Schristos while (remaining) { 4512*3117ece4Schristos ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 4513*3117ece4Schristos U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); 4514*3117ece4Schristos 4515*3117ece4Schristos /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding 4516*3117ece4Schristos * additional 1. We need to revisit and change this logic to be more consistent */ 4517*3117ece4Schristos RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE + 1, 4518*3117ece4Schristos dstSize_tooSmall, 4519*3117ece4Schristos "not enough space to store compressed block"); 4520*3117ece4Schristos if (remaining < blockSize) blockSize = remaining; 4521*3117ece4Schristos 4522*3117ece4Schristos ZSTD_overflowCorrectIfNeeded( 4523*3117ece4Schristos ms, &cctx->workspace, &cctx->appliedParams, ip, ip + blockSize); 4524*3117ece4Schristos ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); 4525*3117ece4Schristos ZSTD_window_enforceMaxDist(&ms->window, ip, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); 4526*3117ece4Schristos 4527*3117ece4Schristos /* Ensure hash/chain table insertion resumes no sooner than lowlimit */ 4528*3117ece4Schristos if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; 4529*3117ece4Schristos 4530*3117ece4Schristos { size_t cSize; 4531*3117ece4Schristos if (ZSTD_useTargetCBlockSize(&cctx->appliedParams)) { 4532*3117ece4Schristos cSize = ZSTD_compressBlock_targetCBlockSize(cctx, op, dstCapacity, ip, blockSize, lastBlock); 4533*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed"); 4534*3117ece4Schristos assert(cSize > 0); 4535*3117ece4Schristos assert(cSize <= blockSize + ZSTD_blockHeaderSize); 4536*3117ece4Schristos } else if (ZSTD_blockSplitterEnabled(&cctx->appliedParams)) { 4537*3117ece4Schristos cSize = ZSTD_compressBlock_splitBlock(cctx, op, dstCapacity, ip, blockSize, lastBlock); 4538*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_splitBlock failed"); 4539*3117ece4Schristos assert(cSize > 0 || cctx->seqCollector.collectSequences == 1); 4540*3117ece4Schristos } else { 4541*3117ece4Schristos cSize = ZSTD_compressBlock_internal(cctx, 4542*3117ece4Schristos op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, 4543*3117ece4Schristos ip, blockSize, 1 /* frame */); 4544*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_internal failed"); 4545*3117ece4Schristos 4546*3117ece4Schristos if (cSize == 0) { /* block is not compressible */ 4547*3117ece4Schristos cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); 4548*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed"); 4549*3117ece4Schristos } else { 4550*3117ece4Schristos U32 const cBlockHeader = cSize == 1 ? 4551*3117ece4Schristos lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : 4552*3117ece4Schristos lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); 4553*3117ece4Schristos MEM_writeLE24(op, cBlockHeader); 4554*3117ece4Schristos cSize += ZSTD_blockHeaderSize; 4555*3117ece4Schristos } 4556*3117ece4Schristos } /* if (ZSTD_useTargetCBlockSize(&cctx->appliedParams))*/ 4557*3117ece4Schristos 4558*3117ece4Schristos 4559*3117ece4Schristos ip += blockSize; 4560*3117ece4Schristos assert(remaining >= blockSize); 4561*3117ece4Schristos remaining -= blockSize; 4562*3117ece4Schristos op += cSize; 4563*3117ece4Schristos assert(dstCapacity >= cSize); 4564*3117ece4Schristos dstCapacity -= cSize; 4565*3117ece4Schristos cctx->isFirstBlock = 0; 4566*3117ece4Schristos DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u", 4567*3117ece4Schristos (unsigned)cSize); 4568*3117ece4Schristos } } 4569*3117ece4Schristos 4570*3117ece4Schristos if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending; 4571*3117ece4Schristos return (size_t)(op-ostart); 4572*3117ece4Schristos } 4573*3117ece4Schristos 4574*3117ece4Schristos 4575*3117ece4Schristos static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, 4576*3117ece4Schristos const ZSTD_CCtx_params* params, U64 pledgedSrcSize, U32 dictID) 4577*3117ece4Schristos { BYTE* const op = (BYTE*)dst; 4578*3117ece4Schristos U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */ 4579*3117ece4Schristos U32 const dictIDSizeCode = params->fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */ 4580*3117ece4Schristos U32 const checksumFlag = params->fParams.checksumFlag>0; 4581*3117ece4Schristos U32 const windowSize = (U32)1 << params->cParams.windowLog; 4582*3117ece4Schristos U32 const singleSegment = params->fParams.contentSizeFlag && (windowSize >= pledgedSrcSize); 4583*3117ece4Schristos BYTE const windowLogByte = (BYTE)((params->cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3); 4584*3117ece4Schristos U32 const fcsCode = params->fParams.contentSizeFlag ? 4585*3117ece4Schristos (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */ 4586*3117ece4Schristos BYTE const frameHeaderDescriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) ); 4587*3117ece4Schristos size_t pos=0; 4588*3117ece4Schristos 4589*3117ece4Schristos assert(!(params->fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)); 4590*3117ece4Schristos RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall, 4591*3117ece4Schristos "dst buf is too small to fit worst-case frame header size."); 4592*3117ece4Schristos DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", 4593*3117ece4Schristos !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode); 4594*3117ece4Schristos if (params->format == ZSTD_f_zstd1) { 4595*3117ece4Schristos MEM_writeLE32(dst, ZSTD_MAGICNUMBER); 4596*3117ece4Schristos pos = 4; 4597*3117ece4Schristos } 4598*3117ece4Schristos op[pos++] = frameHeaderDescriptionByte; 4599*3117ece4Schristos if (!singleSegment) op[pos++] = windowLogByte; 4600*3117ece4Schristos switch(dictIDSizeCode) 4601*3117ece4Schristos { 4602*3117ece4Schristos default: 4603*3117ece4Schristos assert(0); /* impossible */ 4604*3117ece4Schristos ZSTD_FALLTHROUGH; 4605*3117ece4Schristos case 0 : break; 4606*3117ece4Schristos case 1 : op[pos] = (BYTE)(dictID); pos++; break; 4607*3117ece4Schristos case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; 4608*3117ece4Schristos case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break; 4609*3117ece4Schristos } 4610*3117ece4Schristos switch(fcsCode) 4611*3117ece4Schristos { 4612*3117ece4Schristos default: 4613*3117ece4Schristos assert(0); /* impossible */ 4614*3117ece4Schristos ZSTD_FALLTHROUGH; 4615*3117ece4Schristos case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; 4616*3117ece4Schristos case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; 4617*3117ece4Schristos case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; 4618*3117ece4Schristos case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break; 4619*3117ece4Schristos } 4620*3117ece4Schristos return pos; 4621*3117ece4Schristos } 4622*3117ece4Schristos 4623*3117ece4Schristos /* ZSTD_writeSkippableFrame_advanced() : 4624*3117ece4Schristos * Writes out a skippable frame with the specified magic number variant (16 are supported), 4625*3117ece4Schristos * from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15, and the desired source data. 4626*3117ece4Schristos * 4627*3117ece4Schristos * Returns the total number of bytes written, or a ZSTD error code. 4628*3117ece4Schristos */ 4629*3117ece4Schristos size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity, 4630*3117ece4Schristos const void* src, size_t srcSize, unsigned magicVariant) { 4631*3117ece4Schristos BYTE* op = (BYTE*)dst; 4632*3117ece4Schristos RETURN_ERROR_IF(dstCapacity < srcSize + ZSTD_SKIPPABLEHEADERSIZE /* Skippable frame overhead */, 4633*3117ece4Schristos dstSize_tooSmall, "Not enough room for skippable frame"); 4634*3117ece4Schristos RETURN_ERROR_IF(srcSize > (unsigned)0xFFFFFFFF, srcSize_wrong, "Src size too large for skippable frame"); 4635*3117ece4Schristos RETURN_ERROR_IF(magicVariant > 15, parameter_outOfBound, "Skippable frame magic number variant not supported"); 4636*3117ece4Schristos 4637*3117ece4Schristos MEM_writeLE32(op, (U32)(ZSTD_MAGIC_SKIPPABLE_START + magicVariant)); 4638*3117ece4Schristos MEM_writeLE32(op+4, (U32)srcSize); 4639*3117ece4Schristos ZSTD_memcpy(op+8, src, srcSize); 4640*3117ece4Schristos return srcSize + ZSTD_SKIPPABLEHEADERSIZE; 4641*3117ece4Schristos } 4642*3117ece4Schristos 4643*3117ece4Schristos /* ZSTD_writeLastEmptyBlock() : 4644*3117ece4Schristos * output an empty Block with end-of-frame mark to complete a frame 4645*3117ece4Schristos * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h)) 4646*3117ece4Schristos * or an error code if `dstCapacity` is too small (<ZSTD_blockHeaderSize) 4647*3117ece4Schristos */ 4648*3117ece4Schristos size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) 4649*3117ece4Schristos { 4650*3117ece4Schristos RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, 4651*3117ece4Schristos "dst buf is too small to write frame trailer empty block."); 4652*3117ece4Schristos { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */ 4653*3117ece4Schristos MEM_writeLE24(dst, cBlockHeader24); 4654*3117ece4Schristos return ZSTD_blockHeaderSize; 4655*3117ece4Schristos } 4656*3117ece4Schristos } 4657*3117ece4Schristos 4658*3117ece4Schristos void ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) 4659*3117ece4Schristos { 4660*3117ece4Schristos assert(cctx->stage == ZSTDcs_init); 4661*3117ece4Schristos assert(nbSeq == 0 || cctx->appliedParams.ldmParams.enableLdm != ZSTD_ps_enable); 4662*3117ece4Schristos cctx->externSeqStore.seq = seq; 4663*3117ece4Schristos cctx->externSeqStore.size = nbSeq; 4664*3117ece4Schristos cctx->externSeqStore.capacity = nbSeq; 4665*3117ece4Schristos cctx->externSeqStore.pos = 0; 4666*3117ece4Schristos cctx->externSeqStore.posInSequence = 0; 4667*3117ece4Schristos } 4668*3117ece4Schristos 4669*3117ece4Schristos 4670*3117ece4Schristos static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, 4671*3117ece4Schristos void* dst, size_t dstCapacity, 4672*3117ece4Schristos const void* src, size_t srcSize, 4673*3117ece4Schristos U32 frame, U32 lastFrameChunk) 4674*3117ece4Schristos { 4675*3117ece4Schristos ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 4676*3117ece4Schristos size_t fhSize = 0; 4677*3117ece4Schristos 4678*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u", 4679*3117ece4Schristos cctx->stage, (unsigned)srcSize); 4680*3117ece4Schristos RETURN_ERROR_IF(cctx->stage==ZSTDcs_created, stage_wrong, 4681*3117ece4Schristos "missing init (ZSTD_compressBegin)"); 4682*3117ece4Schristos 4683*3117ece4Schristos if (frame && (cctx->stage==ZSTDcs_init)) { 4684*3117ece4Schristos fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 4685*3117ece4Schristos cctx->pledgedSrcSizePlusOne-1, cctx->dictID); 4686*3117ece4Schristos FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed"); 4687*3117ece4Schristos assert(fhSize <= dstCapacity); 4688*3117ece4Schristos dstCapacity -= fhSize; 4689*3117ece4Schristos dst = (char*)dst + fhSize; 4690*3117ece4Schristos cctx->stage = ZSTDcs_ongoing; 4691*3117ece4Schristos } 4692*3117ece4Schristos 4693*3117ece4Schristos if (!srcSize) return fhSize; /* do not generate an empty block if no input */ 4694*3117ece4Schristos 4695*3117ece4Schristos if (!ZSTD_window_update(&ms->window, src, srcSize, ms->forceNonContiguous)) { 4696*3117ece4Schristos ms->forceNonContiguous = 0; 4697*3117ece4Schristos ms->nextToUpdate = ms->window.dictLimit; 4698*3117ece4Schristos } 4699*3117ece4Schristos if (cctx->appliedParams.ldmParams.enableLdm == ZSTD_ps_enable) { 4700*3117ece4Schristos ZSTD_window_update(&cctx->ldmState.window, src, srcSize, /* forceNonContiguous */ 0); 4701*3117ece4Schristos } 4702*3117ece4Schristos 4703*3117ece4Schristos if (!frame) { 4704*3117ece4Schristos /* overflow check and correction for block mode */ 4705*3117ece4Schristos ZSTD_overflowCorrectIfNeeded( 4706*3117ece4Schristos ms, &cctx->workspace, &cctx->appliedParams, 4707*3117ece4Schristos src, (BYTE const*)src + srcSize); 4708*3117ece4Schristos } 4709*3117ece4Schristos 4710*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (unsigned)cctx->blockSize); 4711*3117ece4Schristos { size_t const cSize = frame ? 4712*3117ece4Schristos ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : 4713*3117ece4Schristos ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize, 0 /* frame */); 4714*3117ece4Schristos FORWARD_IF_ERROR(cSize, "%s", frame ? "ZSTD_compress_frameChunk failed" : "ZSTD_compressBlock_internal failed"); 4715*3117ece4Schristos cctx->consumedSrcSize += srcSize; 4716*3117ece4Schristos cctx->producedCSize += (cSize + fhSize); 4717*3117ece4Schristos assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); 4718*3117ece4Schristos if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ 4719*3117ece4Schristos ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); 4720*3117ece4Schristos RETURN_ERROR_IF( 4721*3117ece4Schristos cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne, 4722*3117ece4Schristos srcSize_wrong, 4723*3117ece4Schristos "error : pledgedSrcSize = %u, while realSrcSize >= %u", 4724*3117ece4Schristos (unsigned)cctx->pledgedSrcSizePlusOne-1, 4725*3117ece4Schristos (unsigned)cctx->consumedSrcSize); 4726*3117ece4Schristos } 4727*3117ece4Schristos return cSize + fhSize; 4728*3117ece4Schristos } 4729*3117ece4Schristos } 4730*3117ece4Schristos 4731*3117ece4Schristos size_t ZSTD_compressContinue_public(ZSTD_CCtx* cctx, 4732*3117ece4Schristos void* dst, size_t dstCapacity, 4733*3117ece4Schristos const void* src, size_t srcSize) 4734*3117ece4Schristos { 4735*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize); 4736*3117ece4Schristos return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */); 4737*3117ece4Schristos } 4738*3117ece4Schristos 4739*3117ece4Schristos /* NOTE: Must just wrap ZSTD_compressContinue_public() */ 4740*3117ece4Schristos size_t ZSTD_compressContinue(ZSTD_CCtx* cctx, 4741*3117ece4Schristos void* dst, size_t dstCapacity, 4742*3117ece4Schristos const void* src, size_t srcSize) 4743*3117ece4Schristos { 4744*3117ece4Schristos return ZSTD_compressContinue_public(cctx, dst, dstCapacity, src, srcSize); 4745*3117ece4Schristos } 4746*3117ece4Schristos 4747*3117ece4Schristos static size_t ZSTD_getBlockSize_deprecated(const ZSTD_CCtx* cctx) 4748*3117ece4Schristos { 4749*3117ece4Schristos ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams; 4750*3117ece4Schristos assert(!ZSTD_checkCParams(cParams)); 4751*3117ece4Schristos return MIN(cctx->appliedParams.maxBlockSize, (size_t)1 << cParams.windowLog); 4752*3117ece4Schristos } 4753*3117ece4Schristos 4754*3117ece4Schristos /* NOTE: Must just wrap ZSTD_getBlockSize_deprecated() */ 4755*3117ece4Schristos size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) 4756*3117ece4Schristos { 4757*3117ece4Schristos return ZSTD_getBlockSize_deprecated(cctx); 4758*3117ece4Schristos } 4759*3117ece4Schristos 4760*3117ece4Schristos /* NOTE: Must just wrap ZSTD_compressBlock_deprecated() */ 4761*3117ece4Schristos size_t ZSTD_compressBlock_deprecated(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) 4762*3117ece4Schristos { 4763*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize); 4764*3117ece4Schristos { size_t const blockSizeMax = ZSTD_getBlockSize_deprecated(cctx); 4765*3117ece4Schristos RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong, "input is larger than a block"); } 4766*3117ece4Schristos 4767*3117ece4Schristos return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); 4768*3117ece4Schristos } 4769*3117ece4Schristos 4770*3117ece4Schristos /* NOTE: Must just wrap ZSTD_compressBlock_deprecated() */ 4771*3117ece4Schristos size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) 4772*3117ece4Schristos { 4773*3117ece4Schristos return ZSTD_compressBlock_deprecated(cctx, dst, dstCapacity, src, srcSize); 4774*3117ece4Schristos } 4775*3117ece4Schristos 4776*3117ece4Schristos /*! ZSTD_loadDictionaryContent() : 4777*3117ece4Schristos * @return : 0, or an error code 4778*3117ece4Schristos */ 4779*3117ece4Schristos static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, 4780*3117ece4Schristos ldmState_t* ls, 4781*3117ece4Schristos ZSTD_cwksp* ws, 4782*3117ece4Schristos ZSTD_CCtx_params const* params, 4783*3117ece4Schristos const void* src, size_t srcSize, 4784*3117ece4Schristos ZSTD_dictTableLoadMethod_e dtlm, 4785*3117ece4Schristos ZSTD_tableFillPurpose_e tfp) 4786*3117ece4Schristos { 4787*3117ece4Schristos const BYTE* ip = (const BYTE*) src; 4788*3117ece4Schristos const BYTE* const iend = ip + srcSize; 4789*3117ece4Schristos int const loadLdmDict = params->ldmParams.enableLdm == ZSTD_ps_enable && ls != NULL; 4790*3117ece4Schristos 4791*3117ece4Schristos /* Assert that the ms params match the params we're being given */ 4792*3117ece4Schristos ZSTD_assertEqualCParams(params->cParams, ms->cParams); 4793*3117ece4Schristos 4794*3117ece4Schristos { /* Ensure large dictionaries can't cause index overflow */ 4795*3117ece4Schristos 4796*3117ece4Schristos /* Allow the dictionary to set indices up to exactly ZSTD_CURRENT_MAX. 4797*3117ece4Schristos * Dictionaries right at the edge will immediately trigger overflow 4798*3117ece4Schristos * correction, but I don't want to insert extra constraints here. 4799*3117ece4Schristos */ 4800*3117ece4Schristos U32 maxDictSize = ZSTD_CURRENT_MAX - ZSTD_WINDOW_START_INDEX; 4801*3117ece4Schristos 4802*3117ece4Schristos int const CDictTaggedIndices = ZSTD_CDictIndicesAreTagged(¶ms->cParams); 4803*3117ece4Schristos if (CDictTaggedIndices && tfp == ZSTD_tfp_forCDict) { 4804*3117ece4Schristos /* Some dictionary matchfinders in zstd use "short cache", 4805*3117ece4Schristos * which treats the lower ZSTD_SHORT_CACHE_TAG_BITS of each 4806*3117ece4Schristos * CDict hashtable entry as a tag rather than as part of an index. 4807*3117ece4Schristos * When short cache is used, we need to truncate the dictionary 4808*3117ece4Schristos * so that its indices don't overlap with the tag. */ 4809*3117ece4Schristos U32 const shortCacheMaxDictSize = (1u << (32 - ZSTD_SHORT_CACHE_TAG_BITS)) - ZSTD_WINDOW_START_INDEX; 4810*3117ece4Schristos maxDictSize = MIN(maxDictSize, shortCacheMaxDictSize); 4811*3117ece4Schristos assert(!loadLdmDict); 4812*3117ece4Schristos } 4813*3117ece4Schristos 4814*3117ece4Schristos /* If the dictionary is too large, only load the suffix of the dictionary. */ 4815*3117ece4Schristos if (srcSize > maxDictSize) { 4816*3117ece4Schristos ip = iend - maxDictSize; 4817*3117ece4Schristos src = ip; 4818*3117ece4Schristos srcSize = maxDictSize; 4819*3117ece4Schristos } 4820*3117ece4Schristos } 4821*3117ece4Schristos 4822*3117ece4Schristos if (srcSize > ZSTD_CHUNKSIZE_MAX) { 4823*3117ece4Schristos /* We must have cleared our windows when our source is this large. */ 4824*3117ece4Schristos assert(ZSTD_window_isEmpty(ms->window)); 4825*3117ece4Schristos if (loadLdmDict) assert(ZSTD_window_isEmpty(ls->window)); 4826*3117ece4Schristos } 4827*3117ece4Schristos ZSTD_window_update(&ms->window, src, srcSize, /* forceNonContiguous */ 0); 4828*3117ece4Schristos 4829*3117ece4Schristos DEBUGLOG(4, "ZSTD_loadDictionaryContent(): useRowMatchFinder=%d", (int)params->useRowMatchFinder); 4830*3117ece4Schristos 4831*3117ece4Schristos if (loadLdmDict) { /* Load the entire dict into LDM matchfinders. */ 4832*3117ece4Schristos ZSTD_window_update(&ls->window, src, srcSize, /* forceNonContiguous */ 0); 4833*3117ece4Schristos ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base); 4834*3117ece4Schristos ZSTD_ldm_fillHashTable(ls, ip, iend, ¶ms->ldmParams); 4835*3117ece4Schristos } 4836*3117ece4Schristos 4837*3117ece4Schristos /* If the dict is larger than we can reasonably index in our tables, only load the suffix. */ 4838*3117ece4Schristos if (params->cParams.strategy < ZSTD_btultra) { 4839*3117ece4Schristos U32 maxDictSize = 8U << MIN(MAX(params->cParams.hashLog, params->cParams.chainLog), 28); 4840*3117ece4Schristos if (srcSize > maxDictSize) { 4841*3117ece4Schristos ip = iend - maxDictSize; 4842*3117ece4Schristos src = ip; 4843*3117ece4Schristos srcSize = maxDictSize; 4844*3117ece4Schristos } 4845*3117ece4Schristos } 4846*3117ece4Schristos 4847*3117ece4Schristos ms->nextToUpdate = (U32)(ip - ms->window.base); 4848*3117ece4Schristos ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); 4849*3117ece4Schristos ms->forceNonContiguous = params->deterministicRefPrefix; 4850*3117ece4Schristos 4851*3117ece4Schristos if (srcSize <= HASH_READ_SIZE) return 0; 4852*3117ece4Schristos 4853*3117ece4Schristos ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, iend); 4854*3117ece4Schristos 4855*3117ece4Schristos switch(params->cParams.strategy) 4856*3117ece4Schristos { 4857*3117ece4Schristos case ZSTD_fast: 4858*3117ece4Schristos ZSTD_fillHashTable(ms, iend, dtlm, tfp); 4859*3117ece4Schristos break; 4860*3117ece4Schristos case ZSTD_dfast: 4861*3117ece4Schristos #ifndef ZSTD_EXCLUDE_DFAST_BLOCK_COMPRESSOR 4862*3117ece4Schristos ZSTD_fillDoubleHashTable(ms, iend, dtlm, tfp); 4863*3117ece4Schristos #else 4864*3117ece4Schristos assert(0); /* shouldn't be called: cparams should've been adjusted. */ 4865*3117ece4Schristos #endif 4866*3117ece4Schristos break; 4867*3117ece4Schristos 4868*3117ece4Schristos case ZSTD_greedy: 4869*3117ece4Schristos case ZSTD_lazy: 4870*3117ece4Schristos case ZSTD_lazy2: 4871*3117ece4Schristos #if !defined(ZSTD_EXCLUDE_GREEDY_BLOCK_COMPRESSOR) \ 4872*3117ece4Schristos || !defined(ZSTD_EXCLUDE_LAZY_BLOCK_COMPRESSOR) \ 4873*3117ece4Schristos || !defined(ZSTD_EXCLUDE_LAZY2_BLOCK_COMPRESSOR) 4874*3117ece4Schristos assert(srcSize >= HASH_READ_SIZE); 4875*3117ece4Schristos if (ms->dedicatedDictSearch) { 4876*3117ece4Schristos assert(ms->chainTable != NULL); 4877*3117ece4Schristos ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, iend-HASH_READ_SIZE); 4878*3117ece4Schristos } else { 4879*3117ece4Schristos assert(params->useRowMatchFinder != ZSTD_ps_auto); 4880*3117ece4Schristos if (params->useRowMatchFinder == ZSTD_ps_enable) { 4881*3117ece4Schristos size_t const tagTableSize = ((size_t)1 << params->cParams.hashLog); 4882*3117ece4Schristos ZSTD_memset(ms->tagTable, 0, tagTableSize); 4883*3117ece4Schristos ZSTD_row_update(ms, iend-HASH_READ_SIZE); 4884*3117ece4Schristos DEBUGLOG(4, "Using row-based hash table for lazy dict"); 4885*3117ece4Schristos } else { 4886*3117ece4Schristos ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE); 4887*3117ece4Schristos DEBUGLOG(4, "Using chain-based hash table for lazy dict"); 4888*3117ece4Schristos } 4889*3117ece4Schristos } 4890*3117ece4Schristos #else 4891*3117ece4Schristos assert(0); /* shouldn't be called: cparams should've been adjusted. */ 4892*3117ece4Schristos #endif 4893*3117ece4Schristos break; 4894*3117ece4Schristos 4895*3117ece4Schristos case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ 4896*3117ece4Schristos case ZSTD_btopt: 4897*3117ece4Schristos case ZSTD_btultra: 4898*3117ece4Schristos case ZSTD_btultra2: 4899*3117ece4Schristos #if !defined(ZSTD_EXCLUDE_BTLAZY2_BLOCK_COMPRESSOR) \ 4900*3117ece4Schristos || !defined(ZSTD_EXCLUDE_BTOPT_BLOCK_COMPRESSOR) \ 4901*3117ece4Schristos || !defined(ZSTD_EXCLUDE_BTULTRA_BLOCK_COMPRESSOR) 4902*3117ece4Schristos assert(srcSize >= HASH_READ_SIZE); 4903*3117ece4Schristos ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend); 4904*3117ece4Schristos #else 4905*3117ece4Schristos assert(0); /* shouldn't be called: cparams should've been adjusted. */ 4906*3117ece4Schristos #endif 4907*3117ece4Schristos break; 4908*3117ece4Schristos 4909*3117ece4Schristos default: 4910*3117ece4Schristos assert(0); /* not possible : not a valid strategy id */ 4911*3117ece4Schristos } 4912*3117ece4Schristos 4913*3117ece4Schristos ms->nextToUpdate = (U32)(iend - ms->window.base); 4914*3117ece4Schristos return 0; 4915*3117ece4Schristos } 4916*3117ece4Schristos 4917*3117ece4Schristos 4918*3117ece4Schristos /* Dictionaries that assign zero probability to symbols that show up causes problems 4919*3117ece4Schristos * when FSE encoding. Mark dictionaries with zero probability symbols as FSE_repeat_check 4920*3117ece4Schristos * and only dictionaries with 100% valid symbols can be assumed valid. 4921*3117ece4Schristos */ 4922*3117ece4Schristos static FSE_repeat ZSTD_dictNCountRepeat(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) 4923*3117ece4Schristos { 4924*3117ece4Schristos U32 s; 4925*3117ece4Schristos if (dictMaxSymbolValue < maxSymbolValue) { 4926*3117ece4Schristos return FSE_repeat_check; 4927*3117ece4Schristos } 4928*3117ece4Schristos for (s = 0; s <= maxSymbolValue; ++s) { 4929*3117ece4Schristos if (normalizedCounter[s] == 0) { 4930*3117ece4Schristos return FSE_repeat_check; 4931*3117ece4Schristos } 4932*3117ece4Schristos } 4933*3117ece4Schristos return FSE_repeat_valid; 4934*3117ece4Schristos } 4935*3117ece4Schristos 4936*3117ece4Schristos size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace, 4937*3117ece4Schristos const void* const dict, size_t dictSize) 4938*3117ece4Schristos { 4939*3117ece4Schristos short offcodeNCount[MaxOff+1]; 4940*3117ece4Schristos unsigned offcodeMaxValue = MaxOff; 4941*3117ece4Schristos const BYTE* dictPtr = (const BYTE*)dict; /* skip magic num and dict ID */ 4942*3117ece4Schristos const BYTE* const dictEnd = dictPtr + dictSize; 4943*3117ece4Schristos dictPtr += 8; 4944*3117ece4Schristos bs->entropy.huf.repeatMode = HUF_repeat_check; 4945*3117ece4Schristos 4946*3117ece4Schristos { unsigned maxSymbolValue = 255; 4947*3117ece4Schristos unsigned hasZeroWeights = 1; 4948*3117ece4Schristos size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, 4949*3117ece4Schristos dictEnd-dictPtr, &hasZeroWeights); 4950*3117ece4Schristos 4951*3117ece4Schristos /* We only set the loaded table as valid if it contains all non-zero 4952*3117ece4Schristos * weights. Otherwise, we set it to check */ 4953*3117ece4Schristos if (!hasZeroWeights && maxSymbolValue == 255) 4954*3117ece4Schristos bs->entropy.huf.repeatMode = HUF_repeat_valid; 4955*3117ece4Schristos 4956*3117ece4Schristos RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted, ""); 4957*3117ece4Schristos dictPtr += hufHeaderSize; 4958*3117ece4Schristos } 4959*3117ece4Schristos 4960*3117ece4Schristos { unsigned offcodeLog; 4961*3117ece4Schristos size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); 4962*3117ece4Schristos RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, ""); 4963*3117ece4Schristos RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, ""); 4964*3117ece4Schristos /* fill all offset symbols to avoid garbage at end of table */ 4965*3117ece4Schristos RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 4966*3117ece4Schristos bs->entropy.fse.offcodeCTable, 4967*3117ece4Schristos offcodeNCount, MaxOff, offcodeLog, 4968*3117ece4Schristos workspace, HUF_WORKSPACE_SIZE)), 4969*3117ece4Schristos dictionary_corrupted, ""); 4970*3117ece4Schristos /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ 4971*3117ece4Schristos dictPtr += offcodeHeaderSize; 4972*3117ece4Schristos } 4973*3117ece4Schristos 4974*3117ece4Schristos { short matchlengthNCount[MaxML+1]; 4975*3117ece4Schristos unsigned matchlengthMaxValue = MaxML, matchlengthLog; 4976*3117ece4Schristos size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); 4977*3117ece4Schristos RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, ""); 4978*3117ece4Schristos RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, ""); 4979*3117ece4Schristos RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 4980*3117ece4Schristos bs->entropy.fse.matchlengthCTable, 4981*3117ece4Schristos matchlengthNCount, matchlengthMaxValue, matchlengthLog, 4982*3117ece4Schristos workspace, HUF_WORKSPACE_SIZE)), 4983*3117ece4Schristos dictionary_corrupted, ""); 4984*3117ece4Schristos bs->entropy.fse.matchlength_repeatMode = ZSTD_dictNCountRepeat(matchlengthNCount, matchlengthMaxValue, MaxML); 4985*3117ece4Schristos dictPtr += matchlengthHeaderSize; 4986*3117ece4Schristos } 4987*3117ece4Schristos 4988*3117ece4Schristos { short litlengthNCount[MaxLL+1]; 4989*3117ece4Schristos unsigned litlengthMaxValue = MaxLL, litlengthLog; 4990*3117ece4Schristos size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); 4991*3117ece4Schristos RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, ""); 4992*3117ece4Schristos RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, ""); 4993*3117ece4Schristos RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 4994*3117ece4Schristos bs->entropy.fse.litlengthCTable, 4995*3117ece4Schristos litlengthNCount, litlengthMaxValue, litlengthLog, 4996*3117ece4Schristos workspace, HUF_WORKSPACE_SIZE)), 4997*3117ece4Schristos dictionary_corrupted, ""); 4998*3117ece4Schristos bs->entropy.fse.litlength_repeatMode = ZSTD_dictNCountRepeat(litlengthNCount, litlengthMaxValue, MaxLL); 4999*3117ece4Schristos dictPtr += litlengthHeaderSize; 5000*3117ece4Schristos } 5001*3117ece4Schristos 5002*3117ece4Schristos RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, ""); 5003*3117ece4Schristos bs->rep[0] = MEM_readLE32(dictPtr+0); 5004*3117ece4Schristos bs->rep[1] = MEM_readLE32(dictPtr+4); 5005*3117ece4Schristos bs->rep[2] = MEM_readLE32(dictPtr+8); 5006*3117ece4Schristos dictPtr += 12; 5007*3117ece4Schristos 5008*3117ece4Schristos { size_t const dictContentSize = (size_t)(dictEnd - dictPtr); 5009*3117ece4Schristos U32 offcodeMax = MaxOff; 5010*3117ece4Schristos if (dictContentSize <= ((U32)-1) - 128 KB) { 5011*3117ece4Schristos U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ 5012*3117ece4Schristos offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ 5013*3117ece4Schristos } 5014*3117ece4Schristos /* All offset values <= dictContentSize + 128 KB must be representable for a valid table */ 5015*3117ece4Schristos bs->entropy.fse.offcode_repeatMode = ZSTD_dictNCountRepeat(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)); 5016*3117ece4Schristos 5017*3117ece4Schristos /* All repCodes must be <= dictContentSize and != 0 */ 5018*3117ece4Schristos { U32 u; 5019*3117ece4Schristos for (u=0; u<3; u++) { 5020*3117ece4Schristos RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, ""); 5021*3117ece4Schristos RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, ""); 5022*3117ece4Schristos } } } 5023*3117ece4Schristos 5024*3117ece4Schristos return dictPtr - (const BYTE*)dict; 5025*3117ece4Schristos } 5026*3117ece4Schristos 5027*3117ece4Schristos /* Dictionary format : 5028*3117ece4Schristos * See : 5029*3117ece4Schristos * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#dictionary-format 5030*3117ece4Schristos */ 5031*3117ece4Schristos /*! ZSTD_loadZstdDictionary() : 5032*3117ece4Schristos * @return : dictID, or an error code 5033*3117ece4Schristos * assumptions : magic number supposed already checked 5034*3117ece4Schristos * dictSize supposed >= 8 5035*3117ece4Schristos */ 5036*3117ece4Schristos static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, 5037*3117ece4Schristos ZSTD_matchState_t* ms, 5038*3117ece4Schristos ZSTD_cwksp* ws, 5039*3117ece4Schristos ZSTD_CCtx_params const* params, 5040*3117ece4Schristos const void* dict, size_t dictSize, 5041*3117ece4Schristos ZSTD_dictTableLoadMethod_e dtlm, 5042*3117ece4Schristos ZSTD_tableFillPurpose_e tfp, 5043*3117ece4Schristos void* workspace) 5044*3117ece4Schristos { 5045*3117ece4Schristos const BYTE* dictPtr = (const BYTE*)dict; 5046*3117ece4Schristos const BYTE* const dictEnd = dictPtr + dictSize; 5047*3117ece4Schristos size_t dictID; 5048*3117ece4Schristos size_t eSize; 5049*3117ece4Schristos ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 5050*3117ece4Schristos assert(dictSize >= 8); 5051*3117ece4Schristos assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); 5052*3117ece4Schristos 5053*3117ece4Schristos dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr + 4 /* skip magic number */ ); 5054*3117ece4Schristos eSize = ZSTD_loadCEntropy(bs, workspace, dict, dictSize); 5055*3117ece4Schristos FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed"); 5056*3117ece4Schristos dictPtr += eSize; 5057*3117ece4Schristos 5058*3117ece4Schristos { 5059*3117ece4Schristos size_t const dictContentSize = (size_t)(dictEnd - dictPtr); 5060*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_loadDictionaryContent( 5061*3117ece4Schristos ms, NULL, ws, params, dictPtr, dictContentSize, dtlm, tfp), ""); 5062*3117ece4Schristos } 5063*3117ece4Schristos return dictID; 5064*3117ece4Schristos } 5065*3117ece4Schristos 5066*3117ece4Schristos /** ZSTD_compress_insertDictionary() : 5067*3117ece4Schristos * @return : dictID, or an error code */ 5068*3117ece4Schristos static size_t 5069*3117ece4Schristos ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, 5070*3117ece4Schristos ZSTD_matchState_t* ms, 5071*3117ece4Schristos ldmState_t* ls, 5072*3117ece4Schristos ZSTD_cwksp* ws, 5073*3117ece4Schristos const ZSTD_CCtx_params* params, 5074*3117ece4Schristos const void* dict, size_t dictSize, 5075*3117ece4Schristos ZSTD_dictContentType_e dictContentType, 5076*3117ece4Schristos ZSTD_dictTableLoadMethod_e dtlm, 5077*3117ece4Schristos ZSTD_tableFillPurpose_e tfp, 5078*3117ece4Schristos void* workspace) 5079*3117ece4Schristos { 5080*3117ece4Schristos DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); 5081*3117ece4Schristos if ((dict==NULL) || (dictSize<8)) { 5082*3117ece4Schristos RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, ""); 5083*3117ece4Schristos return 0; 5084*3117ece4Schristos } 5085*3117ece4Schristos 5086*3117ece4Schristos ZSTD_reset_compressedBlockState(bs); 5087*3117ece4Schristos 5088*3117ece4Schristos /* dict restricted modes */ 5089*3117ece4Schristos if (dictContentType == ZSTD_dct_rawContent) 5090*3117ece4Schristos return ZSTD_loadDictionaryContent(ms, ls, ws, params, dict, dictSize, dtlm, tfp); 5091*3117ece4Schristos 5092*3117ece4Schristos if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { 5093*3117ece4Schristos if (dictContentType == ZSTD_dct_auto) { 5094*3117ece4Schristos DEBUGLOG(4, "raw content dictionary detected"); 5095*3117ece4Schristos return ZSTD_loadDictionaryContent( 5096*3117ece4Schristos ms, ls, ws, params, dict, dictSize, dtlm, tfp); 5097*3117ece4Schristos } 5098*3117ece4Schristos RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, ""); 5099*3117ece4Schristos assert(0); /* impossible */ 5100*3117ece4Schristos } 5101*3117ece4Schristos 5102*3117ece4Schristos /* dict as full zstd dictionary */ 5103*3117ece4Schristos return ZSTD_loadZstdDictionary( 5104*3117ece4Schristos bs, ms, ws, params, dict, dictSize, dtlm, tfp, workspace); 5105*3117ece4Schristos } 5106*3117ece4Schristos 5107*3117ece4Schristos #define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB) 5108*3117ece4Schristos #define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6ULL) 5109*3117ece4Schristos 5110*3117ece4Schristos /*! ZSTD_compressBegin_internal() : 5111*3117ece4Schristos * Assumption : either @dict OR @cdict (or none) is non-NULL, never both 5112*3117ece4Schristos * @return : 0, or an error code */ 5113*3117ece4Schristos static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, 5114*3117ece4Schristos const void* dict, size_t dictSize, 5115*3117ece4Schristos ZSTD_dictContentType_e dictContentType, 5116*3117ece4Schristos ZSTD_dictTableLoadMethod_e dtlm, 5117*3117ece4Schristos const ZSTD_CDict* cdict, 5118*3117ece4Schristos const ZSTD_CCtx_params* params, U64 pledgedSrcSize, 5119*3117ece4Schristos ZSTD_buffered_policy_e zbuff) 5120*3117ece4Schristos { 5121*3117ece4Schristos size_t const dictContentSize = cdict ? cdict->dictContentSize : dictSize; 5122*3117ece4Schristos #if ZSTD_TRACE 5123*3117ece4Schristos cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0; 5124*3117ece4Schristos #endif 5125*3117ece4Schristos DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog); 5126*3117ece4Schristos /* params are supposed to be fully validated at this point */ 5127*3117ece4Schristos assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); 5128*3117ece4Schristos assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 5129*3117ece4Schristos if ( (cdict) 5130*3117ece4Schristos && (cdict->dictContentSize > 0) 5131*3117ece4Schristos && ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF 5132*3117ece4Schristos || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER 5133*3117ece4Schristos || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN 5134*3117ece4Schristos || cdict->compressionLevel == 0) 5135*3117ece4Schristos && (params->attachDictPref != ZSTD_dictForceLoad) ) { 5136*3117ece4Schristos return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff); 5137*3117ece4Schristos } 5138*3117ece4Schristos 5139*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 5140*3117ece4Schristos dictContentSize, 5141*3117ece4Schristos ZSTDcrp_makeClean, zbuff) , ""); 5142*3117ece4Schristos { size_t const dictID = cdict ? 5143*3117ece4Schristos ZSTD_compress_insertDictionary( 5144*3117ece4Schristos cctx->blockState.prevCBlock, &cctx->blockState.matchState, 5145*3117ece4Schristos &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent, 5146*3117ece4Schristos cdict->dictContentSize, cdict->dictContentType, dtlm, 5147*3117ece4Schristos ZSTD_tfp_forCCtx, cctx->entropyWorkspace) 5148*3117ece4Schristos : ZSTD_compress_insertDictionary( 5149*3117ece4Schristos cctx->blockState.prevCBlock, &cctx->blockState.matchState, 5150*3117ece4Schristos &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, dict, dictSize, 5151*3117ece4Schristos dictContentType, dtlm, ZSTD_tfp_forCCtx, cctx->entropyWorkspace); 5152*3117ece4Schristos FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed"); 5153*3117ece4Schristos assert(dictID <= UINT_MAX); 5154*3117ece4Schristos cctx->dictID = (U32)dictID; 5155*3117ece4Schristos cctx->dictContentSize = dictContentSize; 5156*3117ece4Schristos } 5157*3117ece4Schristos return 0; 5158*3117ece4Schristos } 5159*3117ece4Schristos 5160*3117ece4Schristos size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, 5161*3117ece4Schristos const void* dict, size_t dictSize, 5162*3117ece4Schristos ZSTD_dictContentType_e dictContentType, 5163*3117ece4Schristos ZSTD_dictTableLoadMethod_e dtlm, 5164*3117ece4Schristos const ZSTD_CDict* cdict, 5165*3117ece4Schristos const ZSTD_CCtx_params* params, 5166*3117ece4Schristos unsigned long long pledgedSrcSize) 5167*3117ece4Schristos { 5168*3117ece4Schristos DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params->cParams.windowLog); 5169*3117ece4Schristos /* compression parameters verification and optimization */ 5170*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_checkCParams(params->cParams) , ""); 5171*3117ece4Schristos return ZSTD_compressBegin_internal(cctx, 5172*3117ece4Schristos dict, dictSize, dictContentType, dtlm, 5173*3117ece4Schristos cdict, 5174*3117ece4Schristos params, pledgedSrcSize, 5175*3117ece4Schristos ZSTDb_not_buffered); 5176*3117ece4Schristos } 5177*3117ece4Schristos 5178*3117ece4Schristos /*! ZSTD_compressBegin_advanced() : 5179*3117ece4Schristos * @return : 0, or an error code */ 5180*3117ece4Schristos size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, 5181*3117ece4Schristos const void* dict, size_t dictSize, 5182*3117ece4Schristos ZSTD_parameters params, unsigned long long pledgedSrcSize) 5183*3117ece4Schristos { 5184*3117ece4Schristos ZSTD_CCtx_params cctxParams; 5185*3117ece4Schristos ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, ZSTD_NO_CLEVEL); 5186*3117ece4Schristos return ZSTD_compressBegin_advanced_internal(cctx, 5187*3117ece4Schristos dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, 5188*3117ece4Schristos NULL /*cdict*/, 5189*3117ece4Schristos &cctxParams, pledgedSrcSize); 5190*3117ece4Schristos } 5191*3117ece4Schristos 5192*3117ece4Schristos static size_t 5193*3117ece4Schristos ZSTD_compressBegin_usingDict_deprecated(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) 5194*3117ece4Schristos { 5195*3117ece4Schristos ZSTD_CCtx_params cctxParams; 5196*3117ece4Schristos { ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict); 5197*3117ece4Schristos ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel); 5198*3117ece4Schristos } 5199*3117ece4Schristos DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize); 5200*3117ece4Schristos return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, 5201*3117ece4Schristos &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); 5202*3117ece4Schristos } 5203*3117ece4Schristos 5204*3117ece4Schristos size_t 5205*3117ece4Schristos ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) 5206*3117ece4Schristos { 5207*3117ece4Schristos return ZSTD_compressBegin_usingDict_deprecated(cctx, dict, dictSize, compressionLevel); 5208*3117ece4Schristos } 5209*3117ece4Schristos 5210*3117ece4Schristos size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) 5211*3117ece4Schristos { 5212*3117ece4Schristos return ZSTD_compressBegin_usingDict_deprecated(cctx, NULL, 0, compressionLevel); 5213*3117ece4Schristos } 5214*3117ece4Schristos 5215*3117ece4Schristos 5216*3117ece4Schristos /*! ZSTD_writeEpilogue() : 5217*3117ece4Schristos * Ends a frame. 5218*3117ece4Schristos * @return : nb of bytes written into dst (or an error code) */ 5219*3117ece4Schristos static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) 5220*3117ece4Schristos { 5221*3117ece4Schristos BYTE* const ostart = (BYTE*)dst; 5222*3117ece4Schristos BYTE* op = ostart; 5223*3117ece4Schristos 5224*3117ece4Schristos DEBUGLOG(4, "ZSTD_writeEpilogue"); 5225*3117ece4Schristos RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing"); 5226*3117ece4Schristos 5227*3117ece4Schristos /* special case : empty frame */ 5228*3117ece4Schristos if (cctx->stage == ZSTDcs_init) { 5229*3117ece4Schristos size_t fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0); 5230*3117ece4Schristos FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed"); 5231*3117ece4Schristos dstCapacity -= fhSize; 5232*3117ece4Schristos op += fhSize; 5233*3117ece4Schristos cctx->stage = ZSTDcs_ongoing; 5234*3117ece4Schristos } 5235*3117ece4Schristos 5236*3117ece4Schristos if (cctx->stage != ZSTDcs_ending) { 5237*3117ece4Schristos /* write one last empty block, make it the "last" block */ 5238*3117ece4Schristos U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0; 5239*3117ece4Schristos ZSTD_STATIC_ASSERT(ZSTD_BLOCKHEADERSIZE == 3); 5240*3117ece4Schristos RETURN_ERROR_IF(dstCapacity<3, dstSize_tooSmall, "no room for epilogue"); 5241*3117ece4Schristos MEM_writeLE24(op, cBlockHeader24); 5242*3117ece4Schristos op += ZSTD_blockHeaderSize; 5243*3117ece4Schristos dstCapacity -= ZSTD_blockHeaderSize; 5244*3117ece4Schristos } 5245*3117ece4Schristos 5246*3117ece4Schristos if (cctx->appliedParams.fParams.checksumFlag) { 5247*3117ece4Schristos U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); 5248*3117ece4Schristos RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum"); 5249*3117ece4Schristos DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum); 5250*3117ece4Schristos MEM_writeLE32(op, checksum); 5251*3117ece4Schristos op += 4; 5252*3117ece4Schristos } 5253*3117ece4Schristos 5254*3117ece4Schristos cctx->stage = ZSTDcs_created; /* return to "created but no init" status */ 5255*3117ece4Schristos return op-ostart; 5256*3117ece4Schristos } 5257*3117ece4Schristos 5258*3117ece4Schristos void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize) 5259*3117ece4Schristos { 5260*3117ece4Schristos #if ZSTD_TRACE 5261*3117ece4Schristos if (cctx->traceCtx && ZSTD_trace_compress_end != NULL) { 5262*3117ece4Schristos int const streaming = cctx->inBuffSize > 0 || cctx->outBuffSize > 0 || cctx->appliedParams.nbWorkers > 0; 5263*3117ece4Schristos ZSTD_Trace trace; 5264*3117ece4Schristos ZSTD_memset(&trace, 0, sizeof(trace)); 5265*3117ece4Schristos trace.version = ZSTD_VERSION_NUMBER; 5266*3117ece4Schristos trace.streaming = streaming; 5267*3117ece4Schristos trace.dictionaryID = cctx->dictID; 5268*3117ece4Schristos trace.dictionarySize = cctx->dictContentSize; 5269*3117ece4Schristos trace.uncompressedSize = cctx->consumedSrcSize; 5270*3117ece4Schristos trace.compressedSize = cctx->producedCSize + extraCSize; 5271*3117ece4Schristos trace.params = &cctx->appliedParams; 5272*3117ece4Schristos trace.cctx = cctx; 5273*3117ece4Schristos ZSTD_trace_compress_end(cctx->traceCtx, &trace); 5274*3117ece4Schristos } 5275*3117ece4Schristos cctx->traceCtx = 0; 5276*3117ece4Schristos #else 5277*3117ece4Schristos (void)cctx; 5278*3117ece4Schristos (void)extraCSize; 5279*3117ece4Schristos #endif 5280*3117ece4Schristos } 5281*3117ece4Schristos 5282*3117ece4Schristos size_t ZSTD_compressEnd_public(ZSTD_CCtx* cctx, 5283*3117ece4Schristos void* dst, size_t dstCapacity, 5284*3117ece4Schristos const void* src, size_t srcSize) 5285*3117ece4Schristos { 5286*3117ece4Schristos size_t endResult; 5287*3117ece4Schristos size_t const cSize = ZSTD_compressContinue_internal(cctx, 5288*3117ece4Schristos dst, dstCapacity, src, srcSize, 5289*3117ece4Schristos 1 /* frame mode */, 1 /* last chunk */); 5290*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_compressContinue_internal failed"); 5291*3117ece4Schristos endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); 5292*3117ece4Schristos FORWARD_IF_ERROR(endResult, "ZSTD_writeEpilogue failed"); 5293*3117ece4Schristos assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); 5294*3117ece4Schristos if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ 5295*3117ece4Schristos ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); 5296*3117ece4Schristos DEBUGLOG(4, "end of frame : controlling src size"); 5297*3117ece4Schristos RETURN_ERROR_IF( 5298*3117ece4Schristos cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1, 5299*3117ece4Schristos srcSize_wrong, 5300*3117ece4Schristos "error : pledgedSrcSize = %u, while realSrcSize = %u", 5301*3117ece4Schristos (unsigned)cctx->pledgedSrcSizePlusOne-1, 5302*3117ece4Schristos (unsigned)cctx->consumedSrcSize); 5303*3117ece4Schristos } 5304*3117ece4Schristos ZSTD_CCtx_trace(cctx, endResult); 5305*3117ece4Schristos return cSize + endResult; 5306*3117ece4Schristos } 5307*3117ece4Schristos 5308*3117ece4Schristos /* NOTE: Must just wrap ZSTD_compressEnd_public() */ 5309*3117ece4Schristos size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, 5310*3117ece4Schristos void* dst, size_t dstCapacity, 5311*3117ece4Schristos const void* src, size_t srcSize) 5312*3117ece4Schristos { 5313*3117ece4Schristos return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); 5314*3117ece4Schristos } 5315*3117ece4Schristos 5316*3117ece4Schristos size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, 5317*3117ece4Schristos void* dst, size_t dstCapacity, 5318*3117ece4Schristos const void* src, size_t srcSize, 5319*3117ece4Schristos const void* dict,size_t dictSize, 5320*3117ece4Schristos ZSTD_parameters params) 5321*3117ece4Schristos { 5322*3117ece4Schristos DEBUGLOG(4, "ZSTD_compress_advanced"); 5323*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), ""); 5324*3117ece4Schristos ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, ZSTD_NO_CLEVEL); 5325*3117ece4Schristos return ZSTD_compress_advanced_internal(cctx, 5326*3117ece4Schristos dst, dstCapacity, 5327*3117ece4Schristos src, srcSize, 5328*3117ece4Schristos dict, dictSize, 5329*3117ece4Schristos &cctx->simpleApiParams); 5330*3117ece4Schristos } 5331*3117ece4Schristos 5332*3117ece4Schristos /* Internal */ 5333*3117ece4Schristos size_t ZSTD_compress_advanced_internal( 5334*3117ece4Schristos ZSTD_CCtx* cctx, 5335*3117ece4Schristos void* dst, size_t dstCapacity, 5336*3117ece4Schristos const void* src, size_t srcSize, 5337*3117ece4Schristos const void* dict,size_t dictSize, 5338*3117ece4Schristos const ZSTD_CCtx_params* params) 5339*3117ece4Schristos { 5340*3117ece4Schristos DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize); 5341*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, 5342*3117ece4Schristos dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, 5343*3117ece4Schristos params, srcSize, ZSTDb_not_buffered) , ""); 5344*3117ece4Schristos return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); 5345*3117ece4Schristos } 5346*3117ece4Schristos 5347*3117ece4Schristos size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, 5348*3117ece4Schristos void* dst, size_t dstCapacity, 5349*3117ece4Schristos const void* src, size_t srcSize, 5350*3117ece4Schristos const void* dict, size_t dictSize, 5351*3117ece4Schristos int compressionLevel) 5352*3117ece4Schristos { 5353*3117ece4Schristos { 5354*3117ece4Schristos ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict); 5355*3117ece4Schristos assert(params.fParams.contentSizeFlag == 1); 5356*3117ece4Schristos ZSTD_CCtxParams_init_internal(&cctx->simpleApiParams, ¶ms, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT: compressionLevel); 5357*3117ece4Schristos } 5358*3117ece4Schristos DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize); 5359*3117ece4Schristos return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctx->simpleApiParams); 5360*3117ece4Schristos } 5361*3117ece4Schristos 5362*3117ece4Schristos size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, 5363*3117ece4Schristos void* dst, size_t dstCapacity, 5364*3117ece4Schristos const void* src, size_t srcSize, 5365*3117ece4Schristos int compressionLevel) 5366*3117ece4Schristos { 5367*3117ece4Schristos DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (unsigned)srcSize); 5368*3117ece4Schristos assert(cctx != NULL); 5369*3117ece4Schristos return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel); 5370*3117ece4Schristos } 5371*3117ece4Schristos 5372*3117ece4Schristos size_t ZSTD_compress(void* dst, size_t dstCapacity, 5373*3117ece4Schristos const void* src, size_t srcSize, 5374*3117ece4Schristos int compressionLevel) 5375*3117ece4Schristos { 5376*3117ece4Schristos size_t result; 5377*3117ece4Schristos #if ZSTD_COMPRESS_HEAPMODE 5378*3117ece4Schristos ZSTD_CCtx* cctx = ZSTD_createCCtx(); 5379*3117ece4Schristos RETURN_ERROR_IF(!cctx, memory_allocation, "ZSTD_createCCtx failed"); 5380*3117ece4Schristos result = ZSTD_compressCCtx(cctx, dst, dstCapacity, src, srcSize, compressionLevel); 5381*3117ece4Schristos ZSTD_freeCCtx(cctx); 5382*3117ece4Schristos #else 5383*3117ece4Schristos ZSTD_CCtx ctxBody; 5384*3117ece4Schristos ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem); 5385*3117ece4Schristos result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); 5386*3117ece4Schristos ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */ 5387*3117ece4Schristos #endif 5388*3117ece4Schristos return result; 5389*3117ece4Schristos } 5390*3117ece4Schristos 5391*3117ece4Schristos 5392*3117ece4Schristos /* ===== Dictionary API ===== */ 5393*3117ece4Schristos 5394*3117ece4Schristos /*! ZSTD_estimateCDictSize_advanced() : 5395*3117ece4Schristos * Estimate amount of memory that will be needed to create a dictionary with following arguments */ 5396*3117ece4Schristos size_t ZSTD_estimateCDictSize_advanced( 5397*3117ece4Schristos size_t dictSize, ZSTD_compressionParameters cParams, 5398*3117ece4Schristos ZSTD_dictLoadMethod_e dictLoadMethod) 5399*3117ece4Schristos { 5400*3117ece4Schristos DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict)); 5401*3117ece4Schristos return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) 5402*3117ece4Schristos + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) 5403*3117ece4Schristos /* enableDedicatedDictSearch == 1 ensures that CDict estimation will not be too small 5404*3117ece4Schristos * in case we are using DDS with row-hash. */ 5405*3117ece4Schristos + ZSTD_sizeof_matchState(&cParams, ZSTD_resolveRowMatchFinderMode(ZSTD_ps_auto, &cParams), 5406*3117ece4Schristos /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0) 5407*3117ece4Schristos + (dictLoadMethod == ZSTD_dlm_byRef ? 0 5408*3117ece4Schristos : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *)))); 5409*3117ece4Schristos } 5410*3117ece4Schristos 5411*3117ece4Schristos size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) 5412*3117ece4Schristos { 5413*3117ece4Schristos ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); 5414*3117ece4Schristos return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); 5415*3117ece4Schristos } 5416*3117ece4Schristos 5417*3117ece4Schristos size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) 5418*3117ece4Schristos { 5419*3117ece4Schristos if (cdict==NULL) return 0; /* support sizeof on NULL */ 5420*3117ece4Schristos DEBUGLOG(5, "sizeof(*cdict) : %u", (unsigned)sizeof(*cdict)); 5421*3117ece4Schristos /* cdict may be in the workspace */ 5422*3117ece4Schristos return (cdict->workspace.workspace == cdict ? 0 : sizeof(*cdict)) 5423*3117ece4Schristos + ZSTD_cwksp_sizeof(&cdict->workspace); 5424*3117ece4Schristos } 5425*3117ece4Schristos 5426*3117ece4Schristos static size_t ZSTD_initCDict_internal( 5427*3117ece4Schristos ZSTD_CDict* cdict, 5428*3117ece4Schristos const void* dictBuffer, size_t dictSize, 5429*3117ece4Schristos ZSTD_dictLoadMethod_e dictLoadMethod, 5430*3117ece4Schristos ZSTD_dictContentType_e dictContentType, 5431*3117ece4Schristos ZSTD_CCtx_params params) 5432*3117ece4Schristos { 5433*3117ece4Schristos DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType); 5434*3117ece4Schristos assert(!ZSTD_checkCParams(params.cParams)); 5435*3117ece4Schristos cdict->matchState.cParams = params.cParams; 5436*3117ece4Schristos cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch; 5437*3117ece4Schristos if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { 5438*3117ece4Schristos cdict->dictContent = dictBuffer; 5439*3117ece4Schristos } else { 5440*3117ece4Schristos void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*))); 5441*3117ece4Schristos RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!"); 5442*3117ece4Schristos cdict->dictContent = internalBuffer; 5443*3117ece4Schristos ZSTD_memcpy(internalBuffer, dictBuffer, dictSize); 5444*3117ece4Schristos } 5445*3117ece4Schristos cdict->dictContentSize = dictSize; 5446*3117ece4Schristos cdict->dictContentType = dictContentType; 5447*3117ece4Schristos 5448*3117ece4Schristos cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE); 5449*3117ece4Schristos 5450*3117ece4Schristos 5451*3117ece4Schristos /* Reset the state to no dictionary */ 5452*3117ece4Schristos ZSTD_reset_compressedBlockState(&cdict->cBlockState); 5453*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_reset_matchState( 5454*3117ece4Schristos &cdict->matchState, 5455*3117ece4Schristos &cdict->workspace, 5456*3117ece4Schristos ¶ms.cParams, 5457*3117ece4Schristos params.useRowMatchFinder, 5458*3117ece4Schristos ZSTDcrp_makeClean, 5459*3117ece4Schristos ZSTDirp_reset, 5460*3117ece4Schristos ZSTD_resetTarget_CDict), ""); 5461*3117ece4Schristos /* (Maybe) load the dictionary 5462*3117ece4Schristos * Skips loading the dictionary if it is < 8 bytes. 5463*3117ece4Schristos */ 5464*3117ece4Schristos { params.compressionLevel = ZSTD_CLEVEL_DEFAULT; 5465*3117ece4Schristos params.fParams.contentSizeFlag = 1; 5466*3117ece4Schristos { size_t const dictID = ZSTD_compress_insertDictionary( 5467*3117ece4Schristos &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace, 5468*3117ece4Schristos ¶ms, cdict->dictContent, cdict->dictContentSize, 5469*3117ece4Schristos dictContentType, ZSTD_dtlm_full, ZSTD_tfp_forCDict, cdict->entropyWorkspace); 5470*3117ece4Schristos FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed"); 5471*3117ece4Schristos assert(dictID <= (size_t)(U32)-1); 5472*3117ece4Schristos cdict->dictID = (U32)dictID; 5473*3117ece4Schristos } 5474*3117ece4Schristos } 5475*3117ece4Schristos 5476*3117ece4Schristos return 0; 5477*3117ece4Schristos } 5478*3117ece4Schristos 5479*3117ece4Schristos static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize, 5480*3117ece4Schristos ZSTD_dictLoadMethod_e dictLoadMethod, 5481*3117ece4Schristos ZSTD_compressionParameters cParams, 5482*3117ece4Schristos ZSTD_paramSwitch_e useRowMatchFinder, 5483*3117ece4Schristos U32 enableDedicatedDictSearch, 5484*3117ece4Schristos ZSTD_customMem customMem) 5485*3117ece4Schristos { 5486*3117ece4Schristos if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL; 5487*3117ece4Schristos 5488*3117ece4Schristos { size_t const workspaceSize = 5489*3117ece4Schristos ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + 5490*3117ece4Schristos ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) + 5491*3117ece4Schristos ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, enableDedicatedDictSearch, /* forCCtx */ 0) + 5492*3117ece4Schristos (dictLoadMethod == ZSTD_dlm_byRef ? 0 5493*3117ece4Schristos : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))); 5494*3117ece4Schristos void* const workspace = ZSTD_customMalloc(workspaceSize, customMem); 5495*3117ece4Schristos ZSTD_cwksp ws; 5496*3117ece4Schristos ZSTD_CDict* cdict; 5497*3117ece4Schristos 5498*3117ece4Schristos if (!workspace) { 5499*3117ece4Schristos ZSTD_customFree(workspace, customMem); 5500*3117ece4Schristos return NULL; 5501*3117ece4Schristos } 5502*3117ece4Schristos 5503*3117ece4Schristos ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_dynamic_alloc); 5504*3117ece4Schristos 5505*3117ece4Schristos cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); 5506*3117ece4Schristos assert(cdict != NULL); 5507*3117ece4Schristos ZSTD_cwksp_move(&cdict->workspace, &ws); 5508*3117ece4Schristos cdict->customMem = customMem; 5509*3117ece4Schristos cdict->compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */ 5510*3117ece4Schristos cdict->useRowMatchFinder = useRowMatchFinder; 5511*3117ece4Schristos return cdict; 5512*3117ece4Schristos } 5513*3117ece4Schristos } 5514*3117ece4Schristos 5515*3117ece4Schristos ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, 5516*3117ece4Schristos ZSTD_dictLoadMethod_e dictLoadMethod, 5517*3117ece4Schristos ZSTD_dictContentType_e dictContentType, 5518*3117ece4Schristos ZSTD_compressionParameters cParams, 5519*3117ece4Schristos ZSTD_customMem customMem) 5520*3117ece4Schristos { 5521*3117ece4Schristos ZSTD_CCtx_params cctxParams; 5522*3117ece4Schristos ZSTD_memset(&cctxParams, 0, sizeof(cctxParams)); 5523*3117ece4Schristos ZSTD_CCtxParams_init(&cctxParams, 0); 5524*3117ece4Schristos cctxParams.cParams = cParams; 5525*3117ece4Schristos cctxParams.customMem = customMem; 5526*3117ece4Schristos return ZSTD_createCDict_advanced2( 5527*3117ece4Schristos dictBuffer, dictSize, 5528*3117ece4Schristos dictLoadMethod, dictContentType, 5529*3117ece4Schristos &cctxParams, customMem); 5530*3117ece4Schristos } 5531*3117ece4Schristos 5532*3117ece4Schristos ZSTD_CDict* ZSTD_createCDict_advanced2( 5533*3117ece4Schristos const void* dict, size_t dictSize, 5534*3117ece4Schristos ZSTD_dictLoadMethod_e dictLoadMethod, 5535*3117ece4Schristos ZSTD_dictContentType_e dictContentType, 5536*3117ece4Schristos const ZSTD_CCtx_params* originalCctxParams, 5537*3117ece4Schristos ZSTD_customMem customMem) 5538*3117ece4Schristos { 5539*3117ece4Schristos ZSTD_CCtx_params cctxParams = *originalCctxParams; 5540*3117ece4Schristos ZSTD_compressionParameters cParams; 5541*3117ece4Schristos ZSTD_CDict* cdict; 5542*3117ece4Schristos 5543*3117ece4Schristos DEBUGLOG(3, "ZSTD_createCDict_advanced2, mode %u", (unsigned)dictContentType); 5544*3117ece4Schristos if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 5545*3117ece4Schristos 5546*3117ece4Schristos if (cctxParams.enableDedicatedDictSearch) { 5547*3117ece4Schristos cParams = ZSTD_dedicatedDictSearch_getCParams( 5548*3117ece4Schristos cctxParams.compressionLevel, dictSize); 5549*3117ece4Schristos ZSTD_overrideCParams(&cParams, &cctxParams.cParams); 5550*3117ece4Schristos } else { 5551*3117ece4Schristos cParams = ZSTD_getCParamsFromCCtxParams( 5552*3117ece4Schristos &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); 5553*3117ece4Schristos } 5554*3117ece4Schristos 5555*3117ece4Schristos if (!ZSTD_dedicatedDictSearch_isSupported(&cParams)) { 5556*3117ece4Schristos /* Fall back to non-DDSS params */ 5557*3117ece4Schristos cctxParams.enableDedicatedDictSearch = 0; 5558*3117ece4Schristos cParams = ZSTD_getCParamsFromCCtxParams( 5559*3117ece4Schristos &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); 5560*3117ece4Schristos } 5561*3117ece4Schristos 5562*3117ece4Schristos DEBUGLOG(3, "ZSTD_createCDict_advanced2: DDS: %u", cctxParams.enableDedicatedDictSearch); 5563*3117ece4Schristos cctxParams.cParams = cParams; 5564*3117ece4Schristos cctxParams.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(cctxParams.useRowMatchFinder, &cParams); 5565*3117ece4Schristos 5566*3117ece4Schristos cdict = ZSTD_createCDict_advanced_internal(dictSize, 5567*3117ece4Schristos dictLoadMethod, cctxParams.cParams, 5568*3117ece4Schristos cctxParams.useRowMatchFinder, cctxParams.enableDedicatedDictSearch, 5569*3117ece4Schristos customMem); 5570*3117ece4Schristos 5571*3117ece4Schristos if (!cdict || ZSTD_isError( ZSTD_initCDict_internal(cdict, 5572*3117ece4Schristos dict, dictSize, 5573*3117ece4Schristos dictLoadMethod, dictContentType, 5574*3117ece4Schristos cctxParams) )) { 5575*3117ece4Schristos ZSTD_freeCDict(cdict); 5576*3117ece4Schristos return NULL; 5577*3117ece4Schristos } 5578*3117ece4Schristos 5579*3117ece4Schristos return cdict; 5580*3117ece4Schristos } 5581*3117ece4Schristos 5582*3117ece4Schristos ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) 5583*3117ece4Schristos { 5584*3117ece4Schristos ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); 5585*3117ece4Schristos ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, 5586*3117ece4Schristos ZSTD_dlm_byCopy, ZSTD_dct_auto, 5587*3117ece4Schristos cParams, ZSTD_defaultCMem); 5588*3117ece4Schristos if (cdict) 5589*3117ece4Schristos cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; 5590*3117ece4Schristos return cdict; 5591*3117ece4Schristos } 5592*3117ece4Schristos 5593*3117ece4Schristos ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) 5594*3117ece4Schristos { 5595*3117ece4Schristos ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict); 5596*3117ece4Schristos ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize, 5597*3117ece4Schristos ZSTD_dlm_byRef, ZSTD_dct_auto, 5598*3117ece4Schristos cParams, ZSTD_defaultCMem); 5599*3117ece4Schristos if (cdict) 5600*3117ece4Schristos cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel; 5601*3117ece4Schristos return cdict; 5602*3117ece4Schristos } 5603*3117ece4Schristos 5604*3117ece4Schristos size_t ZSTD_freeCDict(ZSTD_CDict* cdict) 5605*3117ece4Schristos { 5606*3117ece4Schristos if (cdict==NULL) return 0; /* support free on NULL */ 5607*3117ece4Schristos { ZSTD_customMem const cMem = cdict->customMem; 5608*3117ece4Schristos int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict); 5609*3117ece4Schristos ZSTD_cwksp_free(&cdict->workspace, cMem); 5610*3117ece4Schristos if (!cdictInWorkspace) { 5611*3117ece4Schristos ZSTD_customFree(cdict, cMem); 5612*3117ece4Schristos } 5613*3117ece4Schristos return 0; 5614*3117ece4Schristos } 5615*3117ece4Schristos } 5616*3117ece4Schristos 5617*3117ece4Schristos /*! ZSTD_initStaticCDict_advanced() : 5618*3117ece4Schristos * Generate a digested dictionary in provided memory area. 5619*3117ece4Schristos * workspace: The memory area to emplace the dictionary into. 5620*3117ece4Schristos * Provided pointer must 8-bytes aligned. 5621*3117ece4Schristos * It must outlive dictionary usage. 5622*3117ece4Schristos * workspaceSize: Use ZSTD_estimateCDictSize() 5623*3117ece4Schristos * to determine how large workspace must be. 5624*3117ece4Schristos * cParams : use ZSTD_getCParams() to transform a compression level 5625*3117ece4Schristos * into its relevants cParams. 5626*3117ece4Schristos * @return : pointer to ZSTD_CDict*, or NULL if error (size too small) 5627*3117ece4Schristos * Note : there is no corresponding "free" function. 5628*3117ece4Schristos * Since workspace was allocated externally, it must be freed externally. 5629*3117ece4Schristos */ 5630*3117ece4Schristos const ZSTD_CDict* ZSTD_initStaticCDict( 5631*3117ece4Schristos void* workspace, size_t workspaceSize, 5632*3117ece4Schristos const void* dict, size_t dictSize, 5633*3117ece4Schristos ZSTD_dictLoadMethod_e dictLoadMethod, 5634*3117ece4Schristos ZSTD_dictContentType_e dictContentType, 5635*3117ece4Schristos ZSTD_compressionParameters cParams) 5636*3117ece4Schristos { 5637*3117ece4Schristos ZSTD_paramSwitch_e const useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(ZSTD_ps_auto, &cParams); 5638*3117ece4Schristos /* enableDedicatedDictSearch == 1 ensures matchstate is not too small in case this CDict will be used for DDS + row hash */ 5639*3117ece4Schristos size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, useRowMatchFinder, /* enableDedicatedDictSearch */ 1, /* forCCtx */ 0); 5640*3117ece4Schristos size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) 5641*3117ece4Schristos + (dictLoadMethod == ZSTD_dlm_byRef ? 0 5642*3117ece4Schristos : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))) 5643*3117ece4Schristos + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) 5644*3117ece4Schristos + matchStateSize; 5645*3117ece4Schristos ZSTD_CDict* cdict; 5646*3117ece4Schristos ZSTD_CCtx_params params; 5647*3117ece4Schristos 5648*3117ece4Schristos if ((size_t)workspace & 7) return NULL; /* 8-aligned */ 5649*3117ece4Schristos 5650*3117ece4Schristos { 5651*3117ece4Schristos ZSTD_cwksp ws; 5652*3117ece4Schristos ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc); 5653*3117ece4Schristos cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); 5654*3117ece4Schristos if (cdict == NULL) return NULL; 5655*3117ece4Schristos ZSTD_cwksp_move(&cdict->workspace, &ws); 5656*3117ece4Schristos } 5657*3117ece4Schristos 5658*3117ece4Schristos DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u", 5659*3117ece4Schristos (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize)); 5660*3117ece4Schristos if (workspaceSize < neededSize) return NULL; 5661*3117ece4Schristos 5662*3117ece4Schristos ZSTD_CCtxParams_init(¶ms, 0); 5663*3117ece4Schristos params.cParams = cParams; 5664*3117ece4Schristos params.useRowMatchFinder = useRowMatchFinder; 5665*3117ece4Schristos cdict->useRowMatchFinder = useRowMatchFinder; 5666*3117ece4Schristos cdict->compressionLevel = ZSTD_NO_CLEVEL; 5667*3117ece4Schristos 5668*3117ece4Schristos if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 5669*3117ece4Schristos dict, dictSize, 5670*3117ece4Schristos dictLoadMethod, dictContentType, 5671*3117ece4Schristos params) )) 5672*3117ece4Schristos return NULL; 5673*3117ece4Schristos 5674*3117ece4Schristos return cdict; 5675*3117ece4Schristos } 5676*3117ece4Schristos 5677*3117ece4Schristos ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) 5678*3117ece4Schristos { 5679*3117ece4Schristos assert(cdict != NULL); 5680*3117ece4Schristos return cdict->matchState.cParams; 5681*3117ece4Schristos } 5682*3117ece4Schristos 5683*3117ece4Schristos /*! ZSTD_getDictID_fromCDict() : 5684*3117ece4Schristos * Provides the dictID of the dictionary loaded into `cdict`. 5685*3117ece4Schristos * If @return == 0, the dictionary is not conformant to Zstandard specification, or empty. 5686*3117ece4Schristos * Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */ 5687*3117ece4Schristos unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict) 5688*3117ece4Schristos { 5689*3117ece4Schristos if (cdict==NULL) return 0; 5690*3117ece4Schristos return cdict->dictID; 5691*3117ece4Schristos } 5692*3117ece4Schristos 5693*3117ece4Schristos /* ZSTD_compressBegin_usingCDict_internal() : 5694*3117ece4Schristos * Implementation of various ZSTD_compressBegin_usingCDict* functions. 5695*3117ece4Schristos */ 5696*3117ece4Schristos static size_t ZSTD_compressBegin_usingCDict_internal( 5697*3117ece4Schristos ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, 5698*3117ece4Schristos ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) 5699*3117ece4Schristos { 5700*3117ece4Schristos ZSTD_CCtx_params cctxParams; 5701*3117ece4Schristos DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_internal"); 5702*3117ece4Schristos RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!"); 5703*3117ece4Schristos /* Initialize the cctxParams from the cdict */ 5704*3117ece4Schristos { 5705*3117ece4Schristos ZSTD_parameters params; 5706*3117ece4Schristos params.fParams = fParams; 5707*3117ece4Schristos params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF 5708*3117ece4Schristos || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER 5709*3117ece4Schristos || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN 5710*3117ece4Schristos || cdict->compressionLevel == 0 ) ? 5711*3117ece4Schristos ZSTD_getCParamsFromCDict(cdict) 5712*3117ece4Schristos : ZSTD_getCParams(cdict->compressionLevel, 5713*3117ece4Schristos pledgedSrcSize, 5714*3117ece4Schristos cdict->dictContentSize); 5715*3117ece4Schristos ZSTD_CCtxParams_init_internal(&cctxParams, ¶ms, cdict->compressionLevel); 5716*3117ece4Schristos } 5717*3117ece4Schristos /* Increase window log to fit the entire dictionary and source if the 5718*3117ece4Schristos * source size is known. Limit the increase to 19, which is the 5719*3117ece4Schristos * window log for compression level 1 with the largest source size. 5720*3117ece4Schristos */ 5721*3117ece4Schristos if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { 5722*3117ece4Schristos U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); 5723*3117ece4Schristos U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; 5724*3117ece4Schristos cctxParams.cParams.windowLog = MAX(cctxParams.cParams.windowLog, limitedSrcLog); 5725*3117ece4Schristos } 5726*3117ece4Schristos return ZSTD_compressBegin_internal(cctx, 5727*3117ece4Schristos NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, 5728*3117ece4Schristos cdict, 5729*3117ece4Schristos &cctxParams, pledgedSrcSize, 5730*3117ece4Schristos ZSTDb_not_buffered); 5731*3117ece4Schristos } 5732*3117ece4Schristos 5733*3117ece4Schristos 5734*3117ece4Schristos /* ZSTD_compressBegin_usingCDict_advanced() : 5735*3117ece4Schristos * This function is DEPRECATED. 5736*3117ece4Schristos * cdict must be != NULL */ 5737*3117ece4Schristos size_t ZSTD_compressBegin_usingCDict_advanced( 5738*3117ece4Schristos ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, 5739*3117ece4Schristos ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) 5740*3117ece4Schristos { 5741*3117ece4Schristos return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, pledgedSrcSize); 5742*3117ece4Schristos } 5743*3117ece4Schristos 5744*3117ece4Schristos /* ZSTD_compressBegin_usingCDict() : 5745*3117ece4Schristos * cdict must be != NULL */ 5746*3117ece4Schristos size_t ZSTD_compressBegin_usingCDict_deprecated(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 5747*3117ece4Schristos { 5748*3117ece4Schristos ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 5749*3117ece4Schristos return ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); 5750*3117ece4Schristos } 5751*3117ece4Schristos 5752*3117ece4Schristos size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 5753*3117ece4Schristos { 5754*3117ece4Schristos return ZSTD_compressBegin_usingCDict_deprecated(cctx, cdict); 5755*3117ece4Schristos } 5756*3117ece4Schristos 5757*3117ece4Schristos /*! ZSTD_compress_usingCDict_internal(): 5758*3117ece4Schristos * Implementation of various ZSTD_compress_usingCDict* functions. 5759*3117ece4Schristos */ 5760*3117ece4Schristos static size_t ZSTD_compress_usingCDict_internal(ZSTD_CCtx* cctx, 5761*3117ece4Schristos void* dst, size_t dstCapacity, 5762*3117ece4Schristos const void* src, size_t srcSize, 5763*3117ece4Schristos const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) 5764*3117ece4Schristos { 5765*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_internal(cctx, cdict, fParams, srcSize), ""); /* will check if cdict != NULL */ 5766*3117ece4Schristos return ZSTD_compressEnd_public(cctx, dst, dstCapacity, src, srcSize); 5767*3117ece4Schristos } 5768*3117ece4Schristos 5769*3117ece4Schristos /*! ZSTD_compress_usingCDict_advanced(): 5770*3117ece4Schristos * This function is DEPRECATED. 5771*3117ece4Schristos */ 5772*3117ece4Schristos size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, 5773*3117ece4Schristos void* dst, size_t dstCapacity, 5774*3117ece4Schristos const void* src, size_t srcSize, 5775*3117ece4Schristos const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) 5776*3117ece4Schristos { 5777*3117ece4Schristos return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); 5778*3117ece4Schristos } 5779*3117ece4Schristos 5780*3117ece4Schristos /*! ZSTD_compress_usingCDict() : 5781*3117ece4Schristos * Compression using a digested Dictionary. 5782*3117ece4Schristos * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times. 5783*3117ece4Schristos * Note that compression parameters are decided at CDict creation time 5784*3117ece4Schristos * while frame parameters are hardcoded */ 5785*3117ece4Schristos size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, 5786*3117ece4Schristos void* dst, size_t dstCapacity, 5787*3117ece4Schristos const void* src, size_t srcSize, 5788*3117ece4Schristos const ZSTD_CDict* cdict) 5789*3117ece4Schristos { 5790*3117ece4Schristos ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 5791*3117ece4Schristos return ZSTD_compress_usingCDict_internal(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); 5792*3117ece4Schristos } 5793*3117ece4Schristos 5794*3117ece4Schristos 5795*3117ece4Schristos 5796*3117ece4Schristos /* ****************************************************************** 5797*3117ece4Schristos * Streaming 5798*3117ece4Schristos ********************************************************************/ 5799*3117ece4Schristos 5800*3117ece4Schristos ZSTD_CStream* ZSTD_createCStream(void) 5801*3117ece4Schristos { 5802*3117ece4Schristos DEBUGLOG(3, "ZSTD_createCStream"); 5803*3117ece4Schristos return ZSTD_createCStream_advanced(ZSTD_defaultCMem); 5804*3117ece4Schristos } 5805*3117ece4Schristos 5806*3117ece4Schristos ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize) 5807*3117ece4Schristos { 5808*3117ece4Schristos return ZSTD_initStaticCCtx(workspace, workspaceSize); 5809*3117ece4Schristos } 5810*3117ece4Schristos 5811*3117ece4Schristos ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem) 5812*3117ece4Schristos { /* CStream and CCtx are now same object */ 5813*3117ece4Schristos return ZSTD_createCCtx_advanced(customMem); 5814*3117ece4Schristos } 5815*3117ece4Schristos 5816*3117ece4Schristos size_t ZSTD_freeCStream(ZSTD_CStream* zcs) 5817*3117ece4Schristos { 5818*3117ece4Schristos return ZSTD_freeCCtx(zcs); /* same object */ 5819*3117ece4Schristos } 5820*3117ece4Schristos 5821*3117ece4Schristos 5822*3117ece4Schristos 5823*3117ece4Schristos /*====== Initialization ======*/ 5824*3117ece4Schristos 5825*3117ece4Schristos size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; } 5826*3117ece4Schristos 5827*3117ece4Schristos size_t ZSTD_CStreamOutSize(void) 5828*3117ece4Schristos { 5829*3117ece4Schristos return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; 5830*3117ece4Schristos } 5831*3117ece4Schristos 5832*3117ece4Schristos static ZSTD_cParamMode_e ZSTD_getCParamMode(ZSTD_CDict const* cdict, ZSTD_CCtx_params const* params, U64 pledgedSrcSize) 5833*3117ece4Schristos { 5834*3117ece4Schristos if (cdict != NULL && ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) 5835*3117ece4Schristos return ZSTD_cpm_attachDict; 5836*3117ece4Schristos else 5837*3117ece4Schristos return ZSTD_cpm_noAttachDict; 5838*3117ece4Schristos } 5839*3117ece4Schristos 5840*3117ece4Schristos /* ZSTD_resetCStream(): 5841*3117ece4Schristos * pledgedSrcSize == 0 means "unknown" */ 5842*3117ece4Schristos size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pss) 5843*3117ece4Schristos { 5844*3117ece4Schristos /* temporary : 0 interpreted as "unknown" during transition period. 5845*3117ece4Schristos * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. 5846*3117ece4Schristos * 0 will be interpreted as "empty" in the future. 5847*3117ece4Schristos */ 5848*3117ece4Schristos U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 5849*3117ece4Schristos DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize); 5850*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 5851*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); 5852*3117ece4Schristos return 0; 5853*3117ece4Schristos } 5854*3117ece4Schristos 5855*3117ece4Schristos /*! ZSTD_initCStream_internal() : 5856*3117ece4Schristos * Note : for lib/compress only. Used by zstdmt_compress.c. 5857*3117ece4Schristos * Assumption 1 : params are valid 5858*3117ece4Schristos * Assumption 2 : either dict, or cdict, is defined, not both */ 5859*3117ece4Schristos size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, 5860*3117ece4Schristos const void* dict, size_t dictSize, const ZSTD_CDict* cdict, 5861*3117ece4Schristos const ZSTD_CCtx_params* params, 5862*3117ece4Schristos unsigned long long pledgedSrcSize) 5863*3117ece4Schristos { 5864*3117ece4Schristos DEBUGLOG(4, "ZSTD_initCStream_internal"); 5865*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 5866*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); 5867*3117ece4Schristos assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); 5868*3117ece4Schristos zcs->requestedParams = *params; 5869*3117ece4Schristos assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 5870*3117ece4Schristos if (dict) { 5871*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); 5872*3117ece4Schristos } else { 5873*3117ece4Schristos /* Dictionary is cleared if !cdict */ 5874*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , ""); 5875*3117ece4Schristos } 5876*3117ece4Schristos return 0; 5877*3117ece4Schristos } 5878*3117ece4Schristos 5879*3117ece4Schristos /* ZSTD_initCStream_usingCDict_advanced() : 5880*3117ece4Schristos * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ 5881*3117ece4Schristos size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, 5882*3117ece4Schristos const ZSTD_CDict* cdict, 5883*3117ece4Schristos ZSTD_frameParameters fParams, 5884*3117ece4Schristos unsigned long long pledgedSrcSize) 5885*3117ece4Schristos { 5886*3117ece4Schristos DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced"); 5887*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 5888*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); 5889*3117ece4Schristos zcs->requestedParams.fParams = fParams; 5890*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , ""); 5891*3117ece4Schristos return 0; 5892*3117ece4Schristos } 5893*3117ece4Schristos 5894*3117ece4Schristos /* note : cdict must outlive compression session */ 5895*3117ece4Schristos size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict) 5896*3117ece4Schristos { 5897*3117ece4Schristos DEBUGLOG(4, "ZSTD_initCStream_usingCDict"); 5898*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 5899*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , ""); 5900*3117ece4Schristos return 0; 5901*3117ece4Schristos } 5902*3117ece4Schristos 5903*3117ece4Schristos 5904*3117ece4Schristos /* ZSTD_initCStream_advanced() : 5905*3117ece4Schristos * pledgedSrcSize must be exact. 5906*3117ece4Schristos * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. 5907*3117ece4Schristos * dict is loaded with default parameters ZSTD_dct_auto and ZSTD_dlm_byCopy. */ 5908*3117ece4Schristos size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, 5909*3117ece4Schristos const void* dict, size_t dictSize, 5910*3117ece4Schristos ZSTD_parameters params, unsigned long long pss) 5911*3117ece4Schristos { 5912*3117ece4Schristos /* for compatibility with older programs relying on this behavior. 5913*3117ece4Schristos * Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. 5914*3117ece4Schristos * This line will be removed in the future. 5915*3117ece4Schristos */ 5916*3117ece4Schristos U64 const pledgedSrcSize = (pss==0 && params.fParams.contentSizeFlag==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 5917*3117ece4Schristos DEBUGLOG(4, "ZSTD_initCStream_advanced"); 5918*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 5919*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); 5920*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , ""); 5921*3117ece4Schristos ZSTD_CCtxParams_setZstdParams(&zcs->requestedParams, ¶ms); 5922*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); 5923*3117ece4Schristos return 0; 5924*3117ece4Schristos } 5925*3117ece4Schristos 5926*3117ece4Schristos size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) 5927*3117ece4Schristos { 5928*3117ece4Schristos DEBUGLOG(4, "ZSTD_initCStream_usingDict"); 5929*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 5930*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , ""); 5931*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , ""); 5932*3117ece4Schristos return 0; 5933*3117ece4Schristos } 5934*3117ece4Schristos 5935*3117ece4Schristos size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss) 5936*3117ece4Schristos { 5937*3117ece4Schristos /* temporary : 0 interpreted as "unknown" during transition period. 5938*3117ece4Schristos * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. 5939*3117ece4Schristos * 0 will be interpreted as "empty" in the future. 5940*3117ece4Schristos */ 5941*3117ece4Schristos U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 5942*3117ece4Schristos DEBUGLOG(4, "ZSTD_initCStream_srcSize"); 5943*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 5944*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , ""); 5945*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , ""); 5946*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , ""); 5947*3117ece4Schristos return 0; 5948*3117ece4Schristos } 5949*3117ece4Schristos 5950*3117ece4Schristos size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) 5951*3117ece4Schristos { 5952*3117ece4Schristos DEBUGLOG(4, "ZSTD_initCStream"); 5953*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , ""); 5954*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , ""); 5955*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , ""); 5956*3117ece4Schristos return 0; 5957*3117ece4Schristos } 5958*3117ece4Schristos 5959*3117ece4Schristos /*====== Compression ======*/ 5960*3117ece4Schristos 5961*3117ece4Schristos static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx) 5962*3117ece4Schristos { 5963*3117ece4Schristos if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { 5964*3117ece4Schristos return cctx->blockSize - cctx->stableIn_notConsumed; 5965*3117ece4Schristos } 5966*3117ece4Schristos assert(cctx->appliedParams.inBufferMode == ZSTD_bm_buffered); 5967*3117ece4Schristos { size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; 5968*3117ece4Schristos if (hintInSize==0) hintInSize = cctx->blockSize; 5969*3117ece4Schristos return hintInSize; 5970*3117ece4Schristos } 5971*3117ece4Schristos } 5972*3117ece4Schristos 5973*3117ece4Schristos /** ZSTD_compressStream_generic(): 5974*3117ece4Schristos * internal function for all *compressStream*() variants 5975*3117ece4Schristos * @return : hint size for next input to complete ongoing block */ 5976*3117ece4Schristos static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, 5977*3117ece4Schristos ZSTD_outBuffer* output, 5978*3117ece4Schristos ZSTD_inBuffer* input, 5979*3117ece4Schristos ZSTD_EndDirective const flushMode) 5980*3117ece4Schristos { 5981*3117ece4Schristos const char* const istart = (assert(input != NULL), (const char*)input->src); 5982*3117ece4Schristos const char* const iend = (istart != NULL) ? istart + input->size : istart; 5983*3117ece4Schristos const char* ip = (istart != NULL) ? istart + input->pos : istart; 5984*3117ece4Schristos char* const ostart = (assert(output != NULL), (char*)output->dst); 5985*3117ece4Schristos char* const oend = (ostart != NULL) ? ostart + output->size : ostart; 5986*3117ece4Schristos char* op = (ostart != NULL) ? ostart + output->pos : ostart; 5987*3117ece4Schristos U32 someMoreWork = 1; 5988*3117ece4Schristos 5989*3117ece4Schristos /* check expectations */ 5990*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%i, srcSize = %zu", (int)flushMode, input->size - input->pos); 5991*3117ece4Schristos assert(zcs != NULL); 5992*3117ece4Schristos if (zcs->appliedParams.inBufferMode == ZSTD_bm_stable) { 5993*3117ece4Schristos assert(input->pos >= zcs->stableIn_notConsumed); 5994*3117ece4Schristos input->pos -= zcs->stableIn_notConsumed; 5995*3117ece4Schristos if (ip) ip -= zcs->stableIn_notConsumed; 5996*3117ece4Schristos zcs->stableIn_notConsumed = 0; 5997*3117ece4Schristos } 5998*3117ece4Schristos if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) { 5999*3117ece4Schristos assert(zcs->inBuff != NULL); 6000*3117ece4Schristos assert(zcs->inBuffSize > 0); 6001*3117ece4Schristos } 6002*3117ece4Schristos if (zcs->appliedParams.outBufferMode == ZSTD_bm_buffered) { 6003*3117ece4Schristos assert(zcs->outBuff != NULL); 6004*3117ece4Schristos assert(zcs->outBuffSize > 0); 6005*3117ece4Schristos } 6006*3117ece4Schristos if (input->src == NULL) assert(input->size == 0); 6007*3117ece4Schristos assert(input->pos <= input->size); 6008*3117ece4Schristos if (output->dst == NULL) assert(output->size == 0); 6009*3117ece4Schristos assert(output->pos <= output->size); 6010*3117ece4Schristos assert((U32)flushMode <= (U32)ZSTD_e_end); 6011*3117ece4Schristos 6012*3117ece4Schristos while (someMoreWork) { 6013*3117ece4Schristos switch(zcs->streamStage) 6014*3117ece4Schristos { 6015*3117ece4Schristos case zcss_init: 6016*3117ece4Schristos RETURN_ERROR(init_missing, "call ZSTD_initCStream() first!"); 6017*3117ece4Schristos 6018*3117ece4Schristos case zcss_load: 6019*3117ece4Schristos if ( (flushMode == ZSTD_e_end) 6020*3117ece4Schristos && ( (size_t)(oend-op) >= ZSTD_compressBound(iend-ip) /* Enough output space */ 6021*3117ece4Schristos || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) /* OR we are allowed to return dstSizeTooSmall */ 6022*3117ece4Schristos && (zcs->inBuffPos == 0) ) { 6023*3117ece4Schristos /* shortcut to compression pass directly into output buffer */ 6024*3117ece4Schristos size_t const cSize = ZSTD_compressEnd_public(zcs, 6025*3117ece4Schristos op, oend-op, ip, iend-ip); 6026*3117ece4Schristos DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize); 6027*3117ece4Schristos FORWARD_IF_ERROR(cSize, "ZSTD_compressEnd failed"); 6028*3117ece4Schristos ip = iend; 6029*3117ece4Schristos op += cSize; 6030*3117ece4Schristos zcs->frameEnded = 1; 6031*3117ece4Schristos ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 6032*3117ece4Schristos someMoreWork = 0; break; 6033*3117ece4Schristos } 6034*3117ece4Schristos /* complete loading into inBuffer in buffered mode */ 6035*3117ece4Schristos if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) { 6036*3117ece4Schristos size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; 6037*3117ece4Schristos size_t const loaded = ZSTD_limitCopy( 6038*3117ece4Schristos zcs->inBuff + zcs->inBuffPos, toLoad, 6039*3117ece4Schristos ip, iend-ip); 6040*3117ece4Schristos zcs->inBuffPos += loaded; 6041*3117ece4Schristos if (ip) ip += loaded; 6042*3117ece4Schristos if ( (flushMode == ZSTD_e_continue) 6043*3117ece4Schristos && (zcs->inBuffPos < zcs->inBuffTarget) ) { 6044*3117ece4Schristos /* not enough input to fill full block : stop here */ 6045*3117ece4Schristos someMoreWork = 0; break; 6046*3117ece4Schristos } 6047*3117ece4Schristos if ( (flushMode == ZSTD_e_flush) 6048*3117ece4Schristos && (zcs->inBuffPos == zcs->inToCompress) ) { 6049*3117ece4Schristos /* empty */ 6050*3117ece4Schristos someMoreWork = 0; break; 6051*3117ece4Schristos } 6052*3117ece4Schristos } else { 6053*3117ece4Schristos assert(zcs->appliedParams.inBufferMode == ZSTD_bm_stable); 6054*3117ece4Schristos if ( (flushMode == ZSTD_e_continue) 6055*3117ece4Schristos && ( (size_t)(iend - ip) < zcs->blockSize) ) { 6056*3117ece4Schristos /* can't compress a full block : stop here */ 6057*3117ece4Schristos zcs->stableIn_notConsumed = (size_t)(iend - ip); 6058*3117ece4Schristos ip = iend; /* pretend to have consumed input */ 6059*3117ece4Schristos someMoreWork = 0; break; 6060*3117ece4Schristos } 6061*3117ece4Schristos if ( (flushMode == ZSTD_e_flush) 6062*3117ece4Schristos && (ip == iend) ) { 6063*3117ece4Schristos /* empty */ 6064*3117ece4Schristos someMoreWork = 0; break; 6065*3117ece4Schristos } 6066*3117ece4Schristos } 6067*3117ece4Schristos /* compress current block (note : this stage cannot be stopped in the middle) */ 6068*3117ece4Schristos DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode); 6069*3117ece4Schristos { int const inputBuffered = (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered); 6070*3117ece4Schristos void* cDst; 6071*3117ece4Schristos size_t cSize; 6072*3117ece4Schristos size_t oSize = oend-op; 6073*3117ece4Schristos size_t const iSize = inputBuffered ? zcs->inBuffPos - zcs->inToCompress 6074*3117ece4Schristos : MIN((size_t)(iend - ip), zcs->blockSize); 6075*3117ece4Schristos if (oSize >= ZSTD_compressBound(iSize) || zcs->appliedParams.outBufferMode == ZSTD_bm_stable) 6076*3117ece4Schristos cDst = op; /* compress into output buffer, to skip flush stage */ 6077*3117ece4Schristos else 6078*3117ece4Schristos cDst = zcs->outBuff, oSize = zcs->outBuffSize; 6079*3117ece4Schristos if (inputBuffered) { 6080*3117ece4Schristos unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); 6081*3117ece4Schristos cSize = lastBlock ? 6082*3117ece4Schristos ZSTD_compressEnd_public(zcs, cDst, oSize, 6083*3117ece4Schristos zcs->inBuff + zcs->inToCompress, iSize) : 6084*3117ece4Schristos ZSTD_compressContinue_public(zcs, cDst, oSize, 6085*3117ece4Schristos zcs->inBuff + zcs->inToCompress, iSize); 6086*3117ece4Schristos FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); 6087*3117ece4Schristos zcs->frameEnded = lastBlock; 6088*3117ece4Schristos /* prepare next block */ 6089*3117ece4Schristos zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; 6090*3117ece4Schristos if (zcs->inBuffTarget > zcs->inBuffSize) 6091*3117ece4Schristos zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; 6092*3117ece4Schristos DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", 6093*3117ece4Schristos (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); 6094*3117ece4Schristos if (!lastBlock) 6095*3117ece4Schristos assert(zcs->inBuffTarget <= zcs->inBuffSize); 6096*3117ece4Schristos zcs->inToCompress = zcs->inBuffPos; 6097*3117ece4Schristos } else { /* !inputBuffered, hence ZSTD_bm_stable */ 6098*3117ece4Schristos unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip + iSize == iend); 6099*3117ece4Schristos cSize = lastBlock ? 6100*3117ece4Schristos ZSTD_compressEnd_public(zcs, cDst, oSize, ip, iSize) : 6101*3117ece4Schristos ZSTD_compressContinue_public(zcs, cDst, oSize, ip, iSize); 6102*3117ece4Schristos /* Consume the input prior to error checking to mirror buffered mode. */ 6103*3117ece4Schristos if (ip) ip += iSize; 6104*3117ece4Schristos FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed"); 6105*3117ece4Schristos zcs->frameEnded = lastBlock; 6106*3117ece4Schristos if (lastBlock) assert(ip == iend); 6107*3117ece4Schristos } 6108*3117ece4Schristos if (cDst == op) { /* no need to flush */ 6109*3117ece4Schristos op += cSize; 6110*3117ece4Schristos if (zcs->frameEnded) { 6111*3117ece4Schristos DEBUGLOG(5, "Frame completed directly in outBuffer"); 6112*3117ece4Schristos someMoreWork = 0; 6113*3117ece4Schristos ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 6114*3117ece4Schristos } 6115*3117ece4Schristos break; 6116*3117ece4Schristos } 6117*3117ece4Schristos zcs->outBuffContentSize = cSize; 6118*3117ece4Schristos zcs->outBuffFlushedSize = 0; 6119*3117ece4Schristos zcs->streamStage = zcss_flush; /* pass-through to flush stage */ 6120*3117ece4Schristos } 6121*3117ece4Schristos ZSTD_FALLTHROUGH; 6122*3117ece4Schristos case zcss_flush: 6123*3117ece4Schristos DEBUGLOG(5, "flush stage"); 6124*3117ece4Schristos assert(zcs->appliedParams.outBufferMode == ZSTD_bm_buffered); 6125*3117ece4Schristos { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; 6126*3117ece4Schristos size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op), 6127*3117ece4Schristos zcs->outBuff + zcs->outBuffFlushedSize, toFlush); 6128*3117ece4Schristos DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u", 6129*3117ece4Schristos (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed); 6130*3117ece4Schristos if (flushed) 6131*3117ece4Schristos op += flushed; 6132*3117ece4Schristos zcs->outBuffFlushedSize += flushed; 6133*3117ece4Schristos if (toFlush!=flushed) { 6134*3117ece4Schristos /* flush not fully completed, presumably because dst is too small */ 6135*3117ece4Schristos assert(op==oend); 6136*3117ece4Schristos someMoreWork = 0; 6137*3117ece4Schristos break; 6138*3117ece4Schristos } 6139*3117ece4Schristos zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; 6140*3117ece4Schristos if (zcs->frameEnded) { 6141*3117ece4Schristos DEBUGLOG(5, "Frame completed on flush"); 6142*3117ece4Schristos someMoreWork = 0; 6143*3117ece4Schristos ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 6144*3117ece4Schristos break; 6145*3117ece4Schristos } 6146*3117ece4Schristos zcs->streamStage = zcss_load; 6147*3117ece4Schristos break; 6148*3117ece4Schristos } 6149*3117ece4Schristos 6150*3117ece4Schristos default: /* impossible */ 6151*3117ece4Schristos assert(0); 6152*3117ece4Schristos } 6153*3117ece4Schristos } 6154*3117ece4Schristos 6155*3117ece4Schristos input->pos = ip - istart; 6156*3117ece4Schristos output->pos = op - ostart; 6157*3117ece4Schristos if (zcs->frameEnded) return 0; 6158*3117ece4Schristos return ZSTD_nextInputSizeHint(zcs); 6159*3117ece4Schristos } 6160*3117ece4Schristos 6161*3117ece4Schristos static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx) 6162*3117ece4Schristos { 6163*3117ece4Schristos #ifdef ZSTD_MULTITHREAD 6164*3117ece4Schristos if (cctx->appliedParams.nbWorkers >= 1) { 6165*3117ece4Schristos assert(cctx->mtctx != NULL); 6166*3117ece4Schristos return ZSTDMT_nextInputSizeHint(cctx->mtctx); 6167*3117ece4Schristos } 6168*3117ece4Schristos #endif 6169*3117ece4Schristos return ZSTD_nextInputSizeHint(cctx); 6170*3117ece4Schristos 6171*3117ece4Schristos } 6172*3117ece4Schristos 6173*3117ece4Schristos size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) 6174*3117ece4Schristos { 6175*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) , ""); 6176*3117ece4Schristos return ZSTD_nextInputSizeHint_MTorST(zcs); 6177*3117ece4Schristos } 6178*3117ece4Schristos 6179*3117ece4Schristos /* After a compression call set the expected input/output buffer. 6180*3117ece4Schristos * This is validated at the start of the next compression call. 6181*3117ece4Schristos */ 6182*3117ece4Schristos static void 6183*3117ece4Schristos ZSTD_setBufferExpectations(ZSTD_CCtx* cctx, const ZSTD_outBuffer* output, const ZSTD_inBuffer* input) 6184*3117ece4Schristos { 6185*3117ece4Schristos DEBUGLOG(5, "ZSTD_setBufferExpectations (for advanced stable in/out modes)"); 6186*3117ece4Schristos if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { 6187*3117ece4Schristos cctx->expectedInBuffer = *input; 6188*3117ece4Schristos } 6189*3117ece4Schristos if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) { 6190*3117ece4Schristos cctx->expectedOutBufferSize = output->size - output->pos; 6191*3117ece4Schristos } 6192*3117ece4Schristos } 6193*3117ece4Schristos 6194*3117ece4Schristos /* Validate that the input/output buffers match the expectations set by 6195*3117ece4Schristos * ZSTD_setBufferExpectations. 6196*3117ece4Schristos */ 6197*3117ece4Schristos static size_t ZSTD_checkBufferStability(ZSTD_CCtx const* cctx, 6198*3117ece4Schristos ZSTD_outBuffer const* output, 6199*3117ece4Schristos ZSTD_inBuffer const* input, 6200*3117ece4Schristos ZSTD_EndDirective endOp) 6201*3117ece4Schristos { 6202*3117ece4Schristos if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) { 6203*3117ece4Schristos ZSTD_inBuffer const expect = cctx->expectedInBuffer; 6204*3117ece4Schristos if (expect.src != input->src || expect.pos != input->pos) 6205*3117ece4Schristos RETURN_ERROR(stabilityCondition_notRespected, "ZSTD_c_stableInBuffer enabled but input differs!"); 6206*3117ece4Schristos } 6207*3117ece4Schristos (void)endOp; 6208*3117ece4Schristos if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) { 6209*3117ece4Schristos size_t const outBufferSize = output->size - output->pos; 6210*3117ece4Schristos if (cctx->expectedOutBufferSize != outBufferSize) 6211*3117ece4Schristos RETURN_ERROR(stabilityCondition_notRespected, "ZSTD_c_stableOutBuffer enabled but output size differs!"); 6212*3117ece4Schristos } 6213*3117ece4Schristos return 0; 6214*3117ece4Schristos } 6215*3117ece4Schristos 6216*3117ece4Schristos static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx, 6217*3117ece4Schristos ZSTD_EndDirective endOp, 6218*3117ece4Schristos size_t inSize) 6219*3117ece4Schristos { 6220*3117ece4Schristos ZSTD_CCtx_params params = cctx->requestedParams; 6221*3117ece4Schristos ZSTD_prefixDict const prefixDict = cctx->prefixDict; 6222*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */ 6223*3117ece4Schristos ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ 6224*3117ece4Schristos assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ 6225*3117ece4Schristos if (cctx->cdict && !cctx->localDict.cdict) { 6226*3117ece4Schristos /* Let the cdict's compression level take priority over the requested params. 6227*3117ece4Schristos * But do not take the cdict's compression level if the "cdict" is actually a localDict 6228*3117ece4Schristos * generated from ZSTD_initLocalDict(). 6229*3117ece4Schristos */ 6230*3117ece4Schristos params.compressionLevel = cctx->cdict->compressionLevel; 6231*3117ece4Schristos } 6232*3117ece4Schristos DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); 6233*3117ece4Schristos if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1; /* auto-determine pledgedSrcSize */ 6234*3117ece4Schristos 6235*3117ece4Schristos { size_t const dictSize = prefixDict.dict 6236*3117ece4Schristos ? prefixDict.dictSize 6237*3117ece4Schristos : (cctx->cdict ? cctx->cdict->dictContentSize : 0); 6238*3117ece4Schristos ZSTD_cParamMode_e const mode = ZSTD_getCParamMode(cctx->cdict, ¶ms, cctx->pledgedSrcSizePlusOne - 1); 6239*3117ece4Schristos params.cParams = ZSTD_getCParamsFromCCtxParams( 6240*3117ece4Schristos ¶ms, cctx->pledgedSrcSizePlusOne-1, 6241*3117ece4Schristos dictSize, mode); 6242*3117ece4Schristos } 6243*3117ece4Schristos 6244*3117ece4Schristos params.useBlockSplitter = ZSTD_resolveBlockSplitterMode(params.useBlockSplitter, ¶ms.cParams); 6245*3117ece4Schristos params.ldmParams.enableLdm = ZSTD_resolveEnableLdm(params.ldmParams.enableLdm, ¶ms.cParams); 6246*3117ece4Schristos params.useRowMatchFinder = ZSTD_resolveRowMatchFinderMode(params.useRowMatchFinder, ¶ms.cParams); 6247*3117ece4Schristos params.validateSequences = ZSTD_resolveExternalSequenceValidation(params.validateSequences); 6248*3117ece4Schristos params.maxBlockSize = ZSTD_resolveMaxBlockSize(params.maxBlockSize); 6249*3117ece4Schristos params.searchForExternalRepcodes = ZSTD_resolveExternalRepcodeSearch(params.searchForExternalRepcodes, params.compressionLevel); 6250*3117ece4Schristos 6251*3117ece4Schristos #ifdef ZSTD_MULTITHREAD 6252*3117ece4Schristos /* If external matchfinder is enabled, make sure to fail before checking job size (for consistency) */ 6253*3117ece4Schristos RETURN_ERROR_IF( 6254*3117ece4Schristos ZSTD_hasExtSeqProd(¶ms) && params.nbWorkers >= 1, 6255*3117ece4Schristos parameter_combination_unsupported, 6256*3117ece4Schristos "External sequence producer isn't supported with nbWorkers >= 1" 6257*3117ece4Schristos ); 6258*3117ece4Schristos 6259*3117ece4Schristos if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { 6260*3117ece4Schristos params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ 6261*3117ece4Schristos } 6262*3117ece4Schristos if (params.nbWorkers > 0) { 6263*3117ece4Schristos #if ZSTD_TRACE 6264*3117ece4Schristos cctx->traceCtx = (ZSTD_trace_compress_begin != NULL) ? ZSTD_trace_compress_begin(cctx) : 0; 6265*3117ece4Schristos #endif 6266*3117ece4Schristos /* mt context creation */ 6267*3117ece4Schristos if (cctx->mtctx == NULL) { 6268*3117ece4Schristos DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u", 6269*3117ece4Schristos params.nbWorkers); 6270*3117ece4Schristos cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem, cctx->pool); 6271*3117ece4Schristos RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation, "NULL pointer!"); 6272*3117ece4Schristos } 6273*3117ece4Schristos /* mt compression */ 6274*3117ece4Schristos DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); 6275*3117ece4Schristos FORWARD_IF_ERROR( ZSTDMT_initCStream_internal( 6276*3117ece4Schristos cctx->mtctx, 6277*3117ece4Schristos prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, 6278*3117ece4Schristos cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) , ""); 6279*3117ece4Schristos cctx->dictID = cctx->cdict ? cctx->cdict->dictID : 0; 6280*3117ece4Schristos cctx->dictContentSize = cctx->cdict ? cctx->cdict->dictContentSize : prefixDict.dictSize; 6281*3117ece4Schristos cctx->consumedSrcSize = 0; 6282*3117ece4Schristos cctx->producedCSize = 0; 6283*3117ece4Schristos cctx->streamStage = zcss_load; 6284*3117ece4Schristos cctx->appliedParams = params; 6285*3117ece4Schristos } else 6286*3117ece4Schristos #endif /* ZSTD_MULTITHREAD */ 6287*3117ece4Schristos { U64 const pledgedSrcSize = cctx->pledgedSrcSizePlusOne - 1; 6288*3117ece4Schristos assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 6289*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, 6290*3117ece4Schristos prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, ZSTD_dtlm_fast, 6291*3117ece4Schristos cctx->cdict, 6292*3117ece4Schristos ¶ms, pledgedSrcSize, 6293*3117ece4Schristos ZSTDb_buffered) , ""); 6294*3117ece4Schristos assert(cctx->appliedParams.nbWorkers == 0); 6295*3117ece4Schristos cctx->inToCompress = 0; 6296*3117ece4Schristos cctx->inBuffPos = 0; 6297*3117ece4Schristos if (cctx->appliedParams.inBufferMode == ZSTD_bm_buffered) { 6298*3117ece4Schristos /* for small input: avoid automatic flush on reaching end of block, since 6299*3117ece4Schristos * it would require to add a 3-bytes null block to end frame 6300*3117ece4Schristos */ 6301*3117ece4Schristos cctx->inBuffTarget = cctx->blockSize + (cctx->blockSize == pledgedSrcSize); 6302*3117ece4Schristos } else { 6303*3117ece4Schristos cctx->inBuffTarget = 0; 6304*3117ece4Schristos } 6305*3117ece4Schristos cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; 6306*3117ece4Schristos cctx->streamStage = zcss_load; 6307*3117ece4Schristos cctx->frameEnded = 0; 6308*3117ece4Schristos } 6309*3117ece4Schristos return 0; 6310*3117ece4Schristos } 6311*3117ece4Schristos 6312*3117ece4Schristos /* @return provides a minimum amount of data remaining to be flushed from internal buffers 6313*3117ece4Schristos */ 6314*3117ece4Schristos size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, 6315*3117ece4Schristos ZSTD_outBuffer* output, 6316*3117ece4Schristos ZSTD_inBuffer* input, 6317*3117ece4Schristos ZSTD_EndDirective endOp) 6318*3117ece4Schristos { 6319*3117ece4Schristos DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp); 6320*3117ece4Schristos /* check conditions */ 6321*3117ece4Schristos RETURN_ERROR_IF(output->pos > output->size, dstSize_tooSmall, "invalid output buffer"); 6322*3117ece4Schristos RETURN_ERROR_IF(input->pos > input->size, srcSize_wrong, "invalid input buffer"); 6323*3117ece4Schristos RETURN_ERROR_IF((U32)endOp > (U32)ZSTD_e_end, parameter_outOfBound, "invalid endDirective"); 6324*3117ece4Schristos assert(cctx != NULL); 6325*3117ece4Schristos 6326*3117ece4Schristos /* transparent initialization stage */ 6327*3117ece4Schristos if (cctx->streamStage == zcss_init) { 6328*3117ece4Schristos size_t const inputSize = input->size - input->pos; /* no obligation to start from pos==0 */ 6329*3117ece4Schristos size_t const totalInputSize = inputSize + cctx->stableIn_notConsumed; 6330*3117ece4Schristos if ( (cctx->requestedParams.inBufferMode == ZSTD_bm_stable) /* input is presumed stable, across invocations */ 6331*3117ece4Schristos && (endOp == ZSTD_e_continue) /* no flush requested, more input to come */ 6332*3117ece4Schristos && (totalInputSize < ZSTD_BLOCKSIZE_MAX) ) { /* not even reached one block yet */ 6333*3117ece4Schristos if (cctx->stableIn_notConsumed) { /* not the first time */ 6334*3117ece4Schristos /* check stable source guarantees */ 6335*3117ece4Schristos RETURN_ERROR_IF(input->src != cctx->expectedInBuffer.src, stabilityCondition_notRespected, "stableInBuffer condition not respected: wrong src pointer"); 6336*3117ece4Schristos RETURN_ERROR_IF(input->pos != cctx->expectedInBuffer.size, stabilityCondition_notRespected, "stableInBuffer condition not respected: externally modified pos"); 6337*3117ece4Schristos } 6338*3117ece4Schristos /* pretend input was consumed, to give a sense forward progress */ 6339*3117ece4Schristos input->pos = input->size; 6340*3117ece4Schristos /* save stable inBuffer, for later control, and flush/end */ 6341*3117ece4Schristos cctx->expectedInBuffer = *input; 6342*3117ece4Schristos /* but actually input wasn't consumed, so keep track of position from where compression shall resume */ 6343*3117ece4Schristos cctx->stableIn_notConsumed += inputSize; 6344*3117ece4Schristos /* don't initialize yet, wait for the first block of flush() order, for better parameters adaptation */ 6345*3117ece4Schristos return ZSTD_FRAMEHEADERSIZE_MIN(cctx->requestedParams.format); /* at least some header to produce */ 6346*3117ece4Schristos } 6347*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, endOp, totalInputSize), "compressStream2 initialization failed"); 6348*3117ece4Schristos ZSTD_setBufferExpectations(cctx, output, input); /* Set initial buffer expectations now that we've initialized */ 6349*3117ece4Schristos } 6350*3117ece4Schristos /* end of transparent initialization stage */ 6351*3117ece4Schristos 6352*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_checkBufferStability(cctx, output, input, endOp), "invalid buffers"); 6353*3117ece4Schristos /* compression stage */ 6354*3117ece4Schristos #ifdef ZSTD_MULTITHREAD 6355*3117ece4Schristos if (cctx->appliedParams.nbWorkers > 0) { 6356*3117ece4Schristos size_t flushMin; 6357*3117ece4Schristos if (cctx->cParamsChanged) { 6358*3117ece4Schristos ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams); 6359*3117ece4Schristos cctx->cParamsChanged = 0; 6360*3117ece4Schristos } 6361*3117ece4Schristos if (cctx->stableIn_notConsumed) { 6362*3117ece4Schristos assert(cctx->appliedParams.inBufferMode == ZSTD_bm_stable); 6363*3117ece4Schristos /* some early data was skipped - make it available for consumption */ 6364*3117ece4Schristos assert(input->pos >= cctx->stableIn_notConsumed); 6365*3117ece4Schristos input->pos -= cctx->stableIn_notConsumed; 6366*3117ece4Schristos cctx->stableIn_notConsumed = 0; 6367*3117ece4Schristos } 6368*3117ece4Schristos for (;;) { 6369*3117ece4Schristos size_t const ipos = input->pos; 6370*3117ece4Schristos size_t const opos = output->pos; 6371*3117ece4Schristos flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); 6372*3117ece4Schristos cctx->consumedSrcSize += (U64)(input->pos - ipos); 6373*3117ece4Schristos cctx->producedCSize += (U64)(output->pos - opos); 6374*3117ece4Schristos if ( ZSTD_isError(flushMin) 6375*3117ece4Schristos || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ 6376*3117ece4Schristos if (flushMin == 0) 6377*3117ece4Schristos ZSTD_CCtx_trace(cctx, 0); 6378*3117ece4Schristos ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); 6379*3117ece4Schristos } 6380*3117ece4Schristos FORWARD_IF_ERROR(flushMin, "ZSTDMT_compressStream_generic failed"); 6381*3117ece4Schristos 6382*3117ece4Schristos if (endOp == ZSTD_e_continue) { 6383*3117ece4Schristos /* We only require some progress with ZSTD_e_continue, not maximal progress. 6384*3117ece4Schristos * We're done if we've consumed or produced any bytes, or either buffer is 6385*3117ece4Schristos * full. 6386*3117ece4Schristos */ 6387*3117ece4Schristos if (input->pos != ipos || output->pos != opos || input->pos == input->size || output->pos == output->size) 6388*3117ece4Schristos break; 6389*3117ece4Schristos } else { 6390*3117ece4Schristos assert(endOp == ZSTD_e_flush || endOp == ZSTD_e_end); 6391*3117ece4Schristos /* We require maximal progress. We're done when the flush is complete or the 6392*3117ece4Schristos * output buffer is full. 6393*3117ece4Schristos */ 6394*3117ece4Schristos if (flushMin == 0 || output->pos == output->size) 6395*3117ece4Schristos break; 6396*3117ece4Schristos } 6397*3117ece4Schristos } 6398*3117ece4Schristos DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic"); 6399*3117ece4Schristos /* Either we don't require maximum forward progress, we've finished the 6400*3117ece4Schristos * flush, or we are out of output space. 6401*3117ece4Schristos */ 6402*3117ece4Schristos assert(endOp == ZSTD_e_continue || flushMin == 0 || output->pos == output->size); 6403*3117ece4Schristos ZSTD_setBufferExpectations(cctx, output, input); 6404*3117ece4Schristos return flushMin; 6405*3117ece4Schristos } 6406*3117ece4Schristos #endif /* ZSTD_MULTITHREAD */ 6407*3117ece4Schristos FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , ""); 6408*3117ece4Schristos DEBUGLOG(5, "completed ZSTD_compressStream2"); 6409*3117ece4Schristos ZSTD_setBufferExpectations(cctx, output, input); 6410*3117ece4Schristos return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ 6411*3117ece4Schristos } 6412*3117ece4Schristos 6413*3117ece4Schristos size_t ZSTD_compressStream2_simpleArgs ( 6414*3117ece4Schristos ZSTD_CCtx* cctx, 6415*3117ece4Schristos void* dst, size_t dstCapacity, size_t* dstPos, 6416*3117ece4Schristos const void* src, size_t srcSize, size_t* srcPos, 6417*3117ece4Schristos ZSTD_EndDirective endOp) 6418*3117ece4Schristos { 6419*3117ece4Schristos ZSTD_outBuffer output; 6420*3117ece4Schristos ZSTD_inBuffer input; 6421*3117ece4Schristos output.dst = dst; 6422*3117ece4Schristos output.size = dstCapacity; 6423*3117ece4Schristos output.pos = *dstPos; 6424*3117ece4Schristos input.src = src; 6425*3117ece4Schristos input.size = srcSize; 6426*3117ece4Schristos input.pos = *srcPos; 6427*3117ece4Schristos /* ZSTD_compressStream2() will check validity of dstPos and srcPos */ 6428*3117ece4Schristos { size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp); 6429*3117ece4Schristos *dstPos = output.pos; 6430*3117ece4Schristos *srcPos = input.pos; 6431*3117ece4Schristos return cErr; 6432*3117ece4Schristos } 6433*3117ece4Schristos } 6434*3117ece4Schristos 6435*3117ece4Schristos size_t ZSTD_compress2(ZSTD_CCtx* cctx, 6436*3117ece4Schristos void* dst, size_t dstCapacity, 6437*3117ece4Schristos const void* src, size_t srcSize) 6438*3117ece4Schristos { 6439*3117ece4Schristos ZSTD_bufferMode_e const originalInBufferMode = cctx->requestedParams.inBufferMode; 6440*3117ece4Schristos ZSTD_bufferMode_e const originalOutBufferMode = cctx->requestedParams.outBufferMode; 6441*3117ece4Schristos DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize); 6442*3117ece4Schristos ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); 6443*3117ece4Schristos /* Enable stable input/output buffers. */ 6444*3117ece4Schristos cctx->requestedParams.inBufferMode = ZSTD_bm_stable; 6445*3117ece4Schristos cctx->requestedParams.outBufferMode = ZSTD_bm_stable; 6446*3117ece4Schristos { size_t oPos = 0; 6447*3117ece4Schristos size_t iPos = 0; 6448*3117ece4Schristos size_t const result = ZSTD_compressStream2_simpleArgs(cctx, 6449*3117ece4Schristos dst, dstCapacity, &oPos, 6450*3117ece4Schristos src, srcSize, &iPos, 6451*3117ece4Schristos ZSTD_e_end); 6452*3117ece4Schristos /* Reset to the original values. */ 6453*3117ece4Schristos cctx->requestedParams.inBufferMode = originalInBufferMode; 6454*3117ece4Schristos cctx->requestedParams.outBufferMode = originalOutBufferMode; 6455*3117ece4Schristos 6456*3117ece4Schristos FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed"); 6457*3117ece4Schristos if (result != 0) { /* compression not completed, due to lack of output space */ 6458*3117ece4Schristos assert(oPos == dstCapacity); 6459*3117ece4Schristos RETURN_ERROR(dstSize_tooSmall, ""); 6460*3117ece4Schristos } 6461*3117ece4Schristos assert(iPos == srcSize); /* all input is expected consumed */ 6462*3117ece4Schristos return oPos; 6463*3117ece4Schristos } 6464*3117ece4Schristos } 6465*3117ece4Schristos 6466*3117ece4Schristos /* ZSTD_validateSequence() : 6467*3117ece4Schristos * @offCode : is presumed to follow format required by ZSTD_storeSeq() 6468*3117ece4Schristos * @returns a ZSTD error code if sequence is not valid 6469*3117ece4Schristos */ 6470*3117ece4Schristos static size_t 6471*3117ece4Schristos ZSTD_validateSequence(U32 offCode, U32 matchLength, U32 minMatch, 6472*3117ece4Schristos size_t posInSrc, U32 windowLog, size_t dictSize, int useSequenceProducer) 6473*3117ece4Schristos { 6474*3117ece4Schristos U32 const windowSize = 1u << windowLog; 6475*3117ece4Schristos /* posInSrc represents the amount of data the decoder would decode up to this point. 6476*3117ece4Schristos * As long as the amount of data decoded is less than or equal to window size, offsets may be 6477*3117ece4Schristos * larger than the total length of output decoded in order to reference the dict, even larger than 6478*3117ece4Schristos * window size. After output surpasses windowSize, we're limited to windowSize offsets again. 6479*3117ece4Schristos */ 6480*3117ece4Schristos size_t const offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize; 6481*3117ece4Schristos size_t const matchLenLowerBound = (minMatch == 3 || useSequenceProducer) ? 3 : 4; 6482*3117ece4Schristos RETURN_ERROR_IF(offCode > OFFSET_TO_OFFBASE(offsetBound), externalSequences_invalid, "Offset too large!"); 6483*3117ece4Schristos /* Validate maxNbSeq is large enough for the given matchLength and minMatch */ 6484*3117ece4Schristos RETURN_ERROR_IF(matchLength < matchLenLowerBound, externalSequences_invalid, "Matchlength too small for the minMatch"); 6485*3117ece4Schristos return 0; 6486*3117ece4Schristos } 6487*3117ece4Schristos 6488*3117ece4Schristos /* Returns an offset code, given a sequence's raw offset, the ongoing repcode array, and whether litLength == 0 */ 6489*3117ece4Schristos static U32 ZSTD_finalizeOffBase(U32 rawOffset, const U32 rep[ZSTD_REP_NUM], U32 ll0) 6490*3117ece4Schristos { 6491*3117ece4Schristos U32 offBase = OFFSET_TO_OFFBASE(rawOffset); 6492*3117ece4Schristos 6493*3117ece4Schristos if (!ll0 && rawOffset == rep[0]) { 6494*3117ece4Schristos offBase = REPCODE1_TO_OFFBASE; 6495*3117ece4Schristos } else if (rawOffset == rep[1]) { 6496*3117ece4Schristos offBase = REPCODE_TO_OFFBASE(2 - ll0); 6497*3117ece4Schristos } else if (rawOffset == rep[2]) { 6498*3117ece4Schristos offBase = REPCODE_TO_OFFBASE(3 - ll0); 6499*3117ece4Schristos } else if (ll0 && rawOffset == rep[0] - 1) { 6500*3117ece4Schristos offBase = REPCODE3_TO_OFFBASE; 6501*3117ece4Schristos } 6502*3117ece4Schristos return offBase; 6503*3117ece4Schristos } 6504*3117ece4Schristos 6505*3117ece4Schristos size_t 6506*3117ece4Schristos ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, 6507*3117ece4Schristos ZSTD_sequencePosition* seqPos, 6508*3117ece4Schristos const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, 6509*3117ece4Schristos const void* src, size_t blockSize, 6510*3117ece4Schristos ZSTD_paramSwitch_e externalRepSearch) 6511*3117ece4Schristos { 6512*3117ece4Schristos U32 idx = seqPos->idx; 6513*3117ece4Schristos U32 const startIdx = idx; 6514*3117ece4Schristos BYTE const* ip = (BYTE const*)(src); 6515*3117ece4Schristos const BYTE* const iend = ip + blockSize; 6516*3117ece4Schristos repcodes_t updatedRepcodes; 6517*3117ece4Schristos U32 dictSize; 6518*3117ece4Schristos 6519*3117ece4Schristos DEBUGLOG(5, "ZSTD_copySequencesToSeqStoreExplicitBlockDelim (blockSize = %zu)", blockSize); 6520*3117ece4Schristos 6521*3117ece4Schristos if (cctx->cdict) { 6522*3117ece4Schristos dictSize = (U32)cctx->cdict->dictContentSize; 6523*3117ece4Schristos } else if (cctx->prefixDict.dict) { 6524*3117ece4Schristos dictSize = (U32)cctx->prefixDict.dictSize; 6525*3117ece4Schristos } else { 6526*3117ece4Schristos dictSize = 0; 6527*3117ece4Schristos } 6528*3117ece4Schristos ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); 6529*3117ece4Schristos for (; idx < inSeqsSize && (inSeqs[idx].matchLength != 0 || inSeqs[idx].offset != 0); ++idx) { 6530*3117ece4Schristos U32 const litLength = inSeqs[idx].litLength; 6531*3117ece4Schristos U32 const matchLength = inSeqs[idx].matchLength; 6532*3117ece4Schristos U32 offBase; 6533*3117ece4Schristos 6534*3117ece4Schristos if (externalRepSearch == ZSTD_ps_disable) { 6535*3117ece4Schristos offBase = OFFSET_TO_OFFBASE(inSeqs[idx].offset); 6536*3117ece4Schristos } else { 6537*3117ece4Schristos U32 const ll0 = (litLength == 0); 6538*3117ece4Schristos offBase = ZSTD_finalizeOffBase(inSeqs[idx].offset, updatedRepcodes.rep, ll0); 6539*3117ece4Schristos ZSTD_updateRep(updatedRepcodes.rep, offBase, ll0); 6540*3117ece4Schristos } 6541*3117ece4Schristos 6542*3117ece4Schristos DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); 6543*3117ece4Schristos if (cctx->appliedParams.validateSequences) { 6544*3117ece4Schristos seqPos->posInSrc += litLength + matchLength; 6545*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, 6546*3117ece4Schristos cctx->appliedParams.cParams.windowLog, dictSize, ZSTD_hasExtSeqProd(&cctx->appliedParams)), 6547*3117ece4Schristos "Sequence validation failed"); 6548*3117ece4Schristos } 6549*3117ece4Schristos RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid, 6550*3117ece4Schristos "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); 6551*3117ece4Schristos ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength); 6552*3117ece4Schristos ip += matchLength + litLength; 6553*3117ece4Schristos } 6554*3117ece4Schristos 6555*3117ece4Schristos /* If we skipped repcode search while parsing, we need to update repcodes now */ 6556*3117ece4Schristos assert(externalRepSearch != ZSTD_ps_auto); 6557*3117ece4Schristos assert(idx >= startIdx); 6558*3117ece4Schristos if (externalRepSearch == ZSTD_ps_disable && idx != startIdx) { 6559*3117ece4Schristos U32* const rep = updatedRepcodes.rep; 6560*3117ece4Schristos U32 lastSeqIdx = idx - 1; /* index of last non-block-delimiter sequence */ 6561*3117ece4Schristos 6562*3117ece4Schristos if (lastSeqIdx >= startIdx + 2) { 6563*3117ece4Schristos rep[2] = inSeqs[lastSeqIdx - 2].offset; 6564*3117ece4Schristos rep[1] = inSeqs[lastSeqIdx - 1].offset; 6565*3117ece4Schristos rep[0] = inSeqs[lastSeqIdx].offset; 6566*3117ece4Schristos } else if (lastSeqIdx == startIdx + 1) { 6567*3117ece4Schristos rep[2] = rep[0]; 6568*3117ece4Schristos rep[1] = inSeqs[lastSeqIdx - 1].offset; 6569*3117ece4Schristos rep[0] = inSeqs[lastSeqIdx].offset; 6570*3117ece4Schristos } else { 6571*3117ece4Schristos assert(lastSeqIdx == startIdx); 6572*3117ece4Schristos rep[2] = rep[1]; 6573*3117ece4Schristos rep[1] = rep[0]; 6574*3117ece4Schristos rep[0] = inSeqs[lastSeqIdx].offset; 6575*3117ece4Schristos } 6576*3117ece4Schristos } 6577*3117ece4Schristos 6578*3117ece4Schristos ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t)); 6579*3117ece4Schristos 6580*3117ece4Schristos if (inSeqs[idx].litLength) { 6581*3117ece4Schristos DEBUGLOG(6, "Storing last literals of size: %u", inSeqs[idx].litLength); 6582*3117ece4Schristos ZSTD_storeLastLiterals(&cctx->seqStore, ip, inSeqs[idx].litLength); 6583*3117ece4Schristos ip += inSeqs[idx].litLength; 6584*3117ece4Schristos seqPos->posInSrc += inSeqs[idx].litLength; 6585*3117ece4Schristos } 6586*3117ece4Schristos RETURN_ERROR_IF(ip != iend, externalSequences_invalid, "Blocksize doesn't agree with block delimiter!"); 6587*3117ece4Schristos seqPos->idx = idx+1; 6588*3117ece4Schristos return 0; 6589*3117ece4Schristos } 6590*3117ece4Schristos 6591*3117ece4Schristos size_t 6592*3117ece4Schristos ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, 6593*3117ece4Schristos const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, 6594*3117ece4Schristos const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch) 6595*3117ece4Schristos { 6596*3117ece4Schristos U32 idx = seqPos->idx; 6597*3117ece4Schristos U32 startPosInSequence = seqPos->posInSequence; 6598*3117ece4Schristos U32 endPosInSequence = seqPos->posInSequence + (U32)blockSize; 6599*3117ece4Schristos size_t dictSize; 6600*3117ece4Schristos BYTE const* ip = (BYTE const*)(src); 6601*3117ece4Schristos BYTE const* iend = ip + blockSize; /* May be adjusted if we decide to process fewer than blockSize bytes */ 6602*3117ece4Schristos repcodes_t updatedRepcodes; 6603*3117ece4Schristos U32 bytesAdjustment = 0; 6604*3117ece4Schristos U32 finalMatchSplit = 0; 6605*3117ece4Schristos 6606*3117ece4Schristos /* TODO(embg) support fast parsing mode in noBlockDelim mode */ 6607*3117ece4Schristos (void)externalRepSearch; 6608*3117ece4Schristos 6609*3117ece4Schristos if (cctx->cdict) { 6610*3117ece4Schristos dictSize = cctx->cdict->dictContentSize; 6611*3117ece4Schristos } else if (cctx->prefixDict.dict) { 6612*3117ece4Schristos dictSize = cctx->prefixDict.dictSize; 6613*3117ece4Schristos } else { 6614*3117ece4Schristos dictSize = 0; 6615*3117ece4Schristos } 6616*3117ece4Schristos DEBUGLOG(5, "ZSTD_copySequencesToSeqStoreNoBlockDelim: idx: %u PIS: %u blockSize: %zu", idx, startPosInSequence, blockSize); 6617*3117ece4Schristos DEBUGLOG(5, "Start seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); 6618*3117ece4Schristos ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t)); 6619*3117ece4Schristos while (endPosInSequence && idx < inSeqsSize && !finalMatchSplit) { 6620*3117ece4Schristos const ZSTD_Sequence currSeq = inSeqs[idx]; 6621*3117ece4Schristos U32 litLength = currSeq.litLength; 6622*3117ece4Schristos U32 matchLength = currSeq.matchLength; 6623*3117ece4Schristos U32 const rawOffset = currSeq.offset; 6624*3117ece4Schristos U32 offBase; 6625*3117ece4Schristos 6626*3117ece4Schristos /* Modify the sequence depending on where endPosInSequence lies */ 6627*3117ece4Schristos if (endPosInSequence >= currSeq.litLength + currSeq.matchLength) { 6628*3117ece4Schristos if (startPosInSequence >= litLength) { 6629*3117ece4Schristos startPosInSequence -= litLength; 6630*3117ece4Schristos litLength = 0; 6631*3117ece4Schristos matchLength -= startPosInSequence; 6632*3117ece4Schristos } else { 6633*3117ece4Schristos litLength -= startPosInSequence; 6634*3117ece4Schristos } 6635*3117ece4Schristos /* Move to the next sequence */ 6636*3117ece4Schristos endPosInSequence -= currSeq.litLength + currSeq.matchLength; 6637*3117ece4Schristos startPosInSequence = 0; 6638*3117ece4Schristos } else { 6639*3117ece4Schristos /* This is the final (partial) sequence we're adding from inSeqs, and endPosInSequence 6640*3117ece4Schristos does not reach the end of the match. So, we have to split the sequence */ 6641*3117ece4Schristos DEBUGLOG(6, "Require a split: diff: %u, idx: %u PIS: %u", 6642*3117ece4Schristos currSeq.litLength + currSeq.matchLength - endPosInSequence, idx, endPosInSequence); 6643*3117ece4Schristos if (endPosInSequence > litLength) { 6644*3117ece4Schristos U32 firstHalfMatchLength; 6645*3117ece4Schristos litLength = startPosInSequence >= litLength ? 0 : litLength - startPosInSequence; 6646*3117ece4Schristos firstHalfMatchLength = endPosInSequence - startPosInSequence - litLength; 6647*3117ece4Schristos if (matchLength > blockSize && firstHalfMatchLength >= cctx->appliedParams.cParams.minMatch) { 6648*3117ece4Schristos /* Only ever split the match if it is larger than the block size */ 6649*3117ece4Schristos U32 secondHalfMatchLength = currSeq.matchLength + currSeq.litLength - endPosInSequence; 6650*3117ece4Schristos if (secondHalfMatchLength < cctx->appliedParams.cParams.minMatch) { 6651*3117ece4Schristos /* Move the endPosInSequence backward so that it creates match of minMatch length */ 6652*3117ece4Schristos endPosInSequence -= cctx->appliedParams.cParams.minMatch - secondHalfMatchLength; 6653*3117ece4Schristos bytesAdjustment = cctx->appliedParams.cParams.minMatch - secondHalfMatchLength; 6654*3117ece4Schristos firstHalfMatchLength -= bytesAdjustment; 6655*3117ece4Schristos } 6656*3117ece4Schristos matchLength = firstHalfMatchLength; 6657*3117ece4Schristos /* Flag that we split the last match - after storing the sequence, exit the loop, 6658*3117ece4Schristos but keep the value of endPosInSequence */ 6659*3117ece4Schristos finalMatchSplit = 1; 6660*3117ece4Schristos } else { 6661*3117ece4Schristos /* Move the position in sequence backwards so that we don't split match, and break to store 6662*3117ece4Schristos * the last literals. We use the original currSeq.litLength as a marker for where endPosInSequence 6663*3117ece4Schristos * should go. We prefer to do this whenever it is not necessary to split the match, or if doing so 6664*3117ece4Schristos * would cause the first half of the match to be too small 6665*3117ece4Schristos */ 6666*3117ece4Schristos bytesAdjustment = endPosInSequence - currSeq.litLength; 6667*3117ece4Schristos endPosInSequence = currSeq.litLength; 6668*3117ece4Schristos break; 6669*3117ece4Schristos } 6670*3117ece4Schristos } else { 6671*3117ece4Schristos /* This sequence ends inside the literals, break to store the last literals */ 6672*3117ece4Schristos break; 6673*3117ece4Schristos } 6674*3117ece4Schristos } 6675*3117ece4Schristos /* Check if this offset can be represented with a repcode */ 6676*3117ece4Schristos { U32 const ll0 = (litLength == 0); 6677*3117ece4Schristos offBase = ZSTD_finalizeOffBase(rawOffset, updatedRepcodes.rep, ll0); 6678*3117ece4Schristos ZSTD_updateRep(updatedRepcodes.rep, offBase, ll0); 6679*3117ece4Schristos } 6680*3117ece4Schristos 6681*3117ece4Schristos if (cctx->appliedParams.validateSequences) { 6682*3117ece4Schristos seqPos->posInSrc += litLength + matchLength; 6683*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_validateSequence(offBase, matchLength, cctx->appliedParams.cParams.minMatch, seqPos->posInSrc, 6684*3117ece4Schristos cctx->appliedParams.cParams.windowLog, dictSize, ZSTD_hasExtSeqProd(&cctx->appliedParams)), 6685*3117ece4Schristos "Sequence validation failed"); 6686*3117ece4Schristos } 6687*3117ece4Schristos DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offBase, matchLength, litLength); 6688*3117ece4Schristos RETURN_ERROR_IF(idx - seqPos->idx >= cctx->seqStore.maxNbSeq, externalSequences_invalid, 6689*3117ece4Schristos "Not enough memory allocated. Try adjusting ZSTD_c_minMatch."); 6690*3117ece4Schristos ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offBase, matchLength); 6691*3117ece4Schristos ip += matchLength + litLength; 6692*3117ece4Schristos if (!finalMatchSplit) 6693*3117ece4Schristos idx++; /* Next Sequence */ 6694*3117ece4Schristos } 6695*3117ece4Schristos DEBUGLOG(5, "Ending seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength); 6696*3117ece4Schristos assert(idx == inSeqsSize || endPosInSequence <= inSeqs[idx].litLength + inSeqs[idx].matchLength); 6697*3117ece4Schristos seqPos->idx = idx; 6698*3117ece4Schristos seqPos->posInSequence = endPosInSequence; 6699*3117ece4Schristos ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t)); 6700*3117ece4Schristos 6701*3117ece4Schristos iend -= bytesAdjustment; 6702*3117ece4Schristos if (ip != iend) { 6703*3117ece4Schristos /* Store any last literals */ 6704*3117ece4Schristos U32 lastLLSize = (U32)(iend - ip); 6705*3117ece4Schristos assert(ip <= iend); 6706*3117ece4Schristos DEBUGLOG(6, "Storing last literals of size: %u", lastLLSize); 6707*3117ece4Schristos ZSTD_storeLastLiterals(&cctx->seqStore, ip, lastLLSize); 6708*3117ece4Schristos seqPos->posInSrc += lastLLSize; 6709*3117ece4Schristos } 6710*3117ece4Schristos 6711*3117ece4Schristos return bytesAdjustment; 6712*3117ece4Schristos } 6713*3117ece4Schristos 6714*3117ece4Schristos typedef size_t (*ZSTD_sequenceCopier) (ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos, 6715*3117ece4Schristos const ZSTD_Sequence* const inSeqs, size_t inSeqsSize, 6716*3117ece4Schristos const void* src, size_t blockSize, ZSTD_paramSwitch_e externalRepSearch); 6717*3117ece4Schristos static ZSTD_sequenceCopier ZSTD_selectSequenceCopier(ZSTD_sequenceFormat_e mode) 6718*3117ece4Schristos { 6719*3117ece4Schristos ZSTD_sequenceCopier sequenceCopier = NULL; 6720*3117ece4Schristos assert(ZSTD_cParam_withinBounds(ZSTD_c_blockDelimiters, mode)); 6721*3117ece4Schristos if (mode == ZSTD_sf_explicitBlockDelimiters) { 6722*3117ece4Schristos return ZSTD_copySequencesToSeqStoreExplicitBlockDelim; 6723*3117ece4Schristos } else if (mode == ZSTD_sf_noBlockDelimiters) { 6724*3117ece4Schristos return ZSTD_copySequencesToSeqStoreNoBlockDelim; 6725*3117ece4Schristos } 6726*3117ece4Schristos assert(sequenceCopier != NULL); 6727*3117ece4Schristos return sequenceCopier; 6728*3117ece4Schristos } 6729*3117ece4Schristos 6730*3117ece4Schristos /* Discover the size of next block by searching for the delimiter. 6731*3117ece4Schristos * Note that a block delimiter **must** exist in this mode, 6732*3117ece4Schristos * otherwise it's an input error. 6733*3117ece4Schristos * The block size retrieved will be later compared to ensure it remains within bounds */ 6734*3117ece4Schristos static size_t 6735*3117ece4Schristos blockSize_explicitDelimiter(const ZSTD_Sequence* inSeqs, size_t inSeqsSize, ZSTD_sequencePosition seqPos) 6736*3117ece4Schristos { 6737*3117ece4Schristos int end = 0; 6738*3117ece4Schristos size_t blockSize = 0; 6739*3117ece4Schristos size_t spos = seqPos.idx; 6740*3117ece4Schristos DEBUGLOG(6, "blockSize_explicitDelimiter : seq %zu / %zu", spos, inSeqsSize); 6741*3117ece4Schristos assert(spos <= inSeqsSize); 6742*3117ece4Schristos while (spos < inSeqsSize) { 6743*3117ece4Schristos end = (inSeqs[spos].offset == 0); 6744*3117ece4Schristos blockSize += inSeqs[spos].litLength + inSeqs[spos].matchLength; 6745*3117ece4Schristos if (end) { 6746*3117ece4Schristos if (inSeqs[spos].matchLength != 0) 6747*3117ece4Schristos RETURN_ERROR(externalSequences_invalid, "delimiter format error : both matchlength and offset must be == 0"); 6748*3117ece4Schristos break; 6749*3117ece4Schristos } 6750*3117ece4Schristos spos++; 6751*3117ece4Schristos } 6752*3117ece4Schristos if (!end) 6753*3117ece4Schristos RETURN_ERROR(externalSequences_invalid, "Reached end of sequences without finding a block delimiter"); 6754*3117ece4Schristos return blockSize; 6755*3117ece4Schristos } 6756*3117ece4Schristos 6757*3117ece4Schristos /* More a "target" block size */ 6758*3117ece4Schristos static size_t blockSize_noDelimiter(size_t blockSize, size_t remaining) 6759*3117ece4Schristos { 6760*3117ece4Schristos int const lastBlock = (remaining <= blockSize); 6761*3117ece4Schristos return lastBlock ? remaining : blockSize; 6762*3117ece4Schristos } 6763*3117ece4Schristos 6764*3117ece4Schristos static size_t determine_blockSize(ZSTD_sequenceFormat_e mode, 6765*3117ece4Schristos size_t blockSize, size_t remaining, 6766*3117ece4Schristos const ZSTD_Sequence* inSeqs, size_t inSeqsSize, ZSTD_sequencePosition seqPos) 6767*3117ece4Schristos { 6768*3117ece4Schristos DEBUGLOG(6, "determine_blockSize : remainingSize = %zu", remaining); 6769*3117ece4Schristos if (mode == ZSTD_sf_noBlockDelimiters) 6770*3117ece4Schristos return blockSize_noDelimiter(blockSize, remaining); 6771*3117ece4Schristos { size_t const explicitBlockSize = blockSize_explicitDelimiter(inSeqs, inSeqsSize, seqPos); 6772*3117ece4Schristos FORWARD_IF_ERROR(explicitBlockSize, "Error while determining block size with explicit delimiters"); 6773*3117ece4Schristos if (explicitBlockSize > blockSize) 6774*3117ece4Schristos RETURN_ERROR(externalSequences_invalid, "sequences incorrectly define a too large block"); 6775*3117ece4Schristos if (explicitBlockSize > remaining) 6776*3117ece4Schristos RETURN_ERROR(externalSequences_invalid, "sequences define a frame longer than source"); 6777*3117ece4Schristos return explicitBlockSize; 6778*3117ece4Schristos } 6779*3117ece4Schristos } 6780*3117ece4Schristos 6781*3117ece4Schristos /* Compress, block-by-block, all of the sequences given. 6782*3117ece4Schristos * 6783*3117ece4Schristos * Returns the cumulative size of all compressed blocks (including their headers), 6784*3117ece4Schristos * otherwise a ZSTD error. 6785*3117ece4Schristos */ 6786*3117ece4Schristos static size_t 6787*3117ece4Schristos ZSTD_compressSequences_internal(ZSTD_CCtx* cctx, 6788*3117ece4Schristos void* dst, size_t dstCapacity, 6789*3117ece4Schristos const ZSTD_Sequence* inSeqs, size_t inSeqsSize, 6790*3117ece4Schristos const void* src, size_t srcSize) 6791*3117ece4Schristos { 6792*3117ece4Schristos size_t cSize = 0; 6793*3117ece4Schristos size_t remaining = srcSize; 6794*3117ece4Schristos ZSTD_sequencePosition seqPos = {0, 0, 0}; 6795*3117ece4Schristos 6796*3117ece4Schristos BYTE const* ip = (BYTE const*)src; 6797*3117ece4Schristos BYTE* op = (BYTE*)dst; 6798*3117ece4Schristos ZSTD_sequenceCopier const sequenceCopier = ZSTD_selectSequenceCopier(cctx->appliedParams.blockDelimiters); 6799*3117ece4Schristos 6800*3117ece4Schristos DEBUGLOG(4, "ZSTD_compressSequences_internal srcSize: %zu, inSeqsSize: %zu", srcSize, inSeqsSize); 6801*3117ece4Schristos /* Special case: empty frame */ 6802*3117ece4Schristos if (remaining == 0) { 6803*3117ece4Schristos U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1); 6804*3117ece4Schristos RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "No room for empty frame block header"); 6805*3117ece4Schristos MEM_writeLE32(op, cBlockHeader24); 6806*3117ece4Schristos op += ZSTD_blockHeaderSize; 6807*3117ece4Schristos dstCapacity -= ZSTD_blockHeaderSize; 6808*3117ece4Schristos cSize += ZSTD_blockHeaderSize; 6809*3117ece4Schristos } 6810*3117ece4Schristos 6811*3117ece4Schristos while (remaining) { 6812*3117ece4Schristos size_t compressedSeqsSize; 6813*3117ece4Schristos size_t cBlockSize; 6814*3117ece4Schristos size_t additionalByteAdjustment; 6815*3117ece4Schristos size_t blockSize = determine_blockSize(cctx->appliedParams.blockDelimiters, 6816*3117ece4Schristos cctx->blockSize, remaining, 6817*3117ece4Schristos inSeqs, inSeqsSize, seqPos); 6818*3117ece4Schristos U32 const lastBlock = (blockSize == remaining); 6819*3117ece4Schristos FORWARD_IF_ERROR(blockSize, "Error while trying to determine block size"); 6820*3117ece4Schristos assert(blockSize <= remaining); 6821*3117ece4Schristos ZSTD_resetSeqStore(&cctx->seqStore); 6822*3117ece4Schristos DEBUGLOG(5, "Working on new block. Blocksize: %zu (total:%zu)", blockSize, (ip - (const BYTE*)src) + blockSize); 6823*3117ece4Schristos 6824*3117ece4Schristos additionalByteAdjustment = sequenceCopier(cctx, &seqPos, inSeqs, inSeqsSize, ip, blockSize, cctx->appliedParams.searchForExternalRepcodes); 6825*3117ece4Schristos FORWARD_IF_ERROR(additionalByteAdjustment, "Bad sequence copy"); 6826*3117ece4Schristos blockSize -= additionalByteAdjustment; 6827*3117ece4Schristos 6828*3117ece4Schristos /* If blocks are too small, emit as a nocompress block */ 6829*3117ece4Schristos /* TODO: See 3090. We reduced MIN_CBLOCK_SIZE from 3 to 2 so to compensate we are adding 6830*3117ece4Schristos * additional 1. We need to revisit and change this logic to be more consistent */ 6831*3117ece4Schristos if (blockSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1+1) { 6832*3117ece4Schristos cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); 6833*3117ece4Schristos FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed"); 6834*3117ece4Schristos DEBUGLOG(5, "Block too small, writing out nocompress block: cSize: %zu", cBlockSize); 6835*3117ece4Schristos cSize += cBlockSize; 6836*3117ece4Schristos ip += blockSize; 6837*3117ece4Schristos op += cBlockSize; 6838*3117ece4Schristos remaining -= blockSize; 6839*3117ece4Schristos dstCapacity -= cBlockSize; 6840*3117ece4Schristos continue; 6841*3117ece4Schristos } 6842*3117ece4Schristos 6843*3117ece4Schristos RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall, "not enough dstCapacity to write a new compressed block"); 6844*3117ece4Schristos compressedSeqsSize = ZSTD_entropyCompressSeqStore(&cctx->seqStore, 6845*3117ece4Schristos &cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy, 6846*3117ece4Schristos &cctx->appliedParams, 6847*3117ece4Schristos op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize, 6848*3117ece4Schristos blockSize, 6849*3117ece4Schristos cctx->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */, 6850*3117ece4Schristos cctx->bmi2); 6851*3117ece4Schristos FORWARD_IF_ERROR(compressedSeqsSize, "Compressing sequences of block failed"); 6852*3117ece4Schristos DEBUGLOG(5, "Compressed sequences size: %zu", compressedSeqsSize); 6853*3117ece4Schristos 6854*3117ece4Schristos if (!cctx->isFirstBlock && 6855*3117ece4Schristos ZSTD_maybeRLE(&cctx->seqStore) && 6856*3117ece4Schristos ZSTD_isRLE(ip, blockSize)) { 6857*3117ece4Schristos /* We don't want to emit our first block as a RLE even if it qualifies because 6858*3117ece4Schristos * doing so will cause the decoder (cli only) to throw a "should consume all input error." 6859*3117ece4Schristos * This is only an issue for zstd <= v1.4.3 6860*3117ece4Schristos */ 6861*3117ece4Schristos compressedSeqsSize = 1; 6862*3117ece4Schristos } 6863*3117ece4Schristos 6864*3117ece4Schristos if (compressedSeqsSize == 0) { 6865*3117ece4Schristos /* ZSTD_noCompressBlock writes the block header as well */ 6866*3117ece4Schristos cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); 6867*3117ece4Schristos FORWARD_IF_ERROR(cBlockSize, "ZSTD_noCompressBlock failed"); 6868*3117ece4Schristos DEBUGLOG(5, "Writing out nocompress block, size: %zu", cBlockSize); 6869*3117ece4Schristos } else if (compressedSeqsSize == 1) { 6870*3117ece4Schristos cBlockSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, blockSize, lastBlock); 6871*3117ece4Schristos FORWARD_IF_ERROR(cBlockSize, "ZSTD_rleCompressBlock failed"); 6872*3117ece4Schristos DEBUGLOG(5, "Writing out RLE block, size: %zu", cBlockSize); 6873*3117ece4Schristos } else { 6874*3117ece4Schristos U32 cBlockHeader; 6875*3117ece4Schristos /* Error checking and repcodes update */ 6876*3117ece4Schristos ZSTD_blockState_confirmRepcodesAndEntropyTables(&cctx->blockState); 6877*3117ece4Schristos if (cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) 6878*3117ece4Schristos cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; 6879*3117ece4Schristos 6880*3117ece4Schristos /* Write block header into beginning of block*/ 6881*3117ece4Schristos cBlockHeader = lastBlock + (((U32)bt_compressed)<<1) + (U32)(compressedSeqsSize << 3); 6882*3117ece4Schristos MEM_writeLE24(op, cBlockHeader); 6883*3117ece4Schristos cBlockSize = ZSTD_blockHeaderSize + compressedSeqsSize; 6884*3117ece4Schristos DEBUGLOG(5, "Writing out compressed block, size: %zu", cBlockSize); 6885*3117ece4Schristos } 6886*3117ece4Schristos 6887*3117ece4Schristos cSize += cBlockSize; 6888*3117ece4Schristos 6889*3117ece4Schristos if (lastBlock) { 6890*3117ece4Schristos break; 6891*3117ece4Schristos } else { 6892*3117ece4Schristos ip += blockSize; 6893*3117ece4Schristos op += cBlockSize; 6894*3117ece4Schristos remaining -= blockSize; 6895*3117ece4Schristos dstCapacity -= cBlockSize; 6896*3117ece4Schristos cctx->isFirstBlock = 0; 6897*3117ece4Schristos } 6898*3117ece4Schristos DEBUGLOG(5, "cSize running total: %zu (remaining dstCapacity=%zu)", cSize, dstCapacity); 6899*3117ece4Schristos } 6900*3117ece4Schristos 6901*3117ece4Schristos DEBUGLOG(4, "cSize final total: %zu", cSize); 6902*3117ece4Schristos return cSize; 6903*3117ece4Schristos } 6904*3117ece4Schristos 6905*3117ece4Schristos size_t ZSTD_compressSequences(ZSTD_CCtx* cctx, 6906*3117ece4Schristos void* dst, size_t dstCapacity, 6907*3117ece4Schristos const ZSTD_Sequence* inSeqs, size_t inSeqsSize, 6908*3117ece4Schristos const void* src, size_t srcSize) 6909*3117ece4Schristos { 6910*3117ece4Schristos BYTE* op = (BYTE*)dst; 6911*3117ece4Schristos size_t cSize = 0; 6912*3117ece4Schristos size_t compressedBlocksSize = 0; 6913*3117ece4Schristos size_t frameHeaderSize = 0; 6914*3117ece4Schristos 6915*3117ece4Schristos /* Transparent initialization stage, same as compressStream2() */ 6916*3117ece4Schristos DEBUGLOG(4, "ZSTD_compressSequences (dstCapacity=%zu)", dstCapacity); 6917*3117ece4Schristos assert(cctx != NULL); 6918*3117ece4Schristos FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, ZSTD_e_end, srcSize), "CCtx initialization failed"); 6919*3117ece4Schristos /* Begin writing output, starting with frame header */ 6920*3117ece4Schristos frameHeaderSize = ZSTD_writeFrameHeader(op, dstCapacity, &cctx->appliedParams, srcSize, cctx->dictID); 6921*3117ece4Schristos op += frameHeaderSize; 6922*3117ece4Schristos dstCapacity -= frameHeaderSize; 6923*3117ece4Schristos cSize += frameHeaderSize; 6924*3117ece4Schristos if (cctx->appliedParams.fParams.checksumFlag && srcSize) { 6925*3117ece4Schristos XXH64_update(&cctx->xxhState, src, srcSize); 6926*3117ece4Schristos } 6927*3117ece4Schristos /* cSize includes block header size and compressed sequences size */ 6928*3117ece4Schristos compressedBlocksSize = ZSTD_compressSequences_internal(cctx, 6929*3117ece4Schristos op, dstCapacity, 6930*3117ece4Schristos inSeqs, inSeqsSize, 6931*3117ece4Schristos src, srcSize); 6932*3117ece4Schristos FORWARD_IF_ERROR(compressedBlocksSize, "Compressing blocks failed!"); 6933*3117ece4Schristos cSize += compressedBlocksSize; 6934*3117ece4Schristos dstCapacity -= compressedBlocksSize; 6935*3117ece4Schristos 6936*3117ece4Schristos if (cctx->appliedParams.fParams.checksumFlag) { 6937*3117ece4Schristos U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); 6938*3117ece4Schristos RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum"); 6939*3117ece4Schristos DEBUGLOG(4, "Write checksum : %08X", (unsigned)checksum); 6940*3117ece4Schristos MEM_writeLE32((char*)dst + cSize, checksum); 6941*3117ece4Schristos cSize += 4; 6942*3117ece4Schristos } 6943*3117ece4Schristos 6944*3117ece4Schristos DEBUGLOG(4, "Final compressed size: %zu", cSize); 6945*3117ece4Schristos return cSize; 6946*3117ece4Schristos } 6947*3117ece4Schristos 6948*3117ece4Schristos /*====== Finalize ======*/ 6949*3117ece4Schristos 6950*3117ece4Schristos static ZSTD_inBuffer inBuffer_forEndFlush(const ZSTD_CStream* zcs) 6951*3117ece4Schristos { 6952*3117ece4Schristos const ZSTD_inBuffer nullInput = { NULL, 0, 0 }; 6953*3117ece4Schristos const int stableInput = (zcs->appliedParams.inBufferMode == ZSTD_bm_stable); 6954*3117ece4Schristos return stableInput ? zcs->expectedInBuffer : nullInput; 6955*3117ece4Schristos } 6956*3117ece4Schristos 6957*3117ece4Schristos /*! ZSTD_flushStream() : 6958*3117ece4Schristos * @return : amount of data remaining to flush */ 6959*3117ece4Schristos size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 6960*3117ece4Schristos { 6961*3117ece4Schristos ZSTD_inBuffer input = inBuffer_forEndFlush(zcs); 6962*3117ece4Schristos input.size = input.pos; /* do not ingest more input during flush */ 6963*3117ece4Schristos return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush); 6964*3117ece4Schristos } 6965*3117ece4Schristos 6966*3117ece4Schristos 6967*3117ece4Schristos size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 6968*3117ece4Schristos { 6969*3117ece4Schristos ZSTD_inBuffer input = inBuffer_forEndFlush(zcs); 6970*3117ece4Schristos size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end); 6971*3117ece4Schristos FORWARD_IF_ERROR(remainingToFlush , "ZSTD_compressStream2(,,ZSTD_e_end) failed"); 6972*3117ece4Schristos if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */ 6973*3117ece4Schristos /* single thread mode : attempt to calculate remaining to flush more precisely */ 6974*3117ece4Schristos { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; 6975*3117ece4Schristos size_t const checksumSize = (size_t)(zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4); 6976*3117ece4Schristos size_t const toFlush = remainingToFlush + lastBlockSize + checksumSize; 6977*3117ece4Schristos DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (unsigned)toFlush); 6978*3117ece4Schristos return toFlush; 6979*3117ece4Schristos } 6980*3117ece4Schristos } 6981*3117ece4Schristos 6982*3117ece4Schristos 6983*3117ece4Schristos /*-===== Pre-defined compression levels =====-*/ 6984*3117ece4Schristos #include "clevels.h" 6985*3117ece4Schristos 6986*3117ece4Schristos int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } 6987*3117ece4Schristos int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; } 6988*3117ece4Schristos int ZSTD_defaultCLevel(void) { return ZSTD_CLEVEL_DEFAULT; } 6989*3117ece4Schristos 6990*3117ece4Schristos static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel, size_t const dictSize) 6991*3117ece4Schristos { 6992*3117ece4Schristos ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, 0, dictSize, ZSTD_cpm_createCDict); 6993*3117ece4Schristos switch (cParams.strategy) { 6994*3117ece4Schristos case ZSTD_fast: 6995*3117ece4Schristos case ZSTD_dfast: 6996*3117ece4Schristos break; 6997*3117ece4Schristos case ZSTD_greedy: 6998*3117ece4Schristos case ZSTD_lazy: 6999*3117ece4Schristos case ZSTD_lazy2: 7000*3117ece4Schristos cParams.hashLog += ZSTD_LAZY_DDSS_BUCKET_LOG; 7001*3117ece4Schristos break; 7002*3117ece4Schristos case ZSTD_btlazy2: 7003*3117ece4Schristos case ZSTD_btopt: 7004*3117ece4Schristos case ZSTD_btultra: 7005*3117ece4Schristos case ZSTD_btultra2: 7006*3117ece4Schristos break; 7007*3117ece4Schristos } 7008*3117ece4Schristos return cParams; 7009*3117ece4Schristos } 7010*3117ece4Schristos 7011*3117ece4Schristos static int ZSTD_dedicatedDictSearch_isSupported( 7012*3117ece4Schristos ZSTD_compressionParameters const* cParams) 7013*3117ece4Schristos { 7014*3117ece4Schristos return (cParams->strategy >= ZSTD_greedy) 7015*3117ece4Schristos && (cParams->strategy <= ZSTD_lazy2) 7016*3117ece4Schristos && (cParams->hashLog > cParams->chainLog) 7017*3117ece4Schristos && (cParams->chainLog <= 24); 7018*3117ece4Schristos } 7019*3117ece4Schristos 7020*3117ece4Schristos /** 7021*3117ece4Schristos * Reverses the adjustment applied to cparams when enabling dedicated dict 7022*3117ece4Schristos * search. This is used to recover the params set to be used in the working 7023*3117ece4Schristos * context. (Otherwise, those tables would also grow.) 7024*3117ece4Schristos */ 7025*3117ece4Schristos static void ZSTD_dedicatedDictSearch_revertCParams( 7026*3117ece4Schristos ZSTD_compressionParameters* cParams) { 7027*3117ece4Schristos switch (cParams->strategy) { 7028*3117ece4Schristos case ZSTD_fast: 7029*3117ece4Schristos case ZSTD_dfast: 7030*3117ece4Schristos break; 7031*3117ece4Schristos case ZSTD_greedy: 7032*3117ece4Schristos case ZSTD_lazy: 7033*3117ece4Schristos case ZSTD_lazy2: 7034*3117ece4Schristos cParams->hashLog -= ZSTD_LAZY_DDSS_BUCKET_LOG; 7035*3117ece4Schristos if (cParams->hashLog < ZSTD_HASHLOG_MIN) { 7036*3117ece4Schristos cParams->hashLog = ZSTD_HASHLOG_MIN; 7037*3117ece4Schristos } 7038*3117ece4Schristos break; 7039*3117ece4Schristos case ZSTD_btlazy2: 7040*3117ece4Schristos case ZSTD_btopt: 7041*3117ece4Schristos case ZSTD_btultra: 7042*3117ece4Schristos case ZSTD_btultra2: 7043*3117ece4Schristos break; 7044*3117ece4Schristos } 7045*3117ece4Schristos } 7046*3117ece4Schristos 7047*3117ece4Schristos static U64 ZSTD_getCParamRowSize(U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) 7048*3117ece4Schristos { 7049*3117ece4Schristos switch (mode) { 7050*3117ece4Schristos case ZSTD_cpm_unknown: 7051*3117ece4Schristos case ZSTD_cpm_noAttachDict: 7052*3117ece4Schristos case ZSTD_cpm_createCDict: 7053*3117ece4Schristos break; 7054*3117ece4Schristos case ZSTD_cpm_attachDict: 7055*3117ece4Schristos dictSize = 0; 7056*3117ece4Schristos break; 7057*3117ece4Schristos default: 7058*3117ece4Schristos assert(0); 7059*3117ece4Schristos break; 7060*3117ece4Schristos } 7061*3117ece4Schristos { int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN; 7062*3117ece4Schristos size_t const addedSize = unknown && dictSize > 0 ? 500 : 0; 7063*3117ece4Schristos return unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize; 7064*3117ece4Schristos } 7065*3117ece4Schristos } 7066*3117ece4Schristos 7067*3117ece4Schristos /*! ZSTD_getCParams_internal() : 7068*3117ece4Schristos * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. 7069*3117ece4Schristos * Note: srcSizeHint 0 means 0, use ZSTD_CONTENTSIZE_UNKNOWN for unknown. 7070*3117ece4Schristos * Use dictSize == 0 for unknown or unused. 7071*3117ece4Schristos * Note: `mode` controls how we treat the `dictSize`. See docs for `ZSTD_cParamMode_e`. */ 7072*3117ece4Schristos static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) 7073*3117ece4Schristos { 7074*3117ece4Schristos U64 const rSize = ZSTD_getCParamRowSize(srcSizeHint, dictSize, mode); 7075*3117ece4Schristos U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); 7076*3117ece4Schristos int row; 7077*3117ece4Schristos DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel); 7078*3117ece4Schristos 7079*3117ece4Schristos /* row */ 7080*3117ece4Schristos if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ 7081*3117ece4Schristos else if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ 7082*3117ece4Schristos else if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; 7083*3117ece4Schristos else row = compressionLevel; 7084*3117ece4Schristos 7085*3117ece4Schristos { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row]; 7086*3117ece4Schristos DEBUGLOG(5, "ZSTD_getCParams_internal selected tableID: %u row: %u strat: %u", tableID, row, (U32)cp.strategy); 7087*3117ece4Schristos /* acceleration factor */ 7088*3117ece4Schristos if (compressionLevel < 0) { 7089*3117ece4Schristos int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel); 7090*3117ece4Schristos cp.targetLength = (unsigned)(-clampedCompressionLevel); 7091*3117ece4Schristos } 7092*3117ece4Schristos /* refine parameters based on srcSize & dictSize */ 7093*3117ece4Schristos return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize, mode, ZSTD_ps_auto); 7094*3117ece4Schristos } 7095*3117ece4Schristos } 7096*3117ece4Schristos 7097*3117ece4Schristos /*! ZSTD_getCParams() : 7098*3117ece4Schristos * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. 7099*3117ece4Schristos * Size values are optional, provide 0 if not known or unused */ 7100*3117ece4Schristos ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) 7101*3117ece4Schristos { 7102*3117ece4Schristos if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN; 7103*3117ece4Schristos return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); 7104*3117ece4Schristos } 7105*3117ece4Schristos 7106*3117ece4Schristos /*! ZSTD_getParams() : 7107*3117ece4Schristos * same idea as ZSTD_getCParams() 7108*3117ece4Schristos * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). 7109*3117ece4Schristos * Fields of `ZSTD_frameParameters` are set to default values */ 7110*3117ece4Schristos static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) { 7111*3117ece4Schristos ZSTD_parameters params; 7112*3117ece4Schristos ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, mode); 7113*3117ece4Schristos DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel); 7114*3117ece4Schristos ZSTD_memset(¶ms, 0, sizeof(params)); 7115*3117ece4Schristos params.cParams = cParams; 7116*3117ece4Schristos params.fParams.contentSizeFlag = 1; 7117*3117ece4Schristos return params; 7118*3117ece4Schristos } 7119*3117ece4Schristos 7120*3117ece4Schristos /*! ZSTD_getParams() : 7121*3117ece4Schristos * same idea as ZSTD_getCParams() 7122*3117ece4Schristos * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). 7123*3117ece4Schristos * Fields of `ZSTD_frameParameters` are set to default values */ 7124*3117ece4Schristos ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { 7125*3117ece4Schristos if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN; 7126*3117ece4Schristos return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown); 7127*3117ece4Schristos } 7128*3117ece4Schristos 7129*3117ece4Schristos void ZSTD_registerSequenceProducer( 7130*3117ece4Schristos ZSTD_CCtx* zc, 7131*3117ece4Schristos void* extSeqProdState, 7132*3117ece4Schristos ZSTD_sequenceProducer_F extSeqProdFunc 7133*3117ece4Schristos ) { 7134*3117ece4Schristos assert(zc != NULL); 7135*3117ece4Schristos ZSTD_CCtxParams_registerSequenceProducer( 7136*3117ece4Schristos &zc->requestedParams, extSeqProdState, extSeqProdFunc 7137*3117ece4Schristos ); 7138*3117ece4Schristos } 7139*3117ece4Schristos 7140*3117ece4Schristos void ZSTD_CCtxParams_registerSequenceProducer( 7141*3117ece4Schristos ZSTD_CCtx_params* params, 7142*3117ece4Schristos void* extSeqProdState, 7143*3117ece4Schristos ZSTD_sequenceProducer_F extSeqProdFunc 7144*3117ece4Schristos ) { 7145*3117ece4Schristos assert(params != NULL); 7146*3117ece4Schristos if (extSeqProdFunc != NULL) { 7147*3117ece4Schristos params->extSeqProdFunc = extSeqProdFunc; 7148*3117ece4Schristos params->extSeqProdState = extSeqProdState; 7149*3117ece4Schristos } else { 7150*3117ece4Schristos params->extSeqProdFunc = NULL; 7151*3117ece4Schristos params->extSeqProdState = NULL; 7152*3117ece4Schristos } 7153*3117ece4Schristos } 7154