10c16b537SWarner Losh /* 20c16b537SWarner Losh * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. 30c16b537SWarner Losh * All rights reserved. 40c16b537SWarner Losh * 50c16b537SWarner Losh * This source code is licensed under both the BSD-style license (found in the 60c16b537SWarner Losh * LICENSE file in the root directory of this source tree) and the GPLv2 (found 70c16b537SWarner Losh * in the COPYING file in the root directory of this source tree). 80c16b537SWarner Losh * You may select, at your option, one of the above-listed licenses. 90c16b537SWarner Losh */ 100c16b537SWarner Losh 110c16b537SWarner Losh /*-************************************* 120c16b537SWarner Losh * Dependencies 130c16b537SWarner Losh ***************************************/ 14a0483764SConrad Meyer #include <limits.h> /* INT_MAX */ 150c16b537SWarner Losh #include <string.h> /* memset */ 1619fcbaf1SConrad Meyer #include "cpu.h" 170c16b537SWarner Losh #include "mem.h" 180f743729SConrad Meyer #include "hist.h" /* HIST_countFast_wksp */ 190c16b537SWarner Losh #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */ 200c16b537SWarner Losh #include "fse.h" 210c16b537SWarner Losh #define HUF_STATIC_LINKING_ONLY 220c16b537SWarner Losh #include "huf.h" 23052d3c12SConrad Meyer #include "zstd_compress_internal.h" 244d3f1eafSConrad Meyer #include "zstd_compress_sequences.h" 254d3f1eafSConrad Meyer #include "zstd_compress_literals.h" 260c16b537SWarner Losh #include "zstd_fast.h" 270c16b537SWarner Losh #include "zstd_double_fast.h" 280c16b537SWarner Losh #include "zstd_lazy.h" 290c16b537SWarner Losh #include "zstd_opt.h" 300c16b537SWarner Losh #include "zstd_ldm.h" 310c16b537SWarner Losh 320c16b537SWarner Losh 330c16b537SWarner Losh /*-************************************* 340c16b537SWarner Losh * Helper functions 350c16b537SWarner Losh ***************************************/ 360c16b537SWarner Losh size_t ZSTD_compressBound(size_t srcSize) { 370c16b537SWarner Losh return ZSTD_COMPRESSBOUND(srcSize); 380c16b537SWarner Losh } 390c16b537SWarner Losh 400c16b537SWarner Losh 410c16b537SWarner Losh /*-************************************* 420c16b537SWarner Losh * Context memory management 430c16b537SWarner Losh ***************************************/ 440c16b537SWarner Losh struct ZSTD_CDict_s { 450c16b537SWarner Losh const void* dictContent; 460c16b537SWarner Losh size_t dictContentSize; 47*9cbefe25SConrad Meyer U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */ 48*9cbefe25SConrad Meyer ZSTD_cwksp workspace; 4919fcbaf1SConrad Meyer ZSTD_matchState_t matchState; 5019fcbaf1SConrad Meyer ZSTD_compressedBlockState_t cBlockState; 5119fcbaf1SConrad Meyer ZSTD_customMem customMem; 5219fcbaf1SConrad Meyer U32 dictID; 53*9cbefe25SConrad Meyer int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */ 540c16b537SWarner Losh }; /* typedef'd to ZSTD_CDict within "zstd.h" */ 550c16b537SWarner Losh 560c16b537SWarner Losh ZSTD_CCtx* ZSTD_createCCtx(void) 570c16b537SWarner Losh { 580c16b537SWarner Losh return ZSTD_createCCtx_advanced(ZSTD_defaultCMem); 590c16b537SWarner Losh } 600c16b537SWarner Losh 610f743729SConrad Meyer static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager) 620f743729SConrad Meyer { 630f743729SConrad Meyer assert(cctx != NULL); 640f743729SConrad Meyer memset(cctx, 0, sizeof(*cctx)); 650f743729SConrad Meyer cctx->customMem = memManager; 660f743729SConrad Meyer cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); 67a0483764SConrad Meyer { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters); 680f743729SConrad Meyer assert(!ZSTD_isError(err)); 690f743729SConrad Meyer (void)err; 700f743729SConrad Meyer } 710f743729SConrad Meyer } 720f743729SConrad Meyer 730c16b537SWarner Losh ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) 740c16b537SWarner Losh { 7519fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(zcss_init==0); 7619fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); 770c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 780f743729SConrad Meyer { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem); 790c16b537SWarner Losh if (!cctx) return NULL; 800f743729SConrad Meyer ZSTD_initCCtx(cctx, customMem); 810c16b537SWarner Losh return cctx; 820c16b537SWarner Losh } 8319fcbaf1SConrad Meyer } 840c16b537SWarner Losh 850c16b537SWarner Losh ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize) 860c16b537SWarner Losh { 87*9cbefe25SConrad Meyer ZSTD_cwksp ws; 88*9cbefe25SConrad Meyer ZSTD_CCtx* cctx; 890c16b537SWarner Losh if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */ 900c16b537SWarner Losh if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */ 91*9cbefe25SConrad Meyer ZSTD_cwksp_init(&ws, workspace, workspaceSize); 92*9cbefe25SConrad Meyer 93*9cbefe25SConrad Meyer cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx)); 94*9cbefe25SConrad Meyer if (cctx == NULL) { 95*9cbefe25SConrad Meyer return NULL; 96*9cbefe25SConrad Meyer } 97*9cbefe25SConrad Meyer memset(cctx, 0, sizeof(ZSTD_CCtx)); 98*9cbefe25SConrad Meyer ZSTD_cwksp_move(&cctx->workspace, &ws); 990c16b537SWarner Losh cctx->staticSize = workspaceSize; 1000c16b537SWarner Losh 10119fcbaf1SConrad Meyer /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ 102*9cbefe25SConrad Meyer if (!ZSTD_cwksp_check_available(&cctx->workspace, HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL; 103*9cbefe25SConrad Meyer cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); 104*9cbefe25SConrad Meyer cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t)); 105*9cbefe25SConrad Meyer cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object( 106*9cbefe25SConrad Meyer &cctx->workspace, HUF_WORKSPACE_SIZE); 10719fcbaf1SConrad Meyer cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); 1080c16b537SWarner Losh return cctx; 1090c16b537SWarner Losh } 1100c16b537SWarner Losh 1112b9c00cbSConrad Meyer /** 1122b9c00cbSConrad Meyer * Clears and frees all of the dictionaries in the CCtx. 1132b9c00cbSConrad Meyer */ 1142b9c00cbSConrad Meyer static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx) 1152b9c00cbSConrad Meyer { 1162b9c00cbSConrad Meyer ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem); 1172b9c00cbSConrad Meyer ZSTD_freeCDict(cctx->localDict.cdict); 1182b9c00cbSConrad Meyer memset(&cctx->localDict, 0, sizeof(cctx->localDict)); 1192b9c00cbSConrad Meyer memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); 1202b9c00cbSConrad Meyer cctx->cdict = NULL; 1212b9c00cbSConrad Meyer } 1222b9c00cbSConrad Meyer 1232b9c00cbSConrad Meyer static size_t ZSTD_sizeof_localDict(ZSTD_localDict dict) 1242b9c00cbSConrad Meyer { 1252b9c00cbSConrad Meyer size_t const bufferSize = dict.dictBuffer != NULL ? dict.dictSize : 0; 1262b9c00cbSConrad Meyer size_t const cdictSize = ZSTD_sizeof_CDict(dict.cdict); 1272b9c00cbSConrad Meyer return bufferSize + cdictSize; 1282b9c00cbSConrad Meyer } 1292b9c00cbSConrad Meyer 1300f743729SConrad Meyer static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx) 1310c16b537SWarner Losh { 1320f743729SConrad Meyer assert(cctx != NULL); 1330f743729SConrad Meyer assert(cctx->staticSize == 0); 1342b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); 1350c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 13619fcbaf1SConrad Meyer ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL; 1370c16b537SWarner Losh #endif 138*9cbefe25SConrad Meyer ZSTD_cwksp_free(&cctx->workspace, cctx->customMem); 1390f743729SConrad Meyer } 1400f743729SConrad Meyer 1410f743729SConrad Meyer size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) 1420f743729SConrad Meyer { 1430f743729SConrad Meyer if (cctx==NULL) return 0; /* support free on NULL */ 1442b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->staticSize, memory_allocation, 1452b9c00cbSConrad Meyer "not compatible with static CCtx"); 146*9cbefe25SConrad Meyer { 147*9cbefe25SConrad Meyer int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx); 1480f743729SConrad Meyer ZSTD_freeCCtxContent(cctx); 149*9cbefe25SConrad Meyer if (!cctxInWorkspace) { 1500c16b537SWarner Losh ZSTD_free(cctx, cctx->customMem); 151*9cbefe25SConrad Meyer } 152*9cbefe25SConrad Meyer } 1530f743729SConrad Meyer return 0; 1540c16b537SWarner Losh } 1550c16b537SWarner Losh 1560c16b537SWarner Losh 1570c16b537SWarner Losh static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx) 1580c16b537SWarner Losh { 1590c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 1600c16b537SWarner Losh return ZSTDMT_sizeof_CCtx(cctx->mtctx); 1610c16b537SWarner Losh #else 1620c16b537SWarner Losh (void)cctx; 1630c16b537SWarner Losh return 0; 1640c16b537SWarner Losh #endif 1650c16b537SWarner Losh } 1660c16b537SWarner Losh 1670c16b537SWarner Losh 1680c16b537SWarner Losh size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) 1690c16b537SWarner Losh { 1700c16b537SWarner Losh if (cctx==NULL) return 0; /* support sizeof on NULL */ 171*9cbefe25SConrad Meyer /* cctx may be in the workspace */ 172*9cbefe25SConrad Meyer return (cctx->workspace.workspace == cctx ? 0 : sizeof(*cctx)) 173*9cbefe25SConrad Meyer + ZSTD_cwksp_sizeof(&cctx->workspace) 1742b9c00cbSConrad Meyer + ZSTD_sizeof_localDict(cctx->localDict) 1750c16b537SWarner Losh + ZSTD_sizeof_mtctx(cctx); 1760c16b537SWarner Losh } 1770c16b537SWarner Losh 1780c16b537SWarner Losh size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) 1790c16b537SWarner Losh { 1800c16b537SWarner Losh return ZSTD_sizeof_CCtx(zcs); /* same object */ 1810c16b537SWarner Losh } 1820c16b537SWarner Losh 1830c16b537SWarner Losh /* private API call, for dictBuilder only */ 1840c16b537SWarner Losh const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } 1850c16b537SWarner Losh 1860c16b537SWarner Losh static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( 1870c16b537SWarner Losh ZSTD_compressionParameters cParams) 1880c16b537SWarner Losh { 1890c16b537SWarner Losh ZSTD_CCtx_params cctxParams; 1900c16b537SWarner Losh memset(&cctxParams, 0, sizeof(cctxParams)); 1910c16b537SWarner Losh cctxParams.cParams = cParams; 19219fcbaf1SConrad Meyer cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 19319fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 19419fcbaf1SConrad Meyer cctxParams.fParams.contentSizeFlag = 1; 1950c16b537SWarner Losh return cctxParams; 1960c16b537SWarner Losh } 1970c16b537SWarner Losh 1980c16b537SWarner Losh static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced( 1990c16b537SWarner Losh ZSTD_customMem customMem) 2000c16b537SWarner Losh { 2010c16b537SWarner Losh ZSTD_CCtx_params* params; 2020c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 2030c16b537SWarner Losh params = (ZSTD_CCtx_params*)ZSTD_calloc( 2040c16b537SWarner Losh sizeof(ZSTD_CCtx_params), customMem); 2050c16b537SWarner Losh if (!params) { return NULL; } 2060c16b537SWarner Losh params->customMem = customMem; 2070c16b537SWarner Losh params->compressionLevel = ZSTD_CLEVEL_DEFAULT; 20819fcbaf1SConrad Meyer params->fParams.contentSizeFlag = 1; 2090c16b537SWarner Losh return params; 2100c16b537SWarner Losh } 2110c16b537SWarner Losh 2120c16b537SWarner Losh ZSTD_CCtx_params* ZSTD_createCCtxParams(void) 2130c16b537SWarner Losh { 2140c16b537SWarner Losh return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem); 2150c16b537SWarner Losh } 2160c16b537SWarner Losh 2170c16b537SWarner Losh size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) 2180c16b537SWarner Losh { 2190c16b537SWarner Losh if (params == NULL) { return 0; } 2200c16b537SWarner Losh ZSTD_free(params, params->customMem); 2210c16b537SWarner Losh return 0; 2220c16b537SWarner Losh } 2230c16b537SWarner Losh 22419fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params) 2250c16b537SWarner Losh { 22619fcbaf1SConrad Meyer return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); 2270c16b537SWarner Losh } 2280c16b537SWarner Losh 22919fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) { 2302b9c00cbSConrad Meyer RETURN_ERROR_IF(!cctxParams, GENERIC); 2310c16b537SWarner Losh memset(cctxParams, 0, sizeof(*cctxParams)); 2320c16b537SWarner Losh cctxParams->compressionLevel = compressionLevel; 23319fcbaf1SConrad Meyer cctxParams->fParams.contentSizeFlag = 1; 2340c16b537SWarner Losh return 0; 2350c16b537SWarner Losh } 2360c16b537SWarner Losh 23719fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) 2380c16b537SWarner Losh { 2392b9c00cbSConrad Meyer RETURN_ERROR_IF(!cctxParams, GENERIC); 2402b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) ); 2410c16b537SWarner Losh memset(cctxParams, 0, sizeof(*cctxParams)); 242*9cbefe25SConrad Meyer assert(!ZSTD_checkCParams(params.cParams)); 2430c16b537SWarner Losh cctxParams->cParams = params.cParams; 2440c16b537SWarner Losh cctxParams->fParams = params.fParams; 24519fcbaf1SConrad Meyer cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 2460c16b537SWarner Losh return 0; 2470c16b537SWarner Losh } 2480c16b537SWarner Losh 24919fcbaf1SConrad Meyer /* ZSTD_assignParamsToCCtxParams() : 25019fcbaf1SConrad Meyer * params is presumed valid at this stage */ 2510c16b537SWarner Losh static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( 252*9cbefe25SConrad Meyer const ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) 2530c16b537SWarner Losh { 254*9cbefe25SConrad Meyer ZSTD_CCtx_params ret = *cctxParams; 255*9cbefe25SConrad Meyer assert(!ZSTD_checkCParams(params.cParams)); 2560c16b537SWarner Losh ret.cParams = params.cParams; 2570c16b537SWarner Losh ret.fParams = params.fParams; 25819fcbaf1SConrad Meyer ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 2590c16b537SWarner Losh return ret; 2600c16b537SWarner Losh } 2610c16b537SWarner Losh 262a0483764SConrad Meyer ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) 263a0483764SConrad Meyer { 264a0483764SConrad Meyer ZSTD_bounds bounds = { 0, 0, 0 }; 265a0483764SConrad Meyer 266a0483764SConrad Meyer switch(param) 267a0483764SConrad Meyer { 268a0483764SConrad Meyer case ZSTD_c_compressionLevel: 269a0483764SConrad Meyer bounds.lowerBound = ZSTD_minCLevel(); 270a0483764SConrad Meyer bounds.upperBound = ZSTD_maxCLevel(); 271a0483764SConrad Meyer return bounds; 272a0483764SConrad Meyer 273a0483764SConrad Meyer case ZSTD_c_windowLog: 274a0483764SConrad Meyer bounds.lowerBound = ZSTD_WINDOWLOG_MIN; 275a0483764SConrad Meyer bounds.upperBound = ZSTD_WINDOWLOG_MAX; 276a0483764SConrad Meyer return bounds; 277a0483764SConrad Meyer 278a0483764SConrad Meyer case ZSTD_c_hashLog: 279a0483764SConrad Meyer bounds.lowerBound = ZSTD_HASHLOG_MIN; 280a0483764SConrad Meyer bounds.upperBound = ZSTD_HASHLOG_MAX; 281a0483764SConrad Meyer return bounds; 282a0483764SConrad Meyer 283a0483764SConrad Meyer case ZSTD_c_chainLog: 284a0483764SConrad Meyer bounds.lowerBound = ZSTD_CHAINLOG_MIN; 285a0483764SConrad Meyer bounds.upperBound = ZSTD_CHAINLOG_MAX; 286a0483764SConrad Meyer return bounds; 287a0483764SConrad Meyer 288a0483764SConrad Meyer case ZSTD_c_searchLog: 289a0483764SConrad Meyer bounds.lowerBound = ZSTD_SEARCHLOG_MIN; 290a0483764SConrad Meyer bounds.upperBound = ZSTD_SEARCHLOG_MAX; 291a0483764SConrad Meyer return bounds; 292a0483764SConrad Meyer 293a0483764SConrad Meyer case ZSTD_c_minMatch: 294a0483764SConrad Meyer bounds.lowerBound = ZSTD_MINMATCH_MIN; 295a0483764SConrad Meyer bounds.upperBound = ZSTD_MINMATCH_MAX; 296a0483764SConrad Meyer return bounds; 297a0483764SConrad Meyer 298a0483764SConrad Meyer case ZSTD_c_targetLength: 299a0483764SConrad Meyer bounds.lowerBound = ZSTD_TARGETLENGTH_MIN; 300a0483764SConrad Meyer bounds.upperBound = ZSTD_TARGETLENGTH_MAX; 301a0483764SConrad Meyer return bounds; 302a0483764SConrad Meyer 303a0483764SConrad Meyer case ZSTD_c_strategy: 304a0483764SConrad Meyer bounds.lowerBound = ZSTD_STRATEGY_MIN; 305a0483764SConrad Meyer bounds.upperBound = ZSTD_STRATEGY_MAX; 306a0483764SConrad Meyer return bounds; 307a0483764SConrad Meyer 308a0483764SConrad Meyer case ZSTD_c_contentSizeFlag: 309a0483764SConrad Meyer bounds.lowerBound = 0; 310a0483764SConrad Meyer bounds.upperBound = 1; 311a0483764SConrad Meyer return bounds; 312a0483764SConrad Meyer 313a0483764SConrad Meyer case ZSTD_c_checksumFlag: 314a0483764SConrad Meyer bounds.lowerBound = 0; 315a0483764SConrad Meyer bounds.upperBound = 1; 316a0483764SConrad Meyer return bounds; 317a0483764SConrad Meyer 318a0483764SConrad Meyer case ZSTD_c_dictIDFlag: 319a0483764SConrad Meyer bounds.lowerBound = 0; 320a0483764SConrad Meyer bounds.upperBound = 1; 321a0483764SConrad Meyer return bounds; 322a0483764SConrad Meyer 323a0483764SConrad Meyer case ZSTD_c_nbWorkers: 324a0483764SConrad Meyer bounds.lowerBound = 0; 325a0483764SConrad Meyer #ifdef ZSTD_MULTITHREAD 326a0483764SConrad Meyer bounds.upperBound = ZSTDMT_NBWORKERS_MAX; 327a0483764SConrad Meyer #else 328a0483764SConrad Meyer bounds.upperBound = 0; 329a0483764SConrad Meyer #endif 330a0483764SConrad Meyer return bounds; 331a0483764SConrad Meyer 332a0483764SConrad Meyer case ZSTD_c_jobSize: 333a0483764SConrad Meyer bounds.lowerBound = 0; 334a0483764SConrad Meyer #ifdef ZSTD_MULTITHREAD 335a0483764SConrad Meyer bounds.upperBound = ZSTDMT_JOBSIZE_MAX; 336a0483764SConrad Meyer #else 337a0483764SConrad Meyer bounds.upperBound = 0; 338a0483764SConrad Meyer #endif 339a0483764SConrad Meyer return bounds; 340a0483764SConrad Meyer 341a0483764SConrad Meyer case ZSTD_c_overlapLog: 342a0483764SConrad Meyer bounds.lowerBound = ZSTD_OVERLAPLOG_MIN; 343a0483764SConrad Meyer bounds.upperBound = ZSTD_OVERLAPLOG_MAX; 344a0483764SConrad Meyer return bounds; 345a0483764SConrad Meyer 346a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching: 347a0483764SConrad Meyer bounds.lowerBound = 0; 348a0483764SConrad Meyer bounds.upperBound = 1; 349a0483764SConrad Meyer return bounds; 350a0483764SConrad Meyer 351a0483764SConrad Meyer case ZSTD_c_ldmHashLog: 352a0483764SConrad Meyer bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN; 353a0483764SConrad Meyer bounds.upperBound = ZSTD_LDM_HASHLOG_MAX; 354a0483764SConrad Meyer return bounds; 355a0483764SConrad Meyer 356a0483764SConrad Meyer case ZSTD_c_ldmMinMatch: 357a0483764SConrad Meyer bounds.lowerBound = ZSTD_LDM_MINMATCH_MIN; 358a0483764SConrad Meyer bounds.upperBound = ZSTD_LDM_MINMATCH_MAX; 359a0483764SConrad Meyer return bounds; 360a0483764SConrad Meyer 361a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog: 362a0483764SConrad Meyer bounds.lowerBound = ZSTD_LDM_BUCKETSIZELOG_MIN; 363a0483764SConrad Meyer bounds.upperBound = ZSTD_LDM_BUCKETSIZELOG_MAX; 364a0483764SConrad Meyer return bounds; 365a0483764SConrad Meyer 366a0483764SConrad Meyer case ZSTD_c_ldmHashRateLog: 367a0483764SConrad Meyer bounds.lowerBound = ZSTD_LDM_HASHRATELOG_MIN; 368a0483764SConrad Meyer bounds.upperBound = ZSTD_LDM_HASHRATELOG_MAX; 369a0483764SConrad Meyer return bounds; 370a0483764SConrad Meyer 371a0483764SConrad Meyer /* experimental parameters */ 372a0483764SConrad Meyer case ZSTD_c_rsyncable: 373a0483764SConrad Meyer bounds.lowerBound = 0; 374a0483764SConrad Meyer bounds.upperBound = 1; 375a0483764SConrad Meyer return bounds; 376a0483764SConrad Meyer 377a0483764SConrad Meyer case ZSTD_c_forceMaxWindow : 378a0483764SConrad Meyer bounds.lowerBound = 0; 379a0483764SConrad Meyer bounds.upperBound = 1; 380a0483764SConrad Meyer return bounds; 381a0483764SConrad Meyer 382a0483764SConrad Meyer case ZSTD_c_format: 383a0483764SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless); 384a0483764SConrad Meyer bounds.lowerBound = ZSTD_f_zstd1; 385a0483764SConrad Meyer bounds.upperBound = ZSTD_f_zstd1_magicless; /* note : how to ensure at compile time that this is the highest value enum ? */ 386a0483764SConrad Meyer return bounds; 387a0483764SConrad Meyer 388a0483764SConrad Meyer case ZSTD_c_forceAttachDict: 389a0483764SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy); 390a0483764SConrad Meyer bounds.lowerBound = ZSTD_dictDefaultAttach; 391*9cbefe25SConrad Meyer bounds.upperBound = ZSTD_dictForceLoad; /* note : how to ensure at compile time that this is the highest value enum ? */ 392a0483764SConrad Meyer return bounds; 393a0483764SConrad Meyer 3942b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode: 3952b9c00cbSConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed); 3962b9c00cbSConrad Meyer bounds.lowerBound = ZSTD_lcm_auto; 3972b9c00cbSConrad Meyer bounds.upperBound = ZSTD_lcm_uncompressed; 3982b9c00cbSConrad Meyer return bounds; 3992b9c00cbSConrad Meyer 4004d3f1eafSConrad Meyer case ZSTD_c_targetCBlockSize: 4014d3f1eafSConrad Meyer bounds.lowerBound = ZSTD_TARGETCBLOCKSIZE_MIN; 4024d3f1eafSConrad Meyer bounds.upperBound = ZSTD_TARGETCBLOCKSIZE_MAX; 4034d3f1eafSConrad Meyer return bounds; 4044d3f1eafSConrad Meyer 405*9cbefe25SConrad Meyer case ZSTD_c_srcSizeHint: 406*9cbefe25SConrad Meyer bounds.lowerBound = ZSTD_SRCSIZEHINT_MIN; 407*9cbefe25SConrad Meyer bounds.upperBound = ZSTD_SRCSIZEHINT_MAX; 408*9cbefe25SConrad Meyer return bounds; 409*9cbefe25SConrad Meyer 410a0483764SConrad Meyer default: 411a0483764SConrad Meyer { ZSTD_bounds const boundError = { ERROR(parameter_unsupported), 0, 0 }; 412a0483764SConrad Meyer return boundError; 413a0483764SConrad Meyer } 414a0483764SConrad Meyer } 415a0483764SConrad Meyer } 416a0483764SConrad Meyer 4172b9c00cbSConrad Meyer /* ZSTD_cParam_clampBounds: 4182b9c00cbSConrad Meyer * Clamps the value into the bounded range. 4192b9c00cbSConrad Meyer */ 4202b9c00cbSConrad Meyer static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value) 4212b9c00cbSConrad Meyer { 4222b9c00cbSConrad Meyer ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); 4232b9c00cbSConrad Meyer if (ZSTD_isError(bounds.error)) return bounds.error; 4242b9c00cbSConrad Meyer if (*value < bounds.lowerBound) *value = bounds.lowerBound; 4252b9c00cbSConrad Meyer if (*value > bounds.upperBound) *value = bounds.upperBound; 4262b9c00cbSConrad Meyer return 0; 4272b9c00cbSConrad Meyer } 4282b9c00cbSConrad Meyer 429a0483764SConrad Meyer #define BOUNDCHECK(cParam, val) { \ 4302b9c00cbSConrad Meyer RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \ 4312b9c00cbSConrad Meyer parameter_outOfBound); \ 4322b9c00cbSConrad Meyer } 4330c16b537SWarner Losh 43419fcbaf1SConrad Meyer 43519fcbaf1SConrad Meyer static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) 43619fcbaf1SConrad Meyer { 43719fcbaf1SConrad Meyer switch(param) 43819fcbaf1SConrad Meyer { 439a0483764SConrad Meyer case ZSTD_c_compressionLevel: 440a0483764SConrad Meyer case ZSTD_c_hashLog: 441a0483764SConrad Meyer case ZSTD_c_chainLog: 442a0483764SConrad Meyer case ZSTD_c_searchLog: 443a0483764SConrad Meyer case ZSTD_c_minMatch: 444a0483764SConrad Meyer case ZSTD_c_targetLength: 445a0483764SConrad Meyer case ZSTD_c_strategy: 44619fcbaf1SConrad Meyer return 1; 44719fcbaf1SConrad Meyer 448a0483764SConrad Meyer case ZSTD_c_format: 449a0483764SConrad Meyer case ZSTD_c_windowLog: 450a0483764SConrad Meyer case ZSTD_c_contentSizeFlag: 451a0483764SConrad Meyer case ZSTD_c_checksumFlag: 452a0483764SConrad Meyer case ZSTD_c_dictIDFlag: 453a0483764SConrad Meyer case ZSTD_c_forceMaxWindow : 454a0483764SConrad Meyer case ZSTD_c_nbWorkers: 455a0483764SConrad Meyer case ZSTD_c_jobSize: 456a0483764SConrad Meyer case ZSTD_c_overlapLog: 457a0483764SConrad Meyer case ZSTD_c_rsyncable: 458a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching: 459a0483764SConrad Meyer case ZSTD_c_ldmHashLog: 460a0483764SConrad Meyer case ZSTD_c_ldmMinMatch: 461a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog: 462a0483764SConrad Meyer case ZSTD_c_ldmHashRateLog: 463a0483764SConrad Meyer case ZSTD_c_forceAttachDict: 4642b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode: 4654d3f1eafSConrad Meyer case ZSTD_c_targetCBlockSize: 466*9cbefe25SConrad Meyer case ZSTD_c_srcSizeHint: 46719fcbaf1SConrad Meyer default: 46819fcbaf1SConrad Meyer return 0; 46919fcbaf1SConrad Meyer } 47019fcbaf1SConrad Meyer } 47119fcbaf1SConrad Meyer 472a0483764SConrad Meyer size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) 4730c16b537SWarner Losh { 474a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setParameter (%i, %i)", (int)param, value); 47519fcbaf1SConrad Meyer if (cctx->streamStage != zcss_init) { 47619fcbaf1SConrad Meyer if (ZSTD_isUpdateAuthorized(param)) { 47719fcbaf1SConrad Meyer cctx->cParamsChanged = 1; 47819fcbaf1SConrad Meyer } else { 4792b9c00cbSConrad Meyer RETURN_ERROR(stage_wrong); 48019fcbaf1SConrad Meyer } } 4810c16b537SWarner Losh 4820c16b537SWarner Losh switch(param) 4830c16b537SWarner Losh { 4842b9c00cbSConrad Meyer case ZSTD_c_nbWorkers: 4852b9c00cbSConrad Meyer RETURN_ERROR_IF((value!=0) && cctx->staticSize, parameter_unsupported, 4862b9c00cbSConrad Meyer "MT not compatible with static alloc"); 4872b9c00cbSConrad Meyer break; 4880c16b537SWarner Losh 489a0483764SConrad Meyer case ZSTD_c_compressionLevel: 490a0483764SConrad Meyer case ZSTD_c_windowLog: 491a0483764SConrad Meyer case ZSTD_c_hashLog: 492a0483764SConrad Meyer case ZSTD_c_chainLog: 493a0483764SConrad Meyer case ZSTD_c_searchLog: 494a0483764SConrad Meyer case ZSTD_c_minMatch: 495a0483764SConrad Meyer case ZSTD_c_targetLength: 496a0483764SConrad Meyer case ZSTD_c_strategy: 4972b9c00cbSConrad Meyer case ZSTD_c_ldmHashRateLog: 4982b9c00cbSConrad Meyer case ZSTD_c_format: 499a0483764SConrad Meyer case ZSTD_c_contentSizeFlag: 500a0483764SConrad Meyer case ZSTD_c_checksumFlag: 501a0483764SConrad Meyer case ZSTD_c_dictIDFlag: 5022b9c00cbSConrad Meyer case ZSTD_c_forceMaxWindow: 503a0483764SConrad Meyer case ZSTD_c_forceAttachDict: 5042b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode: 505a0483764SConrad Meyer case ZSTD_c_jobSize: 506a0483764SConrad Meyer case ZSTD_c_overlapLog: 507a0483764SConrad Meyer case ZSTD_c_rsyncable: 508a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching: 509a0483764SConrad Meyer case ZSTD_c_ldmHashLog: 510a0483764SConrad Meyer case ZSTD_c_ldmMinMatch: 511a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog: 5124d3f1eafSConrad Meyer case ZSTD_c_targetCBlockSize: 513*9cbefe25SConrad Meyer case ZSTD_c_srcSizeHint: 5142b9c00cbSConrad Meyer break; 5150c16b537SWarner Losh 5162b9c00cbSConrad Meyer default: RETURN_ERROR(parameter_unsupported); 5170c16b537SWarner Losh } 5182b9c00cbSConrad Meyer return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value); 5190c16b537SWarner Losh } 5200c16b537SWarner Losh 5212b9c00cbSConrad Meyer size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, 522a0483764SConrad Meyer ZSTD_cParameter param, int value) 5230c16b537SWarner Losh { 5242b9c00cbSConrad Meyer DEBUGLOG(4, "ZSTD_CCtxParams_setParameter (%i, %i)", (int)param, value); 5250c16b537SWarner Losh switch(param) 5260c16b537SWarner Losh { 527a0483764SConrad Meyer case ZSTD_c_format : 528a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_format, value); 529052d3c12SConrad Meyer CCtxParams->format = (ZSTD_format_e)value; 530052d3c12SConrad Meyer return (size_t)CCtxParams->format; 5310c16b537SWarner Losh 532a0483764SConrad Meyer case ZSTD_c_compressionLevel : { 5332b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); 5342b9c00cbSConrad Meyer if (value) { /* 0 : does not change current level */ 5352b9c00cbSConrad Meyer CCtxParams->compressionLevel = value; 53619fcbaf1SConrad Meyer } 537*9cbefe25SConrad Meyer if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel; 53819fcbaf1SConrad Meyer return 0; /* return type (size_t) cannot represent negative values */ 53919fcbaf1SConrad Meyer } 5400c16b537SWarner Losh 541a0483764SConrad Meyer case ZSTD_c_windowLog : 542a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 543a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_windowLog, value); 544*9cbefe25SConrad Meyer CCtxParams->cParams.windowLog = (U32)value; 545052d3c12SConrad Meyer return CCtxParams->cParams.windowLog; 5460c16b537SWarner Losh 547a0483764SConrad Meyer case ZSTD_c_hashLog : 548a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 549a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_hashLog, value); 550*9cbefe25SConrad Meyer CCtxParams->cParams.hashLog = (U32)value; 551052d3c12SConrad Meyer return CCtxParams->cParams.hashLog; 5520c16b537SWarner Losh 553a0483764SConrad Meyer case ZSTD_c_chainLog : 554a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 555a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_chainLog, value); 556*9cbefe25SConrad Meyer CCtxParams->cParams.chainLog = (U32)value; 557052d3c12SConrad Meyer return CCtxParams->cParams.chainLog; 5580c16b537SWarner Losh 559a0483764SConrad Meyer case ZSTD_c_searchLog : 560a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 561a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_searchLog, value); 562*9cbefe25SConrad Meyer CCtxParams->cParams.searchLog = (U32)value; 563*9cbefe25SConrad Meyer return (size_t)value; 5640c16b537SWarner Losh 565a0483764SConrad Meyer case ZSTD_c_minMatch : 566a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 567a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_minMatch, value); 568a0483764SConrad Meyer CCtxParams->cParams.minMatch = value; 569a0483764SConrad Meyer return CCtxParams->cParams.minMatch; 5700c16b537SWarner Losh 571a0483764SConrad Meyer case ZSTD_c_targetLength : 572a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_targetLength, value); 573052d3c12SConrad Meyer CCtxParams->cParams.targetLength = value; 574052d3c12SConrad Meyer return CCtxParams->cParams.targetLength; 5750c16b537SWarner Losh 576a0483764SConrad Meyer case ZSTD_c_strategy : 577a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 578a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_strategy, value); 579052d3c12SConrad Meyer CCtxParams->cParams.strategy = (ZSTD_strategy)value; 580052d3c12SConrad Meyer return (size_t)CCtxParams->cParams.strategy; 5810c16b537SWarner Losh 582a0483764SConrad Meyer case ZSTD_c_contentSizeFlag : 5830c16b537SWarner Losh /* Content size written in frame header _when known_ (default:1) */ 584a0483764SConrad Meyer DEBUGLOG(4, "set content size flag = %u", (value!=0)); 585a0483764SConrad Meyer CCtxParams->fParams.contentSizeFlag = value != 0; 586052d3c12SConrad Meyer return CCtxParams->fParams.contentSizeFlag; 5870c16b537SWarner Losh 588a0483764SConrad Meyer case ZSTD_c_checksumFlag : 5890c16b537SWarner Losh /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ 590a0483764SConrad Meyer CCtxParams->fParams.checksumFlag = value != 0; 591052d3c12SConrad Meyer return CCtxParams->fParams.checksumFlag; 5920c16b537SWarner Losh 593a0483764SConrad Meyer case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ 594a0483764SConrad Meyer DEBUGLOG(4, "set dictIDFlag = %u", (value!=0)); 59519fcbaf1SConrad Meyer CCtxParams->fParams.noDictIDFlag = !value; 596052d3c12SConrad Meyer return !CCtxParams->fParams.noDictIDFlag; 5970c16b537SWarner Losh 598a0483764SConrad Meyer case ZSTD_c_forceMaxWindow : 599a0483764SConrad Meyer CCtxParams->forceWindow = (value != 0); 600052d3c12SConrad Meyer return CCtxParams->forceWindow; 6010c16b537SWarner Losh 602a0483764SConrad Meyer case ZSTD_c_forceAttachDict : { 603a0483764SConrad Meyer const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value; 604a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_forceAttachDict, pref); 605a0483764SConrad Meyer CCtxParams->attachDictPref = pref; 6060f743729SConrad Meyer return CCtxParams->attachDictPref; 607a0483764SConrad Meyer } 6080f743729SConrad Meyer 6092b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode : { 6102b9c00cbSConrad Meyer const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value; 6112b9c00cbSConrad Meyer BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm); 6122b9c00cbSConrad Meyer CCtxParams->literalCompressionMode = lcm; 6132b9c00cbSConrad Meyer return CCtxParams->literalCompressionMode; 6142b9c00cbSConrad Meyer } 6152b9c00cbSConrad Meyer 616a0483764SConrad Meyer case ZSTD_c_nbWorkers : 6170c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 6182b9c00cbSConrad Meyer RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 61919fcbaf1SConrad Meyer return 0; 6200c16b537SWarner Losh #else 6212b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); 6222b9c00cbSConrad Meyer CCtxParams->nbWorkers = value; 6232b9c00cbSConrad Meyer return CCtxParams->nbWorkers; 6240c16b537SWarner Losh #endif 6250c16b537SWarner Losh 626a0483764SConrad Meyer case ZSTD_c_jobSize : 6270c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 6282b9c00cbSConrad Meyer RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 6292b9c00cbSConrad Meyer return 0; 6300c16b537SWarner Losh #else 6312b9c00cbSConrad Meyer /* Adjust to the minimum non-default value. */ 6322b9c00cbSConrad Meyer if (value != 0 && value < ZSTDMT_JOBSIZE_MIN) 6332b9c00cbSConrad Meyer value = ZSTDMT_JOBSIZE_MIN; 6342b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); 6352b9c00cbSConrad Meyer assert(value >= 0); 6362b9c00cbSConrad Meyer CCtxParams->jobSize = value; 6372b9c00cbSConrad Meyer return CCtxParams->jobSize; 6380c16b537SWarner Losh #endif 6390c16b537SWarner Losh 640a0483764SConrad Meyer case ZSTD_c_overlapLog : 6410c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 6422b9c00cbSConrad Meyer RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 6432b9c00cbSConrad Meyer return 0; 6440c16b537SWarner Losh #else 6452b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value)); 6462b9c00cbSConrad Meyer CCtxParams->overlapLog = value; 6472b9c00cbSConrad Meyer return CCtxParams->overlapLog; 6480c16b537SWarner Losh #endif 6490c16b537SWarner Losh 650a0483764SConrad Meyer case ZSTD_c_rsyncable : 651a0483764SConrad Meyer #ifndef ZSTD_MULTITHREAD 6522b9c00cbSConrad Meyer RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 6532b9c00cbSConrad Meyer return 0; 654a0483764SConrad Meyer #else 6552b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value)); 6562b9c00cbSConrad Meyer CCtxParams->rsyncable = value; 6572b9c00cbSConrad Meyer return CCtxParams->rsyncable; 658a0483764SConrad Meyer #endif 659a0483764SConrad Meyer 660a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching : 661a0483764SConrad Meyer CCtxParams->ldmParams.enableLdm = (value!=0); 66219fcbaf1SConrad Meyer return CCtxParams->ldmParams.enableLdm; 6630c16b537SWarner Losh 664a0483764SConrad Meyer case ZSTD_c_ldmHashLog : 665a0483764SConrad Meyer if (value!=0) /* 0 ==> auto */ 666a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_ldmHashLog, value); 667052d3c12SConrad Meyer CCtxParams->ldmParams.hashLog = value; 668052d3c12SConrad Meyer return CCtxParams->ldmParams.hashLog; 6690c16b537SWarner Losh 670a0483764SConrad Meyer case ZSTD_c_ldmMinMatch : 671a0483764SConrad Meyer if (value!=0) /* 0 ==> default */ 672a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_ldmMinMatch, value); 673052d3c12SConrad Meyer CCtxParams->ldmParams.minMatchLength = value; 674052d3c12SConrad Meyer return CCtxParams->ldmParams.minMatchLength; 6750c16b537SWarner Losh 676a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog : 677a0483764SConrad Meyer if (value!=0) /* 0 ==> default */ 678a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value); 679052d3c12SConrad Meyer CCtxParams->ldmParams.bucketSizeLog = value; 68019fcbaf1SConrad Meyer return CCtxParams->ldmParams.bucketSizeLog; 6810c16b537SWarner Losh 682a0483764SConrad Meyer case ZSTD_c_ldmHashRateLog : 6832b9c00cbSConrad Meyer RETURN_ERROR_IF(value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN, 6842b9c00cbSConrad Meyer parameter_outOfBound); 685a0483764SConrad Meyer CCtxParams->ldmParams.hashRateLog = value; 686a0483764SConrad Meyer return CCtxParams->ldmParams.hashRateLog; 6870c16b537SWarner Losh 6884d3f1eafSConrad Meyer case ZSTD_c_targetCBlockSize : 6894d3f1eafSConrad Meyer if (value!=0) /* 0 ==> default */ 6904d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_targetCBlockSize, value); 6914d3f1eafSConrad Meyer CCtxParams->targetCBlockSize = value; 6924d3f1eafSConrad Meyer return CCtxParams->targetCBlockSize; 6934d3f1eafSConrad Meyer 694*9cbefe25SConrad Meyer case ZSTD_c_srcSizeHint : 695*9cbefe25SConrad Meyer if (value!=0) /* 0 ==> default */ 696*9cbefe25SConrad Meyer BOUNDCHECK(ZSTD_c_srcSizeHint, value); 697*9cbefe25SConrad Meyer CCtxParams->srcSizeHint = value; 698*9cbefe25SConrad Meyer return CCtxParams->srcSizeHint; 699*9cbefe25SConrad Meyer 7002b9c00cbSConrad Meyer default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); 7010c16b537SWarner Losh } 7020c16b537SWarner Losh } 7030c16b537SWarner Losh 704a0483764SConrad Meyer size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value) 7050f743729SConrad Meyer { 7062b9c00cbSConrad Meyer return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value); 7070f743729SConrad Meyer } 7080f743729SConrad Meyer 7092b9c00cbSConrad Meyer size_t ZSTD_CCtxParams_getParameter( 710a0483764SConrad Meyer ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value) 7110f743729SConrad Meyer { 7120f743729SConrad Meyer switch(param) 7130f743729SConrad Meyer { 714a0483764SConrad Meyer case ZSTD_c_format : 7150f743729SConrad Meyer *value = CCtxParams->format; 7160f743729SConrad Meyer break; 717a0483764SConrad Meyer case ZSTD_c_compressionLevel : 7180f743729SConrad Meyer *value = CCtxParams->compressionLevel; 7190f743729SConrad Meyer break; 720a0483764SConrad Meyer case ZSTD_c_windowLog : 7214d3f1eafSConrad Meyer *value = (int)CCtxParams->cParams.windowLog; 7220f743729SConrad Meyer break; 723a0483764SConrad Meyer case ZSTD_c_hashLog : 7244d3f1eafSConrad Meyer *value = (int)CCtxParams->cParams.hashLog; 7250f743729SConrad Meyer break; 726a0483764SConrad Meyer case ZSTD_c_chainLog : 7274d3f1eafSConrad Meyer *value = (int)CCtxParams->cParams.chainLog; 7280f743729SConrad Meyer break; 729a0483764SConrad Meyer case ZSTD_c_searchLog : 7300f743729SConrad Meyer *value = CCtxParams->cParams.searchLog; 7310f743729SConrad Meyer break; 732a0483764SConrad Meyer case ZSTD_c_minMatch : 733a0483764SConrad Meyer *value = CCtxParams->cParams.minMatch; 7340f743729SConrad Meyer break; 735a0483764SConrad Meyer case ZSTD_c_targetLength : 7360f743729SConrad Meyer *value = CCtxParams->cParams.targetLength; 7370f743729SConrad Meyer break; 738a0483764SConrad Meyer case ZSTD_c_strategy : 7390f743729SConrad Meyer *value = (unsigned)CCtxParams->cParams.strategy; 7400f743729SConrad Meyer break; 741a0483764SConrad Meyer case ZSTD_c_contentSizeFlag : 7420f743729SConrad Meyer *value = CCtxParams->fParams.contentSizeFlag; 7430f743729SConrad Meyer break; 744a0483764SConrad Meyer case ZSTD_c_checksumFlag : 7450f743729SConrad Meyer *value = CCtxParams->fParams.checksumFlag; 7460f743729SConrad Meyer break; 747a0483764SConrad Meyer case ZSTD_c_dictIDFlag : 7480f743729SConrad Meyer *value = !CCtxParams->fParams.noDictIDFlag; 7490f743729SConrad Meyer break; 750a0483764SConrad Meyer case ZSTD_c_forceMaxWindow : 7510f743729SConrad Meyer *value = CCtxParams->forceWindow; 7520f743729SConrad Meyer break; 753a0483764SConrad Meyer case ZSTD_c_forceAttachDict : 7540f743729SConrad Meyer *value = CCtxParams->attachDictPref; 7550f743729SConrad Meyer break; 7562b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode : 7572b9c00cbSConrad Meyer *value = CCtxParams->literalCompressionMode; 7582b9c00cbSConrad Meyer break; 759a0483764SConrad Meyer case ZSTD_c_nbWorkers : 7600f743729SConrad Meyer #ifndef ZSTD_MULTITHREAD 7610f743729SConrad Meyer assert(CCtxParams->nbWorkers == 0); 7620f743729SConrad Meyer #endif 7630f743729SConrad Meyer *value = CCtxParams->nbWorkers; 7640f743729SConrad Meyer break; 765a0483764SConrad Meyer case ZSTD_c_jobSize : 7660f743729SConrad Meyer #ifndef ZSTD_MULTITHREAD 7672b9c00cbSConrad Meyer RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 7680f743729SConrad Meyer #else 769a0483764SConrad Meyer assert(CCtxParams->jobSize <= INT_MAX); 770a0483764SConrad Meyer *value = (int)CCtxParams->jobSize; 7710f743729SConrad Meyer break; 7720f743729SConrad Meyer #endif 773a0483764SConrad Meyer case ZSTD_c_overlapLog : 7740f743729SConrad Meyer #ifndef ZSTD_MULTITHREAD 7752b9c00cbSConrad Meyer RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 7760f743729SConrad Meyer #else 777a0483764SConrad Meyer *value = CCtxParams->overlapLog; 7780f743729SConrad Meyer break; 7790f743729SConrad Meyer #endif 780a0483764SConrad Meyer case ZSTD_c_rsyncable : 781a0483764SConrad Meyer #ifndef ZSTD_MULTITHREAD 7822b9c00cbSConrad Meyer RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 783a0483764SConrad Meyer #else 784a0483764SConrad Meyer *value = CCtxParams->rsyncable; 785a0483764SConrad Meyer break; 786a0483764SConrad Meyer #endif 787a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching : 7880f743729SConrad Meyer *value = CCtxParams->ldmParams.enableLdm; 7890f743729SConrad Meyer break; 790a0483764SConrad Meyer case ZSTD_c_ldmHashLog : 7910f743729SConrad Meyer *value = CCtxParams->ldmParams.hashLog; 7920f743729SConrad Meyer break; 793a0483764SConrad Meyer case ZSTD_c_ldmMinMatch : 7940f743729SConrad Meyer *value = CCtxParams->ldmParams.minMatchLength; 7950f743729SConrad Meyer break; 796a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog : 7970f743729SConrad Meyer *value = CCtxParams->ldmParams.bucketSizeLog; 7980f743729SConrad Meyer break; 799a0483764SConrad Meyer case ZSTD_c_ldmHashRateLog : 800a0483764SConrad Meyer *value = CCtxParams->ldmParams.hashRateLog; 8010f743729SConrad Meyer break; 8024d3f1eafSConrad Meyer case ZSTD_c_targetCBlockSize : 8034d3f1eafSConrad Meyer *value = (int)CCtxParams->targetCBlockSize; 8044d3f1eafSConrad Meyer break; 805*9cbefe25SConrad Meyer case ZSTD_c_srcSizeHint : 806*9cbefe25SConrad Meyer *value = (int)CCtxParams->srcSizeHint; 807*9cbefe25SConrad Meyer break; 8082b9c00cbSConrad Meyer default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); 8090f743729SConrad Meyer } 8100f743729SConrad Meyer return 0; 8110f743729SConrad Meyer } 8120f743729SConrad Meyer 813052d3c12SConrad Meyer /** ZSTD_CCtx_setParametersUsingCCtxParams() : 814052d3c12SConrad Meyer * just applies `params` into `cctx` 815052d3c12SConrad Meyer * no action is performed, parameters are merely stored. 81619fcbaf1SConrad Meyer * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx. 81719fcbaf1SConrad Meyer * This is possible even if a compression is ongoing. 81819fcbaf1SConrad Meyer * In which case, new parameters will be applied on the fly, starting with next compression job. 8190c16b537SWarner Losh */ 8200c16b537SWarner Losh size_t ZSTD_CCtx_setParametersUsingCCtxParams( 8210c16b537SWarner Losh ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) 8220c16b537SWarner Losh { 8230f743729SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams"); 8242b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 8252b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->cdict, stage_wrong); 8260c16b537SWarner Losh 827052d3c12SConrad Meyer cctx->requestedParams = *params; 8280c16b537SWarner Losh return 0; 8290c16b537SWarner Losh } 8300c16b537SWarner Losh 8310c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) 8320c16b537SWarner Losh { 833052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize); 8342b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 8350c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; 8360c16b537SWarner Losh return 0; 8370c16b537SWarner Losh } 8380c16b537SWarner Losh 8392b9c00cbSConrad Meyer /** 8402b9c00cbSConrad Meyer * Initializes the local dict using the requested parameters. 8412b9c00cbSConrad Meyer * NOTE: This does not use the pledged src size, because it may be used for more 8422b9c00cbSConrad Meyer * than one compression. 8432b9c00cbSConrad Meyer */ 8442b9c00cbSConrad Meyer static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) 8452b9c00cbSConrad Meyer { 8462b9c00cbSConrad Meyer ZSTD_localDict* const dl = &cctx->localDict; 8472b9c00cbSConrad Meyer ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams( 8482b9c00cbSConrad Meyer &cctx->requestedParams, 0, dl->dictSize); 8492b9c00cbSConrad Meyer if (dl->dict == NULL) { 8502b9c00cbSConrad Meyer /* No local dictionary. */ 8512b9c00cbSConrad Meyer assert(dl->dictBuffer == NULL); 8522b9c00cbSConrad Meyer assert(dl->cdict == NULL); 8532b9c00cbSConrad Meyer assert(dl->dictSize == 0); 8542b9c00cbSConrad Meyer return 0; 8552b9c00cbSConrad Meyer } 8562b9c00cbSConrad Meyer if (dl->cdict != NULL) { 8572b9c00cbSConrad Meyer assert(cctx->cdict == dl->cdict); 8582b9c00cbSConrad Meyer /* Local dictionary already initialized. */ 8592b9c00cbSConrad Meyer return 0; 8602b9c00cbSConrad Meyer } 8612b9c00cbSConrad Meyer assert(dl->dictSize > 0); 8622b9c00cbSConrad Meyer assert(cctx->cdict == NULL); 8632b9c00cbSConrad Meyer assert(cctx->prefixDict.dict == NULL); 8642b9c00cbSConrad Meyer 8652b9c00cbSConrad Meyer dl->cdict = ZSTD_createCDict_advanced( 8662b9c00cbSConrad Meyer dl->dict, 8672b9c00cbSConrad Meyer dl->dictSize, 8682b9c00cbSConrad Meyer ZSTD_dlm_byRef, 8692b9c00cbSConrad Meyer dl->dictContentType, 8702b9c00cbSConrad Meyer cParams, 8712b9c00cbSConrad Meyer cctx->customMem); 8722b9c00cbSConrad Meyer RETURN_ERROR_IF(!dl->cdict, memory_allocation); 8732b9c00cbSConrad Meyer cctx->cdict = dl->cdict; 8742b9c00cbSConrad Meyer return 0; 8752b9c00cbSConrad Meyer } 8762b9c00cbSConrad Meyer 8770c16b537SWarner Losh size_t ZSTD_CCtx_loadDictionary_advanced( 8780c16b537SWarner Losh ZSTD_CCtx* cctx, const void* dict, size_t dictSize, 87919fcbaf1SConrad Meyer ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType) 8800c16b537SWarner Losh { 8812b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 8822b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->staticSize, memory_allocation, 8832b9c00cbSConrad Meyer "no malloc for static CCtx"); 884052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); 8852b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); /* in case one already exists */ 8862b9c00cbSConrad Meyer if (dict == NULL || dictSize == 0) /* no dictionary mode */ 8872b9c00cbSConrad Meyer return 0; 8882b9c00cbSConrad Meyer if (dictLoadMethod == ZSTD_dlm_byRef) { 8892b9c00cbSConrad Meyer cctx->localDict.dict = dict; 8900c16b537SWarner Losh } else { 8912b9c00cbSConrad Meyer void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem); 8922b9c00cbSConrad Meyer RETURN_ERROR_IF(!dictBuffer, memory_allocation); 8932b9c00cbSConrad Meyer memcpy(dictBuffer, dict, dictSize); 8942b9c00cbSConrad Meyer cctx->localDict.dictBuffer = dictBuffer; 8952b9c00cbSConrad Meyer cctx->localDict.dict = dictBuffer; 8960c16b537SWarner Losh } 8972b9c00cbSConrad Meyer cctx->localDict.dictSize = dictSize; 8982b9c00cbSConrad Meyer cctx->localDict.dictContentType = dictContentType; 8990c16b537SWarner Losh return 0; 9000c16b537SWarner Losh } 9010c16b537SWarner Losh 9020c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( 9030c16b537SWarner Losh ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 9040c16b537SWarner Losh { 9050c16b537SWarner Losh return ZSTD_CCtx_loadDictionary_advanced( 90619fcbaf1SConrad Meyer cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); 9070c16b537SWarner Losh } 9080c16b537SWarner Losh 9090c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 9100c16b537SWarner Losh { 9110c16b537SWarner Losh return ZSTD_CCtx_loadDictionary_advanced( 91219fcbaf1SConrad Meyer cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); 9130c16b537SWarner Losh } 9140c16b537SWarner Losh 9150c16b537SWarner Losh 9160c16b537SWarner Losh size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 9170c16b537SWarner Losh { 9182b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 9192b9c00cbSConrad Meyer /* Free the existing local cdict (if any) to save memory. */ 9202b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); 9210c16b537SWarner Losh cctx->cdict = cdict; 9220c16b537SWarner Losh return 0; 9230c16b537SWarner Losh } 9240c16b537SWarner Losh 9250c16b537SWarner Losh size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) 9260c16b537SWarner Losh { 92719fcbaf1SConrad Meyer return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent); 9280c16b537SWarner Losh } 9290c16b537SWarner Losh 9300c16b537SWarner Losh size_t ZSTD_CCtx_refPrefix_advanced( 93119fcbaf1SConrad Meyer ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) 9320c16b537SWarner Losh { 9332b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 9342b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); 9350c16b537SWarner Losh cctx->prefixDict.dict = prefix; 9360c16b537SWarner Losh cctx->prefixDict.dictSize = prefixSize; 93719fcbaf1SConrad Meyer cctx->prefixDict.dictContentType = dictContentType; 9380c16b537SWarner Losh return 0; 9390c16b537SWarner Losh } 9400c16b537SWarner Losh 9410f743729SConrad Meyer /*! ZSTD_CCtx_reset() : 9420f743729SConrad Meyer * Also dumps dictionary */ 943a0483764SConrad Meyer size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset) 9440c16b537SWarner Losh { 945a0483764SConrad Meyer if ( (reset == ZSTD_reset_session_only) 946a0483764SConrad Meyer || (reset == ZSTD_reset_session_and_parameters) ) { 9470c16b537SWarner Losh cctx->streamStage = zcss_init; 9480c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = 0; 9490c16b537SWarner Losh } 950a0483764SConrad Meyer if ( (reset == ZSTD_reset_parameters) 951a0483764SConrad Meyer || (reset == ZSTD_reset_session_and_parameters) ) { 9522b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 9532b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); 9540f743729SConrad Meyer return ZSTD_CCtxParams_reset(&cctx->requestedParams); 9550c16b537SWarner Losh } 956a0483764SConrad Meyer return 0; 957a0483764SConrad Meyer } 958a0483764SConrad Meyer 9590c16b537SWarner Losh 9600c16b537SWarner Losh /** ZSTD_checkCParams() : 9610c16b537SWarner Losh control CParam values remain within authorized range. 9620c16b537SWarner Losh @return : 0, or an error code if one value is beyond authorized range */ 9630c16b537SWarner Losh size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) 9640c16b537SWarner Losh { 9654d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_windowLog, (int)cParams.windowLog); 9664d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_chainLog, (int)cParams.chainLog); 9674d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_hashLog, (int)cParams.hashLog); 9684d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_searchLog, (int)cParams.searchLog); 9694d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_minMatch, (int)cParams.minMatch); 9704d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_targetLength,(int)cParams.targetLength); 971a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_strategy, cParams.strategy); 9720c16b537SWarner Losh return 0; 9730c16b537SWarner Losh } 9740c16b537SWarner Losh 9750c16b537SWarner Losh /** ZSTD_clampCParams() : 9760c16b537SWarner Losh * make CParam values within valid range. 9770c16b537SWarner Losh * @return : valid CParams */ 9780f743729SConrad Meyer static ZSTD_compressionParameters 9790f743729SConrad Meyer ZSTD_clampCParams(ZSTD_compressionParameters cParams) 9800c16b537SWarner Losh { 981a0483764SConrad Meyer # define CLAMP_TYPE(cParam, val, type) { \ 982a0483764SConrad Meyer ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \ 983a0483764SConrad Meyer if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \ 984a0483764SConrad Meyer else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \ 9850c16b537SWarner Losh } 9864d3f1eafSConrad Meyer # define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned) 987a0483764SConrad Meyer CLAMP(ZSTD_c_windowLog, cParams.windowLog); 988a0483764SConrad Meyer CLAMP(ZSTD_c_chainLog, cParams.chainLog); 989a0483764SConrad Meyer CLAMP(ZSTD_c_hashLog, cParams.hashLog); 990a0483764SConrad Meyer CLAMP(ZSTD_c_searchLog, cParams.searchLog); 991a0483764SConrad Meyer CLAMP(ZSTD_c_minMatch, cParams.minMatch); 992a0483764SConrad Meyer CLAMP(ZSTD_c_targetLength,cParams.targetLength); 993a0483764SConrad Meyer CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy); 9940c16b537SWarner Losh return cParams; 9950c16b537SWarner Losh } 9960c16b537SWarner Losh 9970c16b537SWarner Losh /** ZSTD_cycleLog() : 9980c16b537SWarner Losh * condition for correct operation : hashLog > 1 */ 9990c16b537SWarner Losh static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) 10000c16b537SWarner Losh { 10010c16b537SWarner Losh U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2); 10020c16b537SWarner Losh return hashLog - btScale; 10030c16b537SWarner Losh } 10040c16b537SWarner Losh 10050c16b537SWarner Losh /** ZSTD_adjustCParams_internal() : 10062b9c00cbSConrad Meyer * optimize `cPar` for a specified input (`srcSize` and `dictSize`). 10072b9c00cbSConrad Meyer * mostly downsize to reduce memory consumption and initialization latency. 10082b9c00cbSConrad Meyer * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known. 10092b9c00cbSConrad Meyer * note : for the time being, `srcSize==0` means "unknown" too, for compatibility with older convention. 10102b9c00cbSConrad Meyer * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */ 10110f743729SConrad Meyer static ZSTD_compressionParameters 10120f743729SConrad Meyer ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, 10130f743729SConrad Meyer unsigned long long srcSize, 10140f743729SConrad Meyer size_t dictSize) 10150c16b537SWarner Losh { 10160c16b537SWarner Losh static const U64 minSrcSize = 513; /* (1<<9) + 1 */ 10170c16b537SWarner Losh static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); 10180c16b537SWarner Losh assert(ZSTD_checkCParams(cPar)==0); 10190c16b537SWarner Losh 10202b9c00cbSConrad Meyer if (dictSize && (srcSize+1<2) /* ZSTD_CONTENTSIZE_UNKNOWN and 0 mean "unknown" */ ) 10210c16b537SWarner Losh srcSize = minSrcSize; /* presumed small when there is a dictionary */ 10220c16b537SWarner Losh else if (srcSize == 0) 10230c16b537SWarner Losh srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */ 10240c16b537SWarner Losh 10250c16b537SWarner Losh /* resize windowLog if input is small enough, to use less memory */ 10260c16b537SWarner Losh if ( (srcSize < maxWindowResize) 10270c16b537SWarner Losh && (dictSize < maxWindowResize) ) { 10280c16b537SWarner Losh U32 const tSize = (U32)(srcSize + dictSize); 10290c16b537SWarner Losh static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN; 10300c16b537SWarner Losh U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN : 10310c16b537SWarner Losh ZSTD_highbit32(tSize-1) + 1; 10320c16b537SWarner Losh if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; 10330c16b537SWarner Losh } 10340f743729SConrad Meyer if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1; 10350c16b537SWarner Losh { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); 10360c16b537SWarner Losh if (cycleLog > cPar.windowLog) 10370c16b537SWarner Losh cPar.chainLog -= (cycleLog - cPar.windowLog); 10380c16b537SWarner Losh } 10390c16b537SWarner Losh 10400c16b537SWarner Losh if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) 10412b9c00cbSConrad Meyer cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */ 10420c16b537SWarner Losh 10430c16b537SWarner Losh return cPar; 10440c16b537SWarner Losh } 10450c16b537SWarner Losh 10460f743729SConrad Meyer ZSTD_compressionParameters 10470f743729SConrad Meyer ZSTD_adjustCParams(ZSTD_compressionParameters cPar, 10480f743729SConrad Meyer unsigned long long srcSize, 10490f743729SConrad Meyer size_t dictSize) 10500c16b537SWarner Losh { 10512b9c00cbSConrad Meyer cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */ 10520c16b537SWarner Losh return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); 10530c16b537SWarner Losh } 10540c16b537SWarner Losh 10550f743729SConrad Meyer ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( 10560f743729SConrad Meyer const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize) 10570f743729SConrad Meyer { 1058*9cbefe25SConrad Meyer ZSTD_compressionParameters cParams; 1059*9cbefe25SConrad Meyer if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) { 1060*9cbefe25SConrad Meyer srcSizeHint = CCtxParams->srcSizeHint; 1061*9cbefe25SConrad Meyer } 1062*9cbefe25SConrad Meyer cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize); 10630f743729SConrad Meyer if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; 10640f743729SConrad Meyer if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog; 10650f743729SConrad Meyer if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog; 10660f743729SConrad Meyer if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog; 10670f743729SConrad Meyer if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog; 1068a0483764SConrad Meyer if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch; 10690f743729SConrad Meyer if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength; 10700f743729SConrad Meyer if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy; 10710f743729SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 10720f743729SConrad Meyer return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize); 10730f743729SConrad Meyer } 10740f743729SConrad Meyer 10750f743729SConrad Meyer static size_t 10760f743729SConrad Meyer ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, 10770f743729SConrad Meyer const U32 forCCtx) 107819fcbaf1SConrad Meyer { 107919fcbaf1SConrad Meyer size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); 108019fcbaf1SConrad Meyer size_t const hSize = ((size_t)1) << cParams->hashLog; 1081a0483764SConrad Meyer U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 1082*9cbefe25SConrad Meyer size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; 1083*9cbefe25SConrad Meyer /* We don't use ZSTD_cwksp_alloc_size() here because the tables aren't 1084*9cbefe25SConrad Meyer * surrounded by redzones in ASAN. */ 1085*9cbefe25SConrad Meyer size_t const tableSpace = chainSize * sizeof(U32) 1086*9cbefe25SConrad Meyer + hSize * sizeof(U32) 1087*9cbefe25SConrad Meyer + h3Size * sizeof(U32); 1088*9cbefe25SConrad Meyer size_t const optPotentialSpace = 1089*9cbefe25SConrad Meyer ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32)) 1090*9cbefe25SConrad Meyer + ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32)) 1091*9cbefe25SConrad Meyer + ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32)) 1092*9cbefe25SConrad Meyer + ZSTD_cwksp_alloc_size((1<<Litbits) * sizeof(U32)) 1093*9cbefe25SConrad Meyer + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t)) 1094*9cbefe25SConrad Meyer + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t)); 1095a0483764SConrad Meyer size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt)) 109619fcbaf1SConrad Meyer ? optPotentialSpace 109719fcbaf1SConrad Meyer : 0; 109819fcbaf1SConrad Meyer DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u", 109919fcbaf1SConrad Meyer (U32)chainSize, (U32)hSize, (U32)h3Size); 110019fcbaf1SConrad Meyer return tableSpace + optSpace; 110119fcbaf1SConrad Meyer } 110219fcbaf1SConrad Meyer 11030c16b537SWarner Losh size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) 11040c16b537SWarner Losh { 11052b9c00cbSConrad Meyer RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); 11060c16b537SWarner Losh { ZSTD_compressionParameters const cParams = 110719fcbaf1SConrad Meyer ZSTD_getCParamsFromCCtxParams(params, 0, 0); 11080c16b537SWarner Losh size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); 1109a0483764SConrad Meyer U32 const divider = (cParams.minMatch==3) ? 3 : 4; 11100c16b537SWarner Losh size_t const maxNbSeq = blockSize / divider; 1111*9cbefe25SConrad Meyer size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) 1112*9cbefe25SConrad Meyer + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef)) 1113*9cbefe25SConrad Meyer + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); 1114*9cbefe25SConrad Meyer size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE); 1115*9cbefe25SConrad Meyer size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); 111619fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1); 11170c16b537SWarner Losh 111819fcbaf1SConrad Meyer size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams); 1119*9cbefe25SConrad Meyer size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq)); 11200c16b537SWarner Losh 112119fcbaf1SConrad Meyer size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace + 112219fcbaf1SConrad Meyer matchStateSize + ldmSpace + ldmSeqSpace; 1123*9cbefe25SConrad Meyer size_t const cctxSpace = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)); 11240c16b537SWarner Losh 1125*9cbefe25SConrad Meyer DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)cctxSpace); 1126*9cbefe25SConrad Meyer DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace); 1127*9cbefe25SConrad Meyer return cctxSpace + neededSpace; 11280c16b537SWarner Losh } 11290c16b537SWarner Losh } 11300c16b537SWarner Losh 11310c16b537SWarner Losh size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) 11320c16b537SWarner Losh { 11330c16b537SWarner Losh ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); 11340c16b537SWarner Losh return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms); 11350c16b537SWarner Losh } 11360c16b537SWarner Losh 113719fcbaf1SConrad Meyer static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) 11380c16b537SWarner Losh { 11390c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); 11400c16b537SWarner Losh return ZSTD_estimateCCtxSize_usingCParams(cParams); 11410c16b537SWarner Losh } 11420c16b537SWarner Losh 114319fcbaf1SConrad Meyer size_t ZSTD_estimateCCtxSize(int compressionLevel) 114419fcbaf1SConrad Meyer { 114519fcbaf1SConrad Meyer int level; 114619fcbaf1SConrad Meyer size_t memBudget = 0; 1147a0483764SConrad Meyer for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { 114819fcbaf1SConrad Meyer size_t const newMB = ZSTD_estimateCCtxSize_internal(level); 114919fcbaf1SConrad Meyer if (newMB > memBudget) memBudget = newMB; 115019fcbaf1SConrad Meyer } 115119fcbaf1SConrad Meyer return memBudget; 115219fcbaf1SConrad Meyer } 115319fcbaf1SConrad Meyer 11540c16b537SWarner Losh size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) 11550c16b537SWarner Losh { 11562b9c00cbSConrad Meyer RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); 11572b9c00cbSConrad Meyer { ZSTD_compressionParameters const cParams = 11582b9c00cbSConrad Meyer ZSTD_getCParamsFromCCtxParams(params, 0, 0); 11592b9c00cbSConrad Meyer size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params); 11602b9c00cbSConrad Meyer size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); 11612b9c00cbSConrad Meyer size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize; 11620c16b537SWarner Losh size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; 1163*9cbefe25SConrad Meyer size_t const streamingSize = ZSTD_cwksp_alloc_size(inBuffSize) 1164*9cbefe25SConrad Meyer + ZSTD_cwksp_alloc_size(outBuffSize); 11650c16b537SWarner Losh 11660c16b537SWarner Losh return CCtxSize + streamingSize; 11670c16b537SWarner Losh } 11680c16b537SWarner Losh } 11690c16b537SWarner Losh 11700c16b537SWarner Losh size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) 11710c16b537SWarner Losh { 11720c16b537SWarner Losh ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); 11730c16b537SWarner Losh return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms); 11740c16b537SWarner Losh } 11750c16b537SWarner Losh 11760f743729SConrad Meyer static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) 11770f743729SConrad Meyer { 11780c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); 11790c16b537SWarner Losh return ZSTD_estimateCStreamSize_usingCParams(cParams); 11800c16b537SWarner Losh } 11810c16b537SWarner Losh 11820f743729SConrad Meyer size_t ZSTD_estimateCStreamSize(int compressionLevel) 11830f743729SConrad Meyer { 118419fcbaf1SConrad Meyer int level; 118519fcbaf1SConrad Meyer size_t memBudget = 0; 1186a0483764SConrad Meyer for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { 118719fcbaf1SConrad Meyer size_t const newMB = ZSTD_estimateCStreamSize_internal(level); 118819fcbaf1SConrad Meyer if (newMB > memBudget) memBudget = newMB; 118919fcbaf1SConrad Meyer } 119019fcbaf1SConrad Meyer return memBudget; 119119fcbaf1SConrad Meyer } 119219fcbaf1SConrad Meyer 119319fcbaf1SConrad Meyer /* ZSTD_getFrameProgression(): 119419fcbaf1SConrad Meyer * tells how much data has been consumed (input) and produced (output) for current frame. 119519fcbaf1SConrad Meyer * able to count progression inside worker threads (non-blocking mode). 119619fcbaf1SConrad Meyer */ 119719fcbaf1SConrad Meyer ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx) 119819fcbaf1SConrad Meyer { 119919fcbaf1SConrad Meyer #ifdef ZSTD_MULTITHREAD 120019fcbaf1SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 120119fcbaf1SConrad Meyer return ZSTDMT_getFrameProgression(cctx->mtctx); 120219fcbaf1SConrad Meyer } 120319fcbaf1SConrad Meyer #endif 120419fcbaf1SConrad Meyer { ZSTD_frameProgression fp; 120519fcbaf1SConrad Meyer size_t const buffered = (cctx->inBuff == NULL) ? 0 : 120619fcbaf1SConrad Meyer cctx->inBuffPos - cctx->inToCompress; 120719fcbaf1SConrad Meyer if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress); 120819fcbaf1SConrad Meyer assert(buffered <= ZSTD_BLOCKSIZE_MAX); 120919fcbaf1SConrad Meyer fp.ingested = cctx->consumedSrcSize + buffered; 121019fcbaf1SConrad Meyer fp.consumed = cctx->consumedSrcSize; 121119fcbaf1SConrad Meyer fp.produced = cctx->producedCSize; 12120f743729SConrad Meyer fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */ 12130f743729SConrad Meyer fp.currentJobID = 0; 12140f743729SConrad Meyer fp.nbActiveWorkers = 0; 121519fcbaf1SConrad Meyer return fp; 121619fcbaf1SConrad Meyer } } 121719fcbaf1SConrad Meyer 12180f743729SConrad Meyer /*! ZSTD_toFlushNow() 12190f743729SConrad Meyer * Only useful for multithreading scenarios currently (nbWorkers >= 1). 12200f743729SConrad Meyer */ 12210f743729SConrad Meyer size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx) 12220f743729SConrad Meyer { 12230f743729SConrad Meyer #ifdef ZSTD_MULTITHREAD 12240f743729SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 12250f743729SConrad Meyer return ZSTDMT_toFlushNow(cctx->mtctx); 12260f743729SConrad Meyer } 12270f743729SConrad Meyer #endif 12280f743729SConrad Meyer (void)cctx; 12290f743729SConrad Meyer 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 */ 12300f743729SConrad Meyer } 12310f743729SConrad Meyer 12320f743729SConrad Meyer static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1, 12330f743729SConrad Meyer ZSTD_compressionParameters cParams2) 12340f743729SConrad Meyer { 12350f743729SConrad Meyer (void)cParams1; 12360f743729SConrad Meyer (void)cParams2; 12370f743729SConrad Meyer assert(cParams1.windowLog == cParams2.windowLog); 12380f743729SConrad Meyer assert(cParams1.chainLog == cParams2.chainLog); 12390f743729SConrad Meyer assert(cParams1.hashLog == cParams2.hashLog); 12400f743729SConrad Meyer assert(cParams1.searchLog == cParams2.searchLog); 1241a0483764SConrad Meyer assert(cParams1.minMatch == cParams2.minMatch); 12420f743729SConrad Meyer assert(cParams1.targetLength == cParams2.targetLength); 12430f743729SConrad Meyer assert(cParams1.strategy == cParams2.strategy); 12440f743729SConrad Meyer } 12450f743729SConrad Meyer 124619fcbaf1SConrad Meyer static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) 124719fcbaf1SConrad Meyer { 124819fcbaf1SConrad Meyer int i; 124919fcbaf1SConrad Meyer for (i = 0; i < ZSTD_REP_NUM; ++i) 125019fcbaf1SConrad Meyer bs->rep[i] = repStartValue[i]; 12510f743729SConrad Meyer bs->entropy.huf.repeatMode = HUF_repeat_none; 12520f743729SConrad Meyer bs->entropy.fse.offcode_repeatMode = FSE_repeat_none; 12530f743729SConrad Meyer bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none; 12540f743729SConrad Meyer bs->entropy.fse.litlength_repeatMode = FSE_repeat_none; 125519fcbaf1SConrad Meyer } 125619fcbaf1SConrad Meyer 125719fcbaf1SConrad Meyer /*! ZSTD_invalidateMatchState() 125819fcbaf1SConrad Meyer * Invalidate all the matches in the match finder tables. 125919fcbaf1SConrad Meyer * Requires nextSrc and base to be set (can be NULL). 126019fcbaf1SConrad Meyer */ 126119fcbaf1SConrad Meyer static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms) 126219fcbaf1SConrad Meyer { 126319fcbaf1SConrad Meyer ZSTD_window_clear(&ms->window); 126419fcbaf1SConrad Meyer 1265a0483764SConrad Meyer ms->nextToUpdate = ms->window.dictLimit; 126619fcbaf1SConrad Meyer ms->loadedDictEnd = 0; 126719fcbaf1SConrad Meyer ms->opt.litLengthSum = 0; /* force reset of btopt stats */ 12680f743729SConrad Meyer ms->dictMatchState = NULL; 126919fcbaf1SConrad Meyer } 127019fcbaf1SConrad Meyer 1271*9cbefe25SConrad Meyer /** 1272*9cbefe25SConrad Meyer * Indicates whether this compression proceeds directly from user-provided 1273*9cbefe25SConrad Meyer * source buffer to user-provided destination buffer (ZSTDb_not_buffered), or 1274*9cbefe25SConrad Meyer * whether the context needs to buffer the input/output (ZSTDb_buffered). 1275*9cbefe25SConrad Meyer */ 1276*9cbefe25SConrad Meyer typedef enum { 1277*9cbefe25SConrad Meyer ZSTDb_not_buffered, 1278*9cbefe25SConrad Meyer ZSTDb_buffered 1279*9cbefe25SConrad Meyer } ZSTD_buffered_policy_e; 1280052d3c12SConrad Meyer 1281*9cbefe25SConrad Meyer /** 1282*9cbefe25SConrad Meyer * Controls, for this matchState reset, whether the tables need to be cleared / 1283*9cbefe25SConrad Meyer * prepared for the coming compression (ZSTDcrp_makeClean), or whether the 1284*9cbefe25SConrad Meyer * tables can be left unclean (ZSTDcrp_leaveDirty), because we know that a 1285*9cbefe25SConrad Meyer * subsequent operation will overwrite the table space anyways (e.g., copying 1286*9cbefe25SConrad Meyer * the matchState contents in from a CDict). 1287*9cbefe25SConrad Meyer */ 1288*9cbefe25SConrad Meyer typedef enum { 1289*9cbefe25SConrad Meyer ZSTDcrp_makeClean, 1290*9cbefe25SConrad Meyer ZSTDcrp_leaveDirty 1291*9cbefe25SConrad Meyer } ZSTD_compResetPolicy_e; 12920c16b537SWarner Losh 1293*9cbefe25SConrad Meyer /** 1294*9cbefe25SConrad Meyer * Controls, for this matchState reset, whether indexing can continue where it 1295*9cbefe25SConrad Meyer * left off (ZSTDirp_continue), or whether it needs to be restarted from zero 1296*9cbefe25SConrad Meyer * (ZSTDirp_reset). 1297*9cbefe25SConrad Meyer */ 1298*9cbefe25SConrad Meyer typedef enum { 1299*9cbefe25SConrad Meyer ZSTDirp_continue, 1300*9cbefe25SConrad Meyer ZSTDirp_reset 1301*9cbefe25SConrad Meyer } ZSTD_indexResetPolicy_e; 13020c16b537SWarner Losh 1303*9cbefe25SConrad Meyer typedef enum { 1304*9cbefe25SConrad Meyer ZSTD_resetTarget_CDict, 1305*9cbefe25SConrad Meyer ZSTD_resetTarget_CCtx 1306*9cbefe25SConrad Meyer } ZSTD_resetTarget_e; 13074d3f1eafSConrad Meyer 1308*9cbefe25SConrad Meyer static size_t 13090f743729SConrad Meyer ZSTD_reset_matchState(ZSTD_matchState_t* ms, 1310*9cbefe25SConrad Meyer ZSTD_cwksp* ws, 13110f743729SConrad Meyer const ZSTD_compressionParameters* cParams, 1312*9cbefe25SConrad Meyer const ZSTD_compResetPolicy_e crp, 1313*9cbefe25SConrad Meyer const ZSTD_indexResetPolicy_e forceResetIndex, 1314*9cbefe25SConrad Meyer const ZSTD_resetTarget_e forWho) 131519fcbaf1SConrad Meyer { 131619fcbaf1SConrad Meyer size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); 131719fcbaf1SConrad Meyer size_t const hSize = ((size_t)1) << cParams->hashLog; 13184d3f1eafSConrad Meyer U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 1319*9cbefe25SConrad Meyer size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0; 132019fcbaf1SConrad Meyer 1321*9cbefe25SConrad Meyer DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset); 1322*9cbefe25SConrad Meyer if (forceResetIndex == ZSTDirp_reset) { 132319fcbaf1SConrad Meyer memset(&ms->window, 0, sizeof(ms->window)); 13240f743729SConrad Meyer ms->window.dictLimit = 1; /* start from 1, so that 1st position is valid */ 13250f743729SConrad Meyer ms->window.lowLimit = 1; /* it ensures first and later CCtx usages compress the same */ 13260f743729SConrad Meyer ms->window.nextSrc = ms->window.base + 1; /* see issue #1241 */ 1327*9cbefe25SConrad Meyer ZSTD_cwksp_mark_tables_dirty(ws); 1328*9cbefe25SConrad Meyer } 1329*9cbefe25SConrad Meyer 1330*9cbefe25SConrad Meyer ms->hashLog3 = hashLog3; 1331*9cbefe25SConrad Meyer 133219fcbaf1SConrad Meyer ZSTD_invalidateMatchState(ms); 133319fcbaf1SConrad Meyer 1334*9cbefe25SConrad Meyer assert(!ZSTD_cwksp_reserve_failed(ws)); /* check that allocation hasn't already failed */ 1335*9cbefe25SConrad Meyer 1336*9cbefe25SConrad Meyer ZSTD_cwksp_clear_tables(ws); 1337*9cbefe25SConrad Meyer 1338*9cbefe25SConrad Meyer DEBUGLOG(5, "reserving table space"); 1339*9cbefe25SConrad Meyer /* table Space */ 1340*9cbefe25SConrad Meyer ms->hashTable = (U32*)ZSTD_cwksp_reserve_table(ws, hSize * sizeof(U32)); 1341*9cbefe25SConrad Meyer ms->chainTable = (U32*)ZSTD_cwksp_reserve_table(ws, chainSize * sizeof(U32)); 1342*9cbefe25SConrad Meyer ms->hashTable3 = (U32*)ZSTD_cwksp_reserve_table(ws, h3Size * sizeof(U32)); 1343*9cbefe25SConrad Meyer RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation, 1344*9cbefe25SConrad Meyer "failed a workspace allocation in ZSTD_reset_matchState"); 1345*9cbefe25SConrad Meyer 1346*9cbefe25SConrad Meyer DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_leaveDirty); 1347*9cbefe25SConrad Meyer if (crp!=ZSTDcrp_leaveDirty) { 1348*9cbefe25SConrad Meyer /* reset tables only */ 1349*9cbefe25SConrad Meyer ZSTD_cwksp_clean_tables(ws); 1350*9cbefe25SConrad Meyer } 1351*9cbefe25SConrad Meyer 135219fcbaf1SConrad Meyer /* opt parser space */ 13534d3f1eafSConrad Meyer if ((forWho == ZSTD_resetTarget_CCtx) && (cParams->strategy >= ZSTD_btopt)) { 135419fcbaf1SConrad Meyer DEBUGLOG(4, "reserving optimal parser space"); 1355*9cbefe25SConrad Meyer ms->opt.litFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (1<<Litbits) * sizeof(unsigned)); 1356*9cbefe25SConrad Meyer ms->opt.litLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxLL+1) * sizeof(unsigned)); 1357*9cbefe25SConrad Meyer ms->opt.matchLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxML+1) * sizeof(unsigned)); 1358*9cbefe25SConrad Meyer ms->opt.offCodeFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxOff+1) * sizeof(unsigned)); 1359*9cbefe25SConrad Meyer ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t)); 1360*9cbefe25SConrad Meyer ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t)); 136119fcbaf1SConrad Meyer } 136219fcbaf1SConrad Meyer 13630f743729SConrad Meyer ms->cParams = *cParams; 13640f743729SConrad Meyer 1365*9cbefe25SConrad Meyer RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation, 1366*9cbefe25SConrad Meyer "failed a workspace allocation in ZSTD_reset_matchState"); 1367*9cbefe25SConrad Meyer 1368*9cbefe25SConrad Meyer return 0; 136919fcbaf1SConrad Meyer } 137019fcbaf1SConrad Meyer 13714d3f1eafSConrad Meyer /* ZSTD_indexTooCloseToMax() : 13724d3f1eafSConrad Meyer * minor optimization : prefer memset() rather than reduceIndex() 13734d3f1eafSConrad Meyer * which is measurably slow in some circumstances (reported for Visual Studio). 13744d3f1eafSConrad Meyer * Works when re-using a context for a lot of smallish inputs : 13754d3f1eafSConrad Meyer * if all inputs are smaller than ZSTD_INDEXOVERFLOW_MARGIN, 13764d3f1eafSConrad Meyer * memset() will be triggered before reduceIndex(). 13774d3f1eafSConrad Meyer */ 13784d3f1eafSConrad Meyer #define ZSTD_INDEXOVERFLOW_MARGIN (16 MB) 13794d3f1eafSConrad Meyer static int ZSTD_indexTooCloseToMax(ZSTD_window_t w) 13804d3f1eafSConrad Meyer { 13814d3f1eafSConrad Meyer return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN); 13824d3f1eafSConrad Meyer } 13834d3f1eafSConrad Meyer 13840c16b537SWarner Losh /*! ZSTD_resetCCtx_internal() : 13850c16b537SWarner Losh note : `params` are assumed fully validated at this stage */ 13860c16b537SWarner Losh static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, 13870f743729SConrad Meyer ZSTD_CCtx_params params, 13884d3f1eafSConrad Meyer U64 const pledgedSrcSize, 13890c16b537SWarner Losh ZSTD_compResetPolicy_e const crp, 13900c16b537SWarner Losh ZSTD_buffered_policy_e const zbuff) 13910c16b537SWarner Losh { 1392*9cbefe25SConrad Meyer ZSTD_cwksp* const ws = &zc->workspace; 1393052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u", 1394052d3c12SConrad Meyer (U32)pledgedSrcSize, params.cParams.windowLog); 13950c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 13960c16b537SWarner Losh 1397*9cbefe25SConrad Meyer zc->isFirstBlock = 1; 13980c16b537SWarner Losh 13990c16b537SWarner Losh if (params.ldmParams.enableLdm) { 14000c16b537SWarner Losh /* Adjust long distance matching parameters */ 140119fcbaf1SConrad Meyer ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); 14020c16b537SWarner Losh assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); 1403a0483764SConrad Meyer assert(params.ldmParams.hashRateLog < 32); 1404a0483764SConrad Meyer zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength); 14050c16b537SWarner Losh } 14060c16b537SWarner Losh 1407052d3c12SConrad Meyer { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); 1408052d3c12SConrad Meyer size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); 1409a0483764SConrad Meyer U32 const divider = (params.cParams.minMatch==3) ? 3 : 4; 14100c16b537SWarner Losh size_t const maxNbSeq = blockSize / divider; 1411*9cbefe25SConrad Meyer size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize) 1412*9cbefe25SConrad Meyer + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef)) 1413*9cbefe25SConrad Meyer + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE)); 14140c16b537SWarner Losh size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0; 1415052d3c12SConrad Meyer size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0; 141619fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1); 141719fcbaf1SConrad Meyer size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize); 14180c16b537SWarner Losh 1419*9cbefe25SConrad Meyer ZSTD_indexResetPolicy_e needsIndexReset = ZSTDirp_continue; 1420*9cbefe25SConrad Meyer 1421*9cbefe25SConrad Meyer if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) { 1422*9cbefe25SConrad Meyer needsIndexReset = ZSTDirp_reset; 1423*9cbefe25SConrad Meyer } 1424*9cbefe25SConrad Meyer 1425*9cbefe25SConrad Meyer ZSTD_cwksp_bump_oversized_duration(ws, 0); 1426*9cbefe25SConrad Meyer 1427*9cbefe25SConrad Meyer /* Check if workspace is large enough, alloc a new one if needed */ 1428*9cbefe25SConrad Meyer { size_t const cctxSpace = zc->staticSize ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0; 1429*9cbefe25SConrad Meyer size_t const entropySpace = ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE); 1430*9cbefe25SConrad Meyer size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t)); 1431*9cbefe25SConrad Meyer size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize) + ZSTD_cwksp_alloc_size(buffOutSize); 143219fcbaf1SConrad Meyer size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams); 1433*9cbefe25SConrad Meyer size_t const ldmSeqSpace = ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq)); 143419fcbaf1SConrad Meyer 1435*9cbefe25SConrad Meyer size_t const neededSpace = 1436*9cbefe25SConrad Meyer cctxSpace + 1437*9cbefe25SConrad Meyer entropySpace + 1438*9cbefe25SConrad Meyer blockStateSpace + 1439*9cbefe25SConrad Meyer ldmSpace + 1440*9cbefe25SConrad Meyer ldmSeqSpace + 1441*9cbefe25SConrad Meyer matchStateSize + 1442*9cbefe25SConrad Meyer tokenSpace + 144319fcbaf1SConrad Meyer bufferSpace; 14440c16b537SWarner Losh 1445*9cbefe25SConrad Meyer int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace; 1446*9cbefe25SConrad Meyer int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace); 14470f743729SConrad Meyer 14480f743729SConrad Meyer DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers", 14490f743729SConrad Meyer neededSpace>>10, matchStateSize>>10, bufferSpace>>10); 14500f743729SConrad Meyer DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); 14510f743729SConrad Meyer 1452*9cbefe25SConrad Meyer if (workspaceTooSmall || workspaceWasteful) { 1453*9cbefe25SConrad Meyer DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB", 1454*9cbefe25SConrad Meyer ZSTD_cwksp_sizeof(ws) >> 10, 14550f743729SConrad Meyer neededSpace >> 10); 14562b9c00cbSConrad Meyer 14572b9c00cbSConrad Meyer RETURN_ERROR_IF(zc->staticSize, memory_allocation, "static cctx : no resize"); 14580c16b537SWarner Losh 1459*9cbefe25SConrad Meyer needsIndexReset = ZSTDirp_reset; 14600c16b537SWarner Losh 1461*9cbefe25SConrad Meyer ZSTD_cwksp_free(ws, zc->customMem); 1462*9cbefe25SConrad Meyer FORWARD_IF_ERROR(ZSTD_cwksp_create(ws, neededSpace, zc->customMem)); 1463*9cbefe25SConrad Meyer 1464*9cbefe25SConrad Meyer DEBUGLOG(5, "reserving object space"); 14650f743729SConrad Meyer /* Statically sized space. 14660f743729SConrad Meyer * entropyWorkspace never moves, 14670f743729SConrad Meyer * though prev/next block swap places */ 1468*9cbefe25SConrad Meyer assert(ZSTD_cwksp_check_available(ws, 2 * sizeof(ZSTD_compressedBlockState_t))); 1469*9cbefe25SConrad Meyer zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t)); 1470*9cbefe25SConrad Meyer RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock"); 1471*9cbefe25SConrad Meyer zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t)); 1472*9cbefe25SConrad Meyer RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate nextCBlock"); 1473*9cbefe25SConrad Meyer zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, HUF_WORKSPACE_SIZE); 1474*9cbefe25SConrad Meyer RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace"); 14750c16b537SWarner Losh } } 14760c16b537SWarner Losh 1477*9cbefe25SConrad Meyer ZSTD_cwksp_clear(ws); 1478*9cbefe25SConrad Meyer 14790c16b537SWarner Losh /* init params */ 14800c16b537SWarner Losh zc->appliedParams = params; 14810f743729SConrad Meyer zc->blockState.matchState.cParams = params.cParams; 14820c16b537SWarner Losh zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; 14830c16b537SWarner Losh zc->consumedSrcSize = 0; 148419fcbaf1SConrad Meyer zc->producedCSize = 0; 14850c16b537SWarner Losh if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) 14860c16b537SWarner Losh zc->appliedParams.fParams.contentSizeFlag = 0; 1487052d3c12SConrad Meyer DEBUGLOG(4, "pledged content size : %u ; flag : %u", 1488a0483764SConrad Meyer (unsigned)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag); 14890c16b537SWarner Losh zc->blockSize = blockSize; 14900c16b537SWarner Losh 14910c16b537SWarner Losh XXH64_reset(&zc->xxhState, 0); 14920c16b537SWarner Losh zc->stage = ZSTDcs_init; 14930c16b537SWarner Losh zc->dictID = 0; 14940c16b537SWarner Losh 149519fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock); 14960c16b537SWarner Losh 14970f743729SConrad Meyer /* ZSTD_wildcopy() is used to copy into the literals buffer, 14980f743729SConrad Meyer * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes. 14990f743729SConrad Meyer */ 1500*9cbefe25SConrad Meyer zc->seqStore.litStart = ZSTD_cwksp_reserve_buffer(ws, blockSize + WILDCOPY_OVERLENGTH); 15010f743729SConrad Meyer zc->seqStore.maxNbLit = blockSize; 15020c16b537SWarner Losh 15030c16b537SWarner Losh /* buffers */ 15040c16b537SWarner Losh zc->inBuffSize = buffInSize; 1505*9cbefe25SConrad Meyer zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize); 15060c16b537SWarner Losh zc->outBuffSize = buffOutSize; 1507*9cbefe25SConrad Meyer zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize); 1508*9cbefe25SConrad Meyer 1509*9cbefe25SConrad Meyer /* ldm bucketOffsets table */ 1510*9cbefe25SConrad Meyer if (params.ldmParams.enableLdm) { 1511*9cbefe25SConrad Meyer /* TODO: avoid memset? */ 1512*9cbefe25SConrad Meyer size_t const ldmBucketSize = 1513*9cbefe25SConrad Meyer ((size_t)1) << (params.ldmParams.hashLog - 1514*9cbefe25SConrad Meyer params.ldmParams.bucketSizeLog); 1515*9cbefe25SConrad Meyer zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, ldmBucketSize); 1516*9cbefe25SConrad Meyer memset(zc->ldmState.bucketOffsets, 0, ldmBucketSize); 1517*9cbefe25SConrad Meyer } 1518*9cbefe25SConrad Meyer 1519*9cbefe25SConrad Meyer /* sequences storage */ 1520*9cbefe25SConrad Meyer ZSTD_referenceExternalSequences(zc, NULL, 0); 1521*9cbefe25SConrad Meyer zc->seqStore.maxNbSeq = maxNbSeq; 1522*9cbefe25SConrad Meyer zc->seqStore.llCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); 1523*9cbefe25SConrad Meyer zc->seqStore.mlCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); 1524*9cbefe25SConrad Meyer zc->seqStore.ofCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE)); 1525*9cbefe25SConrad Meyer zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef)); 1526*9cbefe25SConrad Meyer 1527*9cbefe25SConrad Meyer FORWARD_IF_ERROR(ZSTD_reset_matchState( 1528*9cbefe25SConrad Meyer &zc->blockState.matchState, 1529*9cbefe25SConrad Meyer ws, 1530*9cbefe25SConrad Meyer ¶ms.cParams, 1531*9cbefe25SConrad Meyer crp, 1532*9cbefe25SConrad Meyer needsIndexReset, 1533*9cbefe25SConrad Meyer ZSTD_resetTarget_CCtx)); 1534*9cbefe25SConrad Meyer 1535*9cbefe25SConrad Meyer /* ldm hash table */ 1536*9cbefe25SConrad Meyer if (params.ldmParams.enableLdm) { 1537*9cbefe25SConrad Meyer /* TODO: avoid memset? */ 1538*9cbefe25SConrad Meyer size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog; 1539*9cbefe25SConrad Meyer zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t)); 1540*9cbefe25SConrad Meyer memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t)); 1541*9cbefe25SConrad Meyer zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq)); 1542*9cbefe25SConrad Meyer zc->maxNbLdmSequences = maxNbLdmSeq; 1543*9cbefe25SConrad Meyer 1544*9cbefe25SConrad Meyer memset(&zc->ldmState.window, 0, sizeof(zc->ldmState.window)); 1545*9cbefe25SConrad Meyer ZSTD_window_clear(&zc->ldmState.window); 1546*9cbefe25SConrad Meyer } 1547*9cbefe25SConrad Meyer 1548*9cbefe25SConrad Meyer DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws)); 15490c16b537SWarner Losh 15500c16b537SWarner Losh return 0; 15510c16b537SWarner Losh } 15520c16b537SWarner Losh } 15530c16b537SWarner Losh 15540c16b537SWarner Losh /* ZSTD_invalidateRepCodes() : 15550c16b537SWarner Losh * ensures next compression will not use repcodes from previous block. 15560c16b537SWarner Losh * Note : only works with regular variant; 15570c16b537SWarner Losh * do not use with extDict variant ! */ 15580c16b537SWarner Losh void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) { 15590c16b537SWarner Losh int i; 156019fcbaf1SConrad Meyer for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0; 156119fcbaf1SConrad Meyer assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window)); 15620c16b537SWarner Losh } 15630c16b537SWarner Losh 15640f743729SConrad Meyer /* These are the approximate sizes for each strategy past which copying the 15650f743729SConrad Meyer * dictionary tables into the working context is faster than using them 15660f743729SConrad Meyer * in-place. 15670f743729SConrad Meyer */ 1568a0483764SConrad Meyer static const size_t attachDictSizeCutoffs[ZSTD_STRATEGY_MAX+1] = { 15690f743729SConrad Meyer 8 KB, /* unused */ 15700f743729SConrad Meyer 8 KB, /* ZSTD_fast */ 15710f743729SConrad Meyer 16 KB, /* ZSTD_dfast */ 15720f743729SConrad Meyer 32 KB, /* ZSTD_greedy */ 15730f743729SConrad Meyer 32 KB, /* ZSTD_lazy */ 15740f743729SConrad Meyer 32 KB, /* ZSTD_lazy2 */ 15750f743729SConrad Meyer 32 KB, /* ZSTD_btlazy2 */ 15760f743729SConrad Meyer 32 KB, /* ZSTD_btopt */ 1577a0483764SConrad Meyer 8 KB, /* ZSTD_btultra */ 1578a0483764SConrad Meyer 8 KB /* ZSTD_btultra2 */ 15790f743729SConrad Meyer }; 15800f743729SConrad Meyer 15810f743729SConrad Meyer static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, 1582*9cbefe25SConrad Meyer const ZSTD_CCtx_params* params, 15830f743729SConrad Meyer U64 pledgedSrcSize) 15840f743729SConrad Meyer { 15850f743729SConrad Meyer size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy]; 15860f743729SConrad Meyer return ( pledgedSrcSize <= cutoff 15870f743729SConrad Meyer || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN 1588*9cbefe25SConrad Meyer || params->attachDictPref == ZSTD_dictForceAttach ) 1589*9cbefe25SConrad Meyer && params->attachDictPref != ZSTD_dictForceCopy 1590*9cbefe25SConrad Meyer && !params->forceWindow; /* dictMatchState isn't correctly 15910f743729SConrad Meyer * handled in _enforceMaxDist */ 15920f743729SConrad Meyer } 15930f743729SConrad Meyer 15944d3f1eafSConrad Meyer static size_t 15954d3f1eafSConrad Meyer ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, 159619fcbaf1SConrad Meyer const ZSTD_CDict* cdict, 15970f743729SConrad Meyer ZSTD_CCtx_params params, 159819fcbaf1SConrad Meyer U64 pledgedSrcSize, 159919fcbaf1SConrad Meyer ZSTD_buffered_policy_e zbuff) 160019fcbaf1SConrad Meyer { 16014d3f1eafSConrad Meyer { const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams; 16020f743729SConrad Meyer unsigned const windowLog = params.cParams.windowLog; 16030f743729SConrad Meyer assert(windowLog != 0); 16040f743729SConrad Meyer /* Resize working context table params for input only, since the dict 16050f743729SConrad Meyer * has its own tables. */ 16060f743729SConrad Meyer params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0); 16070f743729SConrad Meyer params.cParams.windowLog = windowLog; 1608*9cbefe25SConrad Meyer FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 1609*9cbefe25SConrad Meyer ZSTDcrp_makeClean, zbuff)); 16100f743729SConrad Meyer assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); 16110f743729SConrad Meyer } 16120f743729SConrad Meyer 16134d3f1eafSConrad Meyer { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc 16140f743729SConrad Meyer - cdict->matchState.window.base); 16150f743729SConrad Meyer const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit; 16160f743729SConrad Meyer if (cdictLen == 0) { 16170f743729SConrad Meyer /* don't even attach dictionaries with no contents */ 16180f743729SConrad Meyer DEBUGLOG(4, "skipping attaching empty dictionary"); 16190f743729SConrad Meyer } else { 16200f743729SConrad Meyer DEBUGLOG(4, "attaching dictionary into context"); 16210f743729SConrad Meyer cctx->blockState.matchState.dictMatchState = &cdict->matchState; 16220f743729SConrad Meyer 16230f743729SConrad Meyer /* prep working match state so dict matches never have negative indices 16240f743729SConrad Meyer * when they are translated to the working context's index space. */ 16250f743729SConrad Meyer if (cctx->blockState.matchState.window.dictLimit < cdictEnd) { 16260f743729SConrad Meyer cctx->blockState.matchState.window.nextSrc = 16270f743729SConrad Meyer cctx->blockState.matchState.window.base + cdictEnd; 16280f743729SConrad Meyer ZSTD_window_clear(&cctx->blockState.matchState.window); 16290f743729SConrad Meyer } 16304d3f1eafSConrad Meyer /* loadedDictEnd is expressed within the referential of the active context */ 16310f743729SConrad Meyer cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit; 16324d3f1eafSConrad Meyer } } 16330f743729SConrad Meyer 16340f743729SConrad Meyer cctx->dictID = cdict->dictID; 16350f743729SConrad Meyer 16360f743729SConrad Meyer /* copy block state */ 16370f743729SConrad Meyer memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 16380f743729SConrad Meyer 16390f743729SConrad Meyer return 0; 16400f743729SConrad Meyer } 16410f743729SConrad Meyer 16420f743729SConrad Meyer static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, 16430f743729SConrad Meyer const ZSTD_CDict* cdict, 16440f743729SConrad Meyer ZSTD_CCtx_params params, 16450f743729SConrad Meyer U64 pledgedSrcSize, 16460f743729SConrad Meyer ZSTD_buffered_policy_e zbuff) 16470f743729SConrad Meyer { 16480f743729SConrad Meyer const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; 16490f743729SConrad Meyer 16500f743729SConrad Meyer DEBUGLOG(4, "copying dictionary into context"); 16510f743729SConrad Meyer 16520f743729SConrad Meyer { unsigned const windowLog = params.cParams.windowLog; 16530f743729SConrad Meyer assert(windowLog != 0); 165419fcbaf1SConrad Meyer /* Copy only compression parameters related to tables. */ 16550f743729SConrad Meyer params.cParams = *cdict_cParams; 16560f743729SConrad Meyer params.cParams.windowLog = windowLog; 1657*9cbefe25SConrad Meyer FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 1658*9cbefe25SConrad Meyer ZSTDcrp_leaveDirty, zbuff)); 16590f743729SConrad Meyer assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); 16600f743729SConrad Meyer assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog); 16610f743729SConrad Meyer assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog); 166219fcbaf1SConrad Meyer } 166319fcbaf1SConrad Meyer 1664*9cbefe25SConrad Meyer ZSTD_cwksp_mark_tables_dirty(&cctx->workspace); 1665*9cbefe25SConrad Meyer 166619fcbaf1SConrad Meyer /* copy tables */ 16670f743729SConrad Meyer { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog); 16680f743729SConrad Meyer size_t const hSize = (size_t)1 << cdict_cParams->hashLog; 1669*9cbefe25SConrad Meyer 1670*9cbefe25SConrad Meyer memcpy(cctx->blockState.matchState.hashTable, 1671*9cbefe25SConrad Meyer cdict->matchState.hashTable, 1672*9cbefe25SConrad Meyer hSize * sizeof(U32)); 1673*9cbefe25SConrad Meyer memcpy(cctx->blockState.matchState.chainTable, 1674*9cbefe25SConrad Meyer cdict->matchState.chainTable, 1675*9cbefe25SConrad Meyer chainSize * sizeof(U32)); 167619fcbaf1SConrad Meyer } 16770f743729SConrad Meyer 167819fcbaf1SConrad Meyer /* Zero the hashTable3, since the cdict never fills it */ 1679*9cbefe25SConrad Meyer { int const h3log = cctx->blockState.matchState.hashLog3; 1680*9cbefe25SConrad Meyer size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; 168119fcbaf1SConrad Meyer assert(cdict->matchState.hashLog3 == 0); 168219fcbaf1SConrad Meyer memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); 168319fcbaf1SConrad Meyer } 168419fcbaf1SConrad Meyer 1685*9cbefe25SConrad Meyer ZSTD_cwksp_mark_tables_clean(&cctx->workspace); 1686*9cbefe25SConrad Meyer 168719fcbaf1SConrad Meyer /* copy dictionary offsets */ 16880f743729SConrad Meyer { ZSTD_matchState_t const* srcMatchState = &cdict->matchState; 168919fcbaf1SConrad Meyer ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState; 169019fcbaf1SConrad Meyer dstMatchState->window = srcMatchState->window; 169119fcbaf1SConrad Meyer dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 169219fcbaf1SConrad Meyer dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 169319fcbaf1SConrad Meyer } 16940f743729SConrad Meyer 169519fcbaf1SConrad Meyer cctx->dictID = cdict->dictID; 169619fcbaf1SConrad Meyer 169719fcbaf1SConrad Meyer /* copy block state */ 169819fcbaf1SConrad Meyer memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 169919fcbaf1SConrad Meyer 170019fcbaf1SConrad Meyer return 0; 170119fcbaf1SConrad Meyer } 17020c16b537SWarner Losh 17030f743729SConrad Meyer /* We have a choice between copying the dictionary context into the working 17040f743729SConrad Meyer * context, or referencing the dictionary context from the working context 17050f743729SConrad Meyer * in-place. We decide here which strategy to use. */ 17060f743729SConrad Meyer static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx, 17070f743729SConrad Meyer const ZSTD_CDict* cdict, 1708*9cbefe25SConrad Meyer const ZSTD_CCtx_params* params, 17090f743729SConrad Meyer U64 pledgedSrcSize, 17100f743729SConrad Meyer ZSTD_buffered_policy_e zbuff) 17110f743729SConrad Meyer { 17120f743729SConrad Meyer 1713a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)", 1714a0483764SConrad Meyer (unsigned)pledgedSrcSize); 17150f743729SConrad Meyer 17160f743729SConrad Meyer if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) { 17170f743729SConrad Meyer return ZSTD_resetCCtx_byAttachingCDict( 1718*9cbefe25SConrad Meyer cctx, cdict, *params, pledgedSrcSize, zbuff); 17190f743729SConrad Meyer } else { 17200f743729SConrad Meyer return ZSTD_resetCCtx_byCopyingCDict( 1721*9cbefe25SConrad Meyer cctx, cdict, *params, pledgedSrcSize, zbuff); 17220f743729SConrad Meyer } 17230f743729SConrad Meyer } 17240f743729SConrad Meyer 17250c16b537SWarner Losh /*! ZSTD_copyCCtx_internal() : 17260c16b537SWarner Losh * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 17270c16b537SWarner Losh * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 1728052d3c12SConrad Meyer * The "context", in this case, refers to the hash and chain tables, 1729052d3c12SConrad Meyer * entropy tables, and dictionary references. 1730052d3c12SConrad Meyer * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx. 17310c16b537SWarner Losh * @return : 0, or an error code */ 17320c16b537SWarner Losh static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, 17330c16b537SWarner Losh const ZSTD_CCtx* srcCCtx, 17340c16b537SWarner Losh ZSTD_frameParameters fParams, 1735052d3c12SConrad Meyer U64 pledgedSrcSize, 17360c16b537SWarner Losh ZSTD_buffered_policy_e zbuff) 17370c16b537SWarner Losh { 17380c16b537SWarner Losh DEBUGLOG(5, "ZSTD_copyCCtx_internal"); 17392b9c00cbSConrad Meyer RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong); 17400c16b537SWarner Losh 17410c16b537SWarner Losh memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); 17420c16b537SWarner Losh { ZSTD_CCtx_params params = dstCCtx->requestedParams; 17430c16b537SWarner Losh /* Copy only compression parameters related to tables. */ 17440c16b537SWarner Losh params.cParams = srcCCtx->appliedParams.cParams; 17450c16b537SWarner Losh params.fParams = fParams; 17460c16b537SWarner Losh ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, 1747*9cbefe25SConrad Meyer ZSTDcrp_leaveDirty, zbuff); 174819fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog); 174919fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy); 175019fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog); 175119fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog); 175219fcbaf1SConrad Meyer assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3); 17530c16b537SWarner Losh } 17540c16b537SWarner Losh 1755*9cbefe25SConrad Meyer ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace); 1756*9cbefe25SConrad Meyer 17570c16b537SWarner Losh /* copy tables */ 17580c16b537SWarner Losh { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog); 17590c16b537SWarner Losh size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; 1760*9cbefe25SConrad Meyer int const h3log = srcCCtx->blockState.matchState.hashLog3; 1761*9cbefe25SConrad Meyer size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0; 1762*9cbefe25SConrad Meyer 1763*9cbefe25SConrad Meyer memcpy(dstCCtx->blockState.matchState.hashTable, 1764*9cbefe25SConrad Meyer srcCCtx->blockState.matchState.hashTable, 1765*9cbefe25SConrad Meyer hSize * sizeof(U32)); 1766*9cbefe25SConrad Meyer memcpy(dstCCtx->blockState.matchState.chainTable, 1767*9cbefe25SConrad Meyer srcCCtx->blockState.matchState.chainTable, 1768*9cbefe25SConrad Meyer chainSize * sizeof(U32)); 1769*9cbefe25SConrad Meyer memcpy(dstCCtx->blockState.matchState.hashTable3, 1770*9cbefe25SConrad Meyer srcCCtx->blockState.matchState.hashTable3, 1771*9cbefe25SConrad Meyer h3Size * sizeof(U32)); 17720c16b537SWarner Losh } 17730c16b537SWarner Losh 1774*9cbefe25SConrad Meyer ZSTD_cwksp_mark_tables_clean(&dstCCtx->workspace); 1775*9cbefe25SConrad Meyer 17760c16b537SWarner Losh /* copy dictionary offsets */ 177719fcbaf1SConrad Meyer { 17780f743729SConrad Meyer const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState; 177919fcbaf1SConrad Meyer ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState; 178019fcbaf1SConrad Meyer dstMatchState->window = srcMatchState->window; 178119fcbaf1SConrad Meyer dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 178219fcbaf1SConrad Meyer dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 178319fcbaf1SConrad Meyer } 17840c16b537SWarner Losh dstCCtx->dictID = srcCCtx->dictID; 17850c16b537SWarner Losh 178619fcbaf1SConrad Meyer /* copy block state */ 178719fcbaf1SConrad Meyer memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); 17880c16b537SWarner Losh 17890c16b537SWarner Losh return 0; 17900c16b537SWarner Losh } 17910c16b537SWarner Losh 17920c16b537SWarner Losh /*! ZSTD_copyCCtx() : 17930c16b537SWarner Losh * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 17940c16b537SWarner Losh * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 17950c16b537SWarner Losh * pledgedSrcSize==0 means "unknown". 17960c16b537SWarner Losh * @return : 0, or an error code */ 17970c16b537SWarner Losh size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) 17980c16b537SWarner Losh { 17990c16b537SWarner Losh ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 18000c16b537SWarner Losh ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0); 18010c16b537SWarner Losh ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); 1802052d3c12SConrad Meyer if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; 1803052d3c12SConrad Meyer fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN); 18040c16b537SWarner Losh 1805052d3c12SConrad Meyer return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, 180619fcbaf1SConrad Meyer fParams, pledgedSrcSize, 1807052d3c12SConrad Meyer zbuff); 18080c16b537SWarner Losh } 18090c16b537SWarner Losh 18100c16b537SWarner Losh 181119fcbaf1SConrad Meyer #define ZSTD_ROWSIZE 16 18120c16b537SWarner Losh /*! ZSTD_reduceTable() : 181319fcbaf1SConrad Meyer * reduce table indexes by `reducerValue`, or squash to zero. 181419fcbaf1SConrad Meyer * PreserveMark preserves "unsorted mark" for btlazy2 strategy. 181519fcbaf1SConrad Meyer * It must be set to a clear 0/1 value, to remove branch during inlining. 181619fcbaf1SConrad Meyer * Presume table size is a multiple of ZSTD_ROWSIZE 181719fcbaf1SConrad Meyer * to help auto-vectorization */ 181819fcbaf1SConrad Meyer FORCE_INLINE_TEMPLATE void 181919fcbaf1SConrad Meyer ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark) 18200c16b537SWarner Losh { 182119fcbaf1SConrad Meyer int const nbRows = (int)size / ZSTD_ROWSIZE; 182219fcbaf1SConrad Meyer int cellNb = 0; 182319fcbaf1SConrad Meyer int rowNb; 182419fcbaf1SConrad Meyer assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */ 182519fcbaf1SConrad Meyer assert(size < (1U<<31)); /* can be casted to int */ 1826*9cbefe25SConrad Meyer 1827*9cbefe25SConrad Meyer #if defined (MEMORY_SANITIZER) && !defined (ZSTD_MSAN_DONT_POISON_WORKSPACE) 1828*9cbefe25SConrad Meyer /* To validate that the table re-use logic is sound, and that we don't 1829*9cbefe25SConrad Meyer * access table space that we haven't cleaned, we re-"poison" the table 1830*9cbefe25SConrad Meyer * space every time we mark it dirty. 1831*9cbefe25SConrad Meyer * 1832*9cbefe25SConrad Meyer * This function however is intended to operate on those dirty tables and 1833*9cbefe25SConrad Meyer * re-clean them. So when this function is used correctly, we can unpoison 1834*9cbefe25SConrad Meyer * the memory it operated on. This introduces a blind spot though, since 1835*9cbefe25SConrad Meyer * if we now try to operate on __actually__ poisoned memory, we will not 1836*9cbefe25SConrad Meyer * detect that. */ 1837*9cbefe25SConrad Meyer __msan_unpoison(table, size * sizeof(U32)); 1838*9cbefe25SConrad Meyer #endif 1839*9cbefe25SConrad Meyer 184019fcbaf1SConrad Meyer for (rowNb=0 ; rowNb < nbRows ; rowNb++) { 184119fcbaf1SConrad Meyer int column; 184219fcbaf1SConrad Meyer for (column=0; column<ZSTD_ROWSIZE; column++) { 184319fcbaf1SConrad Meyer if (preserveMark) { 184419fcbaf1SConrad Meyer U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0; 184519fcbaf1SConrad Meyer table[cellNb] += adder; 18460c16b537SWarner Losh } 184719fcbaf1SConrad Meyer if (table[cellNb] < reducerValue) table[cellNb] = 0; 184819fcbaf1SConrad Meyer else table[cellNb] -= reducerValue; 184919fcbaf1SConrad Meyer cellNb++; 185019fcbaf1SConrad Meyer } } 18510c16b537SWarner Losh } 18520c16b537SWarner Losh 185319fcbaf1SConrad Meyer static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue) 18540c16b537SWarner Losh { 185519fcbaf1SConrad Meyer ZSTD_reduceTable_internal(table, size, reducerValue, 0); 18560c16b537SWarner Losh } 185719fcbaf1SConrad Meyer 185819fcbaf1SConrad Meyer static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue) 185919fcbaf1SConrad Meyer { 186019fcbaf1SConrad Meyer ZSTD_reduceTable_internal(table, size, reducerValue, 1); 18610c16b537SWarner Losh } 18620c16b537SWarner Losh 18630c16b537SWarner Losh /*! ZSTD_reduceIndex() : 18640c16b537SWarner Losh * rescale all indexes to avoid future overflow (indexes are U32) */ 18654d3f1eafSConrad Meyer static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const U32 reducerValue) 18660c16b537SWarner Losh { 18674d3f1eafSConrad Meyer { U32 const hSize = (U32)1 << params->cParams.hashLog; 186819fcbaf1SConrad Meyer ZSTD_reduceTable(ms->hashTable, hSize, reducerValue); 18690c16b537SWarner Losh } 187019fcbaf1SConrad Meyer 18714d3f1eafSConrad Meyer if (params->cParams.strategy != ZSTD_fast) { 18724d3f1eafSConrad Meyer U32 const chainSize = (U32)1 << params->cParams.chainLog; 18734d3f1eafSConrad Meyer if (params->cParams.strategy == ZSTD_btlazy2) 187419fcbaf1SConrad Meyer ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue); 187519fcbaf1SConrad Meyer else 187619fcbaf1SConrad Meyer ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue); 187719fcbaf1SConrad Meyer } 187819fcbaf1SConrad Meyer 187919fcbaf1SConrad Meyer if (ms->hashLog3) { 188019fcbaf1SConrad Meyer U32 const h3Size = (U32)1 << ms->hashLog3; 188119fcbaf1SConrad Meyer ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue); 18820c16b537SWarner Losh } 18830c16b537SWarner Losh } 18840c16b537SWarner Losh 18850c16b537SWarner Losh 18860c16b537SWarner Losh /*-******************************************************* 18870c16b537SWarner Losh * Block entropic compression 18880c16b537SWarner Losh *********************************************************/ 18890c16b537SWarner Losh 18900c16b537SWarner Losh /* See doc/zstd_compression_format.md for detailed format description */ 18910c16b537SWarner Losh 18920f743729SConrad Meyer static size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) 18930c16b537SWarner Losh { 18940f743729SConrad Meyer U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3); 18952b9c00cbSConrad Meyer RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity, 18962b9c00cbSConrad Meyer dstSize_tooSmall); 18970f743729SConrad Meyer MEM_writeLE24(dst, cBlockHeader24); 18980c16b537SWarner Losh memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize); 18990c16b537SWarner Losh return ZSTD_blockHeaderSize + srcSize; 19000c16b537SWarner Losh } 19010c16b537SWarner Losh 19020c16b537SWarner Losh void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) 19030c16b537SWarner Losh { 19040c16b537SWarner Losh const seqDef* const sequences = seqStorePtr->sequencesStart; 19050c16b537SWarner Losh BYTE* const llCodeTable = seqStorePtr->llCode; 19060c16b537SWarner Losh BYTE* const ofCodeTable = seqStorePtr->ofCode; 19070c16b537SWarner Losh BYTE* const mlCodeTable = seqStorePtr->mlCode; 19080c16b537SWarner Losh U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 19090c16b537SWarner Losh U32 u; 19100f743729SConrad Meyer assert(nbSeq <= seqStorePtr->maxNbSeq); 19110c16b537SWarner Losh for (u=0; u<nbSeq; u++) { 19120c16b537SWarner Losh U32 const llv = sequences[u].litLength; 19130c16b537SWarner Losh U32 const mlv = sequences[u].matchLength; 1914052d3c12SConrad Meyer llCodeTable[u] = (BYTE)ZSTD_LLcode(llv); 19150c16b537SWarner Losh ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset); 1916052d3c12SConrad Meyer mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv); 19170c16b537SWarner Losh } 19180c16b537SWarner Losh if (seqStorePtr->longLengthID==1) 19190c16b537SWarner Losh llCodeTable[seqStorePtr->longLengthPos] = MaxLL; 19200c16b537SWarner Losh if (seqStorePtr->longLengthID==2) 19210c16b537SWarner Losh mlCodeTable[seqStorePtr->longLengthPos] = MaxML; 19220c16b537SWarner Losh } 19230c16b537SWarner Losh 19242b9c00cbSConrad Meyer static int ZSTD_disableLiteralsCompression(const ZSTD_CCtx_params* cctxParams) 19252b9c00cbSConrad Meyer { 19262b9c00cbSConrad Meyer switch (cctxParams->literalCompressionMode) { 19272b9c00cbSConrad Meyer case ZSTD_lcm_huffman: 19282b9c00cbSConrad Meyer return 0; 19292b9c00cbSConrad Meyer case ZSTD_lcm_uncompressed: 19302b9c00cbSConrad Meyer return 1; 19312b9c00cbSConrad Meyer default: 19322b9c00cbSConrad Meyer assert(0 /* impossible: pre-validated */); 19332b9c00cbSConrad Meyer /* fall-through */ 19342b9c00cbSConrad Meyer case ZSTD_lcm_auto: 19352b9c00cbSConrad Meyer return (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0); 19362b9c00cbSConrad Meyer } 19372b9c00cbSConrad Meyer } 19382b9c00cbSConrad Meyer 1939a0483764SConrad Meyer /* ZSTD_compressSequences_internal(): 1940a0483764SConrad Meyer * actually compresses both literals and sequences */ 1941a0483764SConrad Meyer MEM_STATIC size_t 1942a0483764SConrad Meyer ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, 1943a0483764SConrad Meyer const ZSTD_entropyCTables_t* prevEntropy, 194419fcbaf1SConrad Meyer ZSTD_entropyCTables_t* nextEntropy, 1945a0483764SConrad Meyer const ZSTD_CCtx_params* cctxParams, 1946a0483764SConrad Meyer void* dst, size_t dstCapacity, 1947*9cbefe25SConrad Meyer void* entropyWorkspace, size_t entropyWkspSize, 194819fcbaf1SConrad Meyer const int bmi2) 194919fcbaf1SConrad Meyer { 195019fcbaf1SConrad Meyer const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; 19510f743729SConrad Meyer ZSTD_strategy const strategy = cctxParams->cParams.strategy; 1952a0483764SConrad Meyer unsigned count[MaxSeq+1]; 19530f743729SConrad Meyer FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable; 19540f743729SConrad Meyer FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable; 19550f743729SConrad Meyer FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable; 19560c16b537SWarner Losh U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ 19570c16b537SWarner Losh const seqDef* const sequences = seqStorePtr->sequencesStart; 19580c16b537SWarner Losh const BYTE* const ofCodeTable = seqStorePtr->ofCode; 19590c16b537SWarner Losh const BYTE* const llCodeTable = seqStorePtr->llCode; 19600c16b537SWarner Losh const BYTE* const mlCodeTable = seqStorePtr->mlCode; 19610c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 19620c16b537SWarner Losh BYTE* const oend = ostart + dstCapacity; 19630c16b537SWarner Losh BYTE* op = ostart; 1964*9cbefe25SConrad Meyer size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 19650c16b537SWarner Losh BYTE* seqHead; 19660f743729SConrad Meyer BYTE* lastNCount = NULL; 19670c16b537SWarner Losh 19684d3f1eafSConrad Meyer DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq); 196919fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 19700c16b537SWarner Losh 19710c16b537SWarner Losh /* Compress literals */ 19720c16b537SWarner Losh { const BYTE* const literals = seqStorePtr->litStart; 1973*9cbefe25SConrad Meyer size_t const litSize = (size_t)(seqStorePtr->lit - literals); 19740c16b537SWarner Losh size_t const cSize = ZSTD_compressLiterals( 19750f743729SConrad Meyer &prevEntropy->huf, &nextEntropy->huf, 19762b9c00cbSConrad Meyer cctxParams->cParams.strategy, 19772b9c00cbSConrad Meyer ZSTD_disableLiteralsCompression(cctxParams), 197819fcbaf1SConrad Meyer op, dstCapacity, 197919fcbaf1SConrad Meyer literals, litSize, 1980*9cbefe25SConrad Meyer entropyWorkspace, entropyWkspSize, 1981a0483764SConrad Meyer bmi2); 19822b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 1983052d3c12SConrad Meyer assert(cSize <= dstCapacity); 19840c16b537SWarner Losh op += cSize; 19850c16b537SWarner Losh } 19860c16b537SWarner Losh 19870c16b537SWarner Losh /* Sequences Header */ 19882b9c00cbSConrad Meyer RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, 19892b9c00cbSConrad Meyer dstSize_tooSmall); 1990*9cbefe25SConrad Meyer if (nbSeq < 128) { 1991052d3c12SConrad Meyer *op++ = (BYTE)nbSeq; 1992*9cbefe25SConrad Meyer } else if (nbSeq < LONGNBSEQ) { 1993*9cbefe25SConrad Meyer op[0] = (BYTE)((nbSeq>>8) + 0x80); 1994*9cbefe25SConrad Meyer op[1] = (BYTE)nbSeq; 1995*9cbefe25SConrad Meyer op+=2; 1996*9cbefe25SConrad Meyer } else { 1997*9cbefe25SConrad Meyer op[0]=0xFF; 1998*9cbefe25SConrad Meyer MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)); 1999*9cbefe25SConrad Meyer op+=3; 2000*9cbefe25SConrad Meyer } 20014d3f1eafSConrad Meyer assert(op <= oend); 200219fcbaf1SConrad Meyer if (nbSeq==0) { 20030f743729SConrad Meyer /* Copy the old tables over as if we repeated them */ 20040f743729SConrad Meyer memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); 2005*9cbefe25SConrad Meyer return (size_t)(op - ostart); 200619fcbaf1SConrad Meyer } 20070c16b537SWarner Losh 20080c16b537SWarner Losh /* seqHead : flags for FSE encoding type */ 20090c16b537SWarner Losh seqHead = op++; 20104d3f1eafSConrad Meyer assert(op <= oend); 20110c16b537SWarner Losh 20120c16b537SWarner Losh /* convert length/distances into codes */ 20130c16b537SWarner Losh ZSTD_seqToCodes(seqStorePtr); 2014052d3c12SConrad Meyer /* build CTable for Literal Lengths */ 2015a0483764SConrad Meyer { unsigned max = MaxLL; 2016*9cbefe25SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ 2017052d3c12SConrad Meyer DEBUGLOG(5, "Building LL table"); 20180f743729SConrad Meyer nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode; 2019a0483764SConrad Meyer LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode, 2020a0483764SConrad Meyer count, max, mostFrequent, nbSeq, 2021a0483764SConrad Meyer LLFSELog, prevEntropy->fse.litlengthCTable, 2022a0483764SConrad Meyer LL_defaultNorm, LL_defaultNormLog, 2023a0483764SConrad Meyer ZSTD_defaultAllowed, strategy); 20240f743729SConrad Meyer assert(set_basic < set_compressed && set_rle < set_compressed); 20250f743729SConrad Meyer assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 2026*9cbefe25SConrad Meyer { size_t const countSize = ZSTD_buildCTable( 2027*9cbefe25SConrad Meyer op, (size_t)(oend - op), 2028*9cbefe25SConrad Meyer CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, 2029*9cbefe25SConrad Meyer count, max, llCodeTable, nbSeq, 2030*9cbefe25SConrad Meyer LL_defaultNorm, LL_defaultNormLog, MaxLL, 2031*9cbefe25SConrad Meyer prevEntropy->fse.litlengthCTable, 2032*9cbefe25SConrad Meyer sizeof(prevEntropy->fse.litlengthCTable), 2033*9cbefe25SConrad Meyer entropyWorkspace, entropyWkspSize); 20342b9c00cbSConrad Meyer FORWARD_IF_ERROR(countSize); 20350f743729SConrad Meyer if (LLtype == set_compressed) 20360f743729SConrad Meyer lastNCount = op; 20370c16b537SWarner Losh op += countSize; 20384d3f1eafSConrad Meyer assert(op <= oend); 20390c16b537SWarner Losh } } 2040052d3c12SConrad Meyer /* build CTable for Offsets */ 2041a0483764SConrad Meyer { unsigned max = MaxOff; 2042*9cbefe25SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp( 2043*9cbefe25SConrad Meyer count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ 20440c16b537SWarner Losh /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ 2045052d3c12SConrad Meyer ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; 2046052d3c12SConrad Meyer DEBUGLOG(5, "Building OF table"); 20470f743729SConrad Meyer nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode; 2048a0483764SConrad Meyer Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode, 2049a0483764SConrad Meyer count, max, mostFrequent, nbSeq, 2050a0483764SConrad Meyer OffFSELog, prevEntropy->fse.offcodeCTable, 2051a0483764SConrad Meyer OF_defaultNorm, OF_defaultNormLog, 2052a0483764SConrad Meyer defaultPolicy, strategy); 20530f743729SConrad Meyer assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 2054*9cbefe25SConrad Meyer { size_t const countSize = ZSTD_buildCTable( 2055*9cbefe25SConrad Meyer op, (size_t)(oend - op), 2056*9cbefe25SConrad Meyer CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, 2057*9cbefe25SConrad Meyer count, max, ofCodeTable, nbSeq, 2058*9cbefe25SConrad Meyer OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, 2059*9cbefe25SConrad Meyer prevEntropy->fse.offcodeCTable, 2060*9cbefe25SConrad Meyer sizeof(prevEntropy->fse.offcodeCTable), 2061*9cbefe25SConrad Meyer entropyWorkspace, entropyWkspSize); 20622b9c00cbSConrad Meyer FORWARD_IF_ERROR(countSize); 20630f743729SConrad Meyer if (Offtype == set_compressed) 20640f743729SConrad Meyer lastNCount = op; 20650c16b537SWarner Losh op += countSize; 20664d3f1eafSConrad Meyer assert(op <= oend); 20670c16b537SWarner Losh } } 2068052d3c12SConrad Meyer /* build CTable for MatchLengths */ 2069a0483764SConrad Meyer { unsigned max = MaxML; 2070*9cbefe25SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp( 2071*9cbefe25SConrad Meyer count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize); /* can't fail */ 2072a0483764SConrad Meyer DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); 20730f743729SConrad Meyer nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode; 2074a0483764SConrad Meyer MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode, 2075a0483764SConrad Meyer count, max, mostFrequent, nbSeq, 2076a0483764SConrad Meyer MLFSELog, prevEntropy->fse.matchlengthCTable, 2077a0483764SConrad Meyer ML_defaultNorm, ML_defaultNormLog, 2078a0483764SConrad Meyer ZSTD_defaultAllowed, strategy); 20790f743729SConrad Meyer assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 2080*9cbefe25SConrad Meyer { size_t const countSize = ZSTD_buildCTable( 2081*9cbefe25SConrad Meyer op, (size_t)(oend - op), 2082*9cbefe25SConrad Meyer CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, 2083*9cbefe25SConrad Meyer count, max, mlCodeTable, nbSeq, 2084*9cbefe25SConrad Meyer ML_defaultNorm, ML_defaultNormLog, MaxML, 2085*9cbefe25SConrad Meyer prevEntropy->fse.matchlengthCTable, 2086*9cbefe25SConrad Meyer sizeof(prevEntropy->fse.matchlengthCTable), 2087*9cbefe25SConrad Meyer entropyWorkspace, entropyWkspSize); 20882b9c00cbSConrad Meyer FORWARD_IF_ERROR(countSize); 20890f743729SConrad Meyer if (MLtype == set_compressed) 20900f743729SConrad Meyer lastNCount = op; 20910c16b537SWarner Losh op += countSize; 20924d3f1eafSConrad Meyer assert(op <= oend); 20930c16b537SWarner Losh } } 20940c16b537SWarner Losh 20950c16b537SWarner Losh *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); 20960c16b537SWarner Losh 2097052d3c12SConrad Meyer { size_t const bitstreamSize = ZSTD_encodeSequences( 2098*9cbefe25SConrad Meyer op, (size_t)(oend - op), 20990c16b537SWarner Losh CTable_MatchLength, mlCodeTable, 21000c16b537SWarner Losh CTable_OffsetBits, ofCodeTable, 21010c16b537SWarner Losh CTable_LitLength, llCodeTable, 2102052d3c12SConrad Meyer sequences, nbSeq, 210319fcbaf1SConrad Meyer longOffsets, bmi2); 21042b9c00cbSConrad Meyer FORWARD_IF_ERROR(bitstreamSize); 2105052d3c12SConrad Meyer op += bitstreamSize; 21064d3f1eafSConrad Meyer assert(op <= oend); 21070f743729SConrad Meyer /* zstd versions <= 1.3.4 mistakenly report corruption when 21082b9c00cbSConrad Meyer * FSE_readNCount() receives a buffer < 4 bytes. 21090f743729SConrad Meyer * Fixed by https://github.com/facebook/zstd/pull/1146. 21100f743729SConrad Meyer * This can happen when the last set_compressed table present is 2 21110f743729SConrad Meyer * bytes and the bitstream is only one byte. 21120f743729SConrad Meyer * In this exceedingly rare case, we will simply emit an uncompressed 21130f743729SConrad Meyer * block, since it isn't worth optimizing. 21140f743729SConrad Meyer */ 21150f743729SConrad Meyer if (lastNCount && (op - lastNCount) < 4) { 21160f743729SConrad Meyer /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ 21170f743729SConrad Meyer assert(op - lastNCount == 3); 21180f743729SConrad Meyer DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " 21190f743729SConrad Meyer "emitting an uncompressed block."); 21200f743729SConrad Meyer return 0; 21210f743729SConrad Meyer } 21220c16b537SWarner Losh } 21230c16b537SWarner Losh 2124a0483764SConrad Meyer DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart)); 2125*9cbefe25SConrad Meyer return (size_t)(op - ostart); 21260c16b537SWarner Losh } 21270c16b537SWarner Losh 2128a0483764SConrad Meyer MEM_STATIC size_t 2129a0483764SConrad Meyer ZSTD_compressSequences(seqStore_t* seqStorePtr, 21300f743729SConrad Meyer const ZSTD_entropyCTables_t* prevEntropy, 213119fcbaf1SConrad Meyer ZSTD_entropyCTables_t* nextEntropy, 21320f743729SConrad Meyer const ZSTD_CCtx_params* cctxParams, 21330c16b537SWarner Losh void* dst, size_t dstCapacity, 2134a0483764SConrad Meyer size_t srcSize, 2135*9cbefe25SConrad Meyer void* entropyWorkspace, size_t entropyWkspSize, 2136a0483764SConrad Meyer int bmi2) 21370c16b537SWarner Losh { 213819fcbaf1SConrad Meyer size_t const cSize = ZSTD_compressSequences_internal( 2139a0483764SConrad Meyer seqStorePtr, prevEntropy, nextEntropy, cctxParams, 2140a0483764SConrad Meyer dst, dstCapacity, 2141*9cbefe25SConrad Meyer entropyWorkspace, entropyWkspSize, bmi2); 21420f743729SConrad Meyer if (cSize == 0) return 0; 214319fcbaf1SConrad Meyer /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block. 214419fcbaf1SConrad Meyer * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block. 21450c16b537SWarner Losh */ 214619fcbaf1SConrad Meyer if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) 214719fcbaf1SConrad Meyer return 0; /* block not compressed */ 21482b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 214919fcbaf1SConrad Meyer 215019fcbaf1SConrad Meyer /* Check compressibility */ 21510f743729SConrad Meyer { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy); 215219fcbaf1SConrad Meyer if (cSize >= maxCSize) return 0; /* block not compressed */ 215319fcbaf1SConrad Meyer } 215419fcbaf1SConrad Meyer 21550c16b537SWarner Losh return cSize; 21560c16b537SWarner Losh } 21570c16b537SWarner Losh 21580c16b537SWarner Losh /* ZSTD_selectBlockCompressor() : 21590c16b537SWarner Losh * Not static, but internal use only (used by long distance matcher) 21600c16b537SWarner Losh * assumption : strat is a valid strategy */ 21610f743729SConrad Meyer ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode) 21620c16b537SWarner Losh { 2163a0483764SConrad Meyer static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = { 21640c16b537SWarner Losh { ZSTD_compressBlock_fast /* default for 0 */, 21650f743729SConrad Meyer ZSTD_compressBlock_fast, 21660f743729SConrad Meyer ZSTD_compressBlock_doubleFast, 21670f743729SConrad Meyer ZSTD_compressBlock_greedy, 21680f743729SConrad Meyer ZSTD_compressBlock_lazy, 21690f743729SConrad Meyer ZSTD_compressBlock_lazy2, 21700f743729SConrad Meyer ZSTD_compressBlock_btlazy2, 21710f743729SConrad Meyer ZSTD_compressBlock_btopt, 2172a0483764SConrad Meyer ZSTD_compressBlock_btultra, 2173a0483764SConrad Meyer ZSTD_compressBlock_btultra2 }, 21740c16b537SWarner Losh { ZSTD_compressBlock_fast_extDict /* default for 0 */, 21750f743729SConrad Meyer ZSTD_compressBlock_fast_extDict, 21760f743729SConrad Meyer ZSTD_compressBlock_doubleFast_extDict, 21770f743729SConrad Meyer ZSTD_compressBlock_greedy_extDict, 21780f743729SConrad Meyer ZSTD_compressBlock_lazy_extDict, 21790f743729SConrad Meyer ZSTD_compressBlock_lazy2_extDict, 21800f743729SConrad Meyer ZSTD_compressBlock_btlazy2_extDict, 21810f743729SConrad Meyer ZSTD_compressBlock_btopt_extDict, 2182a0483764SConrad Meyer ZSTD_compressBlock_btultra_extDict, 21830f743729SConrad Meyer ZSTD_compressBlock_btultra_extDict }, 21840f743729SConrad Meyer { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */, 21850f743729SConrad Meyer ZSTD_compressBlock_fast_dictMatchState, 21860f743729SConrad Meyer ZSTD_compressBlock_doubleFast_dictMatchState, 21870f743729SConrad Meyer ZSTD_compressBlock_greedy_dictMatchState, 21880f743729SConrad Meyer ZSTD_compressBlock_lazy_dictMatchState, 21890f743729SConrad Meyer ZSTD_compressBlock_lazy2_dictMatchState, 21900f743729SConrad Meyer ZSTD_compressBlock_btlazy2_dictMatchState, 21910f743729SConrad Meyer ZSTD_compressBlock_btopt_dictMatchState, 2192a0483764SConrad Meyer ZSTD_compressBlock_btultra_dictMatchState, 21930f743729SConrad Meyer ZSTD_compressBlock_btultra_dictMatchState } 21940c16b537SWarner Losh }; 21950f743729SConrad Meyer ZSTD_blockCompressor selectedCompressor; 21960c16b537SWarner Losh ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); 2197052d3c12SConrad Meyer 2198a0483764SConrad Meyer assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); 2199a0483764SConrad Meyer selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; 22000f743729SConrad Meyer assert(selectedCompressor != NULL); 22010f743729SConrad Meyer return selectedCompressor; 22020c16b537SWarner Losh } 22030c16b537SWarner Losh 22040c16b537SWarner Losh static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, 22050c16b537SWarner Losh const BYTE* anchor, size_t lastLLSize) 22060c16b537SWarner Losh { 22070c16b537SWarner Losh memcpy(seqStorePtr->lit, anchor, lastLLSize); 22080c16b537SWarner Losh seqStorePtr->lit += lastLLSize; 22090c16b537SWarner Losh } 22100c16b537SWarner Losh 22110f743729SConrad Meyer void ZSTD_resetSeqStore(seqStore_t* ssPtr) 2212052d3c12SConrad Meyer { 2213052d3c12SConrad Meyer ssPtr->lit = ssPtr->litStart; 2214052d3c12SConrad Meyer ssPtr->sequences = ssPtr->sequencesStart; 2215052d3c12SConrad Meyer ssPtr->longLengthID = 0; 2216052d3c12SConrad Meyer } 2217052d3c12SConrad Meyer 22184d3f1eafSConrad Meyer typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e; 22194d3f1eafSConrad Meyer 22204d3f1eafSConrad Meyer static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) 22210c16b537SWarner Losh { 222219fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &zc->blockState.matchState; 22234d3f1eafSConrad Meyer DEBUGLOG(5, "ZSTD_buildSeqStore (srcSize=%zu)", srcSize); 22240f743729SConrad Meyer assert(srcSize <= ZSTD_BLOCKSIZE_MAX); 22250f743729SConrad Meyer /* Assert that we have correctly flushed the ctx params into the ms's copy */ 22260f743729SConrad Meyer ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); 222719fcbaf1SConrad Meyer if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) { 2228a0483764SConrad Meyer ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); 22294d3f1eafSConrad Meyer return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */ 223019fcbaf1SConrad Meyer } 2231052d3c12SConrad Meyer ZSTD_resetSeqStore(&(zc->seqStore)); 22322b9c00cbSConrad Meyer /* required for optimal parser to read stats from dictionary */ 22332b9c00cbSConrad Meyer ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy; 22342b9c00cbSConrad Meyer /* tell the optimal parser how we expect to compress literals */ 22352b9c00cbSConrad Meyer ms->opt.literalCompressionMode = zc->appliedParams.literalCompressionMode; 22360f743729SConrad Meyer /* a gap between an attached dict and the current window is not safe, 2237a0483764SConrad Meyer * they must remain adjacent, 2238a0483764SConrad Meyer * and when that stops being the case, the dict must be unset */ 22390f743729SConrad Meyer assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit); 2240052d3c12SConrad Meyer 2241052d3c12SConrad Meyer /* limited update after a very long match */ 224219fcbaf1SConrad Meyer { const BYTE* const base = ms->window.base; 22430c16b537SWarner Losh const BYTE* const istart = (const BYTE*)src; 22440c16b537SWarner Losh const U32 current = (U32)(istart-base); 22450f743729SConrad Meyer if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */ 224619fcbaf1SConrad Meyer if (current > ms->nextToUpdate + 384) 224719fcbaf1SConrad Meyer ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384)); 2248052d3c12SConrad Meyer } 224919fcbaf1SConrad Meyer 225019fcbaf1SConrad Meyer /* select and store sequences */ 22510f743729SConrad Meyer { ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms); 225219fcbaf1SConrad Meyer size_t lastLLSize; 225319fcbaf1SConrad Meyer { int i; 225419fcbaf1SConrad Meyer for (i = 0; i < ZSTD_REP_NUM; ++i) 225519fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i]; 2256052d3c12SConrad Meyer } 225719fcbaf1SConrad Meyer if (zc->externSeqStore.pos < zc->externSeqStore.size) { 225819fcbaf1SConrad Meyer assert(!zc->appliedParams.ldmParams.enableLdm); 225919fcbaf1SConrad Meyer /* Updates ldmSeqStore.pos */ 226019fcbaf1SConrad Meyer lastLLSize = 226119fcbaf1SConrad Meyer ZSTD_ldm_blockCompress(&zc->externSeqStore, 226219fcbaf1SConrad Meyer ms, &zc->seqStore, 226319fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep, 22640f743729SConrad Meyer src, srcSize); 226519fcbaf1SConrad Meyer assert(zc->externSeqStore.pos <= zc->externSeqStore.size); 226619fcbaf1SConrad Meyer } else if (zc->appliedParams.ldmParams.enableLdm) { 226719fcbaf1SConrad Meyer rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0}; 226819fcbaf1SConrad Meyer 226919fcbaf1SConrad Meyer ldmSeqStore.seq = zc->ldmSequences; 227019fcbaf1SConrad Meyer ldmSeqStore.capacity = zc->maxNbLdmSequences; 227119fcbaf1SConrad Meyer /* Updates ldmSeqStore.size */ 22722b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore, 227319fcbaf1SConrad Meyer &zc->appliedParams.ldmParams, 227419fcbaf1SConrad Meyer src, srcSize)); 227519fcbaf1SConrad Meyer /* Updates ldmSeqStore.pos */ 227619fcbaf1SConrad Meyer lastLLSize = 227719fcbaf1SConrad Meyer ZSTD_ldm_blockCompress(&ldmSeqStore, 227819fcbaf1SConrad Meyer ms, &zc->seqStore, 227919fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep, 22800f743729SConrad Meyer src, srcSize); 228119fcbaf1SConrad Meyer assert(ldmSeqStore.pos == ldmSeqStore.size); 228219fcbaf1SConrad Meyer } else { /* not long range mode */ 22830f743729SConrad Meyer ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode); 22840f743729SConrad Meyer lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); 228519fcbaf1SConrad Meyer } 228619fcbaf1SConrad Meyer { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; 228719fcbaf1SConrad Meyer ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize); 228819fcbaf1SConrad Meyer } } 22894d3f1eafSConrad Meyer return ZSTDbss_compress; 22904d3f1eafSConrad Meyer } 22914d3f1eafSConrad Meyer 2292*9cbefe25SConrad Meyer static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc) 2293*9cbefe25SConrad Meyer { 2294*9cbefe25SConrad Meyer const seqStore_t* seqStore = ZSTD_getSeqStore(zc); 2295*9cbefe25SConrad Meyer const seqDef* seqs = seqStore->sequencesStart; 2296*9cbefe25SConrad Meyer size_t seqsSize = seqStore->sequences - seqs; 2297*9cbefe25SConrad Meyer 2298*9cbefe25SConrad Meyer ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex]; 2299*9cbefe25SConrad Meyer size_t i; size_t position; int repIdx; 2300*9cbefe25SConrad Meyer 2301*9cbefe25SConrad Meyer assert(zc->seqCollector.seqIndex + 1 < zc->seqCollector.maxSequences); 2302*9cbefe25SConrad Meyer for (i = 0, position = 0; i < seqsSize; ++i) { 2303*9cbefe25SConrad Meyer outSeqs[i].offset = seqs[i].offset; 2304*9cbefe25SConrad Meyer outSeqs[i].litLength = seqs[i].litLength; 2305*9cbefe25SConrad Meyer outSeqs[i].matchLength = seqs[i].matchLength + MINMATCH; 2306*9cbefe25SConrad Meyer 2307*9cbefe25SConrad Meyer if (i == seqStore->longLengthPos) { 2308*9cbefe25SConrad Meyer if (seqStore->longLengthID == 1) { 2309*9cbefe25SConrad Meyer outSeqs[i].litLength += 0x10000; 2310*9cbefe25SConrad Meyer } else if (seqStore->longLengthID == 2) { 2311*9cbefe25SConrad Meyer outSeqs[i].matchLength += 0x10000; 2312*9cbefe25SConrad Meyer } 2313*9cbefe25SConrad Meyer } 2314*9cbefe25SConrad Meyer 2315*9cbefe25SConrad Meyer if (outSeqs[i].offset <= ZSTD_REP_NUM) { 2316*9cbefe25SConrad Meyer outSeqs[i].rep = outSeqs[i].offset; 2317*9cbefe25SConrad Meyer repIdx = (unsigned int)i - outSeqs[i].offset; 2318*9cbefe25SConrad Meyer 2319*9cbefe25SConrad Meyer if (outSeqs[i].litLength == 0) { 2320*9cbefe25SConrad Meyer if (outSeqs[i].offset < 3) { 2321*9cbefe25SConrad Meyer --repIdx; 2322*9cbefe25SConrad Meyer } else { 2323*9cbefe25SConrad Meyer repIdx = (unsigned int)i - 1; 2324*9cbefe25SConrad Meyer } 2325*9cbefe25SConrad Meyer ++outSeqs[i].rep; 2326*9cbefe25SConrad Meyer } 2327*9cbefe25SConrad Meyer assert(repIdx >= -3); 2328*9cbefe25SConrad Meyer outSeqs[i].offset = repIdx >= 0 ? outSeqs[repIdx].offset : repStartValue[-repIdx - 1]; 2329*9cbefe25SConrad Meyer if (outSeqs[i].rep == 4) { 2330*9cbefe25SConrad Meyer --outSeqs[i].offset; 2331*9cbefe25SConrad Meyer } 2332*9cbefe25SConrad Meyer } else { 2333*9cbefe25SConrad Meyer outSeqs[i].offset -= ZSTD_REP_NUM; 2334*9cbefe25SConrad Meyer } 2335*9cbefe25SConrad Meyer 2336*9cbefe25SConrad Meyer position += outSeqs[i].litLength; 2337*9cbefe25SConrad Meyer outSeqs[i].matchPos = (unsigned int)position; 2338*9cbefe25SConrad Meyer position += outSeqs[i].matchLength; 2339*9cbefe25SConrad Meyer } 2340*9cbefe25SConrad Meyer zc->seqCollector.seqIndex += seqsSize; 2341*9cbefe25SConrad Meyer } 2342*9cbefe25SConrad Meyer 2343*9cbefe25SConrad Meyer size_t ZSTD_getSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs, 2344*9cbefe25SConrad Meyer size_t outSeqsSize, const void* src, size_t srcSize) 2345*9cbefe25SConrad Meyer { 2346*9cbefe25SConrad Meyer const size_t dstCapacity = ZSTD_compressBound(srcSize); 2347*9cbefe25SConrad Meyer void* dst = ZSTD_malloc(dstCapacity, ZSTD_defaultCMem); 2348*9cbefe25SConrad Meyer SeqCollector seqCollector; 2349*9cbefe25SConrad Meyer 2350*9cbefe25SConrad Meyer RETURN_ERROR_IF(dst == NULL, memory_allocation); 2351*9cbefe25SConrad Meyer 2352*9cbefe25SConrad Meyer seqCollector.collectSequences = 1; 2353*9cbefe25SConrad Meyer seqCollector.seqStart = outSeqs; 2354*9cbefe25SConrad Meyer seqCollector.seqIndex = 0; 2355*9cbefe25SConrad Meyer seqCollector.maxSequences = outSeqsSize; 2356*9cbefe25SConrad Meyer zc->seqCollector = seqCollector; 2357*9cbefe25SConrad Meyer 2358*9cbefe25SConrad Meyer ZSTD_compress2(zc, dst, dstCapacity, src, srcSize); 2359*9cbefe25SConrad Meyer ZSTD_free(dst, ZSTD_defaultCMem); 2360*9cbefe25SConrad Meyer return zc->seqCollector.seqIndex; 2361*9cbefe25SConrad Meyer } 2362*9cbefe25SConrad Meyer 2363*9cbefe25SConrad Meyer /* Returns true if the given block is a RLE block */ 2364*9cbefe25SConrad Meyer static int ZSTD_isRLE(const BYTE *ip, size_t length) { 2365*9cbefe25SConrad Meyer size_t i; 2366*9cbefe25SConrad Meyer if (length < 2) return 1; 2367*9cbefe25SConrad Meyer for (i = 1; i < length; ++i) { 2368*9cbefe25SConrad Meyer if (ip[0] != ip[i]) return 0; 2369*9cbefe25SConrad Meyer } 2370*9cbefe25SConrad Meyer return 1; 2371*9cbefe25SConrad Meyer } 2372*9cbefe25SConrad Meyer 23734d3f1eafSConrad Meyer static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, 23744d3f1eafSConrad Meyer void* dst, size_t dstCapacity, 2375*9cbefe25SConrad Meyer const void* src, size_t srcSize, U32 frame) 23764d3f1eafSConrad Meyer { 2377*9cbefe25SConrad Meyer /* This the upper bound for the length of an rle block. 2378*9cbefe25SConrad Meyer * This isn't the actual upper bound. Finding the real threshold 2379*9cbefe25SConrad Meyer * needs further investigation. 2380*9cbefe25SConrad Meyer */ 2381*9cbefe25SConrad Meyer const U32 rleMaxLength = 25; 23824d3f1eafSConrad Meyer size_t cSize; 2383*9cbefe25SConrad Meyer const BYTE* ip = (const BYTE*)src; 2384*9cbefe25SConrad Meyer BYTE* op = (BYTE*)dst; 23854d3f1eafSConrad Meyer DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", 2386*9cbefe25SConrad Meyer (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, 2387*9cbefe25SConrad Meyer (unsigned)zc->blockState.matchState.nextToUpdate); 23884d3f1eafSConrad Meyer 23894d3f1eafSConrad Meyer { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); 23904d3f1eafSConrad Meyer FORWARD_IF_ERROR(bss); 23914d3f1eafSConrad Meyer if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; } 23924d3f1eafSConrad Meyer } 239319fcbaf1SConrad Meyer 2394*9cbefe25SConrad Meyer if (zc->seqCollector.collectSequences) { 2395*9cbefe25SConrad Meyer ZSTD_copyBlockSequences(zc); 2396*9cbefe25SConrad Meyer return 0; 2397*9cbefe25SConrad Meyer } 2398*9cbefe25SConrad Meyer 239919fcbaf1SConrad Meyer /* encode sequences and literals */ 24000f743729SConrad Meyer cSize = ZSTD_compressSequences(&zc->seqStore, 240119fcbaf1SConrad Meyer &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, 240219fcbaf1SConrad Meyer &zc->appliedParams, 240319fcbaf1SConrad Meyer dst, dstCapacity, 2404a0483764SConrad Meyer srcSize, 2405a0483764SConrad Meyer zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */, 2406a0483764SConrad Meyer zc->bmi2); 24070f743729SConrad Meyer 2408*9cbefe25SConrad Meyer if (frame && 2409*9cbefe25SConrad Meyer /* We don't want to emit our first block as a RLE even if it qualifies because 2410*9cbefe25SConrad Meyer * doing so will cause the decoder (cli only) to throw a "should consume all input error." 2411*9cbefe25SConrad Meyer * This is only an issue for zstd <= v1.4.3 2412*9cbefe25SConrad Meyer */ 2413*9cbefe25SConrad Meyer !zc->isFirstBlock && 2414*9cbefe25SConrad Meyer cSize < rleMaxLength && 2415*9cbefe25SConrad Meyer ZSTD_isRLE(ip, srcSize)) 2416*9cbefe25SConrad Meyer { 2417*9cbefe25SConrad Meyer cSize = 1; 2418*9cbefe25SConrad Meyer op[0] = ip[0]; 2419*9cbefe25SConrad Meyer } 2420*9cbefe25SConrad Meyer 24210f743729SConrad Meyer out: 2422*9cbefe25SConrad Meyer if (!ZSTD_isError(cSize) && cSize > 1) { 24230f743729SConrad Meyer /* confirm repcodes and entropy tables when emitting a compressed block */ 24240f743729SConrad Meyer ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock; 242519fcbaf1SConrad Meyer zc->blockState.prevCBlock = zc->blockState.nextCBlock; 242619fcbaf1SConrad Meyer zc->blockState.nextCBlock = tmp; 242719fcbaf1SConrad Meyer } 24280f743729SConrad Meyer /* We check that dictionaries have offset codes available for the first 24290f743729SConrad Meyer * block. After the first block, the offcode table might not have large 24300f743729SConrad Meyer * enough codes to represent the offsets in the data. 24310f743729SConrad Meyer */ 24320f743729SConrad Meyer if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) 24330f743729SConrad Meyer zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; 24340f743729SConrad Meyer 243519fcbaf1SConrad Meyer return cSize; 243619fcbaf1SConrad Meyer } 24370c16b537SWarner Losh 24380c16b537SWarner Losh 2439*9cbefe25SConrad Meyer static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, 2440*9cbefe25SConrad Meyer ZSTD_cwksp* ws, 2441*9cbefe25SConrad Meyer ZSTD_CCtx_params const* params, 2442*9cbefe25SConrad Meyer void const* ip, 2443*9cbefe25SConrad Meyer void const* iend) 24444d3f1eafSConrad Meyer { 24454d3f1eafSConrad Meyer if (ZSTD_window_needOverflowCorrection(ms->window, iend)) { 24464d3f1eafSConrad Meyer U32 const maxDist = (U32)1 << params->cParams.windowLog; 24474d3f1eafSConrad Meyer U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); 24484d3f1eafSConrad Meyer U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); 24494d3f1eafSConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); 24504d3f1eafSConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); 24514d3f1eafSConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); 2452*9cbefe25SConrad Meyer ZSTD_cwksp_mark_tables_dirty(ws); 24534d3f1eafSConrad Meyer ZSTD_reduceIndex(ms, params, correction); 2454*9cbefe25SConrad Meyer ZSTD_cwksp_mark_tables_clean(ws); 24554d3f1eafSConrad Meyer if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; 24564d3f1eafSConrad Meyer else ms->nextToUpdate -= correction; 24574d3f1eafSConrad Meyer /* invalidate dictionaries on overflow correction */ 24584d3f1eafSConrad Meyer ms->loadedDictEnd = 0; 24594d3f1eafSConrad Meyer ms->dictMatchState = NULL; 24604d3f1eafSConrad Meyer } 24614d3f1eafSConrad Meyer } 24624d3f1eafSConrad Meyer 24630c16b537SWarner Losh /*! ZSTD_compress_frameChunk() : 24640c16b537SWarner Losh * Compress a chunk of data into one or multiple blocks. 24650c16b537SWarner Losh * All blocks will be terminated, all input will be consumed. 24660c16b537SWarner Losh * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content. 24670c16b537SWarner Losh * Frame is supposed already started (header already produced) 24680c16b537SWarner Losh * @return : compressed size, or an error code 24690c16b537SWarner Losh */ 24700c16b537SWarner Losh static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, 24710c16b537SWarner Losh void* dst, size_t dstCapacity, 24720c16b537SWarner Losh const void* src, size_t srcSize, 24730c16b537SWarner Losh U32 lastFrameChunk) 24740c16b537SWarner Losh { 24750c16b537SWarner Losh size_t blockSize = cctx->blockSize; 24760c16b537SWarner Losh size_t remaining = srcSize; 24770c16b537SWarner Losh const BYTE* ip = (const BYTE*)src; 24780c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 24790c16b537SWarner Losh BYTE* op = ostart; 24800c16b537SWarner Losh U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; 24814d3f1eafSConrad Meyer assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX); 24820c16b537SWarner Losh 2483a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); 24840c16b537SWarner Losh if (cctx->appliedParams.fParams.checksumFlag && srcSize) 24850c16b537SWarner Losh XXH64_update(&cctx->xxhState, src, srcSize); 24860c16b537SWarner Losh 24870c16b537SWarner Losh while (remaining) { 248819fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 24890c16b537SWarner Losh U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); 24900c16b537SWarner Losh 24912b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE, 24922b9c00cbSConrad Meyer dstSize_tooSmall, 24932b9c00cbSConrad Meyer "not enough space to store compressed block"); 24940c16b537SWarner Losh if (remaining < blockSize) blockSize = remaining; 24950c16b537SWarner Losh 2496*9cbefe25SConrad Meyer ZSTD_overflowCorrectIfNeeded( 2497*9cbefe25SConrad Meyer ms, &cctx->workspace, &cctx->appliedParams, ip, ip + blockSize); 24984d3f1eafSConrad Meyer ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); 24994d3f1eafSConrad Meyer 25004d3f1eafSConrad Meyer /* Ensure hash/chain table insertion resumes no sooner than lowlimit */ 250119fcbaf1SConrad Meyer if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; 25020c16b537SWarner Losh 2503052d3c12SConrad Meyer { size_t cSize = ZSTD_compressBlock_internal(cctx, 2504052d3c12SConrad Meyer op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, 2505*9cbefe25SConrad Meyer ip, blockSize, 1 /* frame */); 25062b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 25070c16b537SWarner Losh if (cSize == 0) { /* block is not compressible */ 25080f743729SConrad Meyer cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); 25092b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 25100c16b537SWarner Losh } else { 2511*9cbefe25SConrad Meyer const U32 cBlockHeader = cSize == 1 ? 2512*9cbefe25SConrad Meyer lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) : 2513*9cbefe25SConrad Meyer lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); 2514*9cbefe25SConrad Meyer MEM_writeLE24(op, cBlockHeader); 25150c16b537SWarner Losh cSize += ZSTD_blockHeaderSize; 25160c16b537SWarner Losh } 25170c16b537SWarner Losh 25180c16b537SWarner Losh ip += blockSize; 2519052d3c12SConrad Meyer assert(remaining >= blockSize); 2520052d3c12SConrad Meyer remaining -= blockSize; 25210c16b537SWarner Losh op += cSize; 2522052d3c12SConrad Meyer assert(dstCapacity >= cSize); 2523052d3c12SConrad Meyer dstCapacity -= cSize; 2524*9cbefe25SConrad Meyer cctx->isFirstBlock = 0; 2525052d3c12SConrad Meyer DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u", 2526a0483764SConrad Meyer (unsigned)cSize); 2527052d3c12SConrad Meyer } } 25280c16b537SWarner Losh 25290c16b537SWarner Losh if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending; 25304d3f1eafSConrad Meyer return (size_t)(op-ostart); 25310c16b537SWarner Losh } 25320c16b537SWarner Losh 25330c16b537SWarner Losh 25340c16b537SWarner Losh static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, 2535*9cbefe25SConrad Meyer const ZSTD_CCtx_params* params, U64 pledgedSrcSize, U32 dictID) 25360c16b537SWarner Losh { BYTE* const op = (BYTE*)dst; 25370c16b537SWarner Losh U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */ 2538*9cbefe25SConrad Meyer U32 const dictIDSizeCode = params->fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */ 2539*9cbefe25SConrad Meyer U32 const checksumFlag = params->fParams.checksumFlag>0; 2540*9cbefe25SConrad Meyer U32 const windowSize = (U32)1 << params->cParams.windowLog; 2541*9cbefe25SConrad Meyer U32 const singleSegment = params->fParams.contentSizeFlag && (windowSize >= pledgedSrcSize); 2542*9cbefe25SConrad Meyer BYTE const windowLogByte = (BYTE)((params->cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3); 2543*9cbefe25SConrad Meyer U32 const fcsCode = params->fParams.contentSizeFlag ? 25440c16b537SWarner Losh (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */ 25452b9c00cbSConrad Meyer BYTE const frameHeaderDescriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) ); 25460c16b537SWarner Losh size_t pos=0; 25470c16b537SWarner Losh 2548*9cbefe25SConrad Meyer assert(!(params->fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)); 25492b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall); 25500c16b537SWarner Losh DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", 2551*9cbefe25SConrad Meyer !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode); 25520c16b537SWarner Losh 2553*9cbefe25SConrad Meyer if (params->format == ZSTD_f_zstd1) { 25540c16b537SWarner Losh MEM_writeLE32(dst, ZSTD_MAGICNUMBER); 25550c16b537SWarner Losh pos = 4; 25560c16b537SWarner Losh } 25572b9c00cbSConrad Meyer op[pos++] = frameHeaderDescriptionByte; 25580c16b537SWarner Losh if (!singleSegment) op[pos++] = windowLogByte; 25590c16b537SWarner Losh switch(dictIDSizeCode) 25600c16b537SWarner Losh { 25610c16b537SWarner Losh default: assert(0); /* impossible */ 25620c16b537SWarner Losh case 0 : break; 25630c16b537SWarner Losh case 1 : op[pos] = (BYTE)(dictID); pos++; break; 25640c16b537SWarner Losh case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; 25650c16b537SWarner Losh case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break; 25660c16b537SWarner Losh } 25670c16b537SWarner Losh switch(fcsCode) 25680c16b537SWarner Losh { 25690c16b537SWarner Losh default: assert(0); /* impossible */ 25700c16b537SWarner Losh case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; 25710c16b537SWarner Losh case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; 25720c16b537SWarner Losh case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; 25730c16b537SWarner Losh case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break; 25740c16b537SWarner Losh } 25750c16b537SWarner Losh return pos; 25760c16b537SWarner Losh } 25770c16b537SWarner Losh 257819fcbaf1SConrad Meyer /* ZSTD_writeLastEmptyBlock() : 257919fcbaf1SConrad Meyer * output an empty Block with end-of-frame mark to complete a frame 258019fcbaf1SConrad Meyer * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h)) 25812b9c00cbSConrad Meyer * or an error code if `dstCapacity` is too small (<ZSTD_blockHeaderSize) 258219fcbaf1SConrad Meyer */ 258319fcbaf1SConrad Meyer size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) 258419fcbaf1SConrad Meyer { 25852b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall); 258619fcbaf1SConrad Meyer { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */ 258719fcbaf1SConrad Meyer MEM_writeLE24(dst, cBlockHeader24); 258819fcbaf1SConrad Meyer return ZSTD_blockHeaderSize; 258919fcbaf1SConrad Meyer } 259019fcbaf1SConrad Meyer } 259119fcbaf1SConrad Meyer 259219fcbaf1SConrad Meyer size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) 259319fcbaf1SConrad Meyer { 25942b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong); 25952b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm, 25962b9c00cbSConrad Meyer parameter_unsupported); 259719fcbaf1SConrad Meyer cctx->externSeqStore.seq = seq; 259819fcbaf1SConrad Meyer cctx->externSeqStore.size = nbSeq; 259919fcbaf1SConrad Meyer cctx->externSeqStore.capacity = nbSeq; 260019fcbaf1SConrad Meyer cctx->externSeqStore.pos = 0; 260119fcbaf1SConrad Meyer return 0; 260219fcbaf1SConrad Meyer } 260319fcbaf1SConrad Meyer 26040c16b537SWarner Losh 26050c16b537SWarner Losh static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, 26060c16b537SWarner Losh void* dst, size_t dstCapacity, 26070c16b537SWarner Losh const void* src, size_t srcSize, 26080c16b537SWarner Losh U32 frame, U32 lastFrameChunk) 26090c16b537SWarner Losh { 26100f743729SConrad Meyer ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 26110c16b537SWarner Losh size_t fhSize = 0; 26120c16b537SWarner Losh 261319fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u", 2614a0483764SConrad Meyer cctx->stage, (unsigned)srcSize); 26152b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->stage==ZSTDcs_created, stage_wrong, 26162b9c00cbSConrad Meyer "missing init (ZSTD_compressBegin)"); 26170c16b537SWarner Losh 26180c16b537SWarner Losh if (frame && (cctx->stage==ZSTDcs_init)) { 2619*9cbefe25SConrad Meyer fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 26200c16b537SWarner Losh cctx->pledgedSrcSizePlusOne-1, cctx->dictID); 26212b9c00cbSConrad Meyer FORWARD_IF_ERROR(fhSize); 26224d3f1eafSConrad Meyer assert(fhSize <= dstCapacity); 26230c16b537SWarner Losh dstCapacity -= fhSize; 26240c16b537SWarner Losh dst = (char*)dst + fhSize; 26250c16b537SWarner Losh cctx->stage = ZSTDcs_ongoing; 26260c16b537SWarner Losh } 26270c16b537SWarner Losh 2628052d3c12SConrad Meyer if (!srcSize) return fhSize; /* do not generate an empty block if no input */ 2629052d3c12SConrad Meyer 263019fcbaf1SConrad Meyer if (!ZSTD_window_update(&ms->window, src, srcSize)) { 263119fcbaf1SConrad Meyer ms->nextToUpdate = ms->window.dictLimit; 26320c16b537SWarner Losh } 26330f743729SConrad Meyer if (cctx->appliedParams.ldmParams.enableLdm) { 263419fcbaf1SConrad Meyer ZSTD_window_update(&cctx->ldmState.window, src, srcSize); 26350f743729SConrad Meyer } 26360f743729SConrad Meyer 26370f743729SConrad Meyer if (!frame) { 26380f743729SConrad Meyer /* overflow check and correction for block mode */ 2639*9cbefe25SConrad Meyer ZSTD_overflowCorrectIfNeeded( 2640*9cbefe25SConrad Meyer ms, &cctx->workspace, &cctx->appliedParams, 2641*9cbefe25SConrad Meyer src, (BYTE const*)src + srcSize); 26420f743729SConrad Meyer } 26430c16b537SWarner Losh 2644a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (unsigned)cctx->blockSize); 2645052d3c12SConrad Meyer { size_t const cSize = frame ? 26460c16b537SWarner Losh ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : 2647*9cbefe25SConrad Meyer ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize, 0 /* frame */); 26482b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 26490c16b537SWarner Losh cctx->consumedSrcSize += srcSize; 265019fcbaf1SConrad Meyer cctx->producedCSize += (cSize + fhSize); 26510f743729SConrad Meyer assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); 26520f743729SConrad Meyer if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ 26530f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); 26542b9c00cbSConrad Meyer RETURN_ERROR_IF( 26552b9c00cbSConrad Meyer cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne, 26562b9c00cbSConrad Meyer srcSize_wrong, 26572b9c00cbSConrad Meyer "error : pledgedSrcSize = %u, while realSrcSize >= %u", 26582b9c00cbSConrad Meyer (unsigned)cctx->pledgedSrcSizePlusOne-1, 26592b9c00cbSConrad Meyer (unsigned)cctx->consumedSrcSize); 266019fcbaf1SConrad Meyer } 26610c16b537SWarner Losh return cSize + fhSize; 2662052d3c12SConrad Meyer } 26630c16b537SWarner Losh } 26640c16b537SWarner Losh 26650c16b537SWarner Losh size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, 26660c16b537SWarner Losh void* dst, size_t dstCapacity, 26670c16b537SWarner Losh const void* src, size_t srcSize) 26680c16b537SWarner Losh { 2669a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize); 26700c16b537SWarner Losh return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */); 26710c16b537SWarner Losh } 26720c16b537SWarner Losh 26730c16b537SWarner Losh 26740c16b537SWarner Losh size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) 26750c16b537SWarner Losh { 267619fcbaf1SConrad Meyer ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams; 267719fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 26780c16b537SWarner Losh return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog); 26790c16b537SWarner Losh } 26800c16b537SWarner Losh 26810c16b537SWarner Losh size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) 26820c16b537SWarner Losh { 2683*9cbefe25SConrad Meyer DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize); 2684*9cbefe25SConrad Meyer { size_t const blockSizeMax = ZSTD_getBlockSize(cctx); 2685*9cbefe25SConrad Meyer RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong); } 26860f743729SConrad Meyer 26870c16b537SWarner Losh return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); 26880c16b537SWarner Losh } 26890c16b537SWarner Losh 26900c16b537SWarner Losh /*! ZSTD_loadDictionaryContent() : 26910c16b537SWarner Losh * @return : 0, or an error code 26920c16b537SWarner Losh */ 26930f743729SConrad Meyer static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, 2694*9cbefe25SConrad Meyer ZSTD_cwksp* ws, 26950f743729SConrad Meyer ZSTD_CCtx_params const* params, 26960f743729SConrad Meyer const void* src, size_t srcSize, 26970f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm) 26980c16b537SWarner Losh { 26994d3f1eafSConrad Meyer const BYTE* ip = (const BYTE*) src; 27000c16b537SWarner Losh const BYTE* const iend = ip + srcSize; 27010c16b537SWarner Losh 270219fcbaf1SConrad Meyer ZSTD_window_update(&ms->window, src, srcSize); 270319fcbaf1SConrad Meyer ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); 27040c16b537SWarner Losh 27050f743729SConrad Meyer /* Assert that we the ms params match the params we're being given */ 27060f743729SConrad Meyer ZSTD_assertEqualCParams(params->cParams, ms->cParams); 27070f743729SConrad Meyer 27080c16b537SWarner Losh if (srcSize <= HASH_READ_SIZE) return 0; 27090c16b537SWarner Losh 27104d3f1eafSConrad Meyer while (iend - ip > HASH_READ_SIZE) { 2711*9cbefe25SConrad Meyer size_t const remaining = (size_t)(iend - ip); 27124d3f1eafSConrad Meyer size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX); 27134d3f1eafSConrad Meyer const BYTE* const ichunk = ip + chunk; 27144d3f1eafSConrad Meyer 2715*9cbefe25SConrad Meyer ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk); 27164d3f1eafSConrad Meyer 271719fcbaf1SConrad Meyer switch(params->cParams.strategy) 27180c16b537SWarner Losh { 27190c16b537SWarner Losh case ZSTD_fast: 27204d3f1eafSConrad Meyer ZSTD_fillHashTable(ms, ichunk, dtlm); 27210c16b537SWarner Losh break; 27220c16b537SWarner Losh case ZSTD_dfast: 27234d3f1eafSConrad Meyer ZSTD_fillDoubleHashTable(ms, ichunk, dtlm); 27240c16b537SWarner Losh break; 27250c16b537SWarner Losh 27260c16b537SWarner Losh case ZSTD_greedy: 27270c16b537SWarner Losh case ZSTD_lazy: 27280c16b537SWarner Losh case ZSTD_lazy2: 27294d3f1eafSConrad Meyer if (chunk >= HASH_READ_SIZE) 27304d3f1eafSConrad Meyer ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE); 27310c16b537SWarner Losh break; 27320c16b537SWarner Losh 273319fcbaf1SConrad Meyer case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ 27340c16b537SWarner Losh case ZSTD_btopt: 27350c16b537SWarner Losh case ZSTD_btultra: 2736a0483764SConrad Meyer case ZSTD_btultra2: 27374d3f1eafSConrad Meyer if (chunk >= HASH_READ_SIZE) 27384d3f1eafSConrad Meyer ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk); 27390c16b537SWarner Losh break; 27400c16b537SWarner Losh 27410c16b537SWarner Losh default: 27420c16b537SWarner Losh assert(0); /* not possible : not a valid strategy id */ 27430c16b537SWarner Losh } 27440c16b537SWarner Losh 27454d3f1eafSConrad Meyer ip = ichunk; 27464d3f1eafSConrad Meyer } 27474d3f1eafSConrad Meyer 274819fcbaf1SConrad Meyer ms->nextToUpdate = (U32)(iend - ms->window.base); 27490c16b537SWarner Losh return 0; 27500c16b537SWarner Losh } 27510c16b537SWarner Losh 27520c16b537SWarner Losh 27530c16b537SWarner Losh /* Dictionaries that assign zero probability to symbols that show up causes problems 27540c16b537SWarner Losh when FSE encoding. Refuse dictionaries that assign zero probability to symbols 27550c16b537SWarner Losh that we may encounter during compression. 27560c16b537SWarner Losh NOTE: This behavior is not standard and could be improved in the future. */ 27570c16b537SWarner Losh static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) { 27580c16b537SWarner Losh U32 s; 27592b9c00cbSConrad Meyer RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted); 27600c16b537SWarner Losh for (s = 0; s <= maxSymbolValue; ++s) { 27612b9c00cbSConrad Meyer RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted); 27620c16b537SWarner Losh } 27630c16b537SWarner Losh return 0; 27640c16b537SWarner Losh } 27650c16b537SWarner Losh 27660c16b537SWarner Losh 27670c16b537SWarner Losh /* Dictionary format : 27680c16b537SWarner Losh * See : 27690c16b537SWarner Losh * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format 27700c16b537SWarner Losh */ 27710c16b537SWarner Losh /*! ZSTD_loadZstdDictionary() : 277219fcbaf1SConrad Meyer * @return : dictID, or an error code 27730c16b537SWarner Losh * assumptions : magic number supposed already checked 2774*9cbefe25SConrad Meyer * dictSize supposed >= 8 27750c16b537SWarner Losh */ 27760f743729SConrad Meyer static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, 27770f743729SConrad Meyer ZSTD_matchState_t* ms, 2778*9cbefe25SConrad Meyer ZSTD_cwksp* ws, 27790f743729SConrad Meyer ZSTD_CCtx_params const* params, 27800f743729SConrad Meyer const void* dict, size_t dictSize, 27810f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 27820f743729SConrad Meyer void* workspace) 27830c16b537SWarner Losh { 27840c16b537SWarner Losh const BYTE* dictPtr = (const BYTE*)dict; 27850c16b537SWarner Losh const BYTE* const dictEnd = dictPtr + dictSize; 27860c16b537SWarner Losh short offcodeNCount[MaxOff+1]; 27870c16b537SWarner Losh unsigned offcodeMaxValue = MaxOff; 278819fcbaf1SConrad Meyer size_t dictID; 27890c16b537SWarner Losh 279019fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 2791*9cbefe25SConrad Meyer assert(dictSize >= 8); 27920f743729SConrad Meyer assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); 27930c16b537SWarner Losh 27940c16b537SWarner Losh dictPtr += 4; /* skip magic number */ 279519fcbaf1SConrad Meyer dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr); 27960c16b537SWarner Losh dictPtr += 4; 27970c16b537SWarner Losh 27980c16b537SWarner Losh { unsigned maxSymbolValue = 255; 27990f743729SConrad Meyer size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr); 28002b9c00cbSConrad Meyer RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted); 28012b9c00cbSConrad Meyer RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted); 28020c16b537SWarner Losh dictPtr += hufHeaderSize; 28030c16b537SWarner Losh } 28040c16b537SWarner Losh 28050c16b537SWarner Losh { unsigned offcodeLog; 28060c16b537SWarner Losh size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); 28072b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted); 28082b9c00cbSConrad Meyer RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted); 28090c16b537SWarner Losh /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ 28100f743729SConrad Meyer /* fill all offset symbols to avoid garbage at end of table */ 28112b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 28122b9c00cbSConrad Meyer bs->entropy.fse.offcodeCTable, 2813a0483764SConrad Meyer offcodeNCount, MaxOff, offcodeLog, 28142b9c00cbSConrad Meyer workspace, HUF_WORKSPACE_SIZE)), 28150c16b537SWarner Losh dictionary_corrupted); 28160c16b537SWarner Losh dictPtr += offcodeHeaderSize; 28170c16b537SWarner Losh } 28180c16b537SWarner Losh 28190c16b537SWarner Losh { short matchlengthNCount[MaxML+1]; 28200c16b537SWarner Losh unsigned matchlengthMaxValue = MaxML, matchlengthLog; 28210c16b537SWarner Losh size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); 28222b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted); 28232b9c00cbSConrad Meyer RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted); 28240c16b537SWarner Losh /* Every match length code must have non-zero probability */ 28252b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML)); 28262b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 28272b9c00cbSConrad Meyer bs->entropy.fse.matchlengthCTable, 2828a0483764SConrad Meyer matchlengthNCount, matchlengthMaxValue, matchlengthLog, 28292b9c00cbSConrad Meyer workspace, HUF_WORKSPACE_SIZE)), 28300c16b537SWarner Losh dictionary_corrupted); 28310c16b537SWarner Losh dictPtr += matchlengthHeaderSize; 28320c16b537SWarner Losh } 28330c16b537SWarner Losh 28340c16b537SWarner Losh { short litlengthNCount[MaxLL+1]; 28350c16b537SWarner Losh unsigned litlengthMaxValue = MaxLL, litlengthLog; 28360c16b537SWarner Losh size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); 28372b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted); 28382b9c00cbSConrad Meyer RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted); 28390c16b537SWarner Losh /* Every literal length code must have non-zero probability */ 28402b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL)); 28412b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 28422b9c00cbSConrad Meyer bs->entropy.fse.litlengthCTable, 2843a0483764SConrad Meyer litlengthNCount, litlengthMaxValue, litlengthLog, 28442b9c00cbSConrad Meyer workspace, HUF_WORKSPACE_SIZE)), 28450c16b537SWarner Losh dictionary_corrupted); 28460c16b537SWarner Losh dictPtr += litlengthHeaderSize; 28470c16b537SWarner Losh } 28480c16b537SWarner Losh 28492b9c00cbSConrad Meyer RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted); 285019fcbaf1SConrad Meyer bs->rep[0] = MEM_readLE32(dictPtr+0); 285119fcbaf1SConrad Meyer bs->rep[1] = MEM_readLE32(dictPtr+4); 285219fcbaf1SConrad Meyer bs->rep[2] = MEM_readLE32(dictPtr+8); 28530c16b537SWarner Losh dictPtr += 12; 28540c16b537SWarner Losh 28550c16b537SWarner Losh { size_t const dictContentSize = (size_t)(dictEnd - dictPtr); 28560c16b537SWarner Losh U32 offcodeMax = MaxOff; 28570c16b537SWarner Losh if (dictContentSize <= ((U32)-1) - 128 KB) { 28580c16b537SWarner Losh U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ 28590c16b537SWarner Losh offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ 28600c16b537SWarner Losh } 28610c16b537SWarner Losh /* All offset values <= dictContentSize + 128 KB must be representable */ 28622b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff))); 28630c16b537SWarner Losh /* All repCodes must be <= dictContentSize and != 0*/ 28640c16b537SWarner Losh { U32 u; 28650c16b537SWarner Losh for (u=0; u<3; u++) { 28662b9c00cbSConrad Meyer RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted); 28672b9c00cbSConrad Meyer RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted); 28680c16b537SWarner Losh } } 28690c16b537SWarner Losh 28700f743729SConrad Meyer bs->entropy.huf.repeatMode = HUF_repeat_valid; 28710f743729SConrad Meyer bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid; 28720f743729SConrad Meyer bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid; 28730f743729SConrad Meyer bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid; 2874*9cbefe25SConrad Meyer FORWARD_IF_ERROR(ZSTD_loadDictionaryContent( 2875*9cbefe25SConrad Meyer ms, ws, params, dictPtr, dictContentSize, dtlm)); 287619fcbaf1SConrad Meyer return dictID; 28770c16b537SWarner Losh } 28780c16b537SWarner Losh } 28790c16b537SWarner Losh 28800c16b537SWarner Losh /** ZSTD_compress_insertDictionary() : 288119fcbaf1SConrad Meyer * @return : dictID, or an error code */ 28820f743729SConrad Meyer static size_t 28830f743729SConrad Meyer ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, 28840f743729SConrad Meyer ZSTD_matchState_t* ms, 2885*9cbefe25SConrad Meyer ZSTD_cwksp* ws, 28860f743729SConrad Meyer const ZSTD_CCtx_params* params, 28870c16b537SWarner Losh const void* dict, size_t dictSize, 288819fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 28890f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 289019fcbaf1SConrad Meyer void* workspace) 28910c16b537SWarner Losh { 2892052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); 2893*9cbefe25SConrad Meyer if ((dict==NULL) || (dictSize<8)) { 2894*9cbefe25SConrad Meyer RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong); 2895*9cbefe25SConrad Meyer return 0; 2896*9cbefe25SConrad Meyer } 28970c16b537SWarner Losh 289819fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(bs); 289919fcbaf1SConrad Meyer 29000c16b537SWarner Losh /* dict restricted modes */ 290119fcbaf1SConrad Meyer if (dictContentType == ZSTD_dct_rawContent) 2902*9cbefe25SConrad Meyer return ZSTD_loadDictionaryContent(ms, ws, params, dict, dictSize, dtlm); 29030c16b537SWarner Losh 29040c16b537SWarner Losh if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { 290519fcbaf1SConrad Meyer if (dictContentType == ZSTD_dct_auto) { 2906052d3c12SConrad Meyer DEBUGLOG(4, "raw content dictionary detected"); 2907*9cbefe25SConrad Meyer return ZSTD_loadDictionaryContent( 2908*9cbefe25SConrad Meyer ms, ws, params, dict, dictSize, dtlm); 29090c16b537SWarner Losh } 29102b9c00cbSConrad Meyer RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong); 29110c16b537SWarner Losh assert(0); /* impossible */ 29120c16b537SWarner Losh } 29130c16b537SWarner Losh 29140c16b537SWarner Losh /* dict as full zstd dictionary */ 2915*9cbefe25SConrad Meyer return ZSTD_loadZstdDictionary( 2916*9cbefe25SConrad Meyer bs, ms, ws, params, dict, dictSize, dtlm, workspace); 29170c16b537SWarner Losh } 29180c16b537SWarner Losh 2919*9cbefe25SConrad Meyer #define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB) 2920*9cbefe25SConrad Meyer #define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6) 2921*9cbefe25SConrad Meyer 29220c16b537SWarner Losh /*! ZSTD_compressBegin_internal() : 29230c16b537SWarner Losh * @return : 0, or an error code */ 29240f743729SConrad Meyer static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, 29250c16b537SWarner Losh const void* dict, size_t dictSize, 292619fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 29270f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 29280c16b537SWarner Losh const ZSTD_CDict* cdict, 2929*9cbefe25SConrad Meyer const ZSTD_CCtx_params* params, U64 pledgedSrcSize, 29300c16b537SWarner Losh ZSTD_buffered_policy_e zbuff) 29310c16b537SWarner Losh { 2932*9cbefe25SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog); 29330c16b537SWarner Losh /* params are supposed to be fully validated at this point */ 2934*9cbefe25SConrad Meyer assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); 29350c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 2936*9cbefe25SConrad Meyer if ( (cdict) 2937*9cbefe25SConrad Meyer && (cdict->dictContentSize > 0) 2938*9cbefe25SConrad Meyer && ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF 2939*9cbefe25SConrad Meyer || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER 2940*9cbefe25SConrad Meyer || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN 2941*9cbefe25SConrad Meyer || cdict->compressionLevel == 0) 2942*9cbefe25SConrad Meyer && (params->attachDictPref != ZSTD_dictForceLoad) ) { 29430f743729SConrad Meyer return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff); 29440c16b537SWarner Losh } 29450c16b537SWarner Losh 2946*9cbefe25SConrad Meyer FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, *params, pledgedSrcSize, 2947*9cbefe25SConrad Meyer ZSTDcrp_makeClean, zbuff) ); 2948*9cbefe25SConrad Meyer { size_t const dictID = cdict ? 2949*9cbefe25SConrad Meyer ZSTD_compress_insertDictionary( 295019fcbaf1SConrad Meyer cctx->blockState.prevCBlock, &cctx->blockState.matchState, 2951*9cbefe25SConrad Meyer &cctx->workspace, params, cdict->dictContent, cdict->dictContentSize, 2952*9cbefe25SConrad Meyer dictContentType, dtlm, cctx->entropyWorkspace) 2953*9cbefe25SConrad Meyer : ZSTD_compress_insertDictionary( 2954*9cbefe25SConrad Meyer cctx->blockState.prevCBlock, &cctx->blockState.matchState, 2955*9cbefe25SConrad Meyer &cctx->workspace, params, dict, dictSize, 2956*9cbefe25SConrad Meyer dictContentType, dtlm, cctx->entropyWorkspace); 29572b9c00cbSConrad Meyer FORWARD_IF_ERROR(dictID); 29584d3f1eafSConrad Meyer assert(dictID <= UINT_MAX); 295919fcbaf1SConrad Meyer cctx->dictID = (U32)dictID; 296019fcbaf1SConrad Meyer } 296119fcbaf1SConrad Meyer return 0; 29620c16b537SWarner Losh } 29630c16b537SWarner Losh 2964052d3c12SConrad Meyer size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, 29650c16b537SWarner Losh const void* dict, size_t dictSize, 296619fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 29670f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 2968052d3c12SConrad Meyer const ZSTD_CDict* cdict, 2969*9cbefe25SConrad Meyer const ZSTD_CCtx_params* params, 29700c16b537SWarner Losh unsigned long long pledgedSrcSize) 29710c16b537SWarner Losh { 2972*9cbefe25SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params->cParams.windowLog); 29730c16b537SWarner Losh /* compression parameters verification and optimization */ 2974*9cbefe25SConrad Meyer FORWARD_IF_ERROR( ZSTD_checkCParams(params->cParams) ); 2975052d3c12SConrad Meyer return ZSTD_compressBegin_internal(cctx, 29760f743729SConrad Meyer dict, dictSize, dictContentType, dtlm, 2977052d3c12SConrad Meyer cdict, 29780c16b537SWarner Losh params, pledgedSrcSize, 29790c16b537SWarner Losh ZSTDb_not_buffered); 29800c16b537SWarner Losh } 29810c16b537SWarner Losh 29820c16b537SWarner Losh /*! ZSTD_compressBegin_advanced() : 29830c16b537SWarner Losh * @return : 0, or an error code */ 29840c16b537SWarner Losh size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, 29850c16b537SWarner Losh const void* dict, size_t dictSize, 29860c16b537SWarner Losh ZSTD_parameters params, unsigned long long pledgedSrcSize) 29870c16b537SWarner Losh { 29880c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 2989*9cbefe25SConrad Meyer ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); 2990052d3c12SConrad Meyer return ZSTD_compressBegin_advanced_internal(cctx, 29910f743729SConrad Meyer dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, 2992052d3c12SConrad Meyer NULL /*cdict*/, 2993*9cbefe25SConrad Meyer &cctxParams, pledgedSrcSize); 29940c16b537SWarner Losh } 29950c16b537SWarner Losh 29960c16b537SWarner Losh size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) 29970c16b537SWarner Losh { 299819fcbaf1SConrad Meyer ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); 29990c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 3000*9cbefe25SConrad Meyer ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); 3001a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize); 30020f743729SConrad Meyer return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, 3003*9cbefe25SConrad Meyer &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); 30040c16b537SWarner Losh } 30050c16b537SWarner Losh 30060c16b537SWarner Losh size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) 30070c16b537SWarner Losh { 30080c16b537SWarner Losh return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); 30090c16b537SWarner Losh } 30100c16b537SWarner Losh 30110c16b537SWarner Losh 30120c16b537SWarner Losh /*! ZSTD_writeEpilogue() : 30130c16b537SWarner Losh * Ends a frame. 30140c16b537SWarner Losh * @return : nb of bytes written into dst (or an error code) */ 30150c16b537SWarner Losh static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) 30160c16b537SWarner Losh { 30170c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 30180c16b537SWarner Losh BYTE* op = ostart; 30190c16b537SWarner Losh size_t fhSize = 0; 30200c16b537SWarner Losh 302119fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_writeEpilogue"); 30222b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing"); 30230c16b537SWarner Losh 30240c16b537SWarner Losh /* special case : empty frame */ 30250c16b537SWarner Losh if (cctx->stage == ZSTDcs_init) { 3026*9cbefe25SConrad Meyer fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0); 30272b9c00cbSConrad Meyer FORWARD_IF_ERROR(fhSize); 30280c16b537SWarner Losh dstCapacity -= fhSize; 30290c16b537SWarner Losh op += fhSize; 30300c16b537SWarner Losh cctx->stage = ZSTDcs_ongoing; 30310c16b537SWarner Losh } 30320c16b537SWarner Losh 30330c16b537SWarner Losh if (cctx->stage != ZSTDcs_ending) { 30340c16b537SWarner Losh /* write one last empty block, make it the "last" block */ 30350c16b537SWarner Losh U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0; 30362b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall); 30370c16b537SWarner Losh MEM_writeLE32(op, cBlockHeader24); 30380c16b537SWarner Losh op += ZSTD_blockHeaderSize; 30390c16b537SWarner Losh dstCapacity -= ZSTD_blockHeaderSize; 30400c16b537SWarner Losh } 30410c16b537SWarner Losh 30420c16b537SWarner Losh if (cctx->appliedParams.fParams.checksumFlag) { 30430c16b537SWarner Losh U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); 30442b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall); 3045a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum); 30460c16b537SWarner Losh MEM_writeLE32(op, checksum); 30470c16b537SWarner Losh op += 4; 30480c16b537SWarner Losh } 30490c16b537SWarner Losh 30500c16b537SWarner Losh cctx->stage = ZSTDcs_created; /* return to "created but no init" status */ 30510c16b537SWarner Losh return op-ostart; 30520c16b537SWarner Losh } 30530c16b537SWarner Losh 30540c16b537SWarner Losh size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, 30550c16b537SWarner Losh void* dst, size_t dstCapacity, 30560c16b537SWarner Losh const void* src, size_t srcSize) 30570c16b537SWarner Losh { 30580c16b537SWarner Losh size_t endResult; 30590c16b537SWarner Losh size_t const cSize = ZSTD_compressContinue_internal(cctx, 30600c16b537SWarner Losh dst, dstCapacity, src, srcSize, 30610c16b537SWarner Losh 1 /* frame mode */, 1 /* last chunk */); 30622b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 30630c16b537SWarner Losh endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); 30642b9c00cbSConrad Meyer FORWARD_IF_ERROR(endResult); 30650f743729SConrad Meyer assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); 30660f743729SConrad Meyer if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ 30670f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); 30680c16b537SWarner Losh DEBUGLOG(4, "end of frame : controlling src size"); 30692b9c00cbSConrad Meyer RETURN_ERROR_IF( 30702b9c00cbSConrad Meyer cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1, 30712b9c00cbSConrad Meyer srcSize_wrong, 30722b9c00cbSConrad Meyer "error : pledgedSrcSize = %u, while realSrcSize = %u", 30732b9c00cbSConrad Meyer (unsigned)cctx->pledgedSrcSizePlusOne-1, 30742b9c00cbSConrad Meyer (unsigned)cctx->consumedSrcSize); 30752b9c00cbSConrad Meyer } 30760c16b537SWarner Losh return cSize + endResult; 30770c16b537SWarner Losh } 30780c16b537SWarner Losh 30790c16b537SWarner Losh 30800c16b537SWarner Losh static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, 30810c16b537SWarner Losh void* dst, size_t dstCapacity, 30820c16b537SWarner Losh const void* src, size_t srcSize, 30830c16b537SWarner Losh const void* dict,size_t dictSize, 30840c16b537SWarner Losh ZSTD_parameters params) 30850c16b537SWarner Losh { 30860c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 3087*9cbefe25SConrad Meyer ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); 3088052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_internal"); 30890c16b537SWarner Losh return ZSTD_compress_advanced_internal(cctx, 30900c16b537SWarner Losh dst, dstCapacity, 30910c16b537SWarner Losh src, srcSize, 30920c16b537SWarner Losh dict, dictSize, 3093*9cbefe25SConrad Meyer &cctxParams); 30940c16b537SWarner Losh } 30950c16b537SWarner Losh 30960f743729SConrad Meyer size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, 30970c16b537SWarner Losh void* dst, size_t dstCapacity, 30980c16b537SWarner Losh const void* src, size_t srcSize, 30990c16b537SWarner Losh const void* dict,size_t dictSize, 31000c16b537SWarner Losh ZSTD_parameters params) 31010c16b537SWarner Losh { 3102052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_advanced"); 31032b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams)); 31040f743729SConrad Meyer return ZSTD_compress_internal(cctx, 31050f743729SConrad Meyer dst, dstCapacity, 31060f743729SConrad Meyer src, srcSize, 31070f743729SConrad Meyer dict, dictSize, 31080f743729SConrad Meyer params); 31090c16b537SWarner Losh } 31100c16b537SWarner Losh 31110c16b537SWarner Losh /* Internal */ 31120c16b537SWarner Losh size_t ZSTD_compress_advanced_internal( 31130c16b537SWarner Losh ZSTD_CCtx* cctx, 31140c16b537SWarner Losh void* dst, size_t dstCapacity, 31150c16b537SWarner Losh const void* src, size_t srcSize, 31160c16b537SWarner Losh const void* dict,size_t dictSize, 3117*9cbefe25SConrad Meyer const ZSTD_CCtx_params* params) 31180c16b537SWarner Losh { 3119a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize); 31202b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, 31210f743729SConrad Meyer dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, 31220c16b537SWarner Losh params, srcSize, ZSTDb_not_buffered) ); 31230c16b537SWarner Losh return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 31240c16b537SWarner Losh } 31250c16b537SWarner Losh 31260f743729SConrad Meyer size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, 31270f743729SConrad Meyer void* dst, size_t dstCapacity, 31280f743729SConrad Meyer const void* src, size_t srcSize, 31290f743729SConrad Meyer const void* dict, size_t dictSize, 31300f743729SConrad Meyer int compressionLevel) 31310c16b537SWarner Losh { 31320f743729SConrad Meyer ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize + (!srcSize), dict ? dictSize : 0); 3133*9cbefe25SConrad Meyer ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(&cctx->requestedParams, params); 313419fcbaf1SConrad Meyer assert(params.fParams.contentSizeFlag == 1); 3135*9cbefe25SConrad Meyer return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams); 31360c16b537SWarner Losh } 31370c16b537SWarner Losh 31380f743729SConrad Meyer size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, 31390f743729SConrad Meyer void* dst, size_t dstCapacity, 31400f743729SConrad Meyer const void* src, size_t srcSize, 31410f743729SConrad Meyer int compressionLevel) 31420c16b537SWarner Losh { 3143a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (unsigned)srcSize); 31440f743729SConrad Meyer assert(cctx != NULL); 314519fcbaf1SConrad Meyer return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel); 31460c16b537SWarner Losh } 31470c16b537SWarner Losh 31480f743729SConrad Meyer size_t ZSTD_compress(void* dst, size_t dstCapacity, 31490f743729SConrad Meyer const void* src, size_t srcSize, 31500f743729SConrad Meyer int compressionLevel) 31510c16b537SWarner Losh { 31520c16b537SWarner Losh size_t result; 31530c16b537SWarner Losh ZSTD_CCtx ctxBody; 31540f743729SConrad Meyer ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem); 31550c16b537SWarner Losh result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); 31560f743729SConrad Meyer ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */ 31570c16b537SWarner Losh return result; 31580c16b537SWarner Losh } 31590c16b537SWarner Losh 31600c16b537SWarner Losh 31610c16b537SWarner Losh /* ===== Dictionary API ===== */ 31620c16b537SWarner Losh 31630c16b537SWarner Losh /*! ZSTD_estimateCDictSize_advanced() : 31640c16b537SWarner Losh * Estimate amount of memory that will be needed to create a dictionary with following arguments */ 31650c16b537SWarner Losh size_t ZSTD_estimateCDictSize_advanced( 31660c16b537SWarner Losh size_t dictSize, ZSTD_compressionParameters cParams, 31670c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod) 31680c16b537SWarner Losh { 3169a0483764SConrad Meyer DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict)); 3170*9cbefe25SConrad Meyer return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) 3171*9cbefe25SConrad Meyer + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) 3172*9cbefe25SConrad Meyer + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) 3173*9cbefe25SConrad Meyer + (dictLoadMethod == ZSTD_dlm_byRef ? 0 3174*9cbefe25SConrad Meyer : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *)))); 31750c16b537SWarner Losh } 31760c16b537SWarner Losh 31770c16b537SWarner Losh size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) 31780c16b537SWarner Losh { 31790c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 31800c16b537SWarner Losh return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); 31810c16b537SWarner Losh } 31820c16b537SWarner Losh 31830c16b537SWarner Losh size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) 31840c16b537SWarner Losh { 31850c16b537SWarner Losh if (cdict==NULL) return 0; /* support sizeof on NULL */ 3186a0483764SConrad Meyer DEBUGLOG(5, "sizeof(*cdict) : %u", (unsigned)sizeof(*cdict)); 3187*9cbefe25SConrad Meyer /* cdict may be in the workspace */ 3188*9cbefe25SConrad Meyer return (cdict->workspace.workspace == cdict ? 0 : sizeof(*cdict)) 3189*9cbefe25SConrad Meyer + ZSTD_cwksp_sizeof(&cdict->workspace); 31900c16b537SWarner Losh } 31910c16b537SWarner Losh 31920c16b537SWarner Losh static size_t ZSTD_initCDict_internal( 31930c16b537SWarner Losh ZSTD_CDict* cdict, 31940c16b537SWarner Losh const void* dictBuffer, size_t dictSize, 31950c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 319619fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 31970c16b537SWarner Losh ZSTD_compressionParameters cParams) 31980c16b537SWarner Losh { 3199a0483764SConrad Meyer DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType); 320019fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 32010f743729SConrad Meyer cdict->matchState.cParams = cParams; 32020c16b537SWarner Losh if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { 32030c16b537SWarner Losh cdict->dictContent = dictBuffer; 32040c16b537SWarner Losh } else { 3205*9cbefe25SConrad Meyer void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*))); 32062b9c00cbSConrad Meyer RETURN_ERROR_IF(!internalBuffer, memory_allocation); 3207*9cbefe25SConrad Meyer cdict->dictContent = internalBuffer; 32080c16b537SWarner Losh memcpy(internalBuffer, dictBuffer, dictSize); 32090c16b537SWarner Losh } 32100c16b537SWarner Losh cdict->dictContentSize = dictSize; 32110c16b537SWarner Losh 3212*9cbefe25SConrad Meyer cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE); 3213*9cbefe25SConrad Meyer 3214*9cbefe25SConrad Meyer 321519fcbaf1SConrad Meyer /* Reset the state to no dictionary */ 321619fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(&cdict->cBlockState); 3217*9cbefe25SConrad Meyer FORWARD_IF_ERROR(ZSTD_reset_matchState( 3218*9cbefe25SConrad Meyer &cdict->matchState, 3219*9cbefe25SConrad Meyer &cdict->workspace, 32204d3f1eafSConrad Meyer &cParams, 3221*9cbefe25SConrad Meyer ZSTDcrp_makeClean, 3222*9cbefe25SConrad Meyer ZSTDirp_reset, 3223*9cbefe25SConrad Meyer ZSTD_resetTarget_CDict)); 322419fcbaf1SConrad Meyer /* (Maybe) load the dictionary 3225*9cbefe25SConrad Meyer * Skips loading the dictionary if it is < 8 bytes. 322619fcbaf1SConrad Meyer */ 322719fcbaf1SConrad Meyer { ZSTD_CCtx_params params; 322819fcbaf1SConrad Meyer memset(¶ms, 0, sizeof(params)); 322919fcbaf1SConrad Meyer params.compressionLevel = ZSTD_CLEVEL_DEFAULT; 323019fcbaf1SConrad Meyer params.fParams.contentSizeFlag = 1; 323119fcbaf1SConrad Meyer params.cParams = cParams; 323219fcbaf1SConrad Meyer { size_t const dictID = ZSTD_compress_insertDictionary( 3233*9cbefe25SConrad Meyer &cdict->cBlockState, &cdict->matchState, &cdict->workspace, 3234*9cbefe25SConrad Meyer ¶ms, cdict->dictContent, cdict->dictContentSize, 3235*9cbefe25SConrad Meyer dictContentType, ZSTD_dtlm_full, cdict->entropyWorkspace); 32362b9c00cbSConrad Meyer FORWARD_IF_ERROR(dictID); 323719fcbaf1SConrad Meyer assert(dictID <= (size_t)(U32)-1); 323819fcbaf1SConrad Meyer cdict->dictID = (U32)dictID; 323919fcbaf1SConrad Meyer } 32400c16b537SWarner Losh } 32410c16b537SWarner Losh 32420c16b537SWarner Losh return 0; 32430c16b537SWarner Losh } 32440c16b537SWarner Losh 32450c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, 32460c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 324719fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 32480c16b537SWarner Losh ZSTD_compressionParameters cParams, ZSTD_customMem customMem) 32490c16b537SWarner Losh { 3250a0483764SConrad Meyer DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType); 32510c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 32520c16b537SWarner Losh 3253*9cbefe25SConrad Meyer { size_t const workspaceSize = 3254*9cbefe25SConrad Meyer ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) + 3255*9cbefe25SConrad Meyer ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) + 3256*9cbefe25SConrad Meyer ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) + 3257*9cbefe25SConrad Meyer (dictLoadMethod == ZSTD_dlm_byRef ? 0 3258*9cbefe25SConrad Meyer : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))); 325919fcbaf1SConrad Meyer void* const workspace = ZSTD_malloc(workspaceSize, customMem); 3260*9cbefe25SConrad Meyer ZSTD_cwksp ws; 3261*9cbefe25SConrad Meyer ZSTD_CDict* cdict; 32620c16b537SWarner Losh 3263*9cbefe25SConrad Meyer if (!workspace) { 326419fcbaf1SConrad Meyer ZSTD_free(workspace, customMem); 32650c16b537SWarner Losh return NULL; 32660c16b537SWarner Losh } 3267*9cbefe25SConrad Meyer 3268*9cbefe25SConrad Meyer ZSTD_cwksp_init(&ws, workspace, workspaceSize); 3269*9cbefe25SConrad Meyer 3270*9cbefe25SConrad Meyer cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); 3271*9cbefe25SConrad Meyer assert(cdict != NULL); 3272*9cbefe25SConrad Meyer ZSTD_cwksp_move(&cdict->workspace, &ws); 327319fcbaf1SConrad Meyer cdict->customMem = customMem; 3274*9cbefe25SConrad Meyer cdict->compressionLevel = 0; /* signals advanced API usage */ 3275*9cbefe25SConrad Meyer 32760c16b537SWarner Losh if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 32770c16b537SWarner Losh dictBuffer, dictSize, 327819fcbaf1SConrad Meyer dictLoadMethod, dictContentType, 32790c16b537SWarner Losh cParams) )) { 32800c16b537SWarner Losh ZSTD_freeCDict(cdict); 32810c16b537SWarner Losh return NULL; 32820c16b537SWarner Losh } 32830c16b537SWarner Losh 32840c16b537SWarner Losh return cdict; 32850c16b537SWarner Losh } 32860c16b537SWarner Losh } 32870c16b537SWarner Losh 32880c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) 32890c16b537SWarner Losh { 32900c16b537SWarner Losh ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 3291*9cbefe25SConrad Meyer ZSTD_CDict* cdict = ZSTD_createCDict_advanced(dict, dictSize, 329219fcbaf1SConrad Meyer ZSTD_dlm_byCopy, ZSTD_dct_auto, 32930c16b537SWarner Losh cParams, ZSTD_defaultCMem); 3294*9cbefe25SConrad Meyer if (cdict) 3295*9cbefe25SConrad Meyer cdict->compressionLevel = compressionLevel == 0 ? ZSTD_CLEVEL_DEFAULT : compressionLevel; 3296*9cbefe25SConrad Meyer return cdict; 32970c16b537SWarner Losh } 32980c16b537SWarner Losh 32990c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) 33000c16b537SWarner Losh { 33010c16b537SWarner Losh ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 33020c16b537SWarner Losh return ZSTD_createCDict_advanced(dict, dictSize, 330319fcbaf1SConrad Meyer ZSTD_dlm_byRef, ZSTD_dct_auto, 33040c16b537SWarner Losh cParams, ZSTD_defaultCMem); 33050c16b537SWarner Losh } 33060c16b537SWarner Losh 33070c16b537SWarner Losh size_t ZSTD_freeCDict(ZSTD_CDict* cdict) 33080c16b537SWarner Losh { 33090c16b537SWarner Losh if (cdict==NULL) return 0; /* support free on NULL */ 331019fcbaf1SConrad Meyer { ZSTD_customMem const cMem = cdict->customMem; 3311*9cbefe25SConrad Meyer int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict); 3312*9cbefe25SConrad Meyer ZSTD_cwksp_free(&cdict->workspace, cMem); 3313*9cbefe25SConrad Meyer if (!cdictInWorkspace) { 33140c16b537SWarner Losh ZSTD_free(cdict, cMem); 3315*9cbefe25SConrad Meyer } 33160c16b537SWarner Losh return 0; 33170c16b537SWarner Losh } 33180c16b537SWarner Losh } 33190c16b537SWarner Losh 33200c16b537SWarner Losh /*! ZSTD_initStaticCDict_advanced() : 33210c16b537SWarner Losh * Generate a digested dictionary in provided memory area. 33220c16b537SWarner Losh * workspace: The memory area to emplace the dictionary into. 33230c16b537SWarner Losh * Provided pointer must 8-bytes aligned. 33240c16b537SWarner Losh * It must outlive dictionary usage. 33250c16b537SWarner Losh * workspaceSize: Use ZSTD_estimateCDictSize() 33260c16b537SWarner Losh * to determine how large workspace must be. 33270c16b537SWarner Losh * cParams : use ZSTD_getCParams() to transform a compression level 33280c16b537SWarner Losh * into its relevants cParams. 33290c16b537SWarner Losh * @return : pointer to ZSTD_CDict*, or NULL if error (size too small) 33300c16b537SWarner Losh * Note : there is no corresponding "free" function. 33310c16b537SWarner Losh * Since workspace was allocated externally, it must be freed externally. 33320c16b537SWarner Losh */ 333319fcbaf1SConrad Meyer const ZSTD_CDict* ZSTD_initStaticCDict( 333419fcbaf1SConrad Meyer void* workspace, size_t workspaceSize, 33350c16b537SWarner Losh const void* dict, size_t dictSize, 33360c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 333719fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 33380c16b537SWarner Losh ZSTD_compressionParameters cParams) 33390c16b537SWarner Losh { 334019fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); 3341*9cbefe25SConrad Meyer size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) 3342*9cbefe25SConrad Meyer + (dictLoadMethod == ZSTD_dlm_byRef ? 0 3343*9cbefe25SConrad Meyer : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*)))) 3344*9cbefe25SConrad Meyer + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) 3345*9cbefe25SConrad Meyer + matchStateSize; 3346*9cbefe25SConrad Meyer ZSTD_CDict* cdict; 3347*9cbefe25SConrad Meyer 33480c16b537SWarner Losh if ((size_t)workspace & 7) return NULL; /* 8-aligned */ 3349*9cbefe25SConrad Meyer 3350*9cbefe25SConrad Meyer { 3351*9cbefe25SConrad Meyer ZSTD_cwksp ws; 3352*9cbefe25SConrad Meyer ZSTD_cwksp_init(&ws, workspace, workspaceSize); 3353*9cbefe25SConrad Meyer cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict)); 3354*9cbefe25SConrad Meyer if (cdict == NULL) return NULL; 3355*9cbefe25SConrad Meyer ZSTD_cwksp_move(&cdict->workspace, &ws); 3356*9cbefe25SConrad Meyer } 3357*9cbefe25SConrad Meyer 3358052d3c12SConrad Meyer DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u", 3359a0483764SConrad Meyer (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize)); 33600c16b537SWarner Losh if (workspaceSize < neededSize) return NULL; 33610c16b537SWarner Losh 33620c16b537SWarner Losh if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 33630c16b537SWarner Losh dict, dictSize, 3364*9cbefe25SConrad Meyer dictLoadMethod, dictContentType, 33650c16b537SWarner Losh cParams) )) 33660c16b537SWarner Losh return NULL; 33670c16b537SWarner Losh 33680c16b537SWarner Losh return cdict; 33690c16b537SWarner Losh } 33700c16b537SWarner Losh 337119fcbaf1SConrad Meyer ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) 337219fcbaf1SConrad Meyer { 337319fcbaf1SConrad Meyer assert(cdict != NULL); 33740f743729SConrad Meyer return cdict->matchState.cParams; 33750c16b537SWarner Losh } 33760c16b537SWarner Losh 33770c16b537SWarner Losh /* ZSTD_compressBegin_usingCDict_advanced() : 33780c16b537SWarner Losh * cdict must be != NULL */ 33790c16b537SWarner Losh size_t ZSTD_compressBegin_usingCDict_advanced( 33800c16b537SWarner Losh ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, 33810c16b537SWarner Losh ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) 33820c16b537SWarner Losh { 3383052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced"); 33842b9c00cbSConrad Meyer RETURN_ERROR_IF(cdict==NULL, dictionary_wrong); 33850c16b537SWarner Losh { ZSTD_CCtx_params params = cctx->requestedParams; 3386*9cbefe25SConrad Meyer params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF 3387*9cbefe25SConrad Meyer || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER 3388*9cbefe25SConrad Meyer || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN 3389*9cbefe25SConrad Meyer || cdict->compressionLevel == 0 ) 3390*9cbefe25SConrad Meyer && (params.attachDictPref != ZSTD_dictForceLoad) ? 3391*9cbefe25SConrad Meyer ZSTD_getCParamsFromCDict(cdict) 3392*9cbefe25SConrad Meyer : ZSTD_getCParams(cdict->compressionLevel, 3393*9cbefe25SConrad Meyer pledgedSrcSize, 3394*9cbefe25SConrad Meyer cdict->dictContentSize); 339519fcbaf1SConrad Meyer /* Increase window log to fit the entire dictionary and source if the 339619fcbaf1SConrad Meyer * source size is known. Limit the increase to 19, which is the 339719fcbaf1SConrad Meyer * window log for compression level 1 with the largest source size. 339819fcbaf1SConrad Meyer */ 339919fcbaf1SConrad Meyer if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { 340019fcbaf1SConrad Meyer U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); 340119fcbaf1SConrad Meyer U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; 340219fcbaf1SConrad Meyer params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog); 340319fcbaf1SConrad Meyer } 34040c16b537SWarner Losh params.fParams = fParams; 34050c16b537SWarner Losh return ZSTD_compressBegin_internal(cctx, 34060f743729SConrad Meyer NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, 34070c16b537SWarner Losh cdict, 3408*9cbefe25SConrad Meyer ¶ms, pledgedSrcSize, 34090c16b537SWarner Losh ZSTDb_not_buffered); 34100c16b537SWarner Losh } 34110c16b537SWarner Losh } 34120c16b537SWarner Losh 34130c16b537SWarner Losh /* ZSTD_compressBegin_usingCDict() : 34140c16b537SWarner Losh * pledgedSrcSize=0 means "unknown" 34150c16b537SWarner Losh * if pledgedSrcSize>0, it will enable contentSizeFlag */ 34160c16b537SWarner Losh size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 34170c16b537SWarner Losh { 34180c16b537SWarner Losh ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 3419052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); 34200f743729SConrad Meyer return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); 34210c16b537SWarner Losh } 34220c16b537SWarner Losh 34230c16b537SWarner Losh size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, 34240c16b537SWarner Losh void* dst, size_t dstCapacity, 34250c16b537SWarner Losh const void* src, size_t srcSize, 34260c16b537SWarner Losh const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) 34270c16b537SWarner Losh { 34282b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */ 34290c16b537SWarner Losh return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 34300c16b537SWarner Losh } 34310c16b537SWarner Losh 34320c16b537SWarner Losh /*! ZSTD_compress_usingCDict() : 34330c16b537SWarner Losh * Compression using a digested Dictionary. 34340c16b537SWarner Losh * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times. 34350c16b537SWarner Losh * Note that compression parameters are decided at CDict creation time 34360c16b537SWarner Losh * while frame parameters are hardcoded */ 34370c16b537SWarner Losh size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, 34380c16b537SWarner Losh void* dst, size_t dstCapacity, 34390c16b537SWarner Losh const void* src, size_t srcSize, 34400c16b537SWarner Losh const ZSTD_CDict* cdict) 34410c16b537SWarner Losh { 34420c16b537SWarner Losh ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 34430c16b537SWarner Losh return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); 34440c16b537SWarner Losh } 34450c16b537SWarner Losh 34460c16b537SWarner Losh 34470c16b537SWarner Losh 34480c16b537SWarner Losh /* ****************************************************************** 34490c16b537SWarner Losh * Streaming 34500c16b537SWarner Losh ********************************************************************/ 34510c16b537SWarner Losh 34520c16b537SWarner Losh ZSTD_CStream* ZSTD_createCStream(void) 34530c16b537SWarner Losh { 3454052d3c12SConrad Meyer DEBUGLOG(3, "ZSTD_createCStream"); 34550c16b537SWarner Losh return ZSTD_createCStream_advanced(ZSTD_defaultCMem); 34560c16b537SWarner Losh } 34570c16b537SWarner Losh 34580c16b537SWarner Losh ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize) 34590c16b537SWarner Losh { 34600c16b537SWarner Losh return ZSTD_initStaticCCtx(workspace, workspaceSize); 34610c16b537SWarner Losh } 34620c16b537SWarner Losh 34630c16b537SWarner Losh ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem) 34640c16b537SWarner Losh { /* CStream and CCtx are now same object */ 34650c16b537SWarner Losh return ZSTD_createCCtx_advanced(customMem); 34660c16b537SWarner Losh } 34670c16b537SWarner Losh 34680c16b537SWarner Losh size_t ZSTD_freeCStream(ZSTD_CStream* zcs) 34690c16b537SWarner Losh { 34700c16b537SWarner Losh return ZSTD_freeCCtx(zcs); /* same object */ 34710c16b537SWarner Losh } 34720c16b537SWarner Losh 34730c16b537SWarner Losh 34740c16b537SWarner Losh 34750c16b537SWarner Losh /*====== Initialization ======*/ 34760c16b537SWarner Losh 34770c16b537SWarner Losh size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; } 34780c16b537SWarner Losh 34790c16b537SWarner Losh size_t ZSTD_CStreamOutSize(void) 34800c16b537SWarner Losh { 34810c16b537SWarner Losh return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; 34820c16b537SWarner Losh } 34830c16b537SWarner Losh 348419fcbaf1SConrad Meyer static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx, 348519fcbaf1SConrad Meyer const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType, 3486052d3c12SConrad Meyer const ZSTD_CDict* const cdict, 34870f743729SConrad Meyer ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize) 34880c16b537SWarner Losh { 34890f743729SConrad Meyer DEBUGLOG(4, "ZSTD_resetCStream_internal"); 34900f743729SConrad Meyer /* Finalize the compression parameters */ 34910f743729SConrad Meyer params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, dictSize); 34920c16b537SWarner Losh /* params are supposed to be fully validated at this point */ 34930c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 34940c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 34950c16b537SWarner Losh 34962b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, 34970f743729SConrad Meyer dict, dictSize, dictContentType, ZSTD_dtlm_fast, 34980c16b537SWarner Losh cdict, 3499*9cbefe25SConrad Meyer ¶ms, pledgedSrcSize, 35000c16b537SWarner Losh ZSTDb_buffered) ); 35010c16b537SWarner Losh 350219fcbaf1SConrad Meyer cctx->inToCompress = 0; 350319fcbaf1SConrad Meyer cctx->inBuffPos = 0; 350419fcbaf1SConrad Meyer cctx->inBuffTarget = cctx->blockSize 350519fcbaf1SConrad Meyer + (cctx->blockSize == pledgedSrcSize); /* for small input: avoid automatic flush on reaching end of block, since it would require to add a 3-bytes null block to end frame */ 350619fcbaf1SConrad Meyer cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; 350719fcbaf1SConrad Meyer cctx->streamStage = zcss_load; 350819fcbaf1SConrad Meyer cctx->frameEnded = 0; 35090c16b537SWarner Losh return 0; /* ready to go */ 35100c16b537SWarner Losh } 35110c16b537SWarner Losh 3512052d3c12SConrad Meyer /* ZSTD_resetCStream(): 3513052d3c12SConrad Meyer * pledgedSrcSize == 0 means "unknown" */ 35142b9c00cbSConrad Meyer size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pss) 35150c16b537SWarner Losh { 35162b9c00cbSConrad Meyer /* temporary : 0 interpreted as "unknown" during transition period. 35172b9c00cbSConrad Meyer * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. 35182b9c00cbSConrad Meyer * 0 will be interpreted as "empty" in the future. 35192b9c00cbSConrad Meyer */ 35202b9c00cbSConrad Meyer U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 3521a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize); 35222b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 35232b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 35242b9c00cbSConrad Meyer return 0; 35250c16b537SWarner Losh } 35260c16b537SWarner Losh 35270c16b537SWarner Losh /*! ZSTD_initCStream_internal() : 3528052d3c12SConrad Meyer * Note : for lib/compress only. Used by zstdmt_compress.c. 35290c16b537SWarner Losh * Assumption 1 : params are valid 35300c16b537SWarner Losh * Assumption 2 : either dict, or cdict, is defined, not both */ 35310c16b537SWarner Losh size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, 35320c16b537SWarner Losh const void* dict, size_t dictSize, const ZSTD_CDict* cdict, 3533*9cbefe25SConrad Meyer const ZSTD_CCtx_params* params, 3534*9cbefe25SConrad Meyer unsigned long long pledgedSrcSize) 35350c16b537SWarner Losh { 35360c16b537SWarner Losh DEBUGLOG(4, "ZSTD_initCStream_internal"); 35372b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 35382b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 3539*9cbefe25SConrad Meyer assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams))); 3540*9cbefe25SConrad Meyer zcs->requestedParams = *params; 35410c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 35422b9c00cbSConrad Meyer if (dict) { 35432b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); 35440c16b537SWarner Losh } else { 35452b9c00cbSConrad Meyer /* Dictionary is cleared if !cdict */ 35462b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); 35470c16b537SWarner Losh } 35482b9c00cbSConrad Meyer return 0; 35490c16b537SWarner Losh } 35500c16b537SWarner Losh 35510c16b537SWarner Losh /* ZSTD_initCStream_usingCDict_advanced() : 35520c16b537SWarner Losh * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ 35530c16b537SWarner Losh size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, 35540c16b537SWarner Losh const ZSTD_CDict* cdict, 35550c16b537SWarner Losh ZSTD_frameParameters fParams, 35560c16b537SWarner Losh unsigned long long pledgedSrcSize) 3557052d3c12SConrad Meyer { 3558052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced"); 35592b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 35602b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 35612b9c00cbSConrad Meyer zcs->requestedParams.fParams = fParams; 35622b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); 35632b9c00cbSConrad Meyer return 0; 35640c16b537SWarner Losh } 35650c16b537SWarner Losh 35660c16b537SWarner Losh /* note : cdict must outlive compression session */ 35670c16b537SWarner Losh size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict) 35680c16b537SWarner Losh { 3569052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingCDict"); 35702b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 35712b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); 35722b9c00cbSConrad Meyer return 0; 35730c16b537SWarner Losh } 35740c16b537SWarner Losh 357519fcbaf1SConrad Meyer 3576052d3c12SConrad Meyer /* ZSTD_initCStream_advanced() : 357719fcbaf1SConrad Meyer * pledgedSrcSize must be exact. 3578052d3c12SConrad Meyer * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. 3579*9cbefe25SConrad Meyer * dict is loaded with default parameters ZSTD_dct_auto and ZSTD_dlm_byCopy. */ 35800c16b537SWarner Losh size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, 35810c16b537SWarner Losh const void* dict, size_t dictSize, 35822b9c00cbSConrad Meyer ZSTD_parameters params, unsigned long long pss) 35830c16b537SWarner Losh { 35842b9c00cbSConrad Meyer /* for compatibility with older programs relying on this behavior. 35852b9c00cbSConrad Meyer * Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. 35862b9c00cbSConrad Meyer * This line will be removed in the future. 35872b9c00cbSConrad Meyer */ 35882b9c00cbSConrad Meyer U64 const pledgedSrcSize = (pss==0 && params.fParams.contentSizeFlag==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 35892b9c00cbSConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_advanced"); 35902b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 35912b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 35922b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) ); 3593*9cbefe25SConrad Meyer zcs->requestedParams = ZSTD_assignParamsToCCtxParams(&zcs->requestedParams, params); 35942b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); 35952b9c00cbSConrad Meyer return 0; 359619fcbaf1SConrad Meyer } 35970c16b537SWarner Losh 35980c16b537SWarner Losh size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) 35990c16b537SWarner Losh { 36002b9c00cbSConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingDict"); 36012b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 36022b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); 36032b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); 36042b9c00cbSConrad Meyer return 0; 36050c16b537SWarner Losh } 36060c16b537SWarner Losh 3607052d3c12SConrad Meyer size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss) 36080c16b537SWarner Losh { 36092b9c00cbSConrad Meyer /* temporary : 0 interpreted as "unknown" during transition period. 36102b9c00cbSConrad Meyer * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. 36112b9c00cbSConrad Meyer * 0 will be interpreted as "empty" in the future. 36122b9c00cbSConrad Meyer */ 36132b9c00cbSConrad Meyer U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 36142b9c00cbSConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_srcSize"); 36152b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 36162b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) ); 36172b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); 36182b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 36192b9c00cbSConrad Meyer return 0; 36200c16b537SWarner Losh } 36210c16b537SWarner Losh 36220c16b537SWarner Losh size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) 36230c16b537SWarner Losh { 3624052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream"); 36252b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 36262b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) ); 36272b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); 36282b9c00cbSConrad Meyer return 0; 36290c16b537SWarner Losh } 36300c16b537SWarner Losh 36310c16b537SWarner Losh /*====== Compression ======*/ 36320c16b537SWarner Losh 3633a0483764SConrad Meyer static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx) 3634a0483764SConrad Meyer { 3635a0483764SConrad Meyer size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; 3636a0483764SConrad Meyer if (hintInSize==0) hintInSize = cctx->blockSize; 3637a0483764SConrad Meyer return hintInSize; 3638a0483764SConrad Meyer } 3639a0483764SConrad Meyer 3640a0483764SConrad Meyer static size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, 36410c16b537SWarner Losh const void* src, size_t srcSize) 36420c16b537SWarner Losh { 36430c16b537SWarner Losh size_t const length = MIN(dstCapacity, srcSize); 36440c16b537SWarner Losh if (length) memcpy(dst, src, length); 36450c16b537SWarner Losh return length; 36460c16b537SWarner Losh } 36470c16b537SWarner Losh 36480c16b537SWarner Losh /** ZSTD_compressStream_generic(): 3649a0483764SConrad Meyer * internal function for all *compressStream*() variants 365019fcbaf1SConrad Meyer * non-static, because can be called from zstdmt_compress.c 36510c16b537SWarner Losh * @return : hint size for next input */ 36522b9c00cbSConrad Meyer static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, 36530c16b537SWarner Losh ZSTD_outBuffer* output, 36540c16b537SWarner Losh ZSTD_inBuffer* input, 36550c16b537SWarner Losh ZSTD_EndDirective const flushMode) 36560c16b537SWarner Losh { 36570c16b537SWarner Losh const char* const istart = (const char*)input->src; 36580c16b537SWarner Losh const char* const iend = istart + input->size; 36590c16b537SWarner Losh const char* ip = istart + input->pos; 36600c16b537SWarner Losh char* const ostart = (char*)output->dst; 36610c16b537SWarner Losh char* const oend = ostart + output->size; 36620c16b537SWarner Losh char* op = ostart + output->pos; 36630c16b537SWarner Losh U32 someMoreWork = 1; 36640c16b537SWarner Losh 36650c16b537SWarner Losh /* check expectations */ 3666a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode); 36670c16b537SWarner Losh assert(zcs->inBuff != NULL); 36680c16b537SWarner Losh assert(zcs->inBuffSize > 0); 36690c16b537SWarner Losh assert(zcs->outBuff != NULL); 36700c16b537SWarner Losh assert(zcs->outBuffSize > 0); 36710c16b537SWarner Losh assert(output->pos <= output->size); 36720c16b537SWarner Losh assert(input->pos <= input->size); 36730c16b537SWarner Losh 36740c16b537SWarner Losh while (someMoreWork) { 36750c16b537SWarner Losh switch(zcs->streamStage) 36760c16b537SWarner Losh { 36770c16b537SWarner Losh case zcss_init: 36782b9c00cbSConrad Meyer RETURN_ERROR(init_missing, "call ZSTD_initCStream() first!"); 36790c16b537SWarner Losh 36800c16b537SWarner Losh case zcss_load: 36810c16b537SWarner Losh if ( (flushMode == ZSTD_e_end) 36820c16b537SWarner Losh && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */ 36830c16b537SWarner Losh && (zcs->inBuffPos == 0) ) { 36840c16b537SWarner Losh /* shortcut to compression pass directly into output buffer */ 36850c16b537SWarner Losh size_t const cSize = ZSTD_compressEnd(zcs, 36860c16b537SWarner Losh op, oend-op, ip, iend-ip); 3687a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize); 36882b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 36890c16b537SWarner Losh ip = iend; 36900c16b537SWarner Losh op += cSize; 36910c16b537SWarner Losh zcs->frameEnded = 1; 3692a0483764SConrad Meyer ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 36930c16b537SWarner Losh someMoreWork = 0; break; 36940c16b537SWarner Losh } 36950c16b537SWarner Losh /* complete loading into inBuffer */ 36960c16b537SWarner Losh { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; 36970c16b537SWarner Losh size_t const loaded = ZSTD_limitCopy( 36980c16b537SWarner Losh zcs->inBuff + zcs->inBuffPos, toLoad, 36990c16b537SWarner Losh ip, iend-ip); 37000c16b537SWarner Losh zcs->inBuffPos += loaded; 37010c16b537SWarner Losh ip += loaded; 37020c16b537SWarner Losh if ( (flushMode == ZSTD_e_continue) 37030c16b537SWarner Losh && (zcs->inBuffPos < zcs->inBuffTarget) ) { 37040c16b537SWarner Losh /* not enough input to fill full block : stop here */ 37050c16b537SWarner Losh someMoreWork = 0; break; 37060c16b537SWarner Losh } 37070c16b537SWarner Losh if ( (flushMode == ZSTD_e_flush) 37080c16b537SWarner Losh && (zcs->inBuffPos == zcs->inToCompress) ) { 37090c16b537SWarner Losh /* empty */ 37100c16b537SWarner Losh someMoreWork = 0; break; 37110c16b537SWarner Losh } 37120c16b537SWarner Losh } 37130c16b537SWarner Losh /* compress current block (note : this stage cannot be stopped in the middle) */ 37140c16b537SWarner Losh DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode); 37150c16b537SWarner Losh { void* cDst; 37160c16b537SWarner Losh size_t cSize; 37170c16b537SWarner Losh size_t const iSize = zcs->inBuffPos - zcs->inToCompress; 37180c16b537SWarner Losh size_t oSize = oend-op; 37190c16b537SWarner Losh unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); 37200c16b537SWarner Losh if (oSize >= ZSTD_compressBound(iSize)) 37210c16b537SWarner Losh cDst = op; /* compress into output buffer, to skip flush stage */ 37220c16b537SWarner Losh else 37230c16b537SWarner Losh cDst = zcs->outBuff, oSize = zcs->outBuffSize; 37240c16b537SWarner Losh cSize = lastBlock ? 37250c16b537SWarner Losh ZSTD_compressEnd(zcs, cDst, oSize, 37260c16b537SWarner Losh zcs->inBuff + zcs->inToCompress, iSize) : 37270c16b537SWarner Losh ZSTD_compressContinue(zcs, cDst, oSize, 37280c16b537SWarner Losh zcs->inBuff + zcs->inToCompress, iSize); 37292b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 37300c16b537SWarner Losh zcs->frameEnded = lastBlock; 37310c16b537SWarner Losh /* prepare next block */ 37320c16b537SWarner Losh zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; 37330c16b537SWarner Losh if (zcs->inBuffTarget > zcs->inBuffSize) 37340c16b537SWarner Losh zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; 37350c16b537SWarner Losh DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", 3736a0483764SConrad Meyer (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); 37370c16b537SWarner Losh if (!lastBlock) 37380c16b537SWarner Losh assert(zcs->inBuffTarget <= zcs->inBuffSize); 37390c16b537SWarner Losh zcs->inToCompress = zcs->inBuffPos; 37400c16b537SWarner Losh if (cDst == op) { /* no need to flush */ 37410c16b537SWarner Losh op += cSize; 37420c16b537SWarner Losh if (zcs->frameEnded) { 37430c16b537SWarner Losh DEBUGLOG(5, "Frame completed directly in outBuffer"); 37440c16b537SWarner Losh someMoreWork = 0; 3745a0483764SConrad Meyer ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 37460c16b537SWarner Losh } 37470c16b537SWarner Losh break; 37480c16b537SWarner Losh } 37490c16b537SWarner Losh zcs->outBuffContentSize = cSize; 37500c16b537SWarner Losh zcs->outBuffFlushedSize = 0; 37510c16b537SWarner Losh zcs->streamStage = zcss_flush; /* pass-through to flush stage */ 37520c16b537SWarner Losh } 37530c16b537SWarner Losh /* fall-through */ 37540c16b537SWarner Losh case zcss_flush: 37550c16b537SWarner Losh DEBUGLOG(5, "flush stage"); 37560c16b537SWarner Losh { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; 37574d3f1eafSConrad Meyer size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op), 37580c16b537SWarner Losh zcs->outBuff + zcs->outBuffFlushedSize, toFlush); 37590c16b537SWarner Losh DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u", 3760a0483764SConrad Meyer (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed); 37610c16b537SWarner Losh op += flushed; 37620c16b537SWarner Losh zcs->outBuffFlushedSize += flushed; 37630c16b537SWarner Losh if (toFlush!=flushed) { 37640c16b537SWarner Losh /* flush not fully completed, presumably because dst is too small */ 37650c16b537SWarner Losh assert(op==oend); 37660c16b537SWarner Losh someMoreWork = 0; 37670c16b537SWarner Losh break; 37680c16b537SWarner Losh } 37690c16b537SWarner Losh zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; 37700c16b537SWarner Losh if (zcs->frameEnded) { 37710c16b537SWarner Losh DEBUGLOG(5, "Frame completed on flush"); 37720c16b537SWarner Losh someMoreWork = 0; 3773a0483764SConrad Meyer ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 37740c16b537SWarner Losh break; 37750c16b537SWarner Losh } 37760c16b537SWarner Losh zcs->streamStage = zcss_load; 37770c16b537SWarner Losh break; 37780c16b537SWarner Losh } 37790c16b537SWarner Losh 37800c16b537SWarner Losh default: /* impossible */ 37810c16b537SWarner Losh assert(0); 37820c16b537SWarner Losh } 37830c16b537SWarner Losh } 37840c16b537SWarner Losh 37850c16b537SWarner Losh input->pos = ip - istart; 37860c16b537SWarner Losh output->pos = op - ostart; 37870c16b537SWarner Losh if (zcs->frameEnded) return 0; 3788a0483764SConrad Meyer return ZSTD_nextInputSizeHint(zcs); 37890c16b537SWarner Losh } 3790a0483764SConrad Meyer 3791a0483764SConrad Meyer static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx) 3792a0483764SConrad Meyer { 3793a0483764SConrad Meyer #ifdef ZSTD_MULTITHREAD 3794a0483764SConrad Meyer if (cctx->appliedParams.nbWorkers >= 1) { 3795a0483764SConrad Meyer assert(cctx->mtctx != NULL); 3796a0483764SConrad Meyer return ZSTDMT_nextInputSizeHint(cctx->mtctx); 3797a0483764SConrad Meyer } 3798a0483764SConrad Meyer #endif 3799a0483764SConrad Meyer return ZSTD_nextInputSizeHint(cctx); 3800a0483764SConrad Meyer 38010c16b537SWarner Losh } 38020c16b537SWarner Losh 38030c16b537SWarner Losh size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) 38040c16b537SWarner Losh { 38052b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) ); 3806a0483764SConrad Meyer return ZSTD_nextInputSizeHint_MTorST(zcs); 38070c16b537SWarner Losh } 38080c16b537SWarner Losh 38090c16b537SWarner Losh 3810a0483764SConrad Meyer size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, 38110c16b537SWarner Losh ZSTD_outBuffer* output, 38120c16b537SWarner Losh ZSTD_inBuffer* input, 38130c16b537SWarner Losh ZSTD_EndDirective endOp) 38140c16b537SWarner Losh { 3815a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp); 38160c16b537SWarner Losh /* check conditions */ 38172b9c00cbSConrad Meyer RETURN_ERROR_IF(output->pos > output->size, GENERIC); 38182b9c00cbSConrad Meyer RETURN_ERROR_IF(input->pos > input->size, GENERIC); 38190c16b537SWarner Losh assert(cctx!=NULL); 38200c16b537SWarner Losh 38210c16b537SWarner Losh /* transparent initialization stage */ 38220c16b537SWarner Losh if (cctx->streamStage == zcss_init) { 38230c16b537SWarner Losh ZSTD_CCtx_params params = cctx->requestedParams; 3824052d3c12SConrad Meyer ZSTD_prefixDict const prefixDict = cctx->prefixDict; 38252b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) ); /* Init the local dict if present. */ 38260c16b537SWarner Losh memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ 38270c16b537SWarner Losh assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ 3828a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); 3829052d3c12SConrad Meyer if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */ 3830052d3c12SConrad Meyer params.cParams = ZSTD_getCParamsFromCCtxParams( 383119fcbaf1SConrad Meyer &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); 38320c16b537SWarner Losh 38330f743729SConrad Meyer 38340c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 383519fcbaf1SConrad Meyer if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { 383619fcbaf1SConrad Meyer params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ 383719fcbaf1SConrad Meyer } 383819fcbaf1SConrad Meyer if (params.nbWorkers > 0) { 383919fcbaf1SConrad Meyer /* mt context creation */ 38400f743729SConrad Meyer if (cctx->mtctx == NULL) { 3841a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u", 384219fcbaf1SConrad Meyer params.nbWorkers); 3843*9cbefe25SConrad Meyer cctx->mtctx = ZSTDMT_createCCtx_advanced((U32)params.nbWorkers, cctx->customMem); 38442b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation); 38450c16b537SWarner Losh } 384619fcbaf1SConrad Meyer /* mt compression */ 384719fcbaf1SConrad Meyer DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); 38482b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTDMT_initCStream_internal( 38490c16b537SWarner Losh cctx->mtctx, 385019fcbaf1SConrad Meyer prefixDict.dict, prefixDict.dictSize, ZSTD_dct_rawContent, 38510c16b537SWarner Losh cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); 38520c16b537SWarner Losh cctx->streamStage = zcss_load; 385319fcbaf1SConrad Meyer cctx->appliedParams.nbWorkers = params.nbWorkers; 38540c16b537SWarner Losh } else 38550c16b537SWarner Losh #endif 38562b9c00cbSConrad Meyer { FORWARD_IF_ERROR( ZSTD_resetCStream_internal(cctx, 385719fcbaf1SConrad Meyer prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, 385819fcbaf1SConrad Meyer cctx->cdict, 385919fcbaf1SConrad Meyer params, cctx->pledgedSrcSizePlusOne-1) ); 3860052d3c12SConrad Meyer assert(cctx->streamStage == zcss_load); 386119fcbaf1SConrad Meyer assert(cctx->appliedParams.nbWorkers == 0); 38620c16b537SWarner Losh } } 3863a0483764SConrad Meyer /* end of transparent initialization stage */ 38640c16b537SWarner Losh 38650c16b537SWarner Losh /* compression stage */ 38660c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 386719fcbaf1SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 38682b9c00cbSConrad Meyer int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end); 38692b9c00cbSConrad Meyer size_t flushMin; 38702b9c00cbSConrad Meyer assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */); 387119fcbaf1SConrad Meyer if (cctx->cParamsChanged) { 387219fcbaf1SConrad Meyer ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams); 387319fcbaf1SConrad Meyer cctx->cParamsChanged = 0; 387419fcbaf1SConrad Meyer } 38752b9c00cbSConrad Meyer do { 38762b9c00cbSConrad Meyer flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); 38770c16b537SWarner Losh if ( ZSTD_isError(flushMin) 38780c16b537SWarner Losh || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ 3879a0483764SConrad Meyer ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); 38800c16b537SWarner Losh } 38812b9c00cbSConrad Meyer FORWARD_IF_ERROR(flushMin); 38822b9c00cbSConrad Meyer } while (forceMaxProgress && flushMin != 0 && output->pos < output->size); 3883a0483764SConrad Meyer DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic"); 38842b9c00cbSConrad Meyer /* Either we don't require maximum forward progress, we've finished the 38852b9c00cbSConrad Meyer * flush, or we are out of output space. 38862b9c00cbSConrad Meyer */ 38872b9c00cbSConrad Meyer assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size); 38880c16b537SWarner Losh return flushMin; 38892b9c00cbSConrad Meyer } 38900c16b537SWarner Losh #endif 38912b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) ); 3892a0483764SConrad Meyer DEBUGLOG(5, "completed ZSTD_compressStream2"); 38930c16b537SWarner Losh return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ 38940c16b537SWarner Losh } 38950c16b537SWarner Losh 3896a0483764SConrad Meyer size_t ZSTD_compressStream2_simpleArgs ( 38970c16b537SWarner Losh ZSTD_CCtx* cctx, 38980c16b537SWarner Losh void* dst, size_t dstCapacity, size_t* dstPos, 38990c16b537SWarner Losh const void* src, size_t srcSize, size_t* srcPos, 39000c16b537SWarner Losh ZSTD_EndDirective endOp) 39010c16b537SWarner Losh { 39020c16b537SWarner Losh ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; 39030c16b537SWarner Losh ZSTD_inBuffer input = { src, srcSize, *srcPos }; 3904a0483764SConrad Meyer /* ZSTD_compressStream2() will check validity of dstPos and srcPos */ 3905a0483764SConrad Meyer size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp); 39060c16b537SWarner Losh *dstPos = output.pos; 39070c16b537SWarner Losh *srcPos = input.pos; 39080c16b537SWarner Losh return cErr; 39090c16b537SWarner Losh } 39100c16b537SWarner Losh 3911a0483764SConrad Meyer size_t ZSTD_compress2(ZSTD_CCtx* cctx, 3912a0483764SConrad Meyer void* dst, size_t dstCapacity, 3913a0483764SConrad Meyer const void* src, size_t srcSize) 3914a0483764SConrad Meyer { 3915a0483764SConrad Meyer ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); 3916a0483764SConrad Meyer { size_t oPos = 0; 3917a0483764SConrad Meyer size_t iPos = 0; 3918a0483764SConrad Meyer size_t const result = ZSTD_compressStream2_simpleArgs(cctx, 3919a0483764SConrad Meyer dst, dstCapacity, &oPos, 3920a0483764SConrad Meyer src, srcSize, &iPos, 3921a0483764SConrad Meyer ZSTD_e_end); 39222b9c00cbSConrad Meyer FORWARD_IF_ERROR(result); 3923a0483764SConrad Meyer if (result != 0) { /* compression not completed, due to lack of output space */ 3924a0483764SConrad Meyer assert(oPos == dstCapacity); 39252b9c00cbSConrad Meyer RETURN_ERROR(dstSize_tooSmall); 3926a0483764SConrad Meyer } 3927a0483764SConrad Meyer assert(iPos == srcSize); /* all input is expected consumed */ 3928a0483764SConrad Meyer return oPos; 3929a0483764SConrad Meyer } 3930a0483764SConrad Meyer } 39310c16b537SWarner Losh 39320c16b537SWarner Losh /*====== Finalize ======*/ 39330c16b537SWarner Losh 39340c16b537SWarner Losh /*! ZSTD_flushStream() : 39350c16b537SWarner Losh * @return : amount of data remaining to flush */ 39360c16b537SWarner Losh size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 39370c16b537SWarner Losh { 39380c16b537SWarner Losh ZSTD_inBuffer input = { NULL, 0, 0 }; 3939a0483764SConrad Meyer return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush); 39400c16b537SWarner Losh } 39410c16b537SWarner Losh 39420c16b537SWarner Losh 39430c16b537SWarner Losh size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 39440c16b537SWarner Losh { 39450c16b537SWarner Losh ZSTD_inBuffer input = { NULL, 0, 0 }; 3946a0483764SConrad Meyer size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end); 39472b9c00cbSConrad Meyer FORWARD_IF_ERROR( remainingToFlush ); 3948a0483764SConrad Meyer if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */ 3949a0483764SConrad Meyer /* single thread mode : attempt to calculate remaining to flush more precisely */ 39500c16b537SWarner Losh { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; 39514d3f1eafSConrad Meyer size_t const checksumSize = (size_t)(zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4); 3952a0483764SConrad Meyer size_t const toFlush = remainingToFlush + lastBlockSize + checksumSize; 3953a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (unsigned)toFlush); 39540c16b537SWarner Losh return toFlush; 39550c16b537SWarner Losh } 39560c16b537SWarner Losh } 39570c16b537SWarner Losh 39580c16b537SWarner Losh 39590c16b537SWarner Losh /*-===== Pre-defined compression levels =====-*/ 39600c16b537SWarner Losh 39610c16b537SWarner Losh #define ZSTD_MAX_CLEVEL 22 39620c16b537SWarner Losh int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } 39630f743729SConrad Meyer int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; } 39640c16b537SWarner Losh 39650c16b537SWarner Losh static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { 39662b9c00cbSConrad Meyer { /* "default" - for any srcSize > 256 KB */ 39670c16b537SWarner Losh /* W, C, H, S, L, TL, strat */ 396819fcbaf1SConrad Meyer { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ 39690f743729SConrad Meyer { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ 3970a0483764SConrad Meyer { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ 3971*9cbefe25SConrad Meyer { 21, 16, 17, 1, 5, 0, ZSTD_dfast }, /* level 3 */ 3972*9cbefe25SConrad Meyer { 21, 18, 18, 1, 5, 0, ZSTD_dfast }, /* level 4 */ 3973a0483764SConrad Meyer { 21, 18, 19, 2, 5, 2, ZSTD_greedy }, /* level 5 */ 3974a0483764SConrad Meyer { 21, 19, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */ 3975a0483764SConrad Meyer { 21, 19, 19, 3, 5, 8, ZSTD_lazy }, /* level 7 */ 39760f743729SConrad Meyer { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ 39770f743729SConrad Meyer { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ 3978a0483764SConrad Meyer { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ 3979a0483764SConrad Meyer { 22, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ 3980a0483764SConrad Meyer { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ 3981a0483764SConrad Meyer { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 13 */ 3982a0483764SConrad Meyer { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ 3983a0483764SConrad Meyer { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ 3984a0483764SConrad Meyer { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ 3985a0483764SConrad Meyer { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ 3986a0483764SConrad Meyer { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ 3987a0483764SConrad Meyer { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ 3988a0483764SConrad Meyer { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ 3989a0483764SConrad Meyer { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ 3990a0483764SConrad Meyer { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ 39910c16b537SWarner Losh }, 39920c16b537SWarner Losh { /* for srcSize <= 256 KB */ 39930c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 399419fcbaf1SConrad Meyer { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 39950f743729SConrad Meyer { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ 3996*9cbefe25SConrad Meyer { 18, 14, 14, 1, 5, 0, ZSTD_dfast }, /* level 2 */ 3997*9cbefe25SConrad Meyer { 18, 16, 16, 1, 4, 0, ZSTD_dfast }, /* level 3 */ 39980f743729SConrad Meyer { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/ 39990f743729SConrad Meyer { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/ 40000f743729SConrad Meyer { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ 40010f743729SConrad Meyer { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ 40020f743729SConrad Meyer { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 40030f743729SConrad Meyer { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 40040f743729SConrad Meyer { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 4005a0483764SConrad Meyer { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ 4006a0483764SConrad Meyer { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ 4007a0483764SConrad Meyer { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ 4008a0483764SConrad Meyer { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ 4009a0483764SConrad Meyer { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ 4010a0483764SConrad Meyer { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ 4011a0483764SConrad Meyer { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ 4012a0483764SConrad Meyer { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ 4013a0483764SConrad Meyer { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ 4014a0483764SConrad Meyer { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ 4015a0483764SConrad Meyer { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ 4016a0483764SConrad Meyer { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ 40170c16b537SWarner Losh }, 40180c16b537SWarner Losh { /* for srcSize <= 128 KB */ 40190c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 40200f743729SConrad Meyer { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 40210f743729SConrad Meyer { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ 40220f743729SConrad Meyer { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ 4023*9cbefe25SConrad Meyer { 17, 15, 16, 2, 5, 0, ZSTD_dfast }, /* level 3 */ 4024*9cbefe25SConrad Meyer { 17, 17, 17, 2, 4, 0, ZSTD_dfast }, /* level 4 */ 40250f743729SConrad Meyer { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ 40260f743729SConrad Meyer { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ 40270f743729SConrad Meyer { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ 40280c16b537SWarner Losh { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 40290c16b537SWarner Losh { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 40300c16b537SWarner Losh { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 4031a0483764SConrad Meyer { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ 4032a0483764SConrad Meyer { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ 4033a0483764SConrad Meyer { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ 4034a0483764SConrad Meyer { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ 4035a0483764SConrad Meyer { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ 4036a0483764SConrad Meyer { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ 4037a0483764SConrad Meyer { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ 4038a0483764SConrad Meyer { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ 4039a0483764SConrad Meyer { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ 4040a0483764SConrad Meyer { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ 4041a0483764SConrad Meyer { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ 4042a0483764SConrad Meyer { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ 40430c16b537SWarner Losh }, 40440c16b537SWarner Losh { /* for srcSize <= 16 KB */ 40450c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 404619fcbaf1SConrad Meyer { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 40470f743729SConrad Meyer { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ 40480f743729SConrad Meyer { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ 4049*9cbefe25SConrad Meyer { 14, 14, 15, 2, 4, 0, ZSTD_dfast }, /* level 3 */ 4050a0483764SConrad Meyer { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ 40510f743729SConrad Meyer { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ 40520f743729SConrad Meyer { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ 40530f743729SConrad Meyer { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ 40540f743729SConrad Meyer { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ 40550f743729SConrad Meyer { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ 40560f743729SConrad Meyer { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ 40570f743729SConrad Meyer { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ 4058a0483764SConrad Meyer { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ 4059a0483764SConrad Meyer { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ 4060a0483764SConrad Meyer { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ 4061a0483764SConrad Meyer { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ 4062a0483764SConrad Meyer { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ 4063a0483764SConrad Meyer { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ 4064a0483764SConrad Meyer { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ 4065a0483764SConrad Meyer { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ 4066a0483764SConrad Meyer { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ 4067a0483764SConrad Meyer { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ 4068a0483764SConrad Meyer { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ 40690c16b537SWarner Losh }, 40700c16b537SWarner Losh }; 40710c16b537SWarner Losh 40720c16b537SWarner Losh /*! ZSTD_getCParams() : 407319fcbaf1SConrad Meyer * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. 40740c16b537SWarner Losh * Size values are optional, provide 0 if not known or unused */ 40750c16b537SWarner Losh ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) 40760c16b537SWarner Losh { 40770c16b537SWarner Losh size_t const addedSize = srcSizeHint ? 0 : 500; 40782b9c00cbSConrad Meyer U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : ZSTD_CONTENTSIZE_UNKNOWN; /* intentional overflow for srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN */ 40792b9c00cbSConrad Meyer U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); 408019fcbaf1SConrad Meyer int row = compressionLevel; 408119fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_getCParams (cLevel=%i)", compressionLevel); 408219fcbaf1SConrad Meyer if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ 408319fcbaf1SConrad Meyer if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ 408419fcbaf1SConrad Meyer if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; 408519fcbaf1SConrad Meyer { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row]; 408619fcbaf1SConrad Meyer if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */ 40872b9c00cbSConrad Meyer return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); /* refine parameters based on srcSize & dictSize */ 4088a0483764SConrad Meyer } 40890c16b537SWarner Losh } 40900c16b537SWarner Losh 40910c16b537SWarner Losh /*! ZSTD_getParams() : 40922b9c00cbSConrad Meyer * same idea as ZSTD_getCParams() 40932b9c00cbSConrad Meyer * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). 40942b9c00cbSConrad Meyer * Fields of `ZSTD_frameParameters` are set to default values */ 40950c16b537SWarner Losh ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { 40960c16b537SWarner Losh ZSTD_parameters params; 40970c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize); 409819fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel); 40990c16b537SWarner Losh memset(¶ms, 0, sizeof(params)); 41000c16b537SWarner Losh params.cParams = cParams; 4101052d3c12SConrad Meyer params.fParams.contentSizeFlag = 1; 41020c16b537SWarner Losh return params; 41030c16b537SWarner Losh } 4104