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" 24*4d3f1eafSConrad Meyer #include "zstd_compress_sequences.h" 25*4d3f1eafSConrad 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 void* dictBuffer; 460c16b537SWarner Losh const void* dictContent; 470c16b537SWarner Losh size_t dictContentSize; 4819fcbaf1SConrad Meyer void* workspace; 4919fcbaf1SConrad Meyer size_t workspaceSize; 5019fcbaf1SConrad Meyer ZSTD_matchState_t matchState; 5119fcbaf1SConrad Meyer ZSTD_compressedBlockState_t cBlockState; 5219fcbaf1SConrad Meyer ZSTD_customMem customMem; 5319fcbaf1SConrad Meyer U32 dictID; 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 { 870c16b537SWarner Losh ZSTD_CCtx* const cctx = (ZSTD_CCtx*) workspace; 880c16b537SWarner Losh if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */ 890c16b537SWarner Losh if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */ 900c16b537SWarner Losh memset(workspace, 0, workspaceSize); /* may be a bit generous, could memset be smaller ? */ 910c16b537SWarner Losh cctx->staticSize = workspaceSize; 920c16b537SWarner Losh cctx->workSpace = (void*)(cctx+1); 930c16b537SWarner Losh cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx); 940c16b537SWarner Losh 9519fcbaf1SConrad Meyer /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ 9619fcbaf1SConrad Meyer if (cctx->workSpaceSize < HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t)) return NULL; 970c16b537SWarner Losh assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */ 9819fcbaf1SConrad Meyer cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)cctx->workSpace; 9919fcbaf1SConrad Meyer cctx->blockState.nextCBlock = cctx->blockState.prevCBlock + 1; 10019fcbaf1SConrad Meyer { 10119fcbaf1SConrad Meyer void* const ptr = cctx->blockState.nextCBlock + 1; 10219fcbaf1SConrad Meyer cctx->entropyWorkspace = (U32*)ptr; 10319fcbaf1SConrad Meyer } 10419fcbaf1SConrad Meyer cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); 1050c16b537SWarner Losh return cctx; 1060c16b537SWarner Losh } 1070c16b537SWarner Losh 1082b9c00cbSConrad Meyer /** 1092b9c00cbSConrad Meyer * Clears and frees all of the dictionaries in the CCtx. 1102b9c00cbSConrad Meyer */ 1112b9c00cbSConrad Meyer static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx) 1122b9c00cbSConrad Meyer { 1132b9c00cbSConrad Meyer ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem); 1142b9c00cbSConrad Meyer ZSTD_freeCDict(cctx->localDict.cdict); 1152b9c00cbSConrad Meyer memset(&cctx->localDict, 0, sizeof(cctx->localDict)); 1162b9c00cbSConrad Meyer memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); 1172b9c00cbSConrad Meyer cctx->cdict = NULL; 1182b9c00cbSConrad Meyer } 1192b9c00cbSConrad Meyer 1202b9c00cbSConrad Meyer static size_t ZSTD_sizeof_localDict(ZSTD_localDict dict) 1212b9c00cbSConrad Meyer { 1222b9c00cbSConrad Meyer size_t const bufferSize = dict.dictBuffer != NULL ? dict.dictSize : 0; 1232b9c00cbSConrad Meyer size_t const cdictSize = ZSTD_sizeof_CDict(dict.cdict); 1242b9c00cbSConrad Meyer return bufferSize + cdictSize; 1252b9c00cbSConrad Meyer } 1262b9c00cbSConrad Meyer 1270f743729SConrad Meyer static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx) 1280c16b537SWarner Losh { 1290f743729SConrad Meyer assert(cctx != NULL); 1300f743729SConrad Meyer assert(cctx->staticSize == 0); 13119fcbaf1SConrad Meyer ZSTD_free(cctx->workSpace, cctx->customMem); cctx->workSpace = NULL; 1322b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); 1330c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 13419fcbaf1SConrad Meyer ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL; 1350c16b537SWarner Losh #endif 1360f743729SConrad Meyer } 1370f743729SConrad Meyer 1380f743729SConrad Meyer size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) 1390f743729SConrad Meyer { 1400f743729SConrad Meyer if (cctx==NULL) return 0; /* support free on NULL */ 1412b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->staticSize, memory_allocation, 1422b9c00cbSConrad Meyer "not compatible with static CCtx"); 1430f743729SConrad Meyer ZSTD_freeCCtxContent(cctx); 1440c16b537SWarner Losh ZSTD_free(cctx, cctx->customMem); 1450f743729SConrad Meyer return 0; 1460c16b537SWarner Losh } 1470c16b537SWarner Losh 1480c16b537SWarner Losh 1490c16b537SWarner Losh static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx) 1500c16b537SWarner Losh { 1510c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 1520c16b537SWarner Losh return ZSTDMT_sizeof_CCtx(cctx->mtctx); 1530c16b537SWarner Losh #else 1540c16b537SWarner Losh (void)cctx; 1550c16b537SWarner Losh return 0; 1560c16b537SWarner Losh #endif 1570c16b537SWarner Losh } 1580c16b537SWarner Losh 1590c16b537SWarner Losh 1600c16b537SWarner Losh size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) 1610c16b537SWarner Losh { 1620c16b537SWarner Losh if (cctx==NULL) return 0; /* support sizeof on NULL */ 1630c16b537SWarner Losh return sizeof(*cctx) + cctx->workSpaceSize 1642b9c00cbSConrad Meyer + ZSTD_sizeof_localDict(cctx->localDict) 1650c16b537SWarner Losh + ZSTD_sizeof_mtctx(cctx); 1660c16b537SWarner Losh } 1670c16b537SWarner Losh 1680c16b537SWarner Losh size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) 1690c16b537SWarner Losh { 1700c16b537SWarner Losh return ZSTD_sizeof_CCtx(zcs); /* same object */ 1710c16b537SWarner Losh } 1720c16b537SWarner Losh 1730c16b537SWarner Losh /* private API call, for dictBuilder only */ 1740c16b537SWarner Losh const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } 1750c16b537SWarner Losh 1760c16b537SWarner Losh static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( 1770c16b537SWarner Losh ZSTD_compressionParameters cParams) 1780c16b537SWarner Losh { 1790c16b537SWarner Losh ZSTD_CCtx_params cctxParams; 1800c16b537SWarner Losh memset(&cctxParams, 0, sizeof(cctxParams)); 1810c16b537SWarner Losh cctxParams.cParams = cParams; 18219fcbaf1SConrad Meyer cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 18319fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 18419fcbaf1SConrad Meyer cctxParams.fParams.contentSizeFlag = 1; 1850c16b537SWarner Losh return cctxParams; 1860c16b537SWarner Losh } 1870c16b537SWarner Losh 1880c16b537SWarner Losh static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced( 1890c16b537SWarner Losh ZSTD_customMem customMem) 1900c16b537SWarner Losh { 1910c16b537SWarner Losh ZSTD_CCtx_params* params; 1920c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 1930c16b537SWarner Losh params = (ZSTD_CCtx_params*)ZSTD_calloc( 1940c16b537SWarner Losh sizeof(ZSTD_CCtx_params), customMem); 1950c16b537SWarner Losh if (!params) { return NULL; } 1960c16b537SWarner Losh params->customMem = customMem; 1970c16b537SWarner Losh params->compressionLevel = ZSTD_CLEVEL_DEFAULT; 19819fcbaf1SConrad Meyer params->fParams.contentSizeFlag = 1; 1990c16b537SWarner Losh return params; 2000c16b537SWarner Losh } 2010c16b537SWarner Losh 2020c16b537SWarner Losh ZSTD_CCtx_params* ZSTD_createCCtxParams(void) 2030c16b537SWarner Losh { 2040c16b537SWarner Losh return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem); 2050c16b537SWarner Losh } 2060c16b537SWarner Losh 2070c16b537SWarner Losh size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) 2080c16b537SWarner Losh { 2090c16b537SWarner Losh if (params == NULL) { return 0; } 2100c16b537SWarner Losh ZSTD_free(params, params->customMem); 2110c16b537SWarner Losh return 0; 2120c16b537SWarner Losh } 2130c16b537SWarner Losh 21419fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params) 2150c16b537SWarner Losh { 21619fcbaf1SConrad Meyer return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); 2170c16b537SWarner Losh } 2180c16b537SWarner Losh 21919fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) { 2202b9c00cbSConrad Meyer RETURN_ERROR_IF(!cctxParams, GENERIC); 2210c16b537SWarner Losh memset(cctxParams, 0, sizeof(*cctxParams)); 2220c16b537SWarner Losh cctxParams->compressionLevel = compressionLevel; 22319fcbaf1SConrad Meyer cctxParams->fParams.contentSizeFlag = 1; 2240c16b537SWarner Losh return 0; 2250c16b537SWarner Losh } 2260c16b537SWarner Losh 22719fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) 2280c16b537SWarner Losh { 2292b9c00cbSConrad Meyer RETURN_ERROR_IF(!cctxParams, GENERIC); 2302b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) ); 2310c16b537SWarner Losh memset(cctxParams, 0, sizeof(*cctxParams)); 2320c16b537SWarner Losh cctxParams->cParams = params.cParams; 2330c16b537SWarner Losh cctxParams->fParams = params.fParams; 23419fcbaf1SConrad Meyer cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 23519fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(params.cParams)); 2360c16b537SWarner Losh return 0; 2370c16b537SWarner Losh } 2380c16b537SWarner Losh 23919fcbaf1SConrad Meyer /* ZSTD_assignParamsToCCtxParams() : 24019fcbaf1SConrad Meyer * params is presumed valid at this stage */ 2410c16b537SWarner Losh static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( 2420c16b537SWarner Losh ZSTD_CCtx_params cctxParams, ZSTD_parameters params) 2430c16b537SWarner Losh { 2440c16b537SWarner Losh ZSTD_CCtx_params ret = cctxParams; 2450c16b537SWarner Losh ret.cParams = params.cParams; 2460c16b537SWarner Losh ret.fParams = params.fParams; 24719fcbaf1SConrad Meyer ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 24819fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(params.cParams)); 2490c16b537SWarner Losh return ret; 2500c16b537SWarner Losh } 2510c16b537SWarner Losh 252a0483764SConrad Meyer ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) 253a0483764SConrad Meyer { 254a0483764SConrad Meyer ZSTD_bounds bounds = { 0, 0, 0 }; 255a0483764SConrad Meyer 256a0483764SConrad Meyer switch(param) 257a0483764SConrad Meyer { 258a0483764SConrad Meyer case ZSTD_c_compressionLevel: 259a0483764SConrad Meyer bounds.lowerBound = ZSTD_minCLevel(); 260a0483764SConrad Meyer bounds.upperBound = ZSTD_maxCLevel(); 261a0483764SConrad Meyer return bounds; 262a0483764SConrad Meyer 263a0483764SConrad Meyer case ZSTD_c_windowLog: 264a0483764SConrad Meyer bounds.lowerBound = ZSTD_WINDOWLOG_MIN; 265a0483764SConrad Meyer bounds.upperBound = ZSTD_WINDOWLOG_MAX; 266a0483764SConrad Meyer return bounds; 267a0483764SConrad Meyer 268a0483764SConrad Meyer case ZSTD_c_hashLog: 269a0483764SConrad Meyer bounds.lowerBound = ZSTD_HASHLOG_MIN; 270a0483764SConrad Meyer bounds.upperBound = ZSTD_HASHLOG_MAX; 271a0483764SConrad Meyer return bounds; 272a0483764SConrad Meyer 273a0483764SConrad Meyer case ZSTD_c_chainLog: 274a0483764SConrad Meyer bounds.lowerBound = ZSTD_CHAINLOG_MIN; 275a0483764SConrad Meyer bounds.upperBound = ZSTD_CHAINLOG_MAX; 276a0483764SConrad Meyer return bounds; 277a0483764SConrad Meyer 278a0483764SConrad Meyer case ZSTD_c_searchLog: 279a0483764SConrad Meyer bounds.lowerBound = ZSTD_SEARCHLOG_MIN; 280a0483764SConrad Meyer bounds.upperBound = ZSTD_SEARCHLOG_MAX; 281a0483764SConrad Meyer return bounds; 282a0483764SConrad Meyer 283a0483764SConrad Meyer case ZSTD_c_minMatch: 284a0483764SConrad Meyer bounds.lowerBound = ZSTD_MINMATCH_MIN; 285a0483764SConrad Meyer bounds.upperBound = ZSTD_MINMATCH_MAX; 286a0483764SConrad Meyer return bounds; 287a0483764SConrad Meyer 288a0483764SConrad Meyer case ZSTD_c_targetLength: 289a0483764SConrad Meyer bounds.lowerBound = ZSTD_TARGETLENGTH_MIN; 290a0483764SConrad Meyer bounds.upperBound = ZSTD_TARGETLENGTH_MAX; 291a0483764SConrad Meyer return bounds; 292a0483764SConrad Meyer 293a0483764SConrad Meyer case ZSTD_c_strategy: 294a0483764SConrad Meyer bounds.lowerBound = ZSTD_STRATEGY_MIN; 295a0483764SConrad Meyer bounds.upperBound = ZSTD_STRATEGY_MAX; 296a0483764SConrad Meyer return bounds; 297a0483764SConrad Meyer 298a0483764SConrad Meyer case ZSTD_c_contentSizeFlag: 299a0483764SConrad Meyer bounds.lowerBound = 0; 300a0483764SConrad Meyer bounds.upperBound = 1; 301a0483764SConrad Meyer return bounds; 302a0483764SConrad Meyer 303a0483764SConrad Meyer case ZSTD_c_checksumFlag: 304a0483764SConrad Meyer bounds.lowerBound = 0; 305a0483764SConrad Meyer bounds.upperBound = 1; 306a0483764SConrad Meyer return bounds; 307a0483764SConrad Meyer 308a0483764SConrad Meyer case ZSTD_c_dictIDFlag: 309a0483764SConrad Meyer bounds.lowerBound = 0; 310a0483764SConrad Meyer bounds.upperBound = 1; 311a0483764SConrad Meyer return bounds; 312a0483764SConrad Meyer 313a0483764SConrad Meyer case ZSTD_c_nbWorkers: 314a0483764SConrad Meyer bounds.lowerBound = 0; 315a0483764SConrad Meyer #ifdef ZSTD_MULTITHREAD 316a0483764SConrad Meyer bounds.upperBound = ZSTDMT_NBWORKERS_MAX; 317a0483764SConrad Meyer #else 318a0483764SConrad Meyer bounds.upperBound = 0; 319a0483764SConrad Meyer #endif 320a0483764SConrad Meyer return bounds; 321a0483764SConrad Meyer 322a0483764SConrad Meyer case ZSTD_c_jobSize: 323a0483764SConrad Meyer bounds.lowerBound = 0; 324a0483764SConrad Meyer #ifdef ZSTD_MULTITHREAD 325a0483764SConrad Meyer bounds.upperBound = ZSTDMT_JOBSIZE_MAX; 326a0483764SConrad Meyer #else 327a0483764SConrad Meyer bounds.upperBound = 0; 328a0483764SConrad Meyer #endif 329a0483764SConrad Meyer return bounds; 330a0483764SConrad Meyer 331a0483764SConrad Meyer case ZSTD_c_overlapLog: 332a0483764SConrad Meyer bounds.lowerBound = ZSTD_OVERLAPLOG_MIN; 333a0483764SConrad Meyer bounds.upperBound = ZSTD_OVERLAPLOG_MAX; 334a0483764SConrad Meyer return bounds; 335a0483764SConrad Meyer 336a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching: 337a0483764SConrad Meyer bounds.lowerBound = 0; 338a0483764SConrad Meyer bounds.upperBound = 1; 339a0483764SConrad Meyer return bounds; 340a0483764SConrad Meyer 341a0483764SConrad Meyer case ZSTD_c_ldmHashLog: 342a0483764SConrad Meyer bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN; 343a0483764SConrad Meyer bounds.upperBound = ZSTD_LDM_HASHLOG_MAX; 344a0483764SConrad Meyer return bounds; 345a0483764SConrad Meyer 346a0483764SConrad Meyer case ZSTD_c_ldmMinMatch: 347a0483764SConrad Meyer bounds.lowerBound = ZSTD_LDM_MINMATCH_MIN; 348a0483764SConrad Meyer bounds.upperBound = ZSTD_LDM_MINMATCH_MAX; 349a0483764SConrad Meyer return bounds; 350a0483764SConrad Meyer 351a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog: 352a0483764SConrad Meyer bounds.lowerBound = ZSTD_LDM_BUCKETSIZELOG_MIN; 353a0483764SConrad Meyer bounds.upperBound = ZSTD_LDM_BUCKETSIZELOG_MAX; 354a0483764SConrad Meyer return bounds; 355a0483764SConrad Meyer 356a0483764SConrad Meyer case ZSTD_c_ldmHashRateLog: 357a0483764SConrad Meyer bounds.lowerBound = ZSTD_LDM_HASHRATELOG_MIN; 358a0483764SConrad Meyer bounds.upperBound = ZSTD_LDM_HASHRATELOG_MAX; 359a0483764SConrad Meyer return bounds; 360a0483764SConrad Meyer 361a0483764SConrad Meyer /* experimental parameters */ 362a0483764SConrad Meyer case ZSTD_c_rsyncable: 363a0483764SConrad Meyer bounds.lowerBound = 0; 364a0483764SConrad Meyer bounds.upperBound = 1; 365a0483764SConrad Meyer return bounds; 366a0483764SConrad Meyer 367a0483764SConrad Meyer case ZSTD_c_forceMaxWindow : 368a0483764SConrad Meyer bounds.lowerBound = 0; 369a0483764SConrad Meyer bounds.upperBound = 1; 370a0483764SConrad Meyer return bounds; 371a0483764SConrad Meyer 372a0483764SConrad Meyer case ZSTD_c_format: 373a0483764SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless); 374a0483764SConrad Meyer bounds.lowerBound = ZSTD_f_zstd1; 375a0483764SConrad Meyer bounds.upperBound = ZSTD_f_zstd1_magicless; /* note : how to ensure at compile time that this is the highest value enum ? */ 376a0483764SConrad Meyer return bounds; 377a0483764SConrad Meyer 378a0483764SConrad Meyer case ZSTD_c_forceAttachDict: 379a0483764SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy); 380a0483764SConrad Meyer bounds.lowerBound = ZSTD_dictDefaultAttach; 381a0483764SConrad Meyer bounds.upperBound = ZSTD_dictForceCopy; /* note : how to ensure at compile time that this is the highest value enum ? */ 382a0483764SConrad Meyer return bounds; 383a0483764SConrad Meyer 3842b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode: 3852b9c00cbSConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed); 3862b9c00cbSConrad Meyer bounds.lowerBound = ZSTD_lcm_auto; 3872b9c00cbSConrad Meyer bounds.upperBound = ZSTD_lcm_uncompressed; 3882b9c00cbSConrad Meyer return bounds; 3892b9c00cbSConrad Meyer 390*4d3f1eafSConrad Meyer case ZSTD_c_targetCBlockSize: 391*4d3f1eafSConrad Meyer bounds.lowerBound = ZSTD_TARGETCBLOCKSIZE_MIN; 392*4d3f1eafSConrad Meyer bounds.upperBound = ZSTD_TARGETCBLOCKSIZE_MAX; 393*4d3f1eafSConrad Meyer return bounds; 394*4d3f1eafSConrad Meyer 395a0483764SConrad Meyer default: 396a0483764SConrad Meyer { ZSTD_bounds const boundError = { ERROR(parameter_unsupported), 0, 0 }; 397a0483764SConrad Meyer return boundError; 398a0483764SConrad Meyer } 399a0483764SConrad Meyer } 400a0483764SConrad Meyer } 401a0483764SConrad Meyer 4022b9c00cbSConrad Meyer /* ZSTD_cParam_clampBounds: 4032b9c00cbSConrad Meyer * Clamps the value into the bounded range. 4042b9c00cbSConrad Meyer */ 4052b9c00cbSConrad Meyer static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value) 4062b9c00cbSConrad Meyer { 4072b9c00cbSConrad Meyer ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); 4082b9c00cbSConrad Meyer if (ZSTD_isError(bounds.error)) return bounds.error; 4092b9c00cbSConrad Meyer if (*value < bounds.lowerBound) *value = bounds.lowerBound; 4102b9c00cbSConrad Meyer if (*value > bounds.upperBound) *value = bounds.upperBound; 4112b9c00cbSConrad Meyer return 0; 4122b9c00cbSConrad Meyer } 4132b9c00cbSConrad Meyer 414a0483764SConrad Meyer #define BOUNDCHECK(cParam, val) { \ 4152b9c00cbSConrad Meyer RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \ 4162b9c00cbSConrad Meyer parameter_outOfBound); \ 4172b9c00cbSConrad Meyer } 4180c16b537SWarner Losh 41919fcbaf1SConrad Meyer 42019fcbaf1SConrad Meyer static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) 42119fcbaf1SConrad Meyer { 42219fcbaf1SConrad Meyer switch(param) 42319fcbaf1SConrad Meyer { 424a0483764SConrad Meyer case ZSTD_c_compressionLevel: 425a0483764SConrad Meyer case ZSTD_c_hashLog: 426a0483764SConrad Meyer case ZSTD_c_chainLog: 427a0483764SConrad Meyer case ZSTD_c_searchLog: 428a0483764SConrad Meyer case ZSTD_c_minMatch: 429a0483764SConrad Meyer case ZSTD_c_targetLength: 430a0483764SConrad Meyer case ZSTD_c_strategy: 43119fcbaf1SConrad Meyer return 1; 43219fcbaf1SConrad Meyer 433a0483764SConrad Meyer case ZSTD_c_format: 434a0483764SConrad Meyer case ZSTD_c_windowLog: 435a0483764SConrad Meyer case ZSTD_c_contentSizeFlag: 436a0483764SConrad Meyer case ZSTD_c_checksumFlag: 437a0483764SConrad Meyer case ZSTD_c_dictIDFlag: 438a0483764SConrad Meyer case ZSTD_c_forceMaxWindow : 439a0483764SConrad Meyer case ZSTD_c_nbWorkers: 440a0483764SConrad Meyer case ZSTD_c_jobSize: 441a0483764SConrad Meyer case ZSTD_c_overlapLog: 442a0483764SConrad Meyer case ZSTD_c_rsyncable: 443a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching: 444a0483764SConrad Meyer case ZSTD_c_ldmHashLog: 445a0483764SConrad Meyer case ZSTD_c_ldmMinMatch: 446a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog: 447a0483764SConrad Meyer case ZSTD_c_ldmHashRateLog: 448a0483764SConrad Meyer case ZSTD_c_forceAttachDict: 4492b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode: 450*4d3f1eafSConrad Meyer case ZSTD_c_targetCBlockSize: 45119fcbaf1SConrad Meyer default: 45219fcbaf1SConrad Meyer return 0; 45319fcbaf1SConrad Meyer } 45419fcbaf1SConrad Meyer } 45519fcbaf1SConrad Meyer 456a0483764SConrad Meyer size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) 4570c16b537SWarner Losh { 458a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setParameter (%i, %i)", (int)param, value); 45919fcbaf1SConrad Meyer if (cctx->streamStage != zcss_init) { 46019fcbaf1SConrad Meyer if (ZSTD_isUpdateAuthorized(param)) { 46119fcbaf1SConrad Meyer cctx->cParamsChanged = 1; 46219fcbaf1SConrad Meyer } else { 4632b9c00cbSConrad Meyer RETURN_ERROR(stage_wrong); 46419fcbaf1SConrad Meyer } } 4650c16b537SWarner Losh 4660c16b537SWarner Losh switch(param) 4670c16b537SWarner Losh { 4682b9c00cbSConrad Meyer case ZSTD_c_nbWorkers: 4692b9c00cbSConrad Meyer RETURN_ERROR_IF((value!=0) && cctx->staticSize, parameter_unsupported, 4702b9c00cbSConrad Meyer "MT not compatible with static alloc"); 4712b9c00cbSConrad Meyer break; 4720c16b537SWarner Losh 473a0483764SConrad Meyer case ZSTD_c_compressionLevel: 474a0483764SConrad Meyer case ZSTD_c_windowLog: 475a0483764SConrad Meyer case ZSTD_c_hashLog: 476a0483764SConrad Meyer case ZSTD_c_chainLog: 477a0483764SConrad Meyer case ZSTD_c_searchLog: 478a0483764SConrad Meyer case ZSTD_c_minMatch: 479a0483764SConrad Meyer case ZSTD_c_targetLength: 480a0483764SConrad Meyer case ZSTD_c_strategy: 4812b9c00cbSConrad Meyer case ZSTD_c_ldmHashRateLog: 4822b9c00cbSConrad Meyer case ZSTD_c_format: 483a0483764SConrad Meyer case ZSTD_c_contentSizeFlag: 484a0483764SConrad Meyer case ZSTD_c_checksumFlag: 485a0483764SConrad Meyer case ZSTD_c_dictIDFlag: 4862b9c00cbSConrad Meyer case ZSTD_c_forceMaxWindow: 487a0483764SConrad Meyer case ZSTD_c_forceAttachDict: 4882b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode: 489a0483764SConrad Meyer case ZSTD_c_jobSize: 490a0483764SConrad Meyer case ZSTD_c_overlapLog: 491a0483764SConrad Meyer case ZSTD_c_rsyncable: 492a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching: 493a0483764SConrad Meyer case ZSTD_c_ldmHashLog: 494a0483764SConrad Meyer case ZSTD_c_ldmMinMatch: 495a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog: 496*4d3f1eafSConrad Meyer case ZSTD_c_targetCBlockSize: 4972b9c00cbSConrad Meyer break; 4980c16b537SWarner Losh 4992b9c00cbSConrad Meyer default: RETURN_ERROR(parameter_unsupported); 5000c16b537SWarner Losh } 5012b9c00cbSConrad Meyer return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value); 5020c16b537SWarner Losh } 5030c16b537SWarner Losh 5042b9c00cbSConrad Meyer size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, 505a0483764SConrad Meyer ZSTD_cParameter param, int value) 5060c16b537SWarner Losh { 5072b9c00cbSConrad Meyer DEBUGLOG(4, "ZSTD_CCtxParams_setParameter (%i, %i)", (int)param, value); 5080c16b537SWarner Losh switch(param) 5090c16b537SWarner Losh { 510a0483764SConrad Meyer case ZSTD_c_format : 511a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_format, value); 512052d3c12SConrad Meyer CCtxParams->format = (ZSTD_format_e)value; 513052d3c12SConrad Meyer return (size_t)CCtxParams->format; 5140c16b537SWarner Losh 515a0483764SConrad Meyer case ZSTD_c_compressionLevel : { 5162b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); 5172b9c00cbSConrad Meyer if (value) { /* 0 : does not change current level */ 5182b9c00cbSConrad Meyer CCtxParams->compressionLevel = value; 51919fcbaf1SConrad Meyer } 52019fcbaf1SConrad Meyer if (CCtxParams->compressionLevel >= 0) return CCtxParams->compressionLevel; 52119fcbaf1SConrad Meyer return 0; /* return type (size_t) cannot represent negative values */ 52219fcbaf1SConrad Meyer } 5230c16b537SWarner Losh 524a0483764SConrad Meyer case ZSTD_c_windowLog : 525a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 526a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_windowLog, value); 527052d3c12SConrad Meyer CCtxParams->cParams.windowLog = value; 528052d3c12SConrad Meyer return CCtxParams->cParams.windowLog; 5290c16b537SWarner Losh 530a0483764SConrad Meyer case ZSTD_c_hashLog : 531a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 532a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_hashLog, value); 533052d3c12SConrad Meyer CCtxParams->cParams.hashLog = value; 534052d3c12SConrad Meyer return CCtxParams->cParams.hashLog; 5350c16b537SWarner Losh 536a0483764SConrad Meyer case ZSTD_c_chainLog : 537a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 538a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_chainLog, value); 539052d3c12SConrad Meyer CCtxParams->cParams.chainLog = value; 540052d3c12SConrad Meyer return CCtxParams->cParams.chainLog; 5410c16b537SWarner Losh 542a0483764SConrad Meyer case ZSTD_c_searchLog : 543a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 544a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_searchLog, value); 545052d3c12SConrad Meyer CCtxParams->cParams.searchLog = value; 546052d3c12SConrad Meyer return value; 5470c16b537SWarner Losh 548a0483764SConrad Meyer case ZSTD_c_minMatch : 549a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 550a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_minMatch, value); 551a0483764SConrad Meyer CCtxParams->cParams.minMatch = value; 552a0483764SConrad Meyer return CCtxParams->cParams.minMatch; 5530c16b537SWarner Losh 554a0483764SConrad Meyer case ZSTD_c_targetLength : 555a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_targetLength, value); 556052d3c12SConrad Meyer CCtxParams->cParams.targetLength = value; 557052d3c12SConrad Meyer return CCtxParams->cParams.targetLength; 5580c16b537SWarner Losh 559a0483764SConrad Meyer case ZSTD_c_strategy : 560a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 561a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_strategy, value); 562052d3c12SConrad Meyer CCtxParams->cParams.strategy = (ZSTD_strategy)value; 563052d3c12SConrad Meyer return (size_t)CCtxParams->cParams.strategy; 5640c16b537SWarner Losh 565a0483764SConrad Meyer case ZSTD_c_contentSizeFlag : 5660c16b537SWarner Losh /* Content size written in frame header _when known_ (default:1) */ 567a0483764SConrad Meyer DEBUGLOG(4, "set content size flag = %u", (value!=0)); 568a0483764SConrad Meyer CCtxParams->fParams.contentSizeFlag = value != 0; 569052d3c12SConrad Meyer return CCtxParams->fParams.contentSizeFlag; 5700c16b537SWarner Losh 571a0483764SConrad Meyer case ZSTD_c_checksumFlag : 5720c16b537SWarner Losh /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ 573a0483764SConrad Meyer CCtxParams->fParams.checksumFlag = value != 0; 574052d3c12SConrad Meyer return CCtxParams->fParams.checksumFlag; 5750c16b537SWarner Losh 576a0483764SConrad Meyer case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ 577a0483764SConrad Meyer DEBUGLOG(4, "set dictIDFlag = %u", (value!=0)); 57819fcbaf1SConrad Meyer CCtxParams->fParams.noDictIDFlag = !value; 579052d3c12SConrad Meyer return !CCtxParams->fParams.noDictIDFlag; 5800c16b537SWarner Losh 581a0483764SConrad Meyer case ZSTD_c_forceMaxWindow : 582a0483764SConrad Meyer CCtxParams->forceWindow = (value != 0); 583052d3c12SConrad Meyer return CCtxParams->forceWindow; 5840c16b537SWarner Losh 585a0483764SConrad Meyer case ZSTD_c_forceAttachDict : { 586a0483764SConrad Meyer const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value; 587a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_forceAttachDict, pref); 588a0483764SConrad Meyer CCtxParams->attachDictPref = pref; 5890f743729SConrad Meyer return CCtxParams->attachDictPref; 590a0483764SConrad Meyer } 5910f743729SConrad Meyer 5922b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode : { 5932b9c00cbSConrad Meyer const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value; 5942b9c00cbSConrad Meyer BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm); 5952b9c00cbSConrad Meyer CCtxParams->literalCompressionMode = lcm; 5962b9c00cbSConrad Meyer return CCtxParams->literalCompressionMode; 5972b9c00cbSConrad Meyer } 5982b9c00cbSConrad Meyer 599a0483764SConrad Meyer case ZSTD_c_nbWorkers : 6000c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 6012b9c00cbSConrad Meyer RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 60219fcbaf1SConrad Meyer return 0; 6030c16b537SWarner Losh #else 6042b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); 6052b9c00cbSConrad Meyer CCtxParams->nbWorkers = value; 6062b9c00cbSConrad Meyer return CCtxParams->nbWorkers; 6070c16b537SWarner Losh #endif 6080c16b537SWarner Losh 609a0483764SConrad Meyer case ZSTD_c_jobSize : 6100c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 6112b9c00cbSConrad Meyer RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 6122b9c00cbSConrad Meyer return 0; 6130c16b537SWarner Losh #else 6142b9c00cbSConrad Meyer /* Adjust to the minimum non-default value. */ 6152b9c00cbSConrad Meyer if (value != 0 && value < ZSTDMT_JOBSIZE_MIN) 6162b9c00cbSConrad Meyer value = ZSTDMT_JOBSIZE_MIN; 6172b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); 6182b9c00cbSConrad Meyer assert(value >= 0); 6192b9c00cbSConrad Meyer CCtxParams->jobSize = value; 6202b9c00cbSConrad Meyer return CCtxParams->jobSize; 6210c16b537SWarner Losh #endif 6220c16b537SWarner Losh 623a0483764SConrad Meyer case ZSTD_c_overlapLog : 6240c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 6252b9c00cbSConrad Meyer RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 6262b9c00cbSConrad Meyer return 0; 6270c16b537SWarner Losh #else 6282b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value)); 6292b9c00cbSConrad Meyer CCtxParams->overlapLog = value; 6302b9c00cbSConrad Meyer return CCtxParams->overlapLog; 6310c16b537SWarner Losh #endif 6320c16b537SWarner Losh 633a0483764SConrad Meyer case ZSTD_c_rsyncable : 634a0483764SConrad Meyer #ifndef ZSTD_MULTITHREAD 6352b9c00cbSConrad Meyer RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 6362b9c00cbSConrad Meyer return 0; 637a0483764SConrad Meyer #else 6382b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value)); 6392b9c00cbSConrad Meyer CCtxParams->rsyncable = value; 6402b9c00cbSConrad Meyer return CCtxParams->rsyncable; 641a0483764SConrad Meyer #endif 642a0483764SConrad Meyer 643a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching : 644a0483764SConrad Meyer CCtxParams->ldmParams.enableLdm = (value!=0); 64519fcbaf1SConrad Meyer return CCtxParams->ldmParams.enableLdm; 6460c16b537SWarner Losh 647a0483764SConrad Meyer case ZSTD_c_ldmHashLog : 648a0483764SConrad Meyer if (value!=0) /* 0 ==> auto */ 649a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_ldmHashLog, value); 650052d3c12SConrad Meyer CCtxParams->ldmParams.hashLog = value; 651052d3c12SConrad Meyer return CCtxParams->ldmParams.hashLog; 6520c16b537SWarner Losh 653a0483764SConrad Meyer case ZSTD_c_ldmMinMatch : 654a0483764SConrad Meyer if (value!=0) /* 0 ==> default */ 655a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_ldmMinMatch, value); 656052d3c12SConrad Meyer CCtxParams->ldmParams.minMatchLength = value; 657052d3c12SConrad Meyer return CCtxParams->ldmParams.minMatchLength; 6580c16b537SWarner Losh 659a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog : 660a0483764SConrad Meyer if (value!=0) /* 0 ==> default */ 661a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value); 662052d3c12SConrad Meyer CCtxParams->ldmParams.bucketSizeLog = value; 66319fcbaf1SConrad Meyer return CCtxParams->ldmParams.bucketSizeLog; 6640c16b537SWarner Losh 665a0483764SConrad Meyer case ZSTD_c_ldmHashRateLog : 6662b9c00cbSConrad Meyer RETURN_ERROR_IF(value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN, 6672b9c00cbSConrad Meyer parameter_outOfBound); 668a0483764SConrad Meyer CCtxParams->ldmParams.hashRateLog = value; 669a0483764SConrad Meyer return CCtxParams->ldmParams.hashRateLog; 6700c16b537SWarner Losh 671*4d3f1eafSConrad Meyer case ZSTD_c_targetCBlockSize : 672*4d3f1eafSConrad Meyer if (value!=0) /* 0 ==> default */ 673*4d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_targetCBlockSize, value); 674*4d3f1eafSConrad Meyer CCtxParams->targetCBlockSize = value; 675*4d3f1eafSConrad Meyer return CCtxParams->targetCBlockSize; 676*4d3f1eafSConrad Meyer 6772b9c00cbSConrad Meyer default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); 6780c16b537SWarner Losh } 6790c16b537SWarner Losh } 6800c16b537SWarner Losh 681a0483764SConrad Meyer size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value) 6820f743729SConrad Meyer { 6832b9c00cbSConrad Meyer return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value); 6840f743729SConrad Meyer } 6850f743729SConrad Meyer 6862b9c00cbSConrad Meyer size_t ZSTD_CCtxParams_getParameter( 687a0483764SConrad Meyer ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value) 6880f743729SConrad Meyer { 6890f743729SConrad Meyer switch(param) 6900f743729SConrad Meyer { 691a0483764SConrad Meyer case ZSTD_c_format : 6920f743729SConrad Meyer *value = CCtxParams->format; 6930f743729SConrad Meyer break; 694a0483764SConrad Meyer case ZSTD_c_compressionLevel : 6950f743729SConrad Meyer *value = CCtxParams->compressionLevel; 6960f743729SConrad Meyer break; 697a0483764SConrad Meyer case ZSTD_c_windowLog : 698*4d3f1eafSConrad Meyer *value = (int)CCtxParams->cParams.windowLog; 6990f743729SConrad Meyer break; 700a0483764SConrad Meyer case ZSTD_c_hashLog : 701*4d3f1eafSConrad Meyer *value = (int)CCtxParams->cParams.hashLog; 7020f743729SConrad Meyer break; 703a0483764SConrad Meyer case ZSTD_c_chainLog : 704*4d3f1eafSConrad Meyer *value = (int)CCtxParams->cParams.chainLog; 7050f743729SConrad Meyer break; 706a0483764SConrad Meyer case ZSTD_c_searchLog : 7070f743729SConrad Meyer *value = CCtxParams->cParams.searchLog; 7080f743729SConrad Meyer break; 709a0483764SConrad Meyer case ZSTD_c_minMatch : 710a0483764SConrad Meyer *value = CCtxParams->cParams.minMatch; 7110f743729SConrad Meyer break; 712a0483764SConrad Meyer case ZSTD_c_targetLength : 7130f743729SConrad Meyer *value = CCtxParams->cParams.targetLength; 7140f743729SConrad Meyer break; 715a0483764SConrad Meyer case ZSTD_c_strategy : 7160f743729SConrad Meyer *value = (unsigned)CCtxParams->cParams.strategy; 7170f743729SConrad Meyer break; 718a0483764SConrad Meyer case ZSTD_c_contentSizeFlag : 7190f743729SConrad Meyer *value = CCtxParams->fParams.contentSizeFlag; 7200f743729SConrad Meyer break; 721a0483764SConrad Meyer case ZSTD_c_checksumFlag : 7220f743729SConrad Meyer *value = CCtxParams->fParams.checksumFlag; 7230f743729SConrad Meyer break; 724a0483764SConrad Meyer case ZSTD_c_dictIDFlag : 7250f743729SConrad Meyer *value = !CCtxParams->fParams.noDictIDFlag; 7260f743729SConrad Meyer break; 727a0483764SConrad Meyer case ZSTD_c_forceMaxWindow : 7280f743729SConrad Meyer *value = CCtxParams->forceWindow; 7290f743729SConrad Meyer break; 730a0483764SConrad Meyer case ZSTD_c_forceAttachDict : 7310f743729SConrad Meyer *value = CCtxParams->attachDictPref; 7320f743729SConrad Meyer break; 7332b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode : 7342b9c00cbSConrad Meyer *value = CCtxParams->literalCompressionMode; 7352b9c00cbSConrad Meyer break; 736a0483764SConrad Meyer case ZSTD_c_nbWorkers : 7370f743729SConrad Meyer #ifndef ZSTD_MULTITHREAD 7380f743729SConrad Meyer assert(CCtxParams->nbWorkers == 0); 7390f743729SConrad Meyer #endif 7400f743729SConrad Meyer *value = CCtxParams->nbWorkers; 7410f743729SConrad Meyer break; 742a0483764SConrad Meyer case ZSTD_c_jobSize : 7430f743729SConrad Meyer #ifndef ZSTD_MULTITHREAD 7442b9c00cbSConrad Meyer RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 7450f743729SConrad Meyer #else 746a0483764SConrad Meyer assert(CCtxParams->jobSize <= INT_MAX); 747a0483764SConrad Meyer *value = (int)CCtxParams->jobSize; 7480f743729SConrad Meyer break; 7490f743729SConrad Meyer #endif 750a0483764SConrad Meyer case ZSTD_c_overlapLog : 7510f743729SConrad Meyer #ifndef ZSTD_MULTITHREAD 7522b9c00cbSConrad Meyer RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 7530f743729SConrad Meyer #else 754a0483764SConrad Meyer *value = CCtxParams->overlapLog; 7550f743729SConrad Meyer break; 7560f743729SConrad Meyer #endif 757a0483764SConrad Meyer case ZSTD_c_rsyncable : 758a0483764SConrad Meyer #ifndef ZSTD_MULTITHREAD 7592b9c00cbSConrad Meyer RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 760a0483764SConrad Meyer #else 761a0483764SConrad Meyer *value = CCtxParams->rsyncable; 762a0483764SConrad Meyer break; 763a0483764SConrad Meyer #endif 764a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching : 7650f743729SConrad Meyer *value = CCtxParams->ldmParams.enableLdm; 7660f743729SConrad Meyer break; 767a0483764SConrad Meyer case ZSTD_c_ldmHashLog : 7680f743729SConrad Meyer *value = CCtxParams->ldmParams.hashLog; 7690f743729SConrad Meyer break; 770a0483764SConrad Meyer case ZSTD_c_ldmMinMatch : 7710f743729SConrad Meyer *value = CCtxParams->ldmParams.minMatchLength; 7720f743729SConrad Meyer break; 773a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog : 7740f743729SConrad Meyer *value = CCtxParams->ldmParams.bucketSizeLog; 7750f743729SConrad Meyer break; 776a0483764SConrad Meyer case ZSTD_c_ldmHashRateLog : 777a0483764SConrad Meyer *value = CCtxParams->ldmParams.hashRateLog; 7780f743729SConrad Meyer break; 779*4d3f1eafSConrad Meyer case ZSTD_c_targetCBlockSize : 780*4d3f1eafSConrad Meyer *value = (int)CCtxParams->targetCBlockSize; 781*4d3f1eafSConrad Meyer break; 7822b9c00cbSConrad Meyer default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); 7830f743729SConrad Meyer } 7840f743729SConrad Meyer return 0; 7850f743729SConrad Meyer } 7860f743729SConrad Meyer 787052d3c12SConrad Meyer /** ZSTD_CCtx_setParametersUsingCCtxParams() : 788052d3c12SConrad Meyer * just applies `params` into `cctx` 789052d3c12SConrad Meyer * no action is performed, parameters are merely stored. 79019fcbaf1SConrad Meyer * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx. 79119fcbaf1SConrad Meyer * This is possible even if a compression is ongoing. 79219fcbaf1SConrad Meyer * In which case, new parameters will be applied on the fly, starting with next compression job. 7930c16b537SWarner Losh */ 7940c16b537SWarner Losh size_t ZSTD_CCtx_setParametersUsingCCtxParams( 7950c16b537SWarner Losh ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) 7960c16b537SWarner Losh { 7970f743729SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams"); 7982b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 7992b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->cdict, stage_wrong); 8000c16b537SWarner Losh 801052d3c12SConrad Meyer cctx->requestedParams = *params; 8020c16b537SWarner Losh return 0; 8030c16b537SWarner Losh } 8040c16b537SWarner Losh 8050c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) 8060c16b537SWarner Losh { 807052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize); 8082b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 8090c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; 8100c16b537SWarner Losh return 0; 8110c16b537SWarner Losh } 8120c16b537SWarner Losh 8132b9c00cbSConrad Meyer /** 8142b9c00cbSConrad Meyer * Initializes the local dict using the requested parameters. 8152b9c00cbSConrad Meyer * NOTE: This does not use the pledged src size, because it may be used for more 8162b9c00cbSConrad Meyer * than one compression. 8172b9c00cbSConrad Meyer */ 8182b9c00cbSConrad Meyer static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) 8192b9c00cbSConrad Meyer { 8202b9c00cbSConrad Meyer ZSTD_localDict* const dl = &cctx->localDict; 8212b9c00cbSConrad Meyer ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams( 8222b9c00cbSConrad Meyer &cctx->requestedParams, 0, dl->dictSize); 8232b9c00cbSConrad Meyer if (dl->dict == NULL) { 8242b9c00cbSConrad Meyer /* No local dictionary. */ 8252b9c00cbSConrad Meyer assert(dl->dictBuffer == NULL); 8262b9c00cbSConrad Meyer assert(dl->cdict == NULL); 8272b9c00cbSConrad Meyer assert(dl->dictSize == 0); 8282b9c00cbSConrad Meyer return 0; 8292b9c00cbSConrad Meyer } 8302b9c00cbSConrad Meyer if (dl->cdict != NULL) { 8312b9c00cbSConrad Meyer assert(cctx->cdict == dl->cdict); 8322b9c00cbSConrad Meyer /* Local dictionary already initialized. */ 8332b9c00cbSConrad Meyer return 0; 8342b9c00cbSConrad Meyer } 8352b9c00cbSConrad Meyer assert(dl->dictSize > 0); 8362b9c00cbSConrad Meyer assert(cctx->cdict == NULL); 8372b9c00cbSConrad Meyer assert(cctx->prefixDict.dict == NULL); 8382b9c00cbSConrad Meyer 8392b9c00cbSConrad Meyer dl->cdict = ZSTD_createCDict_advanced( 8402b9c00cbSConrad Meyer dl->dict, 8412b9c00cbSConrad Meyer dl->dictSize, 8422b9c00cbSConrad Meyer ZSTD_dlm_byRef, 8432b9c00cbSConrad Meyer dl->dictContentType, 8442b9c00cbSConrad Meyer cParams, 8452b9c00cbSConrad Meyer cctx->customMem); 8462b9c00cbSConrad Meyer RETURN_ERROR_IF(!dl->cdict, memory_allocation); 8472b9c00cbSConrad Meyer cctx->cdict = dl->cdict; 8482b9c00cbSConrad Meyer return 0; 8492b9c00cbSConrad Meyer } 8502b9c00cbSConrad Meyer 8510c16b537SWarner Losh size_t ZSTD_CCtx_loadDictionary_advanced( 8520c16b537SWarner Losh ZSTD_CCtx* cctx, const void* dict, size_t dictSize, 85319fcbaf1SConrad Meyer ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType) 8540c16b537SWarner Losh { 8552b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 8562b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->staticSize, memory_allocation, 8572b9c00cbSConrad Meyer "no malloc for static CCtx"); 858052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); 8592b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); /* in case one already exists */ 8602b9c00cbSConrad Meyer if (dict == NULL || dictSize == 0) /* no dictionary mode */ 8612b9c00cbSConrad Meyer return 0; 8622b9c00cbSConrad Meyer if (dictLoadMethod == ZSTD_dlm_byRef) { 8632b9c00cbSConrad Meyer cctx->localDict.dict = dict; 8640c16b537SWarner Losh } else { 8652b9c00cbSConrad Meyer void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem); 8662b9c00cbSConrad Meyer RETURN_ERROR_IF(!dictBuffer, memory_allocation); 8672b9c00cbSConrad Meyer memcpy(dictBuffer, dict, dictSize); 8682b9c00cbSConrad Meyer cctx->localDict.dictBuffer = dictBuffer; 8692b9c00cbSConrad Meyer cctx->localDict.dict = dictBuffer; 8700c16b537SWarner Losh } 8712b9c00cbSConrad Meyer cctx->localDict.dictSize = dictSize; 8722b9c00cbSConrad Meyer cctx->localDict.dictContentType = dictContentType; 8730c16b537SWarner Losh return 0; 8740c16b537SWarner Losh } 8750c16b537SWarner Losh 8760c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( 8770c16b537SWarner Losh ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 8780c16b537SWarner Losh { 8790c16b537SWarner Losh return ZSTD_CCtx_loadDictionary_advanced( 88019fcbaf1SConrad Meyer cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); 8810c16b537SWarner Losh } 8820c16b537SWarner Losh 8830c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 8840c16b537SWarner Losh { 8850c16b537SWarner Losh return ZSTD_CCtx_loadDictionary_advanced( 88619fcbaf1SConrad Meyer cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); 8870c16b537SWarner Losh } 8880c16b537SWarner Losh 8890c16b537SWarner Losh 8900c16b537SWarner Losh size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 8910c16b537SWarner Losh { 8922b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 8932b9c00cbSConrad Meyer /* Free the existing local cdict (if any) to save memory. */ 8942b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); 8950c16b537SWarner Losh cctx->cdict = cdict; 8960c16b537SWarner Losh return 0; 8970c16b537SWarner Losh } 8980c16b537SWarner Losh 8990c16b537SWarner Losh size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) 9000c16b537SWarner Losh { 90119fcbaf1SConrad Meyer return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent); 9020c16b537SWarner Losh } 9030c16b537SWarner Losh 9040c16b537SWarner Losh size_t ZSTD_CCtx_refPrefix_advanced( 90519fcbaf1SConrad Meyer ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) 9060c16b537SWarner Losh { 9072b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 9082b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); 9090c16b537SWarner Losh cctx->prefixDict.dict = prefix; 9100c16b537SWarner Losh cctx->prefixDict.dictSize = prefixSize; 91119fcbaf1SConrad Meyer cctx->prefixDict.dictContentType = dictContentType; 9120c16b537SWarner Losh return 0; 9130c16b537SWarner Losh } 9140c16b537SWarner Losh 9150f743729SConrad Meyer /*! ZSTD_CCtx_reset() : 9160f743729SConrad Meyer * Also dumps dictionary */ 917a0483764SConrad Meyer size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset) 9180c16b537SWarner Losh { 919a0483764SConrad Meyer if ( (reset == ZSTD_reset_session_only) 920a0483764SConrad Meyer || (reset == ZSTD_reset_session_and_parameters) ) { 9210c16b537SWarner Losh cctx->streamStage = zcss_init; 9220c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = 0; 9230c16b537SWarner Losh } 924a0483764SConrad Meyer if ( (reset == ZSTD_reset_parameters) 925a0483764SConrad Meyer || (reset == ZSTD_reset_session_and_parameters) ) { 9262b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 9272b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); 9280f743729SConrad Meyer return ZSTD_CCtxParams_reset(&cctx->requestedParams); 9290c16b537SWarner Losh } 930a0483764SConrad Meyer return 0; 931a0483764SConrad Meyer } 932a0483764SConrad Meyer 9330c16b537SWarner Losh 9340c16b537SWarner Losh /** ZSTD_checkCParams() : 9350c16b537SWarner Losh control CParam values remain within authorized range. 9360c16b537SWarner Losh @return : 0, or an error code if one value is beyond authorized range */ 9370c16b537SWarner Losh size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) 9380c16b537SWarner Losh { 939*4d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_windowLog, (int)cParams.windowLog); 940*4d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_chainLog, (int)cParams.chainLog); 941*4d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_hashLog, (int)cParams.hashLog); 942*4d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_searchLog, (int)cParams.searchLog); 943*4d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_minMatch, (int)cParams.minMatch); 944*4d3f1eafSConrad Meyer BOUNDCHECK(ZSTD_c_targetLength,(int)cParams.targetLength); 945a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_strategy, cParams.strategy); 9460c16b537SWarner Losh return 0; 9470c16b537SWarner Losh } 9480c16b537SWarner Losh 9490c16b537SWarner Losh /** ZSTD_clampCParams() : 9500c16b537SWarner Losh * make CParam values within valid range. 9510c16b537SWarner Losh * @return : valid CParams */ 9520f743729SConrad Meyer static ZSTD_compressionParameters 9530f743729SConrad Meyer ZSTD_clampCParams(ZSTD_compressionParameters cParams) 9540c16b537SWarner Losh { 955a0483764SConrad Meyer # define CLAMP_TYPE(cParam, val, type) { \ 956a0483764SConrad Meyer ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \ 957a0483764SConrad Meyer if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \ 958a0483764SConrad Meyer else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \ 9590c16b537SWarner Losh } 960*4d3f1eafSConrad Meyer # define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned) 961a0483764SConrad Meyer CLAMP(ZSTD_c_windowLog, cParams.windowLog); 962a0483764SConrad Meyer CLAMP(ZSTD_c_chainLog, cParams.chainLog); 963a0483764SConrad Meyer CLAMP(ZSTD_c_hashLog, cParams.hashLog); 964a0483764SConrad Meyer CLAMP(ZSTD_c_searchLog, cParams.searchLog); 965a0483764SConrad Meyer CLAMP(ZSTD_c_minMatch, cParams.minMatch); 966a0483764SConrad Meyer CLAMP(ZSTD_c_targetLength,cParams.targetLength); 967a0483764SConrad Meyer CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy); 9680c16b537SWarner Losh return cParams; 9690c16b537SWarner Losh } 9700c16b537SWarner Losh 9710c16b537SWarner Losh /** ZSTD_cycleLog() : 9720c16b537SWarner Losh * condition for correct operation : hashLog > 1 */ 9730c16b537SWarner Losh static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) 9740c16b537SWarner Losh { 9750c16b537SWarner Losh U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2); 9760c16b537SWarner Losh return hashLog - btScale; 9770c16b537SWarner Losh } 9780c16b537SWarner Losh 9790c16b537SWarner Losh /** ZSTD_adjustCParams_internal() : 9802b9c00cbSConrad Meyer * optimize `cPar` for a specified input (`srcSize` and `dictSize`). 9812b9c00cbSConrad Meyer * mostly downsize to reduce memory consumption and initialization latency. 9822b9c00cbSConrad Meyer * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known. 9832b9c00cbSConrad Meyer * note : for the time being, `srcSize==0` means "unknown" too, for compatibility with older convention. 9842b9c00cbSConrad Meyer * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */ 9850f743729SConrad Meyer static ZSTD_compressionParameters 9860f743729SConrad Meyer ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, 9870f743729SConrad Meyer unsigned long long srcSize, 9880f743729SConrad Meyer size_t dictSize) 9890c16b537SWarner Losh { 9900c16b537SWarner Losh static const U64 minSrcSize = 513; /* (1<<9) + 1 */ 9910c16b537SWarner Losh static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); 9920c16b537SWarner Losh assert(ZSTD_checkCParams(cPar)==0); 9930c16b537SWarner Losh 9942b9c00cbSConrad Meyer if (dictSize && (srcSize+1<2) /* ZSTD_CONTENTSIZE_UNKNOWN and 0 mean "unknown" */ ) 9950c16b537SWarner Losh srcSize = minSrcSize; /* presumed small when there is a dictionary */ 9960c16b537SWarner Losh else if (srcSize == 0) 9970c16b537SWarner Losh srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */ 9980c16b537SWarner Losh 9990c16b537SWarner Losh /* resize windowLog if input is small enough, to use less memory */ 10000c16b537SWarner Losh if ( (srcSize < maxWindowResize) 10010c16b537SWarner Losh && (dictSize < maxWindowResize) ) { 10020c16b537SWarner Losh U32 const tSize = (U32)(srcSize + dictSize); 10030c16b537SWarner Losh static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN; 10040c16b537SWarner Losh U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN : 10050c16b537SWarner Losh ZSTD_highbit32(tSize-1) + 1; 10060c16b537SWarner Losh if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; 10070c16b537SWarner Losh } 10080f743729SConrad Meyer if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1; 10090c16b537SWarner Losh { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); 10100c16b537SWarner Losh if (cycleLog > cPar.windowLog) 10110c16b537SWarner Losh cPar.chainLog -= (cycleLog - cPar.windowLog); 10120c16b537SWarner Losh } 10130c16b537SWarner Losh 10140c16b537SWarner Losh if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) 10152b9c00cbSConrad Meyer cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */ 10160c16b537SWarner Losh 10170c16b537SWarner Losh return cPar; 10180c16b537SWarner Losh } 10190c16b537SWarner Losh 10200f743729SConrad Meyer ZSTD_compressionParameters 10210f743729SConrad Meyer ZSTD_adjustCParams(ZSTD_compressionParameters cPar, 10220f743729SConrad Meyer unsigned long long srcSize, 10230f743729SConrad Meyer size_t dictSize) 10240c16b537SWarner Losh { 10252b9c00cbSConrad Meyer cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */ 10260c16b537SWarner Losh return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); 10270c16b537SWarner Losh } 10280c16b537SWarner Losh 10290f743729SConrad Meyer ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( 10300f743729SConrad Meyer const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize) 10310f743729SConrad Meyer { 10320f743729SConrad Meyer ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize); 10330f743729SConrad Meyer if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; 10340f743729SConrad Meyer if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog; 10350f743729SConrad Meyer if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog; 10360f743729SConrad Meyer if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog; 10370f743729SConrad Meyer if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog; 1038a0483764SConrad Meyer if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch; 10390f743729SConrad Meyer if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength; 10400f743729SConrad Meyer if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy; 10410f743729SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 10420f743729SConrad Meyer return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize); 10430f743729SConrad Meyer } 10440f743729SConrad Meyer 10450f743729SConrad Meyer static size_t 10460f743729SConrad Meyer ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, 10470f743729SConrad Meyer const U32 forCCtx) 104819fcbaf1SConrad Meyer { 104919fcbaf1SConrad Meyer size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); 105019fcbaf1SConrad Meyer size_t const hSize = ((size_t)1) << cParams->hashLog; 1051a0483764SConrad Meyer U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 105219fcbaf1SConrad Meyer size_t const h3Size = ((size_t)1) << hashLog3; 105319fcbaf1SConrad Meyer size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 105419fcbaf1SConrad Meyer size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32) 105519fcbaf1SConrad Meyer + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t)); 1056a0483764SConrad Meyer size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt)) 105719fcbaf1SConrad Meyer ? optPotentialSpace 105819fcbaf1SConrad Meyer : 0; 105919fcbaf1SConrad Meyer DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u", 106019fcbaf1SConrad Meyer (U32)chainSize, (U32)hSize, (U32)h3Size); 106119fcbaf1SConrad Meyer return tableSpace + optSpace; 106219fcbaf1SConrad Meyer } 106319fcbaf1SConrad Meyer 10640c16b537SWarner Losh size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) 10650c16b537SWarner Losh { 10662b9c00cbSConrad Meyer RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); 10670c16b537SWarner Losh { ZSTD_compressionParameters const cParams = 106819fcbaf1SConrad Meyer ZSTD_getCParamsFromCCtxParams(params, 0, 0); 10690c16b537SWarner Losh size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); 1070a0483764SConrad Meyer U32 const divider = (cParams.minMatch==3) ? 3 : 4; 10710c16b537SWarner Losh size_t const maxNbSeq = blockSize / divider; 10720f743729SConrad Meyer size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq; 107319fcbaf1SConrad Meyer size_t const entropySpace = HUF_WORKSPACE_SIZE; 107419fcbaf1SConrad Meyer size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t); 107519fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1); 10760c16b537SWarner Losh 107719fcbaf1SConrad Meyer size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams); 107819fcbaf1SConrad Meyer size_t const ldmSeqSpace = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq); 10790c16b537SWarner Losh 108019fcbaf1SConrad Meyer size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace + 108119fcbaf1SConrad Meyer matchStateSize + ldmSpace + ldmSeqSpace; 10820c16b537SWarner Losh 10830c16b537SWarner Losh DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx)); 10840c16b537SWarner Losh DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace); 10850c16b537SWarner Losh return sizeof(ZSTD_CCtx) + neededSpace; 10860c16b537SWarner Losh } 10870c16b537SWarner Losh } 10880c16b537SWarner Losh 10890c16b537SWarner Losh size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) 10900c16b537SWarner Losh { 10910c16b537SWarner Losh ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); 10920c16b537SWarner Losh return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms); 10930c16b537SWarner Losh } 10940c16b537SWarner Losh 109519fcbaf1SConrad Meyer static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) 10960c16b537SWarner Losh { 10970c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); 10980c16b537SWarner Losh return ZSTD_estimateCCtxSize_usingCParams(cParams); 10990c16b537SWarner Losh } 11000c16b537SWarner Losh 110119fcbaf1SConrad Meyer size_t ZSTD_estimateCCtxSize(int compressionLevel) 110219fcbaf1SConrad Meyer { 110319fcbaf1SConrad Meyer int level; 110419fcbaf1SConrad Meyer size_t memBudget = 0; 1105a0483764SConrad Meyer for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { 110619fcbaf1SConrad Meyer size_t const newMB = ZSTD_estimateCCtxSize_internal(level); 110719fcbaf1SConrad Meyer if (newMB > memBudget) memBudget = newMB; 110819fcbaf1SConrad Meyer } 110919fcbaf1SConrad Meyer return memBudget; 111019fcbaf1SConrad Meyer } 111119fcbaf1SConrad Meyer 11120c16b537SWarner Losh size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) 11130c16b537SWarner Losh { 11142b9c00cbSConrad Meyer RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); 11152b9c00cbSConrad Meyer { ZSTD_compressionParameters const cParams = 11162b9c00cbSConrad Meyer ZSTD_getCParamsFromCCtxParams(params, 0, 0); 11172b9c00cbSConrad Meyer size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params); 11182b9c00cbSConrad Meyer size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); 11192b9c00cbSConrad Meyer size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize; 11200c16b537SWarner Losh size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; 11210c16b537SWarner Losh size_t const streamingSize = inBuffSize + outBuffSize; 11220c16b537SWarner Losh 11230c16b537SWarner Losh return CCtxSize + streamingSize; 11240c16b537SWarner Losh } 11250c16b537SWarner Losh } 11260c16b537SWarner Losh 11270c16b537SWarner Losh size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) 11280c16b537SWarner Losh { 11290c16b537SWarner Losh ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); 11300c16b537SWarner Losh return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms); 11310c16b537SWarner Losh } 11320c16b537SWarner Losh 11330f743729SConrad Meyer static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) 11340f743729SConrad Meyer { 11350c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); 11360c16b537SWarner Losh return ZSTD_estimateCStreamSize_usingCParams(cParams); 11370c16b537SWarner Losh } 11380c16b537SWarner Losh 11390f743729SConrad Meyer size_t ZSTD_estimateCStreamSize(int compressionLevel) 11400f743729SConrad Meyer { 114119fcbaf1SConrad Meyer int level; 114219fcbaf1SConrad Meyer size_t memBudget = 0; 1143a0483764SConrad Meyer for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { 114419fcbaf1SConrad Meyer size_t const newMB = ZSTD_estimateCStreamSize_internal(level); 114519fcbaf1SConrad Meyer if (newMB > memBudget) memBudget = newMB; 114619fcbaf1SConrad Meyer } 114719fcbaf1SConrad Meyer return memBudget; 114819fcbaf1SConrad Meyer } 114919fcbaf1SConrad Meyer 115019fcbaf1SConrad Meyer /* ZSTD_getFrameProgression(): 115119fcbaf1SConrad Meyer * tells how much data has been consumed (input) and produced (output) for current frame. 115219fcbaf1SConrad Meyer * able to count progression inside worker threads (non-blocking mode). 115319fcbaf1SConrad Meyer */ 115419fcbaf1SConrad Meyer ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx) 115519fcbaf1SConrad Meyer { 115619fcbaf1SConrad Meyer #ifdef ZSTD_MULTITHREAD 115719fcbaf1SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 115819fcbaf1SConrad Meyer return ZSTDMT_getFrameProgression(cctx->mtctx); 115919fcbaf1SConrad Meyer } 116019fcbaf1SConrad Meyer #endif 116119fcbaf1SConrad Meyer { ZSTD_frameProgression fp; 116219fcbaf1SConrad Meyer size_t const buffered = (cctx->inBuff == NULL) ? 0 : 116319fcbaf1SConrad Meyer cctx->inBuffPos - cctx->inToCompress; 116419fcbaf1SConrad Meyer if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress); 116519fcbaf1SConrad Meyer assert(buffered <= ZSTD_BLOCKSIZE_MAX); 116619fcbaf1SConrad Meyer fp.ingested = cctx->consumedSrcSize + buffered; 116719fcbaf1SConrad Meyer fp.consumed = cctx->consumedSrcSize; 116819fcbaf1SConrad Meyer fp.produced = cctx->producedCSize; 11690f743729SConrad Meyer fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */ 11700f743729SConrad Meyer fp.currentJobID = 0; 11710f743729SConrad Meyer fp.nbActiveWorkers = 0; 117219fcbaf1SConrad Meyer return fp; 117319fcbaf1SConrad Meyer } } 117419fcbaf1SConrad Meyer 11750f743729SConrad Meyer /*! ZSTD_toFlushNow() 11760f743729SConrad Meyer * Only useful for multithreading scenarios currently (nbWorkers >= 1). 11770f743729SConrad Meyer */ 11780f743729SConrad Meyer size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx) 11790f743729SConrad Meyer { 11800f743729SConrad Meyer #ifdef ZSTD_MULTITHREAD 11810f743729SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 11820f743729SConrad Meyer return ZSTDMT_toFlushNow(cctx->mtctx); 11830f743729SConrad Meyer } 11840f743729SConrad Meyer #endif 11850f743729SConrad Meyer (void)cctx; 11860f743729SConrad 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 */ 11870f743729SConrad Meyer } 11880f743729SConrad Meyer 11890f743729SConrad Meyer 119019fcbaf1SConrad Meyer 11910c16b537SWarner Losh static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1, 11920c16b537SWarner Losh ZSTD_compressionParameters cParams2) 11930c16b537SWarner Losh { 1194052d3c12SConrad Meyer return (cParams1.hashLog == cParams2.hashLog) 11950c16b537SWarner Losh & (cParams1.chainLog == cParams2.chainLog) 11960c16b537SWarner Losh & (cParams1.strategy == cParams2.strategy) /* opt parser space */ 1197a0483764SConrad Meyer & ((cParams1.minMatch==3) == (cParams2.minMatch==3)); /* hashlog3 space */ 11980c16b537SWarner Losh } 11990c16b537SWarner Losh 12000f743729SConrad Meyer static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1, 12010f743729SConrad Meyer ZSTD_compressionParameters cParams2) 12020f743729SConrad Meyer { 12030f743729SConrad Meyer (void)cParams1; 12040f743729SConrad Meyer (void)cParams2; 12050f743729SConrad Meyer assert(cParams1.windowLog == cParams2.windowLog); 12060f743729SConrad Meyer assert(cParams1.chainLog == cParams2.chainLog); 12070f743729SConrad Meyer assert(cParams1.hashLog == cParams2.hashLog); 12080f743729SConrad Meyer assert(cParams1.searchLog == cParams2.searchLog); 1209a0483764SConrad Meyer assert(cParams1.minMatch == cParams2.minMatch); 12100f743729SConrad Meyer assert(cParams1.targetLength == cParams2.targetLength); 12110f743729SConrad Meyer assert(cParams1.strategy == cParams2.strategy); 12120f743729SConrad Meyer } 12130f743729SConrad Meyer 12140c16b537SWarner Losh /** The parameters are equivalent if ldm is not enabled in both sets or 12150c16b537SWarner Losh * all the parameters are equivalent. */ 12160c16b537SWarner Losh static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1, 12170c16b537SWarner Losh ldmParams_t ldmParams2) 12180c16b537SWarner Losh { 12190c16b537SWarner Losh return (!ldmParams1.enableLdm && !ldmParams2.enableLdm) || 12200c16b537SWarner Losh (ldmParams1.enableLdm == ldmParams2.enableLdm && 12210c16b537SWarner Losh ldmParams1.hashLog == ldmParams2.hashLog && 12220c16b537SWarner Losh ldmParams1.bucketSizeLog == ldmParams2.bucketSizeLog && 12230c16b537SWarner Losh ldmParams1.minMatchLength == ldmParams2.minMatchLength && 1224a0483764SConrad Meyer ldmParams1.hashRateLog == ldmParams2.hashRateLog); 12250c16b537SWarner Losh } 12260c16b537SWarner Losh 1227052d3c12SConrad Meyer typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e; 1228052d3c12SConrad Meyer 1229052d3c12SConrad Meyer /* ZSTD_sufficientBuff() : 1230052d3c12SConrad Meyer * check internal buffers exist for streaming if buffPol == ZSTDb_buffered . 1231052d3c12SConrad Meyer * Note : they are assumed to be correctly sized if ZSTD_equivalentCParams()==1 */ 12320f743729SConrad Meyer static U32 ZSTD_sufficientBuff(size_t bufferSize1, size_t maxNbSeq1, 12330f743729SConrad Meyer size_t maxNbLit1, 1234052d3c12SConrad Meyer ZSTD_buffered_policy_e buffPol2, 1235052d3c12SConrad Meyer ZSTD_compressionParameters cParams2, 1236052d3c12SConrad Meyer U64 pledgedSrcSize) 1237052d3c12SConrad Meyer { 1238052d3c12SConrad Meyer size_t const windowSize2 = MAX(1, (size_t)MIN(((U64)1 << cParams2.windowLog), pledgedSrcSize)); 1239052d3c12SConrad Meyer size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2); 1240a0483764SConrad Meyer size_t const maxNbSeq2 = blockSize2 / ((cParams2.minMatch == 3) ? 3 : 4); 12410f743729SConrad Meyer size_t const maxNbLit2 = blockSize2; 1242052d3c12SConrad Meyer size_t const neededBufferSize2 = (buffPol2==ZSTDb_buffered) ? windowSize2 + blockSize2 : 0; 12430f743729SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff: is neededBufferSize2=%u <= bufferSize1=%u", 12440f743729SConrad Meyer (U32)neededBufferSize2, (U32)bufferSize1); 12450f743729SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbSeq2=%u <= maxNbSeq1=%u", 12460f743729SConrad Meyer (U32)maxNbSeq2, (U32)maxNbSeq1); 12470f743729SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbLit2=%u <= maxNbLit1=%u", 12480f743729SConrad Meyer (U32)maxNbLit2, (U32)maxNbLit1); 12490f743729SConrad Meyer return (maxNbLit2 <= maxNbLit1) 12500f743729SConrad Meyer & (maxNbSeq2 <= maxNbSeq1) 1251052d3c12SConrad Meyer & (neededBufferSize2 <= bufferSize1); 1252052d3c12SConrad Meyer } 1253052d3c12SConrad Meyer 12540c16b537SWarner Losh /** Equivalence for resetCCtx purposes */ 12550c16b537SWarner Losh static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1, 1256052d3c12SConrad Meyer ZSTD_CCtx_params params2, 12570f743729SConrad Meyer size_t buffSize1, 12580f743729SConrad Meyer size_t maxNbSeq1, size_t maxNbLit1, 1259052d3c12SConrad Meyer ZSTD_buffered_policy_e buffPol2, 1260052d3c12SConrad Meyer U64 pledgedSrcSize) 12610c16b537SWarner Losh { 1262052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentParams: pledgedSrcSize=%u", (U32)pledgedSrcSize); 12630f743729SConrad Meyer if (!ZSTD_equivalentCParams(params1.cParams, params2.cParams)) { 12640f743729SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentCParams() == 0"); 12650f743729SConrad Meyer return 0; 12660f743729SConrad Meyer } 12670f743729SConrad Meyer if (!ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams)) { 12680f743729SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentLdmParams() == 0"); 12690f743729SConrad Meyer return 0; 12700f743729SConrad Meyer } 12710f743729SConrad Meyer if (!ZSTD_sufficientBuff(buffSize1, maxNbSeq1, maxNbLit1, buffPol2, 12720f743729SConrad Meyer params2.cParams, pledgedSrcSize)) { 12730f743729SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff() == 0"); 12740f743729SConrad Meyer return 0; 12750f743729SConrad Meyer } 12760f743729SConrad Meyer return 1; 12770c16b537SWarner Losh } 12780c16b537SWarner Losh 127919fcbaf1SConrad Meyer static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) 128019fcbaf1SConrad Meyer { 128119fcbaf1SConrad Meyer int i; 128219fcbaf1SConrad Meyer for (i = 0; i < ZSTD_REP_NUM; ++i) 128319fcbaf1SConrad Meyer bs->rep[i] = repStartValue[i]; 12840f743729SConrad Meyer bs->entropy.huf.repeatMode = HUF_repeat_none; 12850f743729SConrad Meyer bs->entropy.fse.offcode_repeatMode = FSE_repeat_none; 12860f743729SConrad Meyer bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none; 12870f743729SConrad Meyer bs->entropy.fse.litlength_repeatMode = FSE_repeat_none; 128819fcbaf1SConrad Meyer } 128919fcbaf1SConrad Meyer 129019fcbaf1SConrad Meyer /*! ZSTD_invalidateMatchState() 129119fcbaf1SConrad Meyer * Invalidate all the matches in the match finder tables. 129219fcbaf1SConrad Meyer * Requires nextSrc and base to be set (can be NULL). 129319fcbaf1SConrad Meyer */ 129419fcbaf1SConrad Meyer static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms) 129519fcbaf1SConrad Meyer { 129619fcbaf1SConrad Meyer ZSTD_window_clear(&ms->window); 129719fcbaf1SConrad Meyer 1298a0483764SConrad Meyer ms->nextToUpdate = ms->window.dictLimit; 129919fcbaf1SConrad Meyer ms->loadedDictEnd = 0; 130019fcbaf1SConrad Meyer ms->opt.litLengthSum = 0; /* force reset of btopt stats */ 13010f743729SConrad Meyer ms->dictMatchState = NULL; 130219fcbaf1SConrad Meyer } 130319fcbaf1SConrad Meyer 13040c16b537SWarner Losh /*! ZSTD_continueCCtx() : 13050c16b537SWarner Losh * reuse CCtx without reset (note : requires no dictionary) */ 13060c16b537SWarner Losh static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize) 13070c16b537SWarner Losh { 1308052d3c12SConrad Meyer size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); 1309052d3c12SConrad Meyer size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); 131019fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_continueCCtx: re-use context in place"); 1311052d3c12SConrad Meyer 1312052d3c12SConrad Meyer cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */ 13130c16b537SWarner Losh cctx->appliedParams = params; 13140f743729SConrad Meyer cctx->blockState.matchState.cParams = params.cParams; 13150c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; 13160c16b537SWarner Losh cctx->consumedSrcSize = 0; 131719fcbaf1SConrad Meyer cctx->producedCSize = 0; 13180c16b537SWarner Losh if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) 13190c16b537SWarner Losh cctx->appliedParams.fParams.contentSizeFlag = 0; 13200c16b537SWarner Losh DEBUGLOG(4, "pledged content size : %u ; flag : %u", 13210c16b537SWarner Losh (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag); 13220c16b537SWarner Losh cctx->stage = ZSTDcs_init; 13230c16b537SWarner Losh cctx->dictID = 0; 132419fcbaf1SConrad Meyer if (params.ldmParams.enableLdm) 132519fcbaf1SConrad Meyer ZSTD_window_clear(&cctx->ldmState.window); 132619fcbaf1SConrad Meyer ZSTD_referenceExternalSequences(cctx, NULL, 0); 132719fcbaf1SConrad Meyer ZSTD_invalidateMatchState(&cctx->blockState.matchState); 132819fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(cctx->blockState.prevCBlock); 13290c16b537SWarner Losh XXH64_reset(&cctx->xxhState, 0); 13300c16b537SWarner Losh return 0; 13310c16b537SWarner Losh } 13320c16b537SWarner Losh 13330c16b537SWarner Losh typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e; 13340c16b537SWarner Losh 1335*4d3f1eafSConrad Meyer typedef enum { ZSTD_resetTarget_CDict, ZSTD_resetTarget_CCtx } ZSTD_resetTarget_e; 1336*4d3f1eafSConrad Meyer 13370f743729SConrad Meyer static void* 13380f743729SConrad Meyer ZSTD_reset_matchState(ZSTD_matchState_t* ms, 13390f743729SConrad Meyer void* ptr, 13400f743729SConrad Meyer const ZSTD_compressionParameters* cParams, 1341*4d3f1eafSConrad Meyer ZSTD_compResetPolicy_e const crp, ZSTD_resetTarget_e const forWho) 134219fcbaf1SConrad Meyer { 134319fcbaf1SConrad Meyer size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); 134419fcbaf1SConrad Meyer size_t const hSize = ((size_t)1) << cParams->hashLog; 1345*4d3f1eafSConrad Meyer U32 const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 134619fcbaf1SConrad Meyer size_t const h3Size = ((size_t)1) << hashLog3; 134719fcbaf1SConrad Meyer size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 134819fcbaf1SConrad Meyer 134919fcbaf1SConrad Meyer assert(((size_t)ptr & 3) == 0); 135019fcbaf1SConrad Meyer 135119fcbaf1SConrad Meyer ms->hashLog3 = hashLog3; 135219fcbaf1SConrad Meyer memset(&ms->window, 0, sizeof(ms->window)); 13530f743729SConrad Meyer ms->window.dictLimit = 1; /* start from 1, so that 1st position is valid */ 13540f743729SConrad Meyer ms->window.lowLimit = 1; /* it ensures first and later CCtx usages compress the same */ 13550f743729SConrad Meyer ms->window.nextSrc = ms->window.base + 1; /* see issue #1241 */ 135619fcbaf1SConrad Meyer ZSTD_invalidateMatchState(ms); 135719fcbaf1SConrad Meyer 135819fcbaf1SConrad Meyer /* opt parser space */ 1359*4d3f1eafSConrad Meyer if ((forWho == ZSTD_resetTarget_CCtx) && (cParams->strategy >= ZSTD_btopt)) { 136019fcbaf1SConrad Meyer DEBUGLOG(4, "reserving optimal parser space"); 1361a0483764SConrad Meyer ms->opt.litFreq = (unsigned*)ptr; 136219fcbaf1SConrad Meyer ms->opt.litLengthFreq = ms->opt.litFreq + (1<<Litbits); 136319fcbaf1SConrad Meyer ms->opt.matchLengthFreq = ms->opt.litLengthFreq + (MaxLL+1); 136419fcbaf1SConrad Meyer ms->opt.offCodeFreq = ms->opt.matchLengthFreq + (MaxML+1); 136519fcbaf1SConrad Meyer ptr = ms->opt.offCodeFreq + (MaxOff+1); 136619fcbaf1SConrad Meyer ms->opt.matchTable = (ZSTD_match_t*)ptr; 136719fcbaf1SConrad Meyer ptr = ms->opt.matchTable + ZSTD_OPT_NUM+1; 136819fcbaf1SConrad Meyer ms->opt.priceTable = (ZSTD_optimal_t*)ptr; 136919fcbaf1SConrad Meyer ptr = ms->opt.priceTable + ZSTD_OPT_NUM+1; 137019fcbaf1SConrad Meyer } 137119fcbaf1SConrad Meyer 137219fcbaf1SConrad Meyer /* table Space */ 137319fcbaf1SConrad Meyer DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset); 137419fcbaf1SConrad Meyer assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ 137519fcbaf1SConrad Meyer if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */ 137619fcbaf1SConrad Meyer ms->hashTable = (U32*)(ptr); 137719fcbaf1SConrad Meyer ms->chainTable = ms->hashTable + hSize; 137819fcbaf1SConrad Meyer ms->hashTable3 = ms->chainTable + chainSize; 137919fcbaf1SConrad Meyer ptr = ms->hashTable3 + h3Size; 138019fcbaf1SConrad Meyer 13810f743729SConrad Meyer ms->cParams = *cParams; 13820f743729SConrad Meyer 138319fcbaf1SConrad Meyer assert(((size_t)ptr & 3) == 0); 138419fcbaf1SConrad Meyer return ptr; 138519fcbaf1SConrad Meyer } 138619fcbaf1SConrad Meyer 1387*4d3f1eafSConrad Meyer /* ZSTD_indexTooCloseToMax() : 1388*4d3f1eafSConrad Meyer * minor optimization : prefer memset() rather than reduceIndex() 1389*4d3f1eafSConrad Meyer * which is measurably slow in some circumstances (reported for Visual Studio). 1390*4d3f1eafSConrad Meyer * Works when re-using a context for a lot of smallish inputs : 1391*4d3f1eafSConrad Meyer * if all inputs are smaller than ZSTD_INDEXOVERFLOW_MARGIN, 1392*4d3f1eafSConrad Meyer * memset() will be triggered before reduceIndex(). 1393*4d3f1eafSConrad Meyer */ 1394*4d3f1eafSConrad Meyer #define ZSTD_INDEXOVERFLOW_MARGIN (16 MB) 1395*4d3f1eafSConrad Meyer static int ZSTD_indexTooCloseToMax(ZSTD_window_t w) 1396*4d3f1eafSConrad Meyer { 1397*4d3f1eafSConrad Meyer return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN); 1398*4d3f1eafSConrad Meyer } 1399*4d3f1eafSConrad Meyer 14000f743729SConrad Meyer #define ZSTD_WORKSPACETOOLARGE_FACTOR 3 /* define "workspace is too large" as this number of times larger than needed */ 14010f743729SConrad Meyer #define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 /* when workspace is continuously too large 14020f743729SConrad Meyer * during at least this number of times, 14030f743729SConrad Meyer * context's memory usage is considered wasteful, 14040f743729SConrad Meyer * because it's sized to handle a worst case scenario which rarely happens. 14050f743729SConrad Meyer * In which case, resize it down to free some memory */ 14060f743729SConrad Meyer 14070c16b537SWarner Losh /*! ZSTD_resetCCtx_internal() : 14080c16b537SWarner Losh note : `params` are assumed fully validated at this stage */ 14090c16b537SWarner Losh static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, 14100f743729SConrad Meyer ZSTD_CCtx_params params, 1411*4d3f1eafSConrad Meyer U64 const pledgedSrcSize, 14120c16b537SWarner Losh ZSTD_compResetPolicy_e const crp, 14130c16b537SWarner Losh ZSTD_buffered_policy_e const zbuff) 14140c16b537SWarner Losh { 1415052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u", 1416052d3c12SConrad Meyer (U32)pledgedSrcSize, params.cParams.windowLog); 14170c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 14180c16b537SWarner Losh 14190c16b537SWarner Losh if (crp == ZSTDcrp_continue) { 1420052d3c12SConrad Meyer if (ZSTD_equivalentParams(zc->appliedParams, params, 14210f743729SConrad Meyer zc->inBuffSize, 14220f743729SConrad Meyer zc->seqStore.maxNbSeq, zc->seqStore.maxNbLit, 1423052d3c12SConrad Meyer zbuff, pledgedSrcSize) ) { 1424*4d3f1eafSConrad Meyer DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> consider continue mode"); 14250f743729SConrad Meyer zc->workSpaceOversizedDuration += (zc->workSpaceOversizedDuration > 0); /* if it was too large, it still is */ 1426*4d3f1eafSConrad Meyer if (zc->workSpaceOversizedDuration <= ZSTD_WORKSPACETOOLARGE_MAXDURATION) { 1427*4d3f1eafSConrad Meyer DEBUGLOG(4, "continue mode confirmed (wLog1=%u, blockSize1=%zu)", 1428*4d3f1eafSConrad Meyer zc->appliedParams.cParams.windowLog, zc->blockSize); 1429*4d3f1eafSConrad Meyer if (ZSTD_indexTooCloseToMax(zc->blockState.matchState.window)) { 1430*4d3f1eafSConrad Meyer /* prefer a reset, faster than a rescale */ 1431*4d3f1eafSConrad Meyer ZSTD_reset_matchState(&zc->blockState.matchState, 1432*4d3f1eafSConrad Meyer zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32, 1433*4d3f1eafSConrad Meyer ¶ms.cParams, 1434*4d3f1eafSConrad Meyer crp, ZSTD_resetTarget_CCtx); 1435*4d3f1eafSConrad Meyer } 14360c16b537SWarner Losh return ZSTD_continueCCtx(zc, params, pledgedSrcSize); 1437*4d3f1eafSConrad Meyer } } } 1438052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx"); 14390c16b537SWarner Losh 14400c16b537SWarner Losh if (params.ldmParams.enableLdm) { 14410c16b537SWarner Losh /* Adjust long distance matching parameters */ 144219fcbaf1SConrad Meyer ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); 14430c16b537SWarner Losh assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); 1444a0483764SConrad Meyer assert(params.ldmParams.hashRateLog < 32); 1445a0483764SConrad Meyer zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength); 14460c16b537SWarner Losh } 14470c16b537SWarner Losh 1448052d3c12SConrad Meyer { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); 1449052d3c12SConrad Meyer size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); 1450a0483764SConrad Meyer U32 const divider = (params.cParams.minMatch==3) ? 3 : 4; 14510c16b537SWarner Losh size_t const maxNbSeq = blockSize / divider; 14520f743729SConrad Meyer size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq; 14530c16b537SWarner Losh size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0; 1454052d3c12SConrad Meyer size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0; 145519fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1); 145619fcbaf1SConrad Meyer size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize); 14570f743729SConrad Meyer void* ptr; /* used to partition workSpace */ 14580c16b537SWarner Losh 14590c16b537SWarner Losh /* Check if workSpace is large enough, alloc a new one if needed */ 146019fcbaf1SConrad Meyer { size_t const entropySpace = HUF_WORKSPACE_SIZE; 146119fcbaf1SConrad Meyer size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t); 14620c16b537SWarner Losh size_t const bufferSpace = buffInSize + buffOutSize; 146319fcbaf1SConrad Meyer size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams); 146419fcbaf1SConrad Meyer size_t const ldmSeqSpace = maxNbLdmSeq * sizeof(rawSeq); 146519fcbaf1SConrad Meyer 146619fcbaf1SConrad Meyer size_t const neededSpace = entropySpace + blockStateSpace + ldmSpace + 146719fcbaf1SConrad Meyer ldmSeqSpace + matchStateSize + tokenSpace + 146819fcbaf1SConrad Meyer bufferSpace; 14690c16b537SWarner Losh 14700f743729SConrad Meyer int const workSpaceTooSmall = zc->workSpaceSize < neededSpace; 14710f743729SConrad Meyer int const workSpaceTooLarge = zc->workSpaceSize > ZSTD_WORKSPACETOOLARGE_FACTOR * neededSpace; 14720f743729SConrad Meyer int const workSpaceWasteful = workSpaceTooLarge && (zc->workSpaceOversizedDuration > ZSTD_WORKSPACETOOLARGE_MAXDURATION); 14730f743729SConrad Meyer zc->workSpaceOversizedDuration = workSpaceTooLarge ? zc->workSpaceOversizedDuration+1 : 0; 14740f743729SConrad Meyer 14750f743729SConrad Meyer DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers", 14760f743729SConrad Meyer neededSpace>>10, matchStateSize>>10, bufferSpace>>10); 14770f743729SConrad Meyer DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); 14780f743729SConrad Meyer 14790f743729SConrad Meyer if (workSpaceTooSmall || workSpaceWasteful) { 1480*4d3f1eafSConrad Meyer DEBUGLOG(4, "Resize workSpaceSize from %zuKB to %zuKB", 14810f743729SConrad Meyer zc->workSpaceSize >> 10, 14820f743729SConrad Meyer neededSpace >> 10); 14832b9c00cbSConrad Meyer 14842b9c00cbSConrad Meyer RETURN_ERROR_IF(zc->staticSize, memory_allocation, "static cctx : no resize"); 14850c16b537SWarner Losh 14860c16b537SWarner Losh zc->workSpaceSize = 0; 14870c16b537SWarner Losh ZSTD_free(zc->workSpace, zc->customMem); 14880c16b537SWarner Losh zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem); 14892b9c00cbSConrad Meyer RETURN_ERROR_IF(zc->workSpace == NULL, memory_allocation); 14900c16b537SWarner Losh zc->workSpaceSize = neededSpace; 14910f743729SConrad Meyer zc->workSpaceOversizedDuration = 0; 14920c16b537SWarner Losh 14930f743729SConrad Meyer /* Statically sized space. 14940f743729SConrad Meyer * entropyWorkspace never moves, 14950f743729SConrad Meyer * though prev/next block swap places */ 14960c16b537SWarner Losh assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */ 149719fcbaf1SConrad Meyer assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_compressedBlockState_t)); 149819fcbaf1SConrad Meyer zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)zc->workSpace; 149919fcbaf1SConrad Meyer zc->blockState.nextCBlock = zc->blockState.prevCBlock + 1; 150019fcbaf1SConrad Meyer ptr = zc->blockState.nextCBlock + 1; 150119fcbaf1SConrad Meyer zc->entropyWorkspace = (U32*)ptr; 15020c16b537SWarner Losh } } 15030c16b537SWarner Losh 15040c16b537SWarner Losh /* init params */ 15050c16b537SWarner Losh zc->appliedParams = params; 15060f743729SConrad Meyer zc->blockState.matchState.cParams = params.cParams; 15070c16b537SWarner Losh zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; 15080c16b537SWarner Losh zc->consumedSrcSize = 0; 150919fcbaf1SConrad Meyer zc->producedCSize = 0; 15100c16b537SWarner Losh if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) 15110c16b537SWarner Losh zc->appliedParams.fParams.contentSizeFlag = 0; 1512052d3c12SConrad Meyer DEBUGLOG(4, "pledged content size : %u ; flag : %u", 1513a0483764SConrad Meyer (unsigned)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag); 15140c16b537SWarner Losh zc->blockSize = blockSize; 15150c16b537SWarner Losh 15160c16b537SWarner Losh XXH64_reset(&zc->xxhState, 0); 15170c16b537SWarner Losh zc->stage = ZSTDcs_init; 15180c16b537SWarner Losh zc->dictID = 0; 15190c16b537SWarner Losh 152019fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock); 15210c16b537SWarner Losh 1522*4d3f1eafSConrad Meyer ptr = ZSTD_reset_matchState(&zc->blockState.matchState, 1523*4d3f1eafSConrad Meyer zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32, 1524*4d3f1eafSConrad Meyer ¶ms.cParams, 1525*4d3f1eafSConrad Meyer crp, ZSTD_resetTarget_CCtx); 15260c16b537SWarner Losh 15270c16b537SWarner Losh /* ldm hash table */ 15280c16b537SWarner Losh /* initialize bucketOffsets table later for pointer alignment */ 15290c16b537SWarner Losh if (params.ldmParams.enableLdm) { 15300c16b537SWarner Losh size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog; 15310c16b537SWarner Losh memset(ptr, 0, ldmHSize * sizeof(ldmEntry_t)); 15320c16b537SWarner Losh assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ 15330c16b537SWarner Losh zc->ldmState.hashTable = (ldmEntry_t*)ptr; 15340c16b537SWarner Losh ptr = zc->ldmState.hashTable + ldmHSize; 153519fcbaf1SConrad Meyer zc->ldmSequences = (rawSeq*)ptr; 153619fcbaf1SConrad Meyer ptr = zc->ldmSequences + maxNbLdmSeq; 153719fcbaf1SConrad Meyer zc->maxNbLdmSequences = maxNbLdmSeq; 15380c16b537SWarner Losh 153919fcbaf1SConrad Meyer memset(&zc->ldmState.window, 0, sizeof(zc->ldmState.window)); 154019fcbaf1SConrad Meyer } 15410c16b537SWarner Losh assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ 154219fcbaf1SConrad Meyer 15430c16b537SWarner Losh /* sequences storage */ 15440f743729SConrad Meyer zc->seqStore.maxNbSeq = maxNbSeq; 15450c16b537SWarner Losh zc->seqStore.sequencesStart = (seqDef*)ptr; 15460c16b537SWarner Losh ptr = zc->seqStore.sequencesStart + maxNbSeq; 15470c16b537SWarner Losh zc->seqStore.llCode = (BYTE*) ptr; 15480c16b537SWarner Losh zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq; 15490c16b537SWarner Losh zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq; 15500c16b537SWarner Losh zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq; 15510f743729SConrad Meyer /* ZSTD_wildcopy() is used to copy into the literals buffer, 15520f743729SConrad Meyer * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes. 15530f743729SConrad Meyer */ 15540f743729SConrad Meyer zc->seqStore.maxNbLit = blockSize; 15550f743729SConrad Meyer ptr = zc->seqStore.litStart + blockSize + WILDCOPY_OVERLENGTH; 15560c16b537SWarner Losh 15570c16b537SWarner Losh /* ldm bucketOffsets table */ 15580c16b537SWarner Losh if (params.ldmParams.enableLdm) { 15590c16b537SWarner Losh size_t const ldmBucketSize = 15600c16b537SWarner Losh ((size_t)1) << (params.ldmParams.hashLog - 15610c16b537SWarner Losh params.ldmParams.bucketSizeLog); 15620c16b537SWarner Losh memset(ptr, 0, ldmBucketSize); 15630c16b537SWarner Losh zc->ldmState.bucketOffsets = (BYTE*)ptr; 15640c16b537SWarner Losh ptr = zc->ldmState.bucketOffsets + ldmBucketSize; 156519fcbaf1SConrad Meyer ZSTD_window_clear(&zc->ldmState.window); 15660c16b537SWarner Losh } 156719fcbaf1SConrad Meyer ZSTD_referenceExternalSequences(zc, NULL, 0); 15680c16b537SWarner Losh 15690c16b537SWarner Losh /* buffers */ 15700c16b537SWarner Losh zc->inBuffSize = buffInSize; 15710c16b537SWarner Losh zc->inBuff = (char*)ptr; 15720c16b537SWarner Losh zc->outBuffSize = buffOutSize; 15730c16b537SWarner Losh zc->outBuff = zc->inBuff + buffInSize; 15740c16b537SWarner Losh 15750c16b537SWarner Losh return 0; 15760c16b537SWarner Losh } 15770c16b537SWarner Losh } 15780c16b537SWarner Losh 15790c16b537SWarner Losh /* ZSTD_invalidateRepCodes() : 15800c16b537SWarner Losh * ensures next compression will not use repcodes from previous block. 15810c16b537SWarner Losh * Note : only works with regular variant; 15820c16b537SWarner Losh * do not use with extDict variant ! */ 15830c16b537SWarner Losh void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) { 15840c16b537SWarner Losh int i; 158519fcbaf1SConrad Meyer for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0; 158619fcbaf1SConrad Meyer assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window)); 15870c16b537SWarner Losh } 15880c16b537SWarner Losh 15890f743729SConrad Meyer /* These are the approximate sizes for each strategy past which copying the 15900f743729SConrad Meyer * dictionary tables into the working context is faster than using them 15910f743729SConrad Meyer * in-place. 15920f743729SConrad Meyer */ 1593a0483764SConrad Meyer static const size_t attachDictSizeCutoffs[ZSTD_STRATEGY_MAX+1] = { 15940f743729SConrad Meyer 8 KB, /* unused */ 15950f743729SConrad Meyer 8 KB, /* ZSTD_fast */ 15960f743729SConrad Meyer 16 KB, /* ZSTD_dfast */ 15970f743729SConrad Meyer 32 KB, /* ZSTD_greedy */ 15980f743729SConrad Meyer 32 KB, /* ZSTD_lazy */ 15990f743729SConrad Meyer 32 KB, /* ZSTD_lazy2 */ 16000f743729SConrad Meyer 32 KB, /* ZSTD_btlazy2 */ 16010f743729SConrad Meyer 32 KB, /* ZSTD_btopt */ 1602a0483764SConrad Meyer 8 KB, /* ZSTD_btultra */ 1603a0483764SConrad Meyer 8 KB /* ZSTD_btultra2 */ 16040f743729SConrad Meyer }; 16050f743729SConrad Meyer 16060f743729SConrad Meyer static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, 16070f743729SConrad Meyer ZSTD_CCtx_params params, 16080f743729SConrad Meyer U64 pledgedSrcSize) 16090f743729SConrad Meyer { 16100f743729SConrad Meyer size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy]; 16110f743729SConrad Meyer return ( pledgedSrcSize <= cutoff 16120f743729SConrad Meyer || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN 16130f743729SConrad Meyer || params.attachDictPref == ZSTD_dictForceAttach ) 16140f743729SConrad Meyer && params.attachDictPref != ZSTD_dictForceCopy 16150f743729SConrad Meyer && !params.forceWindow; /* dictMatchState isn't correctly 16160f743729SConrad Meyer * handled in _enforceMaxDist */ 16170f743729SConrad Meyer } 16180f743729SConrad Meyer 1619*4d3f1eafSConrad Meyer static size_t 1620*4d3f1eafSConrad Meyer ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx, 162119fcbaf1SConrad Meyer const ZSTD_CDict* cdict, 16220f743729SConrad Meyer ZSTD_CCtx_params params, 162319fcbaf1SConrad Meyer U64 pledgedSrcSize, 162419fcbaf1SConrad Meyer ZSTD_buffered_policy_e zbuff) 162519fcbaf1SConrad Meyer { 1626*4d3f1eafSConrad Meyer { const ZSTD_compressionParameters* const cdict_cParams = &cdict->matchState.cParams; 16270f743729SConrad Meyer unsigned const windowLog = params.cParams.windowLog; 16280f743729SConrad Meyer assert(windowLog != 0); 16290f743729SConrad Meyer /* Resize working context table params for input only, since the dict 16300f743729SConrad Meyer * has its own tables. */ 16310f743729SConrad Meyer params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0); 16320f743729SConrad Meyer params.cParams.windowLog = windowLog; 16330f743729SConrad Meyer ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 16340f743729SConrad Meyer ZSTDcrp_continue, zbuff); 16350f743729SConrad Meyer assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); 16360f743729SConrad Meyer } 16370f743729SConrad Meyer 1638*4d3f1eafSConrad Meyer { const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc 16390f743729SConrad Meyer - cdict->matchState.window.base); 16400f743729SConrad Meyer const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit; 16410f743729SConrad Meyer if (cdictLen == 0) { 16420f743729SConrad Meyer /* don't even attach dictionaries with no contents */ 16430f743729SConrad Meyer DEBUGLOG(4, "skipping attaching empty dictionary"); 16440f743729SConrad Meyer } else { 16450f743729SConrad Meyer DEBUGLOG(4, "attaching dictionary into context"); 16460f743729SConrad Meyer cctx->blockState.matchState.dictMatchState = &cdict->matchState; 16470f743729SConrad Meyer 16480f743729SConrad Meyer /* prep working match state so dict matches never have negative indices 16490f743729SConrad Meyer * when they are translated to the working context's index space. */ 16500f743729SConrad Meyer if (cctx->blockState.matchState.window.dictLimit < cdictEnd) { 16510f743729SConrad Meyer cctx->blockState.matchState.window.nextSrc = 16520f743729SConrad Meyer cctx->blockState.matchState.window.base + cdictEnd; 16530f743729SConrad Meyer ZSTD_window_clear(&cctx->blockState.matchState.window); 16540f743729SConrad Meyer } 1655*4d3f1eafSConrad Meyer /* loadedDictEnd is expressed within the referential of the active context */ 16560f743729SConrad Meyer cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit; 1657*4d3f1eafSConrad Meyer } } 16580f743729SConrad Meyer 16590f743729SConrad Meyer cctx->dictID = cdict->dictID; 16600f743729SConrad Meyer 16610f743729SConrad Meyer /* copy block state */ 16620f743729SConrad Meyer memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 16630f743729SConrad Meyer 16640f743729SConrad Meyer return 0; 16650f743729SConrad Meyer } 16660f743729SConrad Meyer 16670f743729SConrad Meyer static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, 16680f743729SConrad Meyer const ZSTD_CDict* cdict, 16690f743729SConrad Meyer ZSTD_CCtx_params params, 16700f743729SConrad Meyer U64 pledgedSrcSize, 16710f743729SConrad Meyer ZSTD_buffered_policy_e zbuff) 16720f743729SConrad Meyer { 16730f743729SConrad Meyer const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; 16740f743729SConrad Meyer 16750f743729SConrad Meyer DEBUGLOG(4, "copying dictionary into context"); 16760f743729SConrad Meyer 16770f743729SConrad Meyer { unsigned const windowLog = params.cParams.windowLog; 16780f743729SConrad Meyer assert(windowLog != 0); 167919fcbaf1SConrad Meyer /* Copy only compression parameters related to tables. */ 16800f743729SConrad Meyer params.cParams = *cdict_cParams; 16810f743729SConrad Meyer params.cParams.windowLog = windowLog; 168219fcbaf1SConrad Meyer ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 168319fcbaf1SConrad Meyer ZSTDcrp_noMemset, zbuff); 16840f743729SConrad Meyer assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); 16850f743729SConrad Meyer assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog); 16860f743729SConrad Meyer assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog); 168719fcbaf1SConrad Meyer } 168819fcbaf1SConrad Meyer 168919fcbaf1SConrad Meyer /* copy tables */ 16900f743729SConrad Meyer { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog); 16910f743729SConrad Meyer size_t const hSize = (size_t)1 << cdict_cParams->hashLog; 169219fcbaf1SConrad Meyer size_t const tableSpace = (chainSize + hSize) * sizeof(U32); 169319fcbaf1SConrad Meyer assert((U32*)cctx->blockState.matchState.chainTable == (U32*)cctx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */ 169419fcbaf1SConrad Meyer assert((U32*)cctx->blockState.matchState.hashTable3 == (U32*)cctx->blockState.matchState.chainTable + chainSize); 169519fcbaf1SConrad Meyer assert((U32*)cdict->matchState.chainTable == (U32*)cdict->matchState.hashTable + hSize); /* chainTable must follow hashTable */ 169619fcbaf1SConrad Meyer assert((U32*)cdict->matchState.hashTable3 == (U32*)cdict->matchState.chainTable + chainSize); 169719fcbaf1SConrad Meyer memcpy(cctx->blockState.matchState.hashTable, cdict->matchState.hashTable, tableSpace); /* presumes all tables follow each other */ 169819fcbaf1SConrad Meyer } 16990f743729SConrad Meyer 170019fcbaf1SConrad Meyer /* Zero the hashTable3, since the cdict never fills it */ 170119fcbaf1SConrad Meyer { size_t const h3Size = (size_t)1 << cctx->blockState.matchState.hashLog3; 170219fcbaf1SConrad Meyer assert(cdict->matchState.hashLog3 == 0); 170319fcbaf1SConrad Meyer memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); 170419fcbaf1SConrad Meyer } 170519fcbaf1SConrad Meyer 170619fcbaf1SConrad Meyer /* copy dictionary offsets */ 17070f743729SConrad Meyer { ZSTD_matchState_t const* srcMatchState = &cdict->matchState; 170819fcbaf1SConrad Meyer ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState; 170919fcbaf1SConrad Meyer dstMatchState->window = srcMatchState->window; 171019fcbaf1SConrad Meyer dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 171119fcbaf1SConrad Meyer dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 171219fcbaf1SConrad Meyer } 17130f743729SConrad Meyer 171419fcbaf1SConrad Meyer cctx->dictID = cdict->dictID; 171519fcbaf1SConrad Meyer 171619fcbaf1SConrad Meyer /* copy block state */ 171719fcbaf1SConrad Meyer memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 171819fcbaf1SConrad Meyer 171919fcbaf1SConrad Meyer return 0; 172019fcbaf1SConrad Meyer } 17210c16b537SWarner Losh 17220f743729SConrad Meyer /* We have a choice between copying the dictionary context into the working 17230f743729SConrad Meyer * context, or referencing the dictionary context from the working context 17240f743729SConrad Meyer * in-place. We decide here which strategy to use. */ 17250f743729SConrad Meyer static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx, 17260f743729SConrad Meyer const ZSTD_CDict* cdict, 17270f743729SConrad Meyer ZSTD_CCtx_params params, 17280f743729SConrad Meyer U64 pledgedSrcSize, 17290f743729SConrad Meyer ZSTD_buffered_policy_e zbuff) 17300f743729SConrad Meyer { 17310f743729SConrad Meyer 1732a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)", 1733a0483764SConrad Meyer (unsigned)pledgedSrcSize); 17340f743729SConrad Meyer 17350f743729SConrad Meyer if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) { 17360f743729SConrad Meyer return ZSTD_resetCCtx_byAttachingCDict( 17370f743729SConrad Meyer cctx, cdict, params, pledgedSrcSize, zbuff); 17380f743729SConrad Meyer } else { 17390f743729SConrad Meyer return ZSTD_resetCCtx_byCopyingCDict( 17400f743729SConrad Meyer cctx, cdict, params, pledgedSrcSize, zbuff); 17410f743729SConrad Meyer } 17420f743729SConrad Meyer } 17430f743729SConrad Meyer 17440c16b537SWarner Losh /*! ZSTD_copyCCtx_internal() : 17450c16b537SWarner Losh * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 17460c16b537SWarner Losh * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 1747052d3c12SConrad Meyer * The "context", in this case, refers to the hash and chain tables, 1748052d3c12SConrad Meyer * entropy tables, and dictionary references. 1749052d3c12SConrad Meyer * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx. 17500c16b537SWarner Losh * @return : 0, or an error code */ 17510c16b537SWarner Losh static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, 17520c16b537SWarner Losh const ZSTD_CCtx* srcCCtx, 17530c16b537SWarner Losh ZSTD_frameParameters fParams, 1754052d3c12SConrad Meyer U64 pledgedSrcSize, 17550c16b537SWarner Losh ZSTD_buffered_policy_e zbuff) 17560c16b537SWarner Losh { 17570c16b537SWarner Losh DEBUGLOG(5, "ZSTD_copyCCtx_internal"); 17582b9c00cbSConrad Meyer RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong); 17590c16b537SWarner Losh 17600c16b537SWarner Losh memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); 17610c16b537SWarner Losh { ZSTD_CCtx_params params = dstCCtx->requestedParams; 17620c16b537SWarner Losh /* Copy only compression parameters related to tables. */ 17630c16b537SWarner Losh params.cParams = srcCCtx->appliedParams.cParams; 17640c16b537SWarner Losh params.fParams = fParams; 17650c16b537SWarner Losh ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, 17660c16b537SWarner Losh ZSTDcrp_noMemset, zbuff); 176719fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog); 176819fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy); 176919fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog); 177019fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog); 177119fcbaf1SConrad Meyer assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3); 17720c16b537SWarner Losh } 17730c16b537SWarner Losh 17740c16b537SWarner Losh /* copy tables */ 17750c16b537SWarner Losh { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog); 17760c16b537SWarner Losh size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; 177719fcbaf1SConrad Meyer size_t const h3Size = (size_t)1 << srcCCtx->blockState.matchState.hashLog3; 17780c16b537SWarner Losh size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 177919fcbaf1SConrad Meyer assert((U32*)dstCCtx->blockState.matchState.chainTable == (U32*)dstCCtx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */ 178019fcbaf1SConrad Meyer assert((U32*)dstCCtx->blockState.matchState.hashTable3 == (U32*)dstCCtx->blockState.matchState.chainTable + chainSize); 178119fcbaf1SConrad Meyer memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, tableSpace); /* presumes all tables follow each other */ 17820c16b537SWarner Losh } 17830c16b537SWarner Losh 17840c16b537SWarner Losh /* copy dictionary offsets */ 178519fcbaf1SConrad Meyer { 17860f743729SConrad Meyer const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState; 178719fcbaf1SConrad Meyer ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState; 178819fcbaf1SConrad Meyer dstMatchState->window = srcMatchState->window; 178919fcbaf1SConrad Meyer dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 179019fcbaf1SConrad Meyer dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 179119fcbaf1SConrad Meyer } 17920c16b537SWarner Losh dstCCtx->dictID = srcCCtx->dictID; 17930c16b537SWarner Losh 179419fcbaf1SConrad Meyer /* copy block state */ 179519fcbaf1SConrad Meyer memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); 17960c16b537SWarner Losh 17970c16b537SWarner Losh return 0; 17980c16b537SWarner Losh } 17990c16b537SWarner Losh 18000c16b537SWarner Losh /*! ZSTD_copyCCtx() : 18010c16b537SWarner Losh * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 18020c16b537SWarner Losh * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 18030c16b537SWarner Losh * pledgedSrcSize==0 means "unknown". 18040c16b537SWarner Losh * @return : 0, or an error code */ 18050c16b537SWarner Losh size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) 18060c16b537SWarner Losh { 18070c16b537SWarner Losh ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 18080c16b537SWarner Losh ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0); 18090c16b537SWarner Losh ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); 1810052d3c12SConrad Meyer if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; 1811052d3c12SConrad Meyer fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN); 18120c16b537SWarner Losh 1813052d3c12SConrad Meyer return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, 181419fcbaf1SConrad Meyer fParams, pledgedSrcSize, 1815052d3c12SConrad Meyer zbuff); 18160c16b537SWarner Losh } 18170c16b537SWarner Losh 18180c16b537SWarner Losh 181919fcbaf1SConrad Meyer #define ZSTD_ROWSIZE 16 18200c16b537SWarner Losh /*! ZSTD_reduceTable() : 182119fcbaf1SConrad Meyer * reduce table indexes by `reducerValue`, or squash to zero. 182219fcbaf1SConrad Meyer * PreserveMark preserves "unsorted mark" for btlazy2 strategy. 182319fcbaf1SConrad Meyer * It must be set to a clear 0/1 value, to remove branch during inlining. 182419fcbaf1SConrad Meyer * Presume table size is a multiple of ZSTD_ROWSIZE 182519fcbaf1SConrad Meyer * to help auto-vectorization */ 182619fcbaf1SConrad Meyer FORCE_INLINE_TEMPLATE void 182719fcbaf1SConrad Meyer ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark) 18280c16b537SWarner Losh { 182919fcbaf1SConrad Meyer int const nbRows = (int)size / ZSTD_ROWSIZE; 183019fcbaf1SConrad Meyer int cellNb = 0; 183119fcbaf1SConrad Meyer int rowNb; 183219fcbaf1SConrad Meyer assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */ 183319fcbaf1SConrad Meyer assert(size < (1U<<31)); /* can be casted to int */ 183419fcbaf1SConrad Meyer for (rowNb=0 ; rowNb < nbRows ; rowNb++) { 183519fcbaf1SConrad Meyer int column; 183619fcbaf1SConrad Meyer for (column=0; column<ZSTD_ROWSIZE; column++) { 183719fcbaf1SConrad Meyer if (preserveMark) { 183819fcbaf1SConrad Meyer U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0; 183919fcbaf1SConrad Meyer table[cellNb] += adder; 18400c16b537SWarner Losh } 184119fcbaf1SConrad Meyer if (table[cellNb] < reducerValue) table[cellNb] = 0; 184219fcbaf1SConrad Meyer else table[cellNb] -= reducerValue; 184319fcbaf1SConrad Meyer cellNb++; 184419fcbaf1SConrad Meyer } } 18450c16b537SWarner Losh } 18460c16b537SWarner Losh 184719fcbaf1SConrad Meyer static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue) 18480c16b537SWarner Losh { 184919fcbaf1SConrad Meyer ZSTD_reduceTable_internal(table, size, reducerValue, 0); 18500c16b537SWarner Losh } 185119fcbaf1SConrad Meyer 185219fcbaf1SConrad Meyer static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue) 185319fcbaf1SConrad Meyer { 185419fcbaf1SConrad Meyer ZSTD_reduceTable_internal(table, size, reducerValue, 1); 18550c16b537SWarner Losh } 18560c16b537SWarner Losh 18570c16b537SWarner Losh /*! ZSTD_reduceIndex() : 18580c16b537SWarner Losh * rescale all indexes to avoid future overflow (indexes are U32) */ 1859*4d3f1eafSConrad Meyer static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const U32 reducerValue) 18600c16b537SWarner Losh { 1861*4d3f1eafSConrad Meyer { U32 const hSize = (U32)1 << params->cParams.hashLog; 186219fcbaf1SConrad Meyer ZSTD_reduceTable(ms->hashTable, hSize, reducerValue); 18630c16b537SWarner Losh } 186419fcbaf1SConrad Meyer 1865*4d3f1eafSConrad Meyer if (params->cParams.strategy != ZSTD_fast) { 1866*4d3f1eafSConrad Meyer U32 const chainSize = (U32)1 << params->cParams.chainLog; 1867*4d3f1eafSConrad Meyer if (params->cParams.strategy == ZSTD_btlazy2) 186819fcbaf1SConrad Meyer ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue); 186919fcbaf1SConrad Meyer else 187019fcbaf1SConrad Meyer ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue); 187119fcbaf1SConrad Meyer } 187219fcbaf1SConrad Meyer 187319fcbaf1SConrad Meyer if (ms->hashLog3) { 187419fcbaf1SConrad Meyer U32 const h3Size = (U32)1 << ms->hashLog3; 187519fcbaf1SConrad Meyer ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue); 18760c16b537SWarner Losh } 18770c16b537SWarner Losh } 18780c16b537SWarner Losh 18790c16b537SWarner Losh 18800c16b537SWarner Losh /*-******************************************************* 18810c16b537SWarner Losh * Block entropic compression 18820c16b537SWarner Losh *********************************************************/ 18830c16b537SWarner Losh 18840c16b537SWarner Losh /* See doc/zstd_compression_format.md for detailed format description */ 18850c16b537SWarner Losh 18860f743729SConrad Meyer static size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) 18870c16b537SWarner Losh { 18880f743729SConrad Meyer U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3); 18892b9c00cbSConrad Meyer RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity, 18902b9c00cbSConrad Meyer dstSize_tooSmall); 18910f743729SConrad Meyer MEM_writeLE24(dst, cBlockHeader24); 18920c16b537SWarner Losh memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize); 18930c16b537SWarner Losh return ZSTD_blockHeaderSize + srcSize; 18940c16b537SWarner Losh } 18950c16b537SWarner Losh 18960c16b537SWarner Losh void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) 18970c16b537SWarner Losh { 18980c16b537SWarner Losh const seqDef* const sequences = seqStorePtr->sequencesStart; 18990c16b537SWarner Losh BYTE* const llCodeTable = seqStorePtr->llCode; 19000c16b537SWarner Losh BYTE* const ofCodeTable = seqStorePtr->ofCode; 19010c16b537SWarner Losh BYTE* const mlCodeTable = seqStorePtr->mlCode; 19020c16b537SWarner Losh U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 19030c16b537SWarner Losh U32 u; 19040f743729SConrad Meyer assert(nbSeq <= seqStorePtr->maxNbSeq); 19050c16b537SWarner Losh for (u=0; u<nbSeq; u++) { 19060c16b537SWarner Losh U32 const llv = sequences[u].litLength; 19070c16b537SWarner Losh U32 const mlv = sequences[u].matchLength; 1908052d3c12SConrad Meyer llCodeTable[u] = (BYTE)ZSTD_LLcode(llv); 19090c16b537SWarner Losh ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset); 1910052d3c12SConrad Meyer mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv); 19110c16b537SWarner Losh } 19120c16b537SWarner Losh if (seqStorePtr->longLengthID==1) 19130c16b537SWarner Losh llCodeTable[seqStorePtr->longLengthPos] = MaxLL; 19140c16b537SWarner Losh if (seqStorePtr->longLengthID==2) 19150c16b537SWarner Losh mlCodeTable[seqStorePtr->longLengthPos] = MaxML; 19160c16b537SWarner Losh } 19170c16b537SWarner Losh 19182b9c00cbSConrad Meyer static int ZSTD_disableLiteralsCompression(const ZSTD_CCtx_params* cctxParams) 19192b9c00cbSConrad Meyer { 19202b9c00cbSConrad Meyer switch (cctxParams->literalCompressionMode) { 19212b9c00cbSConrad Meyer case ZSTD_lcm_huffman: 19222b9c00cbSConrad Meyer return 0; 19232b9c00cbSConrad Meyer case ZSTD_lcm_uncompressed: 19242b9c00cbSConrad Meyer return 1; 19252b9c00cbSConrad Meyer default: 19262b9c00cbSConrad Meyer assert(0 /* impossible: pre-validated */); 19272b9c00cbSConrad Meyer /* fall-through */ 19282b9c00cbSConrad Meyer case ZSTD_lcm_auto: 19292b9c00cbSConrad Meyer return (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0); 19302b9c00cbSConrad Meyer } 19312b9c00cbSConrad Meyer } 19322b9c00cbSConrad Meyer 1933a0483764SConrad Meyer /* ZSTD_compressSequences_internal(): 1934a0483764SConrad Meyer * actually compresses both literals and sequences */ 1935a0483764SConrad Meyer MEM_STATIC size_t 1936a0483764SConrad Meyer ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, 1937a0483764SConrad Meyer const ZSTD_entropyCTables_t* prevEntropy, 193819fcbaf1SConrad Meyer ZSTD_entropyCTables_t* nextEntropy, 1939a0483764SConrad Meyer const ZSTD_CCtx_params* cctxParams, 1940a0483764SConrad Meyer void* dst, size_t dstCapacity, 1941a0483764SConrad Meyer void* workspace, size_t wkspSize, 194219fcbaf1SConrad Meyer const int bmi2) 194319fcbaf1SConrad Meyer { 194419fcbaf1SConrad Meyer const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; 19450f743729SConrad Meyer ZSTD_strategy const strategy = cctxParams->cParams.strategy; 1946a0483764SConrad Meyer unsigned count[MaxSeq+1]; 19470f743729SConrad Meyer FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable; 19480f743729SConrad Meyer FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable; 19490f743729SConrad Meyer FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable; 19500c16b537SWarner Losh U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ 19510c16b537SWarner Losh const seqDef* const sequences = seqStorePtr->sequencesStart; 19520c16b537SWarner Losh const BYTE* const ofCodeTable = seqStorePtr->ofCode; 19530c16b537SWarner Losh const BYTE* const llCodeTable = seqStorePtr->llCode; 19540c16b537SWarner Losh const BYTE* const mlCodeTable = seqStorePtr->mlCode; 19550c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 19560c16b537SWarner Losh BYTE* const oend = ostart + dstCapacity; 19570c16b537SWarner Losh BYTE* op = ostart; 19580c16b537SWarner Losh size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart; 19590c16b537SWarner Losh BYTE* seqHead; 19600f743729SConrad Meyer BYTE* lastNCount = NULL; 19610c16b537SWarner Losh 1962*4d3f1eafSConrad Meyer DEBUGLOG(5, "ZSTD_compressSequences_internal (nbSeq=%zu)", nbSeq); 196319fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 19640c16b537SWarner Losh 19650c16b537SWarner Losh /* Compress literals */ 19660c16b537SWarner Losh { const BYTE* const literals = seqStorePtr->litStart; 19670c16b537SWarner Losh size_t const litSize = seqStorePtr->lit - literals; 19680c16b537SWarner Losh size_t const cSize = ZSTD_compressLiterals( 19690f743729SConrad Meyer &prevEntropy->huf, &nextEntropy->huf, 19702b9c00cbSConrad Meyer cctxParams->cParams.strategy, 19712b9c00cbSConrad Meyer ZSTD_disableLiteralsCompression(cctxParams), 197219fcbaf1SConrad Meyer op, dstCapacity, 197319fcbaf1SConrad Meyer literals, litSize, 1974a0483764SConrad Meyer workspace, wkspSize, 1975a0483764SConrad Meyer bmi2); 19762b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 1977052d3c12SConrad Meyer assert(cSize <= dstCapacity); 19780c16b537SWarner Losh op += cSize; 19790c16b537SWarner Losh } 19800c16b537SWarner Losh 19810c16b537SWarner Losh /* Sequences Header */ 19822b9c00cbSConrad Meyer RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, 19832b9c00cbSConrad Meyer dstSize_tooSmall); 1984052d3c12SConrad Meyer if (nbSeq < 0x7F) 1985052d3c12SConrad Meyer *op++ = (BYTE)nbSeq; 1986052d3c12SConrad Meyer else if (nbSeq < LONGNBSEQ) 1987052d3c12SConrad Meyer op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; 1988052d3c12SConrad Meyer else 1989052d3c12SConrad Meyer op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; 1990*4d3f1eafSConrad Meyer assert(op <= oend); 199119fcbaf1SConrad Meyer if (nbSeq==0) { 19920f743729SConrad Meyer /* Copy the old tables over as if we repeated them */ 19930f743729SConrad Meyer memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); 199419fcbaf1SConrad Meyer return op - ostart; 199519fcbaf1SConrad Meyer } 19960c16b537SWarner Losh 19970c16b537SWarner Losh /* seqHead : flags for FSE encoding type */ 19980c16b537SWarner Losh seqHead = op++; 1999*4d3f1eafSConrad Meyer assert(op <= oend); 20000c16b537SWarner Losh 20010c16b537SWarner Losh /* convert length/distances into codes */ 20020c16b537SWarner Losh ZSTD_seqToCodes(seqStorePtr); 2003052d3c12SConrad Meyer /* build CTable for Literal Lengths */ 2004a0483764SConrad Meyer { unsigned max = MaxLL; 2005a0483764SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ 2006052d3c12SConrad Meyer DEBUGLOG(5, "Building LL table"); 20070f743729SConrad Meyer nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode; 2008a0483764SConrad Meyer LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode, 2009a0483764SConrad Meyer count, max, mostFrequent, nbSeq, 2010a0483764SConrad Meyer LLFSELog, prevEntropy->fse.litlengthCTable, 2011a0483764SConrad Meyer LL_defaultNorm, LL_defaultNormLog, 2012a0483764SConrad Meyer ZSTD_defaultAllowed, strategy); 20130f743729SConrad Meyer assert(set_basic < set_compressed && set_rle < set_compressed); 20140f743729SConrad Meyer assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 20150c16b537SWarner Losh { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, 20160c16b537SWarner Losh count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL, 20170f743729SConrad Meyer prevEntropy->fse.litlengthCTable, sizeof(prevEntropy->fse.litlengthCTable), 2018a0483764SConrad Meyer workspace, wkspSize); 20192b9c00cbSConrad Meyer FORWARD_IF_ERROR(countSize); 20200f743729SConrad Meyer if (LLtype == set_compressed) 20210f743729SConrad Meyer lastNCount = op; 20220c16b537SWarner Losh op += countSize; 2023*4d3f1eafSConrad Meyer assert(op <= oend); 20240c16b537SWarner Losh } } 2025052d3c12SConrad Meyer /* build CTable for Offsets */ 2026a0483764SConrad Meyer { unsigned max = MaxOff; 2027a0483764SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ 20280c16b537SWarner Losh /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ 2029052d3c12SConrad Meyer ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; 2030052d3c12SConrad Meyer DEBUGLOG(5, "Building OF table"); 20310f743729SConrad Meyer nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode; 2032a0483764SConrad Meyer Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode, 2033a0483764SConrad Meyer count, max, mostFrequent, nbSeq, 2034a0483764SConrad Meyer OffFSELog, prevEntropy->fse.offcodeCTable, 2035a0483764SConrad Meyer OF_defaultNorm, OF_defaultNormLog, 2036a0483764SConrad Meyer defaultPolicy, strategy); 20370f743729SConrad Meyer assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 20380c16b537SWarner Losh { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, 20390c16b537SWarner Losh count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, 20400f743729SConrad Meyer prevEntropy->fse.offcodeCTable, sizeof(prevEntropy->fse.offcodeCTable), 2041a0483764SConrad Meyer workspace, wkspSize); 20422b9c00cbSConrad Meyer FORWARD_IF_ERROR(countSize); 20430f743729SConrad Meyer if (Offtype == set_compressed) 20440f743729SConrad Meyer lastNCount = op; 20450c16b537SWarner Losh op += countSize; 2046*4d3f1eafSConrad Meyer assert(op <= oend); 20470c16b537SWarner Losh } } 2048052d3c12SConrad Meyer /* build CTable for MatchLengths */ 2049a0483764SConrad Meyer { unsigned max = MaxML; 2050a0483764SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ 2051a0483764SConrad Meyer DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); 20520f743729SConrad Meyer nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode; 2053a0483764SConrad Meyer MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode, 2054a0483764SConrad Meyer count, max, mostFrequent, nbSeq, 2055a0483764SConrad Meyer MLFSELog, prevEntropy->fse.matchlengthCTable, 2056a0483764SConrad Meyer ML_defaultNorm, ML_defaultNormLog, 2057a0483764SConrad Meyer ZSTD_defaultAllowed, strategy); 20580f743729SConrad Meyer assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 20590c16b537SWarner Losh { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, 20600c16b537SWarner Losh count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML, 20610f743729SConrad Meyer prevEntropy->fse.matchlengthCTable, sizeof(prevEntropy->fse.matchlengthCTable), 2062a0483764SConrad Meyer workspace, wkspSize); 20632b9c00cbSConrad Meyer FORWARD_IF_ERROR(countSize); 20640f743729SConrad Meyer if (MLtype == set_compressed) 20650f743729SConrad Meyer lastNCount = op; 20660c16b537SWarner Losh op += countSize; 2067*4d3f1eafSConrad Meyer assert(op <= oend); 20680c16b537SWarner Losh } } 20690c16b537SWarner Losh 20700c16b537SWarner Losh *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); 20710c16b537SWarner Losh 2072052d3c12SConrad Meyer { size_t const bitstreamSize = ZSTD_encodeSequences( 2073052d3c12SConrad Meyer op, oend - op, 20740c16b537SWarner Losh CTable_MatchLength, mlCodeTable, 20750c16b537SWarner Losh CTable_OffsetBits, ofCodeTable, 20760c16b537SWarner Losh CTable_LitLength, llCodeTable, 2077052d3c12SConrad Meyer sequences, nbSeq, 207819fcbaf1SConrad Meyer longOffsets, bmi2); 20792b9c00cbSConrad Meyer FORWARD_IF_ERROR(bitstreamSize); 2080052d3c12SConrad Meyer op += bitstreamSize; 2081*4d3f1eafSConrad Meyer assert(op <= oend); 20820f743729SConrad Meyer /* zstd versions <= 1.3.4 mistakenly report corruption when 20832b9c00cbSConrad Meyer * FSE_readNCount() receives a buffer < 4 bytes. 20840f743729SConrad Meyer * Fixed by https://github.com/facebook/zstd/pull/1146. 20850f743729SConrad Meyer * This can happen when the last set_compressed table present is 2 20860f743729SConrad Meyer * bytes and the bitstream is only one byte. 20870f743729SConrad Meyer * In this exceedingly rare case, we will simply emit an uncompressed 20880f743729SConrad Meyer * block, since it isn't worth optimizing. 20890f743729SConrad Meyer */ 20900f743729SConrad Meyer if (lastNCount && (op - lastNCount) < 4) { 20910f743729SConrad Meyer /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ 20920f743729SConrad Meyer assert(op - lastNCount == 3); 20930f743729SConrad Meyer DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " 20940f743729SConrad Meyer "emitting an uncompressed block."); 20950f743729SConrad Meyer return 0; 20960f743729SConrad Meyer } 20970c16b537SWarner Losh } 20980c16b537SWarner Losh 2099a0483764SConrad Meyer DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart)); 21000c16b537SWarner Losh return op - ostart; 21010c16b537SWarner Losh } 21020c16b537SWarner Losh 2103a0483764SConrad Meyer MEM_STATIC size_t 2104a0483764SConrad Meyer ZSTD_compressSequences(seqStore_t* seqStorePtr, 21050f743729SConrad Meyer const ZSTD_entropyCTables_t* prevEntropy, 210619fcbaf1SConrad Meyer ZSTD_entropyCTables_t* nextEntropy, 21070f743729SConrad Meyer const ZSTD_CCtx_params* cctxParams, 21080c16b537SWarner Losh void* dst, size_t dstCapacity, 2109a0483764SConrad Meyer size_t srcSize, 2110a0483764SConrad Meyer void* workspace, size_t wkspSize, 2111a0483764SConrad Meyer int bmi2) 21120c16b537SWarner Losh { 211319fcbaf1SConrad Meyer size_t const cSize = ZSTD_compressSequences_internal( 2114a0483764SConrad Meyer seqStorePtr, prevEntropy, nextEntropy, cctxParams, 2115a0483764SConrad Meyer dst, dstCapacity, 2116a0483764SConrad Meyer workspace, wkspSize, bmi2); 21170f743729SConrad Meyer if (cSize == 0) return 0; 211819fcbaf1SConrad Meyer /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block. 211919fcbaf1SConrad Meyer * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block. 21200c16b537SWarner Losh */ 212119fcbaf1SConrad Meyer if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) 212219fcbaf1SConrad Meyer return 0; /* block not compressed */ 21232b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 212419fcbaf1SConrad Meyer 212519fcbaf1SConrad Meyer /* Check compressibility */ 21260f743729SConrad Meyer { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy); 212719fcbaf1SConrad Meyer if (cSize >= maxCSize) return 0; /* block not compressed */ 212819fcbaf1SConrad Meyer } 212919fcbaf1SConrad Meyer 21300c16b537SWarner Losh return cSize; 21310c16b537SWarner Losh } 21320c16b537SWarner Losh 21330c16b537SWarner Losh /* ZSTD_selectBlockCompressor() : 21340c16b537SWarner Losh * Not static, but internal use only (used by long distance matcher) 21350c16b537SWarner Losh * assumption : strat is a valid strategy */ 21360f743729SConrad Meyer ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode) 21370c16b537SWarner Losh { 2138a0483764SConrad Meyer static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = { 21390c16b537SWarner Losh { ZSTD_compressBlock_fast /* default for 0 */, 21400f743729SConrad Meyer ZSTD_compressBlock_fast, 21410f743729SConrad Meyer ZSTD_compressBlock_doubleFast, 21420f743729SConrad Meyer ZSTD_compressBlock_greedy, 21430f743729SConrad Meyer ZSTD_compressBlock_lazy, 21440f743729SConrad Meyer ZSTD_compressBlock_lazy2, 21450f743729SConrad Meyer ZSTD_compressBlock_btlazy2, 21460f743729SConrad Meyer ZSTD_compressBlock_btopt, 2147a0483764SConrad Meyer ZSTD_compressBlock_btultra, 2148a0483764SConrad Meyer ZSTD_compressBlock_btultra2 }, 21490c16b537SWarner Losh { ZSTD_compressBlock_fast_extDict /* default for 0 */, 21500f743729SConrad Meyer ZSTD_compressBlock_fast_extDict, 21510f743729SConrad Meyer ZSTD_compressBlock_doubleFast_extDict, 21520f743729SConrad Meyer ZSTD_compressBlock_greedy_extDict, 21530f743729SConrad Meyer ZSTD_compressBlock_lazy_extDict, 21540f743729SConrad Meyer ZSTD_compressBlock_lazy2_extDict, 21550f743729SConrad Meyer ZSTD_compressBlock_btlazy2_extDict, 21560f743729SConrad Meyer ZSTD_compressBlock_btopt_extDict, 2157a0483764SConrad Meyer ZSTD_compressBlock_btultra_extDict, 21580f743729SConrad Meyer ZSTD_compressBlock_btultra_extDict }, 21590f743729SConrad Meyer { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */, 21600f743729SConrad Meyer ZSTD_compressBlock_fast_dictMatchState, 21610f743729SConrad Meyer ZSTD_compressBlock_doubleFast_dictMatchState, 21620f743729SConrad Meyer ZSTD_compressBlock_greedy_dictMatchState, 21630f743729SConrad Meyer ZSTD_compressBlock_lazy_dictMatchState, 21640f743729SConrad Meyer ZSTD_compressBlock_lazy2_dictMatchState, 21650f743729SConrad Meyer ZSTD_compressBlock_btlazy2_dictMatchState, 21660f743729SConrad Meyer ZSTD_compressBlock_btopt_dictMatchState, 2167a0483764SConrad Meyer ZSTD_compressBlock_btultra_dictMatchState, 21680f743729SConrad Meyer ZSTD_compressBlock_btultra_dictMatchState } 21690c16b537SWarner Losh }; 21700f743729SConrad Meyer ZSTD_blockCompressor selectedCompressor; 21710c16b537SWarner Losh ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); 2172052d3c12SConrad Meyer 2173a0483764SConrad Meyer assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); 2174a0483764SConrad Meyer selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; 21750f743729SConrad Meyer assert(selectedCompressor != NULL); 21760f743729SConrad Meyer return selectedCompressor; 21770c16b537SWarner Losh } 21780c16b537SWarner Losh 21790c16b537SWarner Losh static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, 21800c16b537SWarner Losh const BYTE* anchor, size_t lastLLSize) 21810c16b537SWarner Losh { 21820c16b537SWarner Losh memcpy(seqStorePtr->lit, anchor, lastLLSize); 21830c16b537SWarner Losh seqStorePtr->lit += lastLLSize; 21840c16b537SWarner Losh } 21850c16b537SWarner Losh 21860f743729SConrad Meyer void ZSTD_resetSeqStore(seqStore_t* ssPtr) 2187052d3c12SConrad Meyer { 2188052d3c12SConrad Meyer ssPtr->lit = ssPtr->litStart; 2189052d3c12SConrad Meyer ssPtr->sequences = ssPtr->sequencesStart; 2190052d3c12SConrad Meyer ssPtr->longLengthID = 0; 2191052d3c12SConrad Meyer } 2192052d3c12SConrad Meyer 2193*4d3f1eafSConrad Meyer typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e; 2194*4d3f1eafSConrad Meyer 2195*4d3f1eafSConrad Meyer static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize) 21960c16b537SWarner Losh { 219719fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &zc->blockState.matchState; 2198*4d3f1eafSConrad Meyer DEBUGLOG(5, "ZSTD_buildSeqStore (srcSize=%zu)", srcSize); 21990f743729SConrad Meyer assert(srcSize <= ZSTD_BLOCKSIZE_MAX); 22000f743729SConrad Meyer /* Assert that we have correctly flushed the ctx params into the ms's copy */ 22010f743729SConrad Meyer ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); 220219fcbaf1SConrad Meyer if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) { 2203a0483764SConrad Meyer ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); 2204*4d3f1eafSConrad Meyer return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */ 220519fcbaf1SConrad Meyer } 2206052d3c12SConrad Meyer ZSTD_resetSeqStore(&(zc->seqStore)); 22072b9c00cbSConrad Meyer /* required for optimal parser to read stats from dictionary */ 22082b9c00cbSConrad Meyer ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy; 22092b9c00cbSConrad Meyer /* tell the optimal parser how we expect to compress literals */ 22102b9c00cbSConrad Meyer ms->opt.literalCompressionMode = zc->appliedParams.literalCompressionMode; 22110f743729SConrad Meyer /* a gap between an attached dict and the current window is not safe, 2212a0483764SConrad Meyer * they must remain adjacent, 2213a0483764SConrad Meyer * and when that stops being the case, the dict must be unset */ 22140f743729SConrad Meyer assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit); 2215052d3c12SConrad Meyer 2216052d3c12SConrad Meyer /* limited update after a very long match */ 221719fcbaf1SConrad Meyer { const BYTE* const base = ms->window.base; 22180c16b537SWarner Losh const BYTE* const istart = (const BYTE*)src; 22190c16b537SWarner Losh const U32 current = (U32)(istart-base); 22200f743729SConrad Meyer if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */ 222119fcbaf1SConrad Meyer if (current > ms->nextToUpdate + 384) 222219fcbaf1SConrad Meyer ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384)); 2223052d3c12SConrad Meyer } 222419fcbaf1SConrad Meyer 222519fcbaf1SConrad Meyer /* select and store sequences */ 22260f743729SConrad Meyer { ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms); 222719fcbaf1SConrad Meyer size_t lastLLSize; 222819fcbaf1SConrad Meyer { int i; 222919fcbaf1SConrad Meyer for (i = 0; i < ZSTD_REP_NUM; ++i) 223019fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i]; 2231052d3c12SConrad Meyer } 223219fcbaf1SConrad Meyer if (zc->externSeqStore.pos < zc->externSeqStore.size) { 223319fcbaf1SConrad Meyer assert(!zc->appliedParams.ldmParams.enableLdm); 223419fcbaf1SConrad Meyer /* Updates ldmSeqStore.pos */ 223519fcbaf1SConrad Meyer lastLLSize = 223619fcbaf1SConrad Meyer ZSTD_ldm_blockCompress(&zc->externSeqStore, 223719fcbaf1SConrad Meyer ms, &zc->seqStore, 223819fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep, 22390f743729SConrad Meyer src, srcSize); 224019fcbaf1SConrad Meyer assert(zc->externSeqStore.pos <= zc->externSeqStore.size); 224119fcbaf1SConrad Meyer } else if (zc->appliedParams.ldmParams.enableLdm) { 224219fcbaf1SConrad Meyer rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0}; 224319fcbaf1SConrad Meyer 224419fcbaf1SConrad Meyer ldmSeqStore.seq = zc->ldmSequences; 224519fcbaf1SConrad Meyer ldmSeqStore.capacity = zc->maxNbLdmSequences; 224619fcbaf1SConrad Meyer /* Updates ldmSeqStore.size */ 22472b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore, 224819fcbaf1SConrad Meyer &zc->appliedParams.ldmParams, 224919fcbaf1SConrad Meyer src, srcSize)); 225019fcbaf1SConrad Meyer /* Updates ldmSeqStore.pos */ 225119fcbaf1SConrad Meyer lastLLSize = 225219fcbaf1SConrad Meyer ZSTD_ldm_blockCompress(&ldmSeqStore, 225319fcbaf1SConrad Meyer ms, &zc->seqStore, 225419fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep, 22550f743729SConrad Meyer src, srcSize); 225619fcbaf1SConrad Meyer assert(ldmSeqStore.pos == ldmSeqStore.size); 225719fcbaf1SConrad Meyer } else { /* not long range mode */ 22580f743729SConrad Meyer ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode); 22590f743729SConrad Meyer lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); 226019fcbaf1SConrad Meyer } 226119fcbaf1SConrad Meyer { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; 226219fcbaf1SConrad Meyer ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize); 226319fcbaf1SConrad Meyer } } 2264*4d3f1eafSConrad Meyer return ZSTDbss_compress; 2265*4d3f1eafSConrad Meyer } 2266*4d3f1eafSConrad Meyer 2267*4d3f1eafSConrad Meyer static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, 2268*4d3f1eafSConrad Meyer void* dst, size_t dstCapacity, 2269*4d3f1eafSConrad Meyer const void* src, size_t srcSize) 2270*4d3f1eafSConrad Meyer { 2271*4d3f1eafSConrad Meyer size_t cSize; 2272*4d3f1eafSConrad Meyer DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", 2273*4d3f1eafSConrad Meyer (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, (unsigned)zc->blockState.matchState.nextToUpdate); 2274*4d3f1eafSConrad Meyer 2275*4d3f1eafSConrad Meyer { const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize); 2276*4d3f1eafSConrad Meyer FORWARD_IF_ERROR(bss); 2277*4d3f1eafSConrad Meyer if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; } 2278*4d3f1eafSConrad Meyer } 227919fcbaf1SConrad Meyer 228019fcbaf1SConrad Meyer /* encode sequences and literals */ 22810f743729SConrad Meyer cSize = ZSTD_compressSequences(&zc->seqStore, 228219fcbaf1SConrad Meyer &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, 228319fcbaf1SConrad Meyer &zc->appliedParams, 228419fcbaf1SConrad Meyer dst, dstCapacity, 2285a0483764SConrad Meyer srcSize, 2286a0483764SConrad Meyer zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */, 2287a0483764SConrad Meyer zc->bmi2); 22880f743729SConrad Meyer 22890f743729SConrad Meyer out: 22900f743729SConrad Meyer if (!ZSTD_isError(cSize) && cSize != 0) { 22910f743729SConrad Meyer /* confirm repcodes and entropy tables when emitting a compressed block */ 22920f743729SConrad Meyer ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock; 229319fcbaf1SConrad Meyer zc->blockState.prevCBlock = zc->blockState.nextCBlock; 229419fcbaf1SConrad Meyer zc->blockState.nextCBlock = tmp; 229519fcbaf1SConrad Meyer } 22960f743729SConrad Meyer /* We check that dictionaries have offset codes available for the first 22970f743729SConrad Meyer * block. After the first block, the offcode table might not have large 22980f743729SConrad Meyer * enough codes to represent the offsets in the data. 22990f743729SConrad Meyer */ 23000f743729SConrad Meyer if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) 23010f743729SConrad Meyer zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; 23020f743729SConrad Meyer 230319fcbaf1SConrad Meyer return cSize; 230419fcbaf1SConrad Meyer } 23050c16b537SWarner Losh 23060c16b537SWarner Losh 2307*4d3f1eafSConrad Meyer static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, void const* ip, void const* iend) 2308*4d3f1eafSConrad Meyer { 2309*4d3f1eafSConrad Meyer if (ZSTD_window_needOverflowCorrection(ms->window, iend)) { 2310*4d3f1eafSConrad Meyer U32 const maxDist = (U32)1 << params->cParams.windowLog; 2311*4d3f1eafSConrad Meyer U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy); 2312*4d3f1eafSConrad Meyer U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); 2313*4d3f1eafSConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); 2314*4d3f1eafSConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); 2315*4d3f1eafSConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); 2316*4d3f1eafSConrad Meyer ZSTD_reduceIndex(ms, params, correction); 2317*4d3f1eafSConrad Meyer if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; 2318*4d3f1eafSConrad Meyer else ms->nextToUpdate -= correction; 2319*4d3f1eafSConrad Meyer /* invalidate dictionaries on overflow correction */ 2320*4d3f1eafSConrad Meyer ms->loadedDictEnd = 0; 2321*4d3f1eafSConrad Meyer ms->dictMatchState = NULL; 2322*4d3f1eafSConrad Meyer } 2323*4d3f1eafSConrad Meyer } 2324*4d3f1eafSConrad Meyer 2325*4d3f1eafSConrad Meyer 23260c16b537SWarner Losh /*! ZSTD_compress_frameChunk() : 23270c16b537SWarner Losh * Compress a chunk of data into one or multiple blocks. 23280c16b537SWarner Losh * All blocks will be terminated, all input will be consumed. 23290c16b537SWarner Losh * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content. 23300c16b537SWarner Losh * Frame is supposed already started (header already produced) 23310c16b537SWarner Losh * @return : compressed size, or an error code 23320c16b537SWarner Losh */ 23330c16b537SWarner Losh static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, 23340c16b537SWarner Losh void* dst, size_t dstCapacity, 23350c16b537SWarner Losh const void* src, size_t srcSize, 23360c16b537SWarner Losh U32 lastFrameChunk) 23370c16b537SWarner Losh { 23380c16b537SWarner Losh size_t blockSize = cctx->blockSize; 23390c16b537SWarner Losh size_t remaining = srcSize; 23400c16b537SWarner Losh const BYTE* ip = (const BYTE*)src; 23410c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 23420c16b537SWarner Losh BYTE* op = ostart; 23430c16b537SWarner Losh U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; 2344*4d3f1eafSConrad Meyer assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX); 23450c16b537SWarner Losh 2346a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); 23470c16b537SWarner Losh if (cctx->appliedParams.fParams.checksumFlag && srcSize) 23480c16b537SWarner Losh XXH64_update(&cctx->xxhState, src, srcSize); 23490c16b537SWarner Losh 23500c16b537SWarner Losh while (remaining) { 235119fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 23520c16b537SWarner Losh U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); 23530c16b537SWarner Losh 23542b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE, 23552b9c00cbSConrad Meyer dstSize_tooSmall, 23562b9c00cbSConrad Meyer "not enough space to store compressed block"); 23570c16b537SWarner Losh if (remaining < blockSize) blockSize = remaining; 23580c16b537SWarner Losh 2359*4d3f1eafSConrad Meyer ZSTD_overflowCorrectIfNeeded(ms, &cctx->appliedParams, ip, ip + blockSize); 2360*4d3f1eafSConrad Meyer ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); 2361*4d3f1eafSConrad Meyer 2362*4d3f1eafSConrad Meyer /* Ensure hash/chain table insertion resumes no sooner than lowlimit */ 236319fcbaf1SConrad Meyer if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; 23640c16b537SWarner Losh 2365052d3c12SConrad Meyer { size_t cSize = ZSTD_compressBlock_internal(cctx, 2366052d3c12SConrad Meyer op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, 2367052d3c12SConrad Meyer ip, blockSize); 23682b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 23690c16b537SWarner Losh 23700c16b537SWarner Losh if (cSize == 0) { /* block is not compressible */ 23710f743729SConrad Meyer cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); 23722b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 23730c16b537SWarner Losh } else { 23740c16b537SWarner Losh U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); 23750c16b537SWarner Losh MEM_writeLE24(op, cBlockHeader24); 23760c16b537SWarner Losh cSize += ZSTD_blockHeaderSize; 23770c16b537SWarner Losh } 23780c16b537SWarner Losh 23790c16b537SWarner Losh ip += blockSize; 2380052d3c12SConrad Meyer assert(remaining >= blockSize); 2381052d3c12SConrad Meyer remaining -= blockSize; 23820c16b537SWarner Losh op += cSize; 2383052d3c12SConrad Meyer assert(dstCapacity >= cSize); 2384052d3c12SConrad Meyer dstCapacity -= cSize; 2385052d3c12SConrad Meyer DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u", 2386a0483764SConrad Meyer (unsigned)cSize); 2387052d3c12SConrad Meyer } } 23880c16b537SWarner Losh 23890c16b537SWarner Losh if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending; 2390*4d3f1eafSConrad Meyer return (size_t)(op-ostart); 23910c16b537SWarner Losh } 23920c16b537SWarner Losh 23930c16b537SWarner Losh 23940c16b537SWarner Losh static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, 23950c16b537SWarner Losh ZSTD_CCtx_params params, U64 pledgedSrcSize, U32 dictID) 23960c16b537SWarner Losh { BYTE* const op = (BYTE*)dst; 23970c16b537SWarner Losh U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */ 23980c16b537SWarner Losh U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */ 23990c16b537SWarner Losh U32 const checksumFlag = params.fParams.checksumFlag>0; 24000c16b537SWarner Losh U32 const windowSize = (U32)1 << params.cParams.windowLog; 24010c16b537SWarner Losh U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize); 24020c16b537SWarner Losh BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3); 24030c16b537SWarner Losh U32 const fcsCode = params.fParams.contentSizeFlag ? 24040c16b537SWarner Losh (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */ 24052b9c00cbSConrad Meyer BYTE const frameHeaderDescriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) ); 24060c16b537SWarner Losh size_t pos=0; 24070c16b537SWarner Losh 24080f743729SConrad Meyer assert(!(params.fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)); 24092b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall); 24100c16b537SWarner Losh DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", 2411a0483764SConrad Meyer !params.fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode); 24120c16b537SWarner Losh 24130c16b537SWarner Losh if (params.format == ZSTD_f_zstd1) { 24140c16b537SWarner Losh MEM_writeLE32(dst, ZSTD_MAGICNUMBER); 24150c16b537SWarner Losh pos = 4; 24160c16b537SWarner Losh } 24172b9c00cbSConrad Meyer op[pos++] = frameHeaderDescriptionByte; 24180c16b537SWarner Losh if (!singleSegment) op[pos++] = windowLogByte; 24190c16b537SWarner Losh switch(dictIDSizeCode) 24200c16b537SWarner Losh { 24210c16b537SWarner Losh default: assert(0); /* impossible */ 24220c16b537SWarner Losh case 0 : break; 24230c16b537SWarner Losh case 1 : op[pos] = (BYTE)(dictID); pos++; break; 24240c16b537SWarner Losh case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; 24250c16b537SWarner Losh case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break; 24260c16b537SWarner Losh } 24270c16b537SWarner Losh switch(fcsCode) 24280c16b537SWarner Losh { 24290c16b537SWarner Losh default: assert(0); /* impossible */ 24300c16b537SWarner Losh case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; 24310c16b537SWarner Losh case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; 24320c16b537SWarner Losh case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; 24330c16b537SWarner Losh case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break; 24340c16b537SWarner Losh } 24350c16b537SWarner Losh return pos; 24360c16b537SWarner Losh } 24370c16b537SWarner Losh 243819fcbaf1SConrad Meyer /* ZSTD_writeLastEmptyBlock() : 243919fcbaf1SConrad Meyer * output an empty Block with end-of-frame mark to complete a frame 244019fcbaf1SConrad Meyer * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h)) 24412b9c00cbSConrad Meyer * or an error code if `dstCapacity` is too small (<ZSTD_blockHeaderSize) 244219fcbaf1SConrad Meyer */ 244319fcbaf1SConrad Meyer size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) 244419fcbaf1SConrad Meyer { 24452b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall); 244619fcbaf1SConrad Meyer { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */ 244719fcbaf1SConrad Meyer MEM_writeLE24(dst, cBlockHeader24); 244819fcbaf1SConrad Meyer return ZSTD_blockHeaderSize; 244919fcbaf1SConrad Meyer } 245019fcbaf1SConrad Meyer } 245119fcbaf1SConrad Meyer 245219fcbaf1SConrad Meyer size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) 245319fcbaf1SConrad Meyer { 24542b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong); 24552b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm, 24562b9c00cbSConrad Meyer parameter_unsupported); 245719fcbaf1SConrad Meyer cctx->externSeqStore.seq = seq; 245819fcbaf1SConrad Meyer cctx->externSeqStore.size = nbSeq; 245919fcbaf1SConrad Meyer cctx->externSeqStore.capacity = nbSeq; 246019fcbaf1SConrad Meyer cctx->externSeqStore.pos = 0; 246119fcbaf1SConrad Meyer return 0; 246219fcbaf1SConrad Meyer } 246319fcbaf1SConrad Meyer 24640c16b537SWarner Losh 24650c16b537SWarner Losh static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, 24660c16b537SWarner Losh void* dst, size_t dstCapacity, 24670c16b537SWarner Losh const void* src, size_t srcSize, 24680c16b537SWarner Losh U32 frame, U32 lastFrameChunk) 24690c16b537SWarner Losh { 24700f743729SConrad Meyer ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 24710c16b537SWarner Losh size_t fhSize = 0; 24720c16b537SWarner Losh 247319fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u", 2474a0483764SConrad Meyer cctx->stage, (unsigned)srcSize); 24752b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->stage==ZSTDcs_created, stage_wrong, 24762b9c00cbSConrad Meyer "missing init (ZSTD_compressBegin)"); 24770c16b537SWarner Losh 24780c16b537SWarner Losh if (frame && (cctx->stage==ZSTDcs_init)) { 24790c16b537SWarner Losh fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 24800c16b537SWarner Losh cctx->pledgedSrcSizePlusOne-1, cctx->dictID); 24812b9c00cbSConrad Meyer FORWARD_IF_ERROR(fhSize); 2482*4d3f1eafSConrad Meyer assert(fhSize <= dstCapacity); 24830c16b537SWarner Losh dstCapacity -= fhSize; 24840c16b537SWarner Losh dst = (char*)dst + fhSize; 24850c16b537SWarner Losh cctx->stage = ZSTDcs_ongoing; 24860c16b537SWarner Losh } 24870c16b537SWarner Losh 2488052d3c12SConrad Meyer if (!srcSize) return fhSize; /* do not generate an empty block if no input */ 2489052d3c12SConrad Meyer 249019fcbaf1SConrad Meyer if (!ZSTD_window_update(&ms->window, src, srcSize)) { 249119fcbaf1SConrad Meyer ms->nextToUpdate = ms->window.dictLimit; 24920c16b537SWarner Losh } 24930f743729SConrad Meyer if (cctx->appliedParams.ldmParams.enableLdm) { 249419fcbaf1SConrad Meyer ZSTD_window_update(&cctx->ldmState.window, src, srcSize); 24950f743729SConrad Meyer } 24960f743729SConrad Meyer 24970f743729SConrad Meyer if (!frame) { 24980f743729SConrad Meyer /* overflow check and correction for block mode */ 2499*4d3f1eafSConrad Meyer ZSTD_overflowCorrectIfNeeded(ms, &cctx->appliedParams, src, (BYTE const*)src + srcSize); 25000f743729SConrad Meyer } 25010c16b537SWarner Losh 2502a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (unsigned)cctx->blockSize); 2503052d3c12SConrad Meyer { size_t const cSize = frame ? 25040c16b537SWarner Losh ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : 25050c16b537SWarner Losh ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize); 25062b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 25070c16b537SWarner Losh cctx->consumedSrcSize += srcSize; 250819fcbaf1SConrad Meyer cctx->producedCSize += (cSize + fhSize); 25090f743729SConrad Meyer assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); 25100f743729SConrad Meyer if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ 25110f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); 25122b9c00cbSConrad Meyer RETURN_ERROR_IF( 25132b9c00cbSConrad Meyer cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne, 25142b9c00cbSConrad Meyer srcSize_wrong, 25152b9c00cbSConrad Meyer "error : pledgedSrcSize = %u, while realSrcSize >= %u", 25162b9c00cbSConrad Meyer (unsigned)cctx->pledgedSrcSizePlusOne-1, 25172b9c00cbSConrad Meyer (unsigned)cctx->consumedSrcSize); 251819fcbaf1SConrad Meyer } 25190c16b537SWarner Losh return cSize + fhSize; 2520052d3c12SConrad Meyer } 25210c16b537SWarner Losh } 25220c16b537SWarner Losh 25230c16b537SWarner Losh size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, 25240c16b537SWarner Losh void* dst, size_t dstCapacity, 25250c16b537SWarner Losh const void* src, size_t srcSize) 25260c16b537SWarner Losh { 2527a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize); 25280c16b537SWarner Losh return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */); 25290c16b537SWarner Losh } 25300c16b537SWarner Losh 25310c16b537SWarner Losh 25320c16b537SWarner Losh size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) 25330c16b537SWarner Losh { 253419fcbaf1SConrad Meyer ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams; 253519fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 25360c16b537SWarner Losh return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog); 25370c16b537SWarner Losh } 25380c16b537SWarner Losh 25390c16b537SWarner Losh size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) 25400c16b537SWarner Losh { 25410c16b537SWarner Losh size_t const blockSizeMax = ZSTD_getBlockSize(cctx); 25422b9c00cbSConrad Meyer RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong); 25430f743729SConrad Meyer 25440c16b537SWarner Losh return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); 25450c16b537SWarner Losh } 25460c16b537SWarner Losh 25470c16b537SWarner Losh /*! ZSTD_loadDictionaryContent() : 25480c16b537SWarner Losh * @return : 0, or an error code 25490c16b537SWarner Losh */ 25500f743729SConrad Meyer static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, 25510f743729SConrad Meyer ZSTD_CCtx_params const* params, 25520f743729SConrad Meyer const void* src, size_t srcSize, 25530f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm) 25540c16b537SWarner Losh { 2555*4d3f1eafSConrad Meyer const BYTE* ip = (const BYTE*) src; 25560c16b537SWarner Losh const BYTE* const iend = ip + srcSize; 25570c16b537SWarner Losh 255819fcbaf1SConrad Meyer ZSTD_window_update(&ms->window, src, srcSize); 255919fcbaf1SConrad Meyer ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); 25600c16b537SWarner Losh 25610f743729SConrad Meyer /* Assert that we the ms params match the params we're being given */ 25620f743729SConrad Meyer ZSTD_assertEqualCParams(params->cParams, ms->cParams); 25630f743729SConrad Meyer 25640c16b537SWarner Losh if (srcSize <= HASH_READ_SIZE) return 0; 25650c16b537SWarner Losh 2566*4d3f1eafSConrad Meyer while (iend - ip > HASH_READ_SIZE) { 2567*4d3f1eafSConrad Meyer size_t const remaining = iend - ip; 2568*4d3f1eafSConrad Meyer size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX); 2569*4d3f1eafSConrad Meyer const BYTE* const ichunk = ip + chunk; 2570*4d3f1eafSConrad Meyer 2571*4d3f1eafSConrad Meyer ZSTD_overflowCorrectIfNeeded(ms, params, ip, ichunk); 2572*4d3f1eafSConrad Meyer 257319fcbaf1SConrad Meyer switch(params->cParams.strategy) 25740c16b537SWarner Losh { 25750c16b537SWarner Losh case ZSTD_fast: 2576*4d3f1eafSConrad Meyer ZSTD_fillHashTable(ms, ichunk, dtlm); 25770c16b537SWarner Losh break; 25780c16b537SWarner Losh case ZSTD_dfast: 2579*4d3f1eafSConrad Meyer ZSTD_fillDoubleHashTable(ms, ichunk, dtlm); 25800c16b537SWarner Losh break; 25810c16b537SWarner Losh 25820c16b537SWarner Losh case ZSTD_greedy: 25830c16b537SWarner Losh case ZSTD_lazy: 25840c16b537SWarner Losh case ZSTD_lazy2: 2585*4d3f1eafSConrad Meyer if (chunk >= HASH_READ_SIZE) 2586*4d3f1eafSConrad Meyer ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE); 25870c16b537SWarner Losh break; 25880c16b537SWarner Losh 258919fcbaf1SConrad Meyer case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ 25900c16b537SWarner Losh case ZSTD_btopt: 25910c16b537SWarner Losh case ZSTD_btultra: 2592a0483764SConrad Meyer case ZSTD_btultra2: 2593*4d3f1eafSConrad Meyer if (chunk >= HASH_READ_SIZE) 2594*4d3f1eafSConrad Meyer ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk); 25950c16b537SWarner Losh break; 25960c16b537SWarner Losh 25970c16b537SWarner Losh default: 25980c16b537SWarner Losh assert(0); /* not possible : not a valid strategy id */ 25990c16b537SWarner Losh } 26000c16b537SWarner Losh 2601*4d3f1eafSConrad Meyer ip = ichunk; 2602*4d3f1eafSConrad Meyer } 2603*4d3f1eafSConrad Meyer 260419fcbaf1SConrad Meyer ms->nextToUpdate = (U32)(iend - ms->window.base); 26050c16b537SWarner Losh return 0; 26060c16b537SWarner Losh } 26070c16b537SWarner Losh 26080c16b537SWarner Losh 26090c16b537SWarner Losh /* Dictionaries that assign zero probability to symbols that show up causes problems 26100c16b537SWarner Losh when FSE encoding. Refuse dictionaries that assign zero probability to symbols 26110c16b537SWarner Losh that we may encounter during compression. 26120c16b537SWarner Losh NOTE: This behavior is not standard and could be improved in the future. */ 26130c16b537SWarner Losh static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) { 26140c16b537SWarner Losh U32 s; 26152b9c00cbSConrad Meyer RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted); 26160c16b537SWarner Losh for (s = 0; s <= maxSymbolValue; ++s) { 26172b9c00cbSConrad Meyer RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted); 26180c16b537SWarner Losh } 26190c16b537SWarner Losh return 0; 26200c16b537SWarner Losh } 26210c16b537SWarner Losh 26220c16b537SWarner Losh 26230c16b537SWarner Losh /* Dictionary format : 26240c16b537SWarner Losh * See : 26250c16b537SWarner Losh * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format 26260c16b537SWarner Losh */ 26270c16b537SWarner Losh /*! ZSTD_loadZstdDictionary() : 262819fcbaf1SConrad Meyer * @return : dictID, or an error code 26290c16b537SWarner Losh * assumptions : magic number supposed already checked 26300c16b537SWarner Losh * dictSize supposed > 8 26310c16b537SWarner Losh */ 26320f743729SConrad Meyer static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, 26330f743729SConrad Meyer ZSTD_matchState_t* ms, 26340f743729SConrad Meyer ZSTD_CCtx_params const* params, 26350f743729SConrad Meyer const void* dict, size_t dictSize, 26360f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 26370f743729SConrad Meyer void* workspace) 26380c16b537SWarner Losh { 26390c16b537SWarner Losh const BYTE* dictPtr = (const BYTE*)dict; 26400c16b537SWarner Losh const BYTE* const dictEnd = dictPtr + dictSize; 26410c16b537SWarner Losh short offcodeNCount[MaxOff+1]; 26420c16b537SWarner Losh unsigned offcodeMaxValue = MaxOff; 264319fcbaf1SConrad Meyer size_t dictID; 26440c16b537SWarner Losh 264519fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 26460f743729SConrad Meyer assert(dictSize > 8); 26470f743729SConrad Meyer assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); 26480c16b537SWarner Losh 26490c16b537SWarner Losh dictPtr += 4; /* skip magic number */ 265019fcbaf1SConrad Meyer dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr); 26510c16b537SWarner Losh dictPtr += 4; 26520c16b537SWarner Losh 26530c16b537SWarner Losh { unsigned maxSymbolValue = 255; 26540f743729SConrad Meyer size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr); 26552b9c00cbSConrad Meyer RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted); 26562b9c00cbSConrad Meyer RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted); 26570c16b537SWarner Losh dictPtr += hufHeaderSize; 26580c16b537SWarner Losh } 26590c16b537SWarner Losh 26600c16b537SWarner Losh { unsigned offcodeLog; 26610c16b537SWarner Losh size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); 26622b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted); 26632b9c00cbSConrad Meyer RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted); 26640c16b537SWarner Losh /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ 26650f743729SConrad Meyer /* fill all offset symbols to avoid garbage at end of table */ 26662b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 26672b9c00cbSConrad Meyer bs->entropy.fse.offcodeCTable, 2668a0483764SConrad Meyer offcodeNCount, MaxOff, offcodeLog, 26692b9c00cbSConrad Meyer workspace, HUF_WORKSPACE_SIZE)), 26700c16b537SWarner Losh dictionary_corrupted); 26710c16b537SWarner Losh dictPtr += offcodeHeaderSize; 26720c16b537SWarner Losh } 26730c16b537SWarner Losh 26740c16b537SWarner Losh { short matchlengthNCount[MaxML+1]; 26750c16b537SWarner Losh unsigned matchlengthMaxValue = MaxML, matchlengthLog; 26760c16b537SWarner Losh size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); 26772b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted); 26782b9c00cbSConrad Meyer RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted); 26790c16b537SWarner Losh /* Every match length code must have non-zero probability */ 26802b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML)); 26812b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 26822b9c00cbSConrad Meyer bs->entropy.fse.matchlengthCTable, 2683a0483764SConrad Meyer matchlengthNCount, matchlengthMaxValue, matchlengthLog, 26842b9c00cbSConrad Meyer workspace, HUF_WORKSPACE_SIZE)), 26850c16b537SWarner Losh dictionary_corrupted); 26860c16b537SWarner Losh dictPtr += matchlengthHeaderSize; 26870c16b537SWarner Losh } 26880c16b537SWarner Losh 26890c16b537SWarner Losh { short litlengthNCount[MaxLL+1]; 26900c16b537SWarner Losh unsigned litlengthMaxValue = MaxLL, litlengthLog; 26910c16b537SWarner Losh size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); 26922b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted); 26932b9c00cbSConrad Meyer RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted); 26940c16b537SWarner Losh /* Every literal length code must have non-zero probability */ 26952b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL)); 26962b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 26972b9c00cbSConrad Meyer bs->entropy.fse.litlengthCTable, 2698a0483764SConrad Meyer litlengthNCount, litlengthMaxValue, litlengthLog, 26992b9c00cbSConrad Meyer workspace, HUF_WORKSPACE_SIZE)), 27000c16b537SWarner Losh dictionary_corrupted); 27010c16b537SWarner Losh dictPtr += litlengthHeaderSize; 27020c16b537SWarner Losh } 27030c16b537SWarner Losh 27042b9c00cbSConrad Meyer RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted); 270519fcbaf1SConrad Meyer bs->rep[0] = MEM_readLE32(dictPtr+0); 270619fcbaf1SConrad Meyer bs->rep[1] = MEM_readLE32(dictPtr+4); 270719fcbaf1SConrad Meyer bs->rep[2] = MEM_readLE32(dictPtr+8); 27080c16b537SWarner Losh dictPtr += 12; 27090c16b537SWarner Losh 27100c16b537SWarner Losh { size_t const dictContentSize = (size_t)(dictEnd - dictPtr); 27110c16b537SWarner Losh U32 offcodeMax = MaxOff; 27120c16b537SWarner Losh if (dictContentSize <= ((U32)-1) - 128 KB) { 27130c16b537SWarner Losh U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ 27140c16b537SWarner Losh offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ 27150c16b537SWarner Losh } 27160c16b537SWarner Losh /* All offset values <= dictContentSize + 128 KB must be representable */ 27172b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff))); 27180c16b537SWarner Losh /* All repCodes must be <= dictContentSize and != 0*/ 27190c16b537SWarner Losh { U32 u; 27200c16b537SWarner Losh for (u=0; u<3; u++) { 27212b9c00cbSConrad Meyer RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted); 27222b9c00cbSConrad Meyer RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted); 27230c16b537SWarner Losh } } 27240c16b537SWarner Losh 27250f743729SConrad Meyer bs->entropy.huf.repeatMode = HUF_repeat_valid; 27260f743729SConrad Meyer bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid; 27270f743729SConrad Meyer bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid; 27280f743729SConrad Meyer bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid; 27292b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize, dtlm)); 273019fcbaf1SConrad Meyer return dictID; 27310c16b537SWarner Losh } 27320c16b537SWarner Losh } 27330c16b537SWarner Losh 27340c16b537SWarner Losh /** ZSTD_compress_insertDictionary() : 273519fcbaf1SConrad Meyer * @return : dictID, or an error code */ 27360f743729SConrad Meyer static size_t 27370f743729SConrad Meyer ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, 27380f743729SConrad Meyer ZSTD_matchState_t* ms, 27390f743729SConrad Meyer const ZSTD_CCtx_params* params, 27400c16b537SWarner Losh const void* dict, size_t dictSize, 274119fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 27420f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 274319fcbaf1SConrad Meyer void* workspace) 27440c16b537SWarner Losh { 2745052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); 27460c16b537SWarner Losh if ((dict==NULL) || (dictSize<=8)) return 0; 27470c16b537SWarner Losh 274819fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(bs); 274919fcbaf1SConrad Meyer 27500c16b537SWarner Losh /* dict restricted modes */ 275119fcbaf1SConrad Meyer if (dictContentType == ZSTD_dct_rawContent) 27520f743729SConrad Meyer return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm); 27530c16b537SWarner Losh 27540c16b537SWarner Losh if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { 275519fcbaf1SConrad Meyer if (dictContentType == ZSTD_dct_auto) { 2756052d3c12SConrad Meyer DEBUGLOG(4, "raw content dictionary detected"); 27570f743729SConrad Meyer return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm); 27580c16b537SWarner Losh } 27592b9c00cbSConrad Meyer RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong); 27600c16b537SWarner Losh assert(0); /* impossible */ 27610c16b537SWarner Losh } 27620c16b537SWarner Losh 27630c16b537SWarner Losh /* dict as full zstd dictionary */ 27640f743729SConrad Meyer return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, dtlm, workspace); 27650c16b537SWarner Losh } 27660c16b537SWarner Losh 27670c16b537SWarner Losh /*! ZSTD_compressBegin_internal() : 27680c16b537SWarner Losh * @return : 0, or an error code */ 27690f743729SConrad Meyer static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, 27700c16b537SWarner Losh const void* dict, size_t dictSize, 277119fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 27720f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 27730c16b537SWarner Losh const ZSTD_CDict* cdict, 27740c16b537SWarner Losh ZSTD_CCtx_params params, U64 pledgedSrcSize, 27750c16b537SWarner Losh ZSTD_buffered_policy_e zbuff) 27760c16b537SWarner Losh { 2777052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params.cParams.windowLog); 27780c16b537SWarner Losh /* params are supposed to be fully validated at this point */ 27790c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 27800c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 27810c16b537SWarner Losh 27820c16b537SWarner Losh if (cdict && cdict->dictContentSize>0) { 27830f743729SConrad Meyer return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff); 27840c16b537SWarner Losh } 27850c16b537SWarner Losh 27862b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 27870c16b537SWarner Losh ZSTDcrp_continue, zbuff) ); 2788*4d3f1eafSConrad Meyer { size_t const dictID = ZSTD_compress_insertDictionary( 278919fcbaf1SConrad Meyer cctx->blockState.prevCBlock, &cctx->blockState.matchState, 27900f743729SConrad Meyer ¶ms, dict, dictSize, dictContentType, dtlm, cctx->entropyWorkspace); 27912b9c00cbSConrad Meyer FORWARD_IF_ERROR(dictID); 2792*4d3f1eafSConrad Meyer assert(dictID <= UINT_MAX); 279319fcbaf1SConrad Meyer cctx->dictID = (U32)dictID; 279419fcbaf1SConrad Meyer } 279519fcbaf1SConrad Meyer return 0; 27960c16b537SWarner Losh } 27970c16b537SWarner Losh 2798052d3c12SConrad Meyer size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, 27990c16b537SWarner Losh const void* dict, size_t dictSize, 280019fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 28010f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 2802052d3c12SConrad Meyer const ZSTD_CDict* cdict, 28030c16b537SWarner Losh ZSTD_CCtx_params params, 28040c16b537SWarner Losh unsigned long long pledgedSrcSize) 28050c16b537SWarner Losh { 2806052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params.cParams.windowLog); 28070c16b537SWarner Losh /* compression parameters verification and optimization */ 28082b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) ); 2809052d3c12SConrad Meyer return ZSTD_compressBegin_internal(cctx, 28100f743729SConrad Meyer dict, dictSize, dictContentType, dtlm, 2811052d3c12SConrad Meyer cdict, 28120c16b537SWarner Losh params, pledgedSrcSize, 28130c16b537SWarner Losh ZSTDb_not_buffered); 28140c16b537SWarner Losh } 28150c16b537SWarner Losh 28160c16b537SWarner Losh /*! ZSTD_compressBegin_advanced() : 28170c16b537SWarner Losh * @return : 0, or an error code */ 28180c16b537SWarner Losh size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, 28190c16b537SWarner Losh const void* dict, size_t dictSize, 28200c16b537SWarner Losh ZSTD_parameters params, unsigned long long pledgedSrcSize) 28210c16b537SWarner Losh { 28220c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 28230c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 2824052d3c12SConrad Meyer return ZSTD_compressBegin_advanced_internal(cctx, 28250f743729SConrad Meyer dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, 2826052d3c12SConrad Meyer NULL /*cdict*/, 2827052d3c12SConrad Meyer cctxParams, pledgedSrcSize); 28280c16b537SWarner Losh } 28290c16b537SWarner Losh 28300c16b537SWarner Losh size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) 28310c16b537SWarner Losh { 283219fcbaf1SConrad Meyer ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); 28330c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 28340c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 2835a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize); 28360f743729SConrad Meyer return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, 2837052d3c12SConrad Meyer cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); 28380c16b537SWarner Losh } 28390c16b537SWarner Losh 28400c16b537SWarner Losh size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) 28410c16b537SWarner Losh { 28420c16b537SWarner Losh return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); 28430c16b537SWarner Losh } 28440c16b537SWarner Losh 28450c16b537SWarner Losh 28460c16b537SWarner Losh /*! ZSTD_writeEpilogue() : 28470c16b537SWarner Losh * Ends a frame. 28480c16b537SWarner Losh * @return : nb of bytes written into dst (or an error code) */ 28490c16b537SWarner Losh static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) 28500c16b537SWarner Losh { 28510c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 28520c16b537SWarner Losh BYTE* op = ostart; 28530c16b537SWarner Losh size_t fhSize = 0; 28540c16b537SWarner Losh 285519fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_writeEpilogue"); 28562b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing"); 28570c16b537SWarner Losh 28580c16b537SWarner Losh /* special case : empty frame */ 28590c16b537SWarner Losh if (cctx->stage == ZSTDcs_init) { 28600c16b537SWarner Losh fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0); 28612b9c00cbSConrad Meyer FORWARD_IF_ERROR(fhSize); 28620c16b537SWarner Losh dstCapacity -= fhSize; 28630c16b537SWarner Losh op += fhSize; 28640c16b537SWarner Losh cctx->stage = ZSTDcs_ongoing; 28650c16b537SWarner Losh } 28660c16b537SWarner Losh 28670c16b537SWarner Losh if (cctx->stage != ZSTDcs_ending) { 28680c16b537SWarner Losh /* write one last empty block, make it the "last" block */ 28690c16b537SWarner Losh U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0; 28702b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall); 28710c16b537SWarner Losh MEM_writeLE32(op, cBlockHeader24); 28720c16b537SWarner Losh op += ZSTD_blockHeaderSize; 28730c16b537SWarner Losh dstCapacity -= ZSTD_blockHeaderSize; 28740c16b537SWarner Losh } 28750c16b537SWarner Losh 28760c16b537SWarner Losh if (cctx->appliedParams.fParams.checksumFlag) { 28770c16b537SWarner Losh U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); 28782b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall); 2879a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum); 28800c16b537SWarner Losh MEM_writeLE32(op, checksum); 28810c16b537SWarner Losh op += 4; 28820c16b537SWarner Losh } 28830c16b537SWarner Losh 28840c16b537SWarner Losh cctx->stage = ZSTDcs_created; /* return to "created but no init" status */ 28850c16b537SWarner Losh return op-ostart; 28860c16b537SWarner Losh } 28870c16b537SWarner Losh 28880c16b537SWarner Losh size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, 28890c16b537SWarner Losh void* dst, size_t dstCapacity, 28900c16b537SWarner Losh const void* src, size_t srcSize) 28910c16b537SWarner Losh { 28920c16b537SWarner Losh size_t endResult; 28930c16b537SWarner Losh size_t const cSize = ZSTD_compressContinue_internal(cctx, 28940c16b537SWarner Losh dst, dstCapacity, src, srcSize, 28950c16b537SWarner Losh 1 /* frame mode */, 1 /* last chunk */); 28962b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 28970c16b537SWarner Losh endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); 28982b9c00cbSConrad Meyer FORWARD_IF_ERROR(endResult); 28990f743729SConrad Meyer assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); 29000f743729SConrad Meyer if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ 29010f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); 29020c16b537SWarner Losh DEBUGLOG(4, "end of frame : controlling src size"); 29032b9c00cbSConrad Meyer RETURN_ERROR_IF( 29042b9c00cbSConrad Meyer cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1, 29052b9c00cbSConrad Meyer srcSize_wrong, 29062b9c00cbSConrad Meyer "error : pledgedSrcSize = %u, while realSrcSize = %u", 29072b9c00cbSConrad Meyer (unsigned)cctx->pledgedSrcSizePlusOne-1, 29082b9c00cbSConrad Meyer (unsigned)cctx->consumedSrcSize); 29092b9c00cbSConrad Meyer } 29100c16b537SWarner Losh return cSize + endResult; 29110c16b537SWarner Losh } 29120c16b537SWarner Losh 29130c16b537SWarner Losh 29140c16b537SWarner Losh static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, 29150c16b537SWarner Losh void* dst, size_t dstCapacity, 29160c16b537SWarner Losh const void* src, size_t srcSize, 29170c16b537SWarner Losh const void* dict,size_t dictSize, 29180c16b537SWarner Losh ZSTD_parameters params) 29190c16b537SWarner Losh { 29200c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 29210c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 2922052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_internal"); 29230c16b537SWarner Losh return ZSTD_compress_advanced_internal(cctx, 29240c16b537SWarner Losh dst, dstCapacity, 29250c16b537SWarner Losh src, srcSize, 29260c16b537SWarner Losh dict, dictSize, 29270c16b537SWarner Losh cctxParams); 29280c16b537SWarner Losh } 29290c16b537SWarner Losh 29300f743729SConrad Meyer size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, 29310c16b537SWarner Losh void* dst, size_t dstCapacity, 29320c16b537SWarner Losh const void* src, size_t srcSize, 29330c16b537SWarner Losh const void* dict,size_t dictSize, 29340c16b537SWarner Losh ZSTD_parameters params) 29350c16b537SWarner Losh { 2936052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_advanced"); 29372b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams)); 29380f743729SConrad Meyer return ZSTD_compress_internal(cctx, 29390f743729SConrad Meyer dst, dstCapacity, 29400f743729SConrad Meyer src, srcSize, 29410f743729SConrad Meyer dict, dictSize, 29420f743729SConrad Meyer params); 29430c16b537SWarner Losh } 29440c16b537SWarner Losh 29450c16b537SWarner Losh /* Internal */ 29460c16b537SWarner Losh size_t ZSTD_compress_advanced_internal( 29470c16b537SWarner Losh ZSTD_CCtx* cctx, 29480c16b537SWarner Losh void* dst, size_t dstCapacity, 29490c16b537SWarner Losh const void* src, size_t srcSize, 29500c16b537SWarner Losh const void* dict,size_t dictSize, 29510c16b537SWarner Losh ZSTD_CCtx_params params) 29520c16b537SWarner Losh { 2953a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize); 29542b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, 29550f743729SConrad Meyer dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, 29560c16b537SWarner Losh params, srcSize, ZSTDb_not_buffered) ); 29570c16b537SWarner Losh return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 29580c16b537SWarner Losh } 29590c16b537SWarner Losh 29600f743729SConrad Meyer size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, 29610f743729SConrad Meyer void* dst, size_t dstCapacity, 29620f743729SConrad Meyer const void* src, size_t srcSize, 29630f743729SConrad Meyer const void* dict, size_t dictSize, 29640f743729SConrad Meyer int compressionLevel) 29650c16b537SWarner Losh { 29660f743729SConrad Meyer ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize + (!srcSize), dict ? dictSize : 0); 296719fcbaf1SConrad Meyer ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 296819fcbaf1SConrad Meyer assert(params.fParams.contentSizeFlag == 1); 296919fcbaf1SConrad Meyer return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, cctxParams); 29700c16b537SWarner Losh } 29710c16b537SWarner Losh 29720f743729SConrad Meyer size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, 29730f743729SConrad Meyer void* dst, size_t dstCapacity, 29740f743729SConrad Meyer const void* src, size_t srcSize, 29750f743729SConrad Meyer int compressionLevel) 29760c16b537SWarner Losh { 2977a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (unsigned)srcSize); 29780f743729SConrad Meyer assert(cctx != NULL); 297919fcbaf1SConrad Meyer return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel); 29800c16b537SWarner Losh } 29810c16b537SWarner Losh 29820f743729SConrad Meyer size_t ZSTD_compress(void* dst, size_t dstCapacity, 29830f743729SConrad Meyer const void* src, size_t srcSize, 29840f743729SConrad Meyer int compressionLevel) 29850c16b537SWarner Losh { 29860c16b537SWarner Losh size_t result; 29870c16b537SWarner Losh ZSTD_CCtx ctxBody; 29880f743729SConrad Meyer ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem); 29890c16b537SWarner Losh result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); 29900f743729SConrad Meyer ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */ 29910c16b537SWarner Losh return result; 29920c16b537SWarner Losh } 29930c16b537SWarner Losh 29940c16b537SWarner Losh 29950c16b537SWarner Losh /* ===== Dictionary API ===== */ 29960c16b537SWarner Losh 29970c16b537SWarner Losh /*! ZSTD_estimateCDictSize_advanced() : 29980c16b537SWarner Losh * Estimate amount of memory that will be needed to create a dictionary with following arguments */ 29990c16b537SWarner Losh size_t ZSTD_estimateCDictSize_advanced( 30000c16b537SWarner Losh size_t dictSize, ZSTD_compressionParameters cParams, 30010c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod) 30020c16b537SWarner Losh { 3003a0483764SConrad Meyer DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict)); 300419fcbaf1SConrad Meyer return sizeof(ZSTD_CDict) + HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) 30050c16b537SWarner Losh + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); 30060c16b537SWarner Losh } 30070c16b537SWarner Losh 30080c16b537SWarner Losh size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) 30090c16b537SWarner Losh { 30100c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 30110c16b537SWarner Losh return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); 30120c16b537SWarner Losh } 30130c16b537SWarner Losh 30140c16b537SWarner Losh size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) 30150c16b537SWarner Losh { 30160c16b537SWarner Losh if (cdict==NULL) return 0; /* support sizeof on NULL */ 3017a0483764SConrad Meyer DEBUGLOG(5, "sizeof(*cdict) : %u", (unsigned)sizeof(*cdict)); 301819fcbaf1SConrad Meyer return cdict->workspaceSize + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict); 30190c16b537SWarner Losh } 30200c16b537SWarner Losh 30210c16b537SWarner Losh static size_t ZSTD_initCDict_internal( 30220c16b537SWarner Losh ZSTD_CDict* cdict, 30230c16b537SWarner Losh const void* dictBuffer, size_t dictSize, 30240c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 302519fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 30260c16b537SWarner Losh ZSTD_compressionParameters cParams) 30270c16b537SWarner Losh { 3028a0483764SConrad Meyer DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType); 302919fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 30300f743729SConrad Meyer cdict->matchState.cParams = cParams; 30310c16b537SWarner Losh if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { 30320c16b537SWarner Losh cdict->dictBuffer = NULL; 30330c16b537SWarner Losh cdict->dictContent = dictBuffer; 30340c16b537SWarner Losh } else { 303519fcbaf1SConrad Meyer void* const internalBuffer = ZSTD_malloc(dictSize, cdict->customMem); 30360c16b537SWarner Losh cdict->dictBuffer = internalBuffer; 30370c16b537SWarner Losh cdict->dictContent = internalBuffer; 30382b9c00cbSConrad Meyer RETURN_ERROR_IF(!internalBuffer, memory_allocation); 30390c16b537SWarner Losh memcpy(internalBuffer, dictBuffer, dictSize); 30400c16b537SWarner Losh } 30410c16b537SWarner Losh cdict->dictContentSize = dictSize; 30420c16b537SWarner Losh 304319fcbaf1SConrad Meyer /* Reset the state to no dictionary */ 304419fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(&cdict->cBlockState); 3045*4d3f1eafSConrad Meyer { void* const end = ZSTD_reset_matchState(&cdict->matchState, 304619fcbaf1SConrad Meyer (U32*)cdict->workspace + HUF_WORKSPACE_SIZE_U32, 3047*4d3f1eafSConrad Meyer &cParams, 3048*4d3f1eafSConrad Meyer ZSTDcrp_continue, ZSTD_resetTarget_CDict); 304919fcbaf1SConrad Meyer assert(end == (char*)cdict->workspace + cdict->workspaceSize); 305019fcbaf1SConrad Meyer (void)end; 305119fcbaf1SConrad Meyer } 305219fcbaf1SConrad Meyer /* (Maybe) load the dictionary 305319fcbaf1SConrad Meyer * Skips loading the dictionary if it is <= 8 bytes. 305419fcbaf1SConrad Meyer */ 305519fcbaf1SConrad Meyer { ZSTD_CCtx_params params; 305619fcbaf1SConrad Meyer memset(¶ms, 0, sizeof(params)); 305719fcbaf1SConrad Meyer params.compressionLevel = ZSTD_CLEVEL_DEFAULT; 305819fcbaf1SConrad Meyer params.fParams.contentSizeFlag = 1; 305919fcbaf1SConrad Meyer params.cParams = cParams; 306019fcbaf1SConrad Meyer { size_t const dictID = ZSTD_compress_insertDictionary( 306119fcbaf1SConrad Meyer &cdict->cBlockState, &cdict->matchState, ¶ms, 306219fcbaf1SConrad Meyer cdict->dictContent, cdict->dictContentSize, 30630f743729SConrad Meyer dictContentType, ZSTD_dtlm_full, cdict->workspace); 30642b9c00cbSConrad Meyer FORWARD_IF_ERROR(dictID); 306519fcbaf1SConrad Meyer assert(dictID <= (size_t)(U32)-1); 306619fcbaf1SConrad Meyer cdict->dictID = (U32)dictID; 306719fcbaf1SConrad Meyer } 30680c16b537SWarner Losh } 30690c16b537SWarner Losh 30700c16b537SWarner Losh return 0; 30710c16b537SWarner Losh } 30720c16b537SWarner Losh 30730c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, 30740c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 307519fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 30760c16b537SWarner Losh ZSTD_compressionParameters cParams, ZSTD_customMem customMem) 30770c16b537SWarner Losh { 3078a0483764SConrad Meyer DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType); 30790c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 30800c16b537SWarner Losh 30810c16b537SWarner Losh { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); 308219fcbaf1SConrad Meyer size_t const workspaceSize = HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); 308319fcbaf1SConrad Meyer void* const workspace = ZSTD_malloc(workspaceSize, customMem); 30840c16b537SWarner Losh 308519fcbaf1SConrad Meyer if (!cdict || !workspace) { 30860c16b537SWarner Losh ZSTD_free(cdict, customMem); 308719fcbaf1SConrad Meyer ZSTD_free(workspace, customMem); 30880c16b537SWarner Losh return NULL; 30890c16b537SWarner Losh } 309019fcbaf1SConrad Meyer cdict->customMem = customMem; 309119fcbaf1SConrad Meyer cdict->workspace = workspace; 309219fcbaf1SConrad Meyer cdict->workspaceSize = workspaceSize; 30930c16b537SWarner Losh if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 30940c16b537SWarner Losh dictBuffer, dictSize, 309519fcbaf1SConrad Meyer dictLoadMethod, dictContentType, 30960c16b537SWarner Losh cParams) )) { 30970c16b537SWarner Losh ZSTD_freeCDict(cdict); 30980c16b537SWarner Losh return NULL; 30990c16b537SWarner Losh } 31000c16b537SWarner Losh 31010c16b537SWarner Losh return cdict; 31020c16b537SWarner Losh } 31030c16b537SWarner Losh } 31040c16b537SWarner Losh 31050c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) 31060c16b537SWarner Losh { 31070c16b537SWarner Losh ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 31080c16b537SWarner Losh return ZSTD_createCDict_advanced(dict, dictSize, 310919fcbaf1SConrad Meyer ZSTD_dlm_byCopy, ZSTD_dct_auto, 31100c16b537SWarner Losh cParams, ZSTD_defaultCMem); 31110c16b537SWarner Losh } 31120c16b537SWarner Losh 31130c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) 31140c16b537SWarner Losh { 31150c16b537SWarner Losh ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 31160c16b537SWarner Losh return ZSTD_createCDict_advanced(dict, dictSize, 311719fcbaf1SConrad Meyer ZSTD_dlm_byRef, ZSTD_dct_auto, 31180c16b537SWarner Losh cParams, ZSTD_defaultCMem); 31190c16b537SWarner Losh } 31200c16b537SWarner Losh 31210c16b537SWarner Losh size_t ZSTD_freeCDict(ZSTD_CDict* cdict) 31220c16b537SWarner Losh { 31230c16b537SWarner Losh if (cdict==NULL) return 0; /* support free on NULL */ 312419fcbaf1SConrad Meyer { ZSTD_customMem const cMem = cdict->customMem; 312519fcbaf1SConrad Meyer ZSTD_free(cdict->workspace, cMem); 31260c16b537SWarner Losh ZSTD_free(cdict->dictBuffer, cMem); 31270c16b537SWarner Losh ZSTD_free(cdict, cMem); 31280c16b537SWarner Losh return 0; 31290c16b537SWarner Losh } 31300c16b537SWarner Losh } 31310c16b537SWarner Losh 31320c16b537SWarner Losh /*! ZSTD_initStaticCDict_advanced() : 31330c16b537SWarner Losh * Generate a digested dictionary in provided memory area. 31340c16b537SWarner Losh * workspace: The memory area to emplace the dictionary into. 31350c16b537SWarner Losh * Provided pointer must 8-bytes aligned. 31360c16b537SWarner Losh * It must outlive dictionary usage. 31370c16b537SWarner Losh * workspaceSize: Use ZSTD_estimateCDictSize() 31380c16b537SWarner Losh * to determine how large workspace must be. 31390c16b537SWarner Losh * cParams : use ZSTD_getCParams() to transform a compression level 31400c16b537SWarner Losh * into its relevants cParams. 31410c16b537SWarner Losh * @return : pointer to ZSTD_CDict*, or NULL if error (size too small) 31420c16b537SWarner Losh * Note : there is no corresponding "free" function. 31430c16b537SWarner Losh * Since workspace was allocated externally, it must be freed externally. 31440c16b537SWarner Losh */ 314519fcbaf1SConrad Meyer const ZSTD_CDict* ZSTD_initStaticCDict( 314619fcbaf1SConrad Meyer void* workspace, size_t workspaceSize, 31470c16b537SWarner Losh const void* dict, size_t dictSize, 31480c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 314919fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 31500c16b537SWarner Losh ZSTD_compressionParameters cParams) 31510c16b537SWarner Losh { 315219fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); 31530c16b537SWarner Losh size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize) 315419fcbaf1SConrad Meyer + HUF_WORKSPACE_SIZE + matchStateSize; 31550c16b537SWarner Losh ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; 31560c16b537SWarner Losh void* ptr; 31570c16b537SWarner Losh if ((size_t)workspace & 7) return NULL; /* 8-aligned */ 3158052d3c12SConrad Meyer DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u", 3159a0483764SConrad Meyer (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize)); 31600c16b537SWarner Losh if (workspaceSize < neededSize) return NULL; 31610c16b537SWarner Losh 31620c16b537SWarner Losh if (dictLoadMethod == ZSTD_dlm_byCopy) { 31630c16b537SWarner Losh memcpy(cdict+1, dict, dictSize); 31640c16b537SWarner Losh dict = cdict+1; 31650c16b537SWarner Losh ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize; 31660c16b537SWarner Losh } else { 31670c16b537SWarner Losh ptr = cdict+1; 31680c16b537SWarner Losh } 316919fcbaf1SConrad Meyer cdict->workspace = ptr; 317019fcbaf1SConrad Meyer cdict->workspaceSize = HUF_WORKSPACE_SIZE + matchStateSize; 31710c16b537SWarner Losh 31720c16b537SWarner Losh if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 31730c16b537SWarner Losh dict, dictSize, 317419fcbaf1SConrad Meyer ZSTD_dlm_byRef, dictContentType, 31750c16b537SWarner Losh cParams) )) 31760c16b537SWarner Losh return NULL; 31770c16b537SWarner Losh 31780c16b537SWarner Losh return cdict; 31790c16b537SWarner Losh } 31800c16b537SWarner Losh 318119fcbaf1SConrad Meyer ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) 318219fcbaf1SConrad Meyer { 318319fcbaf1SConrad Meyer assert(cdict != NULL); 31840f743729SConrad Meyer return cdict->matchState.cParams; 31850c16b537SWarner Losh } 31860c16b537SWarner Losh 31870c16b537SWarner Losh /* ZSTD_compressBegin_usingCDict_advanced() : 31880c16b537SWarner Losh * cdict must be != NULL */ 31890c16b537SWarner Losh size_t ZSTD_compressBegin_usingCDict_advanced( 31900c16b537SWarner Losh ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, 31910c16b537SWarner Losh ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) 31920c16b537SWarner Losh { 3193052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced"); 31942b9c00cbSConrad Meyer RETURN_ERROR_IF(cdict==NULL, dictionary_wrong); 31950c16b537SWarner Losh { ZSTD_CCtx_params params = cctx->requestedParams; 31960c16b537SWarner Losh params.cParams = ZSTD_getCParamsFromCDict(cdict); 319719fcbaf1SConrad Meyer /* Increase window log to fit the entire dictionary and source if the 319819fcbaf1SConrad Meyer * source size is known. Limit the increase to 19, which is the 319919fcbaf1SConrad Meyer * window log for compression level 1 with the largest source size. 320019fcbaf1SConrad Meyer */ 320119fcbaf1SConrad Meyer if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { 320219fcbaf1SConrad Meyer U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); 320319fcbaf1SConrad Meyer U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; 320419fcbaf1SConrad Meyer params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog); 320519fcbaf1SConrad Meyer } 32060c16b537SWarner Losh params.fParams = fParams; 32070c16b537SWarner Losh return ZSTD_compressBegin_internal(cctx, 32080f743729SConrad Meyer NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, 32090c16b537SWarner Losh cdict, 32100c16b537SWarner Losh params, pledgedSrcSize, 32110c16b537SWarner Losh ZSTDb_not_buffered); 32120c16b537SWarner Losh } 32130c16b537SWarner Losh } 32140c16b537SWarner Losh 32150c16b537SWarner Losh /* ZSTD_compressBegin_usingCDict() : 32160c16b537SWarner Losh * pledgedSrcSize=0 means "unknown" 32170c16b537SWarner Losh * if pledgedSrcSize>0, it will enable contentSizeFlag */ 32180c16b537SWarner Losh size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 32190c16b537SWarner Losh { 32200c16b537SWarner Losh ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 3221052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); 32220f743729SConrad Meyer return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); 32230c16b537SWarner Losh } 32240c16b537SWarner Losh 32250c16b537SWarner Losh size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, 32260c16b537SWarner Losh void* dst, size_t dstCapacity, 32270c16b537SWarner Losh const void* src, size_t srcSize, 32280c16b537SWarner Losh const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) 32290c16b537SWarner Losh { 32302b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */ 32310c16b537SWarner Losh return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 32320c16b537SWarner Losh } 32330c16b537SWarner Losh 32340c16b537SWarner Losh /*! ZSTD_compress_usingCDict() : 32350c16b537SWarner Losh * Compression using a digested Dictionary. 32360c16b537SWarner Losh * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times. 32370c16b537SWarner Losh * Note that compression parameters are decided at CDict creation time 32380c16b537SWarner Losh * while frame parameters are hardcoded */ 32390c16b537SWarner Losh size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, 32400c16b537SWarner Losh void* dst, size_t dstCapacity, 32410c16b537SWarner Losh const void* src, size_t srcSize, 32420c16b537SWarner Losh const ZSTD_CDict* cdict) 32430c16b537SWarner Losh { 32440c16b537SWarner Losh ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 32450c16b537SWarner Losh return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); 32460c16b537SWarner Losh } 32470c16b537SWarner Losh 32480c16b537SWarner Losh 32490c16b537SWarner Losh 32500c16b537SWarner Losh /* ****************************************************************** 32510c16b537SWarner Losh * Streaming 32520c16b537SWarner Losh ********************************************************************/ 32530c16b537SWarner Losh 32540c16b537SWarner Losh ZSTD_CStream* ZSTD_createCStream(void) 32550c16b537SWarner Losh { 3256052d3c12SConrad Meyer DEBUGLOG(3, "ZSTD_createCStream"); 32570c16b537SWarner Losh return ZSTD_createCStream_advanced(ZSTD_defaultCMem); 32580c16b537SWarner Losh } 32590c16b537SWarner Losh 32600c16b537SWarner Losh ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize) 32610c16b537SWarner Losh { 32620c16b537SWarner Losh return ZSTD_initStaticCCtx(workspace, workspaceSize); 32630c16b537SWarner Losh } 32640c16b537SWarner Losh 32650c16b537SWarner Losh ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem) 32660c16b537SWarner Losh { /* CStream and CCtx are now same object */ 32670c16b537SWarner Losh return ZSTD_createCCtx_advanced(customMem); 32680c16b537SWarner Losh } 32690c16b537SWarner Losh 32700c16b537SWarner Losh size_t ZSTD_freeCStream(ZSTD_CStream* zcs) 32710c16b537SWarner Losh { 32720c16b537SWarner Losh return ZSTD_freeCCtx(zcs); /* same object */ 32730c16b537SWarner Losh } 32740c16b537SWarner Losh 32750c16b537SWarner Losh 32760c16b537SWarner Losh 32770c16b537SWarner Losh /*====== Initialization ======*/ 32780c16b537SWarner Losh 32790c16b537SWarner Losh size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; } 32800c16b537SWarner Losh 32810c16b537SWarner Losh size_t ZSTD_CStreamOutSize(void) 32820c16b537SWarner Losh { 32830c16b537SWarner Losh return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; 32840c16b537SWarner Losh } 32850c16b537SWarner Losh 328619fcbaf1SConrad Meyer static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx, 328719fcbaf1SConrad Meyer const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType, 3288052d3c12SConrad Meyer const ZSTD_CDict* const cdict, 32890f743729SConrad Meyer ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize) 32900c16b537SWarner Losh { 32910f743729SConrad Meyer DEBUGLOG(4, "ZSTD_resetCStream_internal"); 32920f743729SConrad Meyer /* Finalize the compression parameters */ 32930f743729SConrad Meyer params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, dictSize); 32940c16b537SWarner Losh /* params are supposed to be fully validated at this point */ 32950c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 32960c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 32970c16b537SWarner Losh 32982b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, 32990f743729SConrad Meyer dict, dictSize, dictContentType, ZSTD_dtlm_fast, 33000c16b537SWarner Losh cdict, 33010c16b537SWarner Losh params, pledgedSrcSize, 33020c16b537SWarner Losh ZSTDb_buffered) ); 33030c16b537SWarner Losh 330419fcbaf1SConrad Meyer cctx->inToCompress = 0; 330519fcbaf1SConrad Meyer cctx->inBuffPos = 0; 330619fcbaf1SConrad Meyer cctx->inBuffTarget = cctx->blockSize 330719fcbaf1SConrad 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 */ 330819fcbaf1SConrad Meyer cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; 330919fcbaf1SConrad Meyer cctx->streamStage = zcss_load; 331019fcbaf1SConrad Meyer cctx->frameEnded = 0; 33110c16b537SWarner Losh return 0; /* ready to go */ 33120c16b537SWarner Losh } 33130c16b537SWarner Losh 3314052d3c12SConrad Meyer /* ZSTD_resetCStream(): 3315052d3c12SConrad Meyer * pledgedSrcSize == 0 means "unknown" */ 33162b9c00cbSConrad Meyer size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pss) 33170c16b537SWarner Losh { 33182b9c00cbSConrad Meyer /* temporary : 0 interpreted as "unknown" during transition period. 33192b9c00cbSConrad Meyer * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. 33202b9c00cbSConrad Meyer * 0 will be interpreted as "empty" in the future. 33212b9c00cbSConrad Meyer */ 33222b9c00cbSConrad Meyer U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 3323a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize); 33242b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 33252b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 33262b9c00cbSConrad Meyer return 0; 33270c16b537SWarner Losh } 33280c16b537SWarner Losh 33290c16b537SWarner Losh /*! ZSTD_initCStream_internal() : 3330052d3c12SConrad Meyer * Note : for lib/compress only. Used by zstdmt_compress.c. 33310c16b537SWarner Losh * Assumption 1 : params are valid 33320c16b537SWarner Losh * Assumption 2 : either dict, or cdict, is defined, not both */ 33330c16b537SWarner Losh size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, 33340c16b537SWarner Losh const void* dict, size_t dictSize, const ZSTD_CDict* cdict, 33350c16b537SWarner Losh ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) 33360c16b537SWarner Losh { 33370c16b537SWarner Losh DEBUGLOG(4, "ZSTD_initCStream_internal"); 33382b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 33392b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 33400c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 33412b9c00cbSConrad Meyer zcs->requestedParams = params; 33420c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 33432b9c00cbSConrad Meyer if (dict) { 33442b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); 33450c16b537SWarner Losh } else { 33462b9c00cbSConrad Meyer /* Dictionary is cleared if !cdict */ 33472b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); 33480c16b537SWarner Losh } 33492b9c00cbSConrad Meyer return 0; 33500c16b537SWarner Losh } 33510c16b537SWarner Losh 33520c16b537SWarner Losh /* ZSTD_initCStream_usingCDict_advanced() : 33530c16b537SWarner Losh * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ 33540c16b537SWarner Losh size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, 33550c16b537SWarner Losh const ZSTD_CDict* cdict, 33560c16b537SWarner Losh ZSTD_frameParameters fParams, 33570c16b537SWarner Losh unsigned long long pledgedSrcSize) 3358052d3c12SConrad Meyer { 3359052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced"); 33602b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 33612b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 33622b9c00cbSConrad Meyer zcs->requestedParams.fParams = fParams; 33632b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); 33642b9c00cbSConrad Meyer return 0; 33650c16b537SWarner Losh } 33660c16b537SWarner Losh 33670c16b537SWarner Losh /* note : cdict must outlive compression session */ 33680c16b537SWarner Losh size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict) 33690c16b537SWarner Losh { 3370052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingCDict"); 33712b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 33722b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); 33732b9c00cbSConrad Meyer return 0; 33740c16b537SWarner Losh } 33750c16b537SWarner Losh 337619fcbaf1SConrad Meyer 3377052d3c12SConrad Meyer /* ZSTD_initCStream_advanced() : 337819fcbaf1SConrad Meyer * pledgedSrcSize must be exact. 3379052d3c12SConrad Meyer * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. 3380052d3c12SConrad Meyer * dict is loaded with default parameters ZSTD_dm_auto and ZSTD_dlm_byCopy. */ 33810c16b537SWarner Losh size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, 33820c16b537SWarner Losh const void* dict, size_t dictSize, 33832b9c00cbSConrad Meyer ZSTD_parameters params, unsigned long long pss) 33840c16b537SWarner Losh { 33852b9c00cbSConrad Meyer /* for compatibility with older programs relying on this behavior. 33862b9c00cbSConrad Meyer * Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. 33872b9c00cbSConrad Meyer * This line will be removed in the future. 33882b9c00cbSConrad Meyer */ 33892b9c00cbSConrad Meyer U64 const pledgedSrcSize = (pss==0 && params.fParams.contentSizeFlag==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 33902b9c00cbSConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_advanced"); 33912b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 33922b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 33932b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) ); 33940f743729SConrad Meyer zcs->requestedParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); 33952b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); 33962b9c00cbSConrad Meyer return 0; 339719fcbaf1SConrad Meyer } 33980c16b537SWarner Losh 33990c16b537SWarner Losh size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) 34000c16b537SWarner Losh { 34012b9c00cbSConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingDict"); 34022b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 34032b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); 34042b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); 34052b9c00cbSConrad Meyer return 0; 34060c16b537SWarner Losh } 34070c16b537SWarner Losh 3408052d3c12SConrad Meyer size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss) 34090c16b537SWarner Losh { 34102b9c00cbSConrad Meyer /* temporary : 0 interpreted as "unknown" during transition period. 34112b9c00cbSConrad Meyer * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. 34122b9c00cbSConrad Meyer * 0 will be interpreted as "empty" in the future. 34132b9c00cbSConrad Meyer */ 34142b9c00cbSConrad Meyer U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 34152b9c00cbSConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_srcSize"); 34162b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 34172b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) ); 34182b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); 34192b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 34202b9c00cbSConrad Meyer return 0; 34210c16b537SWarner Losh } 34220c16b537SWarner Losh 34230c16b537SWarner Losh size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) 34240c16b537SWarner Losh { 3425052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream"); 34262b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 34272b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) ); 34282b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); 34292b9c00cbSConrad Meyer return 0; 34300c16b537SWarner Losh } 34310c16b537SWarner Losh 34320c16b537SWarner Losh /*====== Compression ======*/ 34330c16b537SWarner Losh 3434a0483764SConrad Meyer static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx) 3435a0483764SConrad Meyer { 3436a0483764SConrad Meyer size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; 3437a0483764SConrad Meyer if (hintInSize==0) hintInSize = cctx->blockSize; 3438a0483764SConrad Meyer return hintInSize; 3439a0483764SConrad Meyer } 3440a0483764SConrad Meyer 3441a0483764SConrad Meyer static size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, 34420c16b537SWarner Losh const void* src, size_t srcSize) 34430c16b537SWarner Losh { 34440c16b537SWarner Losh size_t const length = MIN(dstCapacity, srcSize); 34450c16b537SWarner Losh if (length) memcpy(dst, src, length); 34460c16b537SWarner Losh return length; 34470c16b537SWarner Losh } 34480c16b537SWarner Losh 34490c16b537SWarner Losh /** ZSTD_compressStream_generic(): 3450a0483764SConrad Meyer * internal function for all *compressStream*() variants 345119fcbaf1SConrad Meyer * non-static, because can be called from zstdmt_compress.c 34520c16b537SWarner Losh * @return : hint size for next input */ 34532b9c00cbSConrad Meyer static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, 34540c16b537SWarner Losh ZSTD_outBuffer* output, 34550c16b537SWarner Losh ZSTD_inBuffer* input, 34560c16b537SWarner Losh ZSTD_EndDirective const flushMode) 34570c16b537SWarner Losh { 34580c16b537SWarner Losh const char* const istart = (const char*)input->src; 34590c16b537SWarner Losh const char* const iend = istart + input->size; 34600c16b537SWarner Losh const char* ip = istart + input->pos; 34610c16b537SWarner Losh char* const ostart = (char*)output->dst; 34620c16b537SWarner Losh char* const oend = ostart + output->size; 34630c16b537SWarner Losh char* op = ostart + output->pos; 34640c16b537SWarner Losh U32 someMoreWork = 1; 34650c16b537SWarner Losh 34660c16b537SWarner Losh /* check expectations */ 3467a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode); 34680c16b537SWarner Losh assert(zcs->inBuff != NULL); 34690c16b537SWarner Losh assert(zcs->inBuffSize > 0); 34700c16b537SWarner Losh assert(zcs->outBuff != NULL); 34710c16b537SWarner Losh assert(zcs->outBuffSize > 0); 34720c16b537SWarner Losh assert(output->pos <= output->size); 34730c16b537SWarner Losh assert(input->pos <= input->size); 34740c16b537SWarner Losh 34750c16b537SWarner Losh while (someMoreWork) { 34760c16b537SWarner Losh switch(zcs->streamStage) 34770c16b537SWarner Losh { 34780c16b537SWarner Losh case zcss_init: 34792b9c00cbSConrad Meyer RETURN_ERROR(init_missing, "call ZSTD_initCStream() first!"); 34800c16b537SWarner Losh 34810c16b537SWarner Losh case zcss_load: 34820c16b537SWarner Losh if ( (flushMode == ZSTD_e_end) 34830c16b537SWarner Losh && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */ 34840c16b537SWarner Losh && (zcs->inBuffPos == 0) ) { 34850c16b537SWarner Losh /* shortcut to compression pass directly into output buffer */ 34860c16b537SWarner Losh size_t const cSize = ZSTD_compressEnd(zcs, 34870c16b537SWarner Losh op, oend-op, ip, iend-ip); 3488a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize); 34892b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 34900c16b537SWarner Losh ip = iend; 34910c16b537SWarner Losh op += cSize; 34920c16b537SWarner Losh zcs->frameEnded = 1; 3493a0483764SConrad Meyer ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 34940c16b537SWarner Losh someMoreWork = 0; break; 34950c16b537SWarner Losh } 34960c16b537SWarner Losh /* complete loading into inBuffer */ 34970c16b537SWarner Losh { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; 34980c16b537SWarner Losh size_t const loaded = ZSTD_limitCopy( 34990c16b537SWarner Losh zcs->inBuff + zcs->inBuffPos, toLoad, 35000c16b537SWarner Losh ip, iend-ip); 35010c16b537SWarner Losh zcs->inBuffPos += loaded; 35020c16b537SWarner Losh ip += loaded; 35030c16b537SWarner Losh if ( (flushMode == ZSTD_e_continue) 35040c16b537SWarner Losh && (zcs->inBuffPos < zcs->inBuffTarget) ) { 35050c16b537SWarner Losh /* not enough input to fill full block : stop here */ 35060c16b537SWarner Losh someMoreWork = 0; break; 35070c16b537SWarner Losh } 35080c16b537SWarner Losh if ( (flushMode == ZSTD_e_flush) 35090c16b537SWarner Losh && (zcs->inBuffPos == zcs->inToCompress) ) { 35100c16b537SWarner Losh /* empty */ 35110c16b537SWarner Losh someMoreWork = 0; break; 35120c16b537SWarner Losh } 35130c16b537SWarner Losh } 35140c16b537SWarner Losh /* compress current block (note : this stage cannot be stopped in the middle) */ 35150c16b537SWarner Losh DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode); 35160c16b537SWarner Losh { void* cDst; 35170c16b537SWarner Losh size_t cSize; 35180c16b537SWarner Losh size_t const iSize = zcs->inBuffPos - zcs->inToCompress; 35190c16b537SWarner Losh size_t oSize = oend-op; 35200c16b537SWarner Losh unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); 35210c16b537SWarner Losh if (oSize >= ZSTD_compressBound(iSize)) 35220c16b537SWarner Losh cDst = op; /* compress into output buffer, to skip flush stage */ 35230c16b537SWarner Losh else 35240c16b537SWarner Losh cDst = zcs->outBuff, oSize = zcs->outBuffSize; 35250c16b537SWarner Losh cSize = lastBlock ? 35260c16b537SWarner Losh ZSTD_compressEnd(zcs, cDst, oSize, 35270c16b537SWarner Losh zcs->inBuff + zcs->inToCompress, iSize) : 35280c16b537SWarner Losh ZSTD_compressContinue(zcs, cDst, oSize, 35290c16b537SWarner Losh zcs->inBuff + zcs->inToCompress, iSize); 35302b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 35310c16b537SWarner Losh zcs->frameEnded = lastBlock; 35320c16b537SWarner Losh /* prepare next block */ 35330c16b537SWarner Losh zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; 35340c16b537SWarner Losh if (zcs->inBuffTarget > zcs->inBuffSize) 35350c16b537SWarner Losh zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; 35360c16b537SWarner Losh DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", 3537a0483764SConrad Meyer (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); 35380c16b537SWarner Losh if (!lastBlock) 35390c16b537SWarner Losh assert(zcs->inBuffTarget <= zcs->inBuffSize); 35400c16b537SWarner Losh zcs->inToCompress = zcs->inBuffPos; 35410c16b537SWarner Losh if (cDst == op) { /* no need to flush */ 35420c16b537SWarner Losh op += cSize; 35430c16b537SWarner Losh if (zcs->frameEnded) { 35440c16b537SWarner Losh DEBUGLOG(5, "Frame completed directly in outBuffer"); 35450c16b537SWarner Losh someMoreWork = 0; 3546a0483764SConrad Meyer ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 35470c16b537SWarner Losh } 35480c16b537SWarner Losh break; 35490c16b537SWarner Losh } 35500c16b537SWarner Losh zcs->outBuffContentSize = cSize; 35510c16b537SWarner Losh zcs->outBuffFlushedSize = 0; 35520c16b537SWarner Losh zcs->streamStage = zcss_flush; /* pass-through to flush stage */ 35530c16b537SWarner Losh } 35540c16b537SWarner Losh /* fall-through */ 35550c16b537SWarner Losh case zcss_flush: 35560c16b537SWarner Losh DEBUGLOG(5, "flush stage"); 35570c16b537SWarner Losh { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; 3558*4d3f1eafSConrad Meyer size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op), 35590c16b537SWarner Losh zcs->outBuff + zcs->outBuffFlushedSize, toFlush); 35600c16b537SWarner Losh DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u", 3561a0483764SConrad Meyer (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed); 35620c16b537SWarner Losh op += flushed; 35630c16b537SWarner Losh zcs->outBuffFlushedSize += flushed; 35640c16b537SWarner Losh if (toFlush!=flushed) { 35650c16b537SWarner Losh /* flush not fully completed, presumably because dst is too small */ 35660c16b537SWarner Losh assert(op==oend); 35670c16b537SWarner Losh someMoreWork = 0; 35680c16b537SWarner Losh break; 35690c16b537SWarner Losh } 35700c16b537SWarner Losh zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; 35710c16b537SWarner Losh if (zcs->frameEnded) { 35720c16b537SWarner Losh DEBUGLOG(5, "Frame completed on flush"); 35730c16b537SWarner Losh someMoreWork = 0; 3574a0483764SConrad Meyer ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 35750c16b537SWarner Losh break; 35760c16b537SWarner Losh } 35770c16b537SWarner Losh zcs->streamStage = zcss_load; 35780c16b537SWarner Losh break; 35790c16b537SWarner Losh } 35800c16b537SWarner Losh 35810c16b537SWarner Losh default: /* impossible */ 35820c16b537SWarner Losh assert(0); 35830c16b537SWarner Losh } 35840c16b537SWarner Losh } 35850c16b537SWarner Losh 35860c16b537SWarner Losh input->pos = ip - istart; 35870c16b537SWarner Losh output->pos = op - ostart; 35880c16b537SWarner Losh if (zcs->frameEnded) return 0; 3589a0483764SConrad Meyer return ZSTD_nextInputSizeHint(zcs); 35900c16b537SWarner Losh } 3591a0483764SConrad Meyer 3592a0483764SConrad Meyer static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx) 3593a0483764SConrad Meyer { 3594a0483764SConrad Meyer #ifdef ZSTD_MULTITHREAD 3595a0483764SConrad Meyer if (cctx->appliedParams.nbWorkers >= 1) { 3596a0483764SConrad Meyer assert(cctx->mtctx != NULL); 3597a0483764SConrad Meyer return ZSTDMT_nextInputSizeHint(cctx->mtctx); 3598a0483764SConrad Meyer } 3599a0483764SConrad Meyer #endif 3600a0483764SConrad Meyer return ZSTD_nextInputSizeHint(cctx); 3601a0483764SConrad Meyer 36020c16b537SWarner Losh } 36030c16b537SWarner Losh 36040c16b537SWarner Losh size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) 36050c16b537SWarner Losh { 36062b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) ); 3607a0483764SConrad Meyer return ZSTD_nextInputSizeHint_MTorST(zcs); 36080c16b537SWarner Losh } 36090c16b537SWarner Losh 36100c16b537SWarner Losh 3611a0483764SConrad Meyer size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, 36120c16b537SWarner Losh ZSTD_outBuffer* output, 36130c16b537SWarner Losh ZSTD_inBuffer* input, 36140c16b537SWarner Losh ZSTD_EndDirective endOp) 36150c16b537SWarner Losh { 3616a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp); 36170c16b537SWarner Losh /* check conditions */ 36182b9c00cbSConrad Meyer RETURN_ERROR_IF(output->pos > output->size, GENERIC); 36192b9c00cbSConrad Meyer RETURN_ERROR_IF(input->pos > input->size, GENERIC); 36200c16b537SWarner Losh assert(cctx!=NULL); 36210c16b537SWarner Losh 36220c16b537SWarner Losh /* transparent initialization stage */ 36230c16b537SWarner Losh if (cctx->streamStage == zcss_init) { 36240c16b537SWarner Losh ZSTD_CCtx_params params = cctx->requestedParams; 3625052d3c12SConrad Meyer ZSTD_prefixDict const prefixDict = cctx->prefixDict; 36262b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) ); /* Init the local dict if present. */ 36270c16b537SWarner Losh memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ 36280c16b537SWarner Losh assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ 3629a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); 3630052d3c12SConrad Meyer if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */ 3631052d3c12SConrad Meyer params.cParams = ZSTD_getCParamsFromCCtxParams( 363219fcbaf1SConrad Meyer &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); 36330c16b537SWarner Losh 36340f743729SConrad Meyer 36350c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 363619fcbaf1SConrad Meyer if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { 363719fcbaf1SConrad Meyer params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ 363819fcbaf1SConrad Meyer } 363919fcbaf1SConrad Meyer if (params.nbWorkers > 0) { 364019fcbaf1SConrad Meyer /* mt context creation */ 36410f743729SConrad Meyer if (cctx->mtctx == NULL) { 3642a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u", 364319fcbaf1SConrad Meyer params.nbWorkers); 364419fcbaf1SConrad Meyer cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbWorkers, cctx->customMem); 36452b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation); 36460c16b537SWarner Losh } 364719fcbaf1SConrad Meyer /* mt compression */ 364819fcbaf1SConrad Meyer DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); 36492b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTDMT_initCStream_internal( 36500c16b537SWarner Losh cctx->mtctx, 365119fcbaf1SConrad Meyer prefixDict.dict, prefixDict.dictSize, ZSTD_dct_rawContent, 36520c16b537SWarner Losh cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); 36530c16b537SWarner Losh cctx->streamStage = zcss_load; 365419fcbaf1SConrad Meyer cctx->appliedParams.nbWorkers = params.nbWorkers; 36550c16b537SWarner Losh } else 36560c16b537SWarner Losh #endif 36572b9c00cbSConrad Meyer { FORWARD_IF_ERROR( ZSTD_resetCStream_internal(cctx, 365819fcbaf1SConrad Meyer prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, 365919fcbaf1SConrad Meyer cctx->cdict, 366019fcbaf1SConrad Meyer params, cctx->pledgedSrcSizePlusOne-1) ); 3661052d3c12SConrad Meyer assert(cctx->streamStage == zcss_load); 366219fcbaf1SConrad Meyer assert(cctx->appliedParams.nbWorkers == 0); 36630c16b537SWarner Losh } } 3664a0483764SConrad Meyer /* end of transparent initialization stage */ 36650c16b537SWarner Losh 36660c16b537SWarner Losh /* compression stage */ 36670c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 366819fcbaf1SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 36692b9c00cbSConrad Meyer int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end); 36702b9c00cbSConrad Meyer size_t flushMin; 36712b9c00cbSConrad Meyer assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */); 367219fcbaf1SConrad Meyer if (cctx->cParamsChanged) { 367319fcbaf1SConrad Meyer ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams); 367419fcbaf1SConrad Meyer cctx->cParamsChanged = 0; 367519fcbaf1SConrad Meyer } 36762b9c00cbSConrad Meyer do { 36772b9c00cbSConrad Meyer flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); 36780c16b537SWarner Losh if ( ZSTD_isError(flushMin) 36790c16b537SWarner Losh || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ 3680a0483764SConrad Meyer ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); 36810c16b537SWarner Losh } 36822b9c00cbSConrad Meyer FORWARD_IF_ERROR(flushMin); 36832b9c00cbSConrad Meyer } while (forceMaxProgress && flushMin != 0 && output->pos < output->size); 3684a0483764SConrad Meyer DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic"); 36852b9c00cbSConrad Meyer /* Either we don't require maximum forward progress, we've finished the 36862b9c00cbSConrad Meyer * flush, or we are out of output space. 36872b9c00cbSConrad Meyer */ 36882b9c00cbSConrad Meyer assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size); 36890c16b537SWarner Losh return flushMin; 36902b9c00cbSConrad Meyer } 36910c16b537SWarner Losh #endif 36922b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) ); 3693a0483764SConrad Meyer DEBUGLOG(5, "completed ZSTD_compressStream2"); 36940c16b537SWarner Losh return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ 36950c16b537SWarner Losh } 36960c16b537SWarner Losh 3697a0483764SConrad Meyer size_t ZSTD_compressStream2_simpleArgs ( 36980c16b537SWarner Losh ZSTD_CCtx* cctx, 36990c16b537SWarner Losh void* dst, size_t dstCapacity, size_t* dstPos, 37000c16b537SWarner Losh const void* src, size_t srcSize, size_t* srcPos, 37010c16b537SWarner Losh ZSTD_EndDirective endOp) 37020c16b537SWarner Losh { 37030c16b537SWarner Losh ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; 37040c16b537SWarner Losh ZSTD_inBuffer input = { src, srcSize, *srcPos }; 3705a0483764SConrad Meyer /* ZSTD_compressStream2() will check validity of dstPos and srcPos */ 3706a0483764SConrad Meyer size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp); 37070c16b537SWarner Losh *dstPos = output.pos; 37080c16b537SWarner Losh *srcPos = input.pos; 37090c16b537SWarner Losh return cErr; 37100c16b537SWarner Losh } 37110c16b537SWarner Losh 3712a0483764SConrad Meyer size_t ZSTD_compress2(ZSTD_CCtx* cctx, 3713a0483764SConrad Meyer void* dst, size_t dstCapacity, 3714a0483764SConrad Meyer const void* src, size_t srcSize) 3715a0483764SConrad Meyer { 3716a0483764SConrad Meyer ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); 3717a0483764SConrad Meyer { size_t oPos = 0; 3718a0483764SConrad Meyer size_t iPos = 0; 3719a0483764SConrad Meyer size_t const result = ZSTD_compressStream2_simpleArgs(cctx, 3720a0483764SConrad Meyer dst, dstCapacity, &oPos, 3721a0483764SConrad Meyer src, srcSize, &iPos, 3722a0483764SConrad Meyer ZSTD_e_end); 37232b9c00cbSConrad Meyer FORWARD_IF_ERROR(result); 3724a0483764SConrad Meyer if (result != 0) { /* compression not completed, due to lack of output space */ 3725a0483764SConrad Meyer assert(oPos == dstCapacity); 37262b9c00cbSConrad Meyer RETURN_ERROR(dstSize_tooSmall); 3727a0483764SConrad Meyer } 3728a0483764SConrad Meyer assert(iPos == srcSize); /* all input is expected consumed */ 3729a0483764SConrad Meyer return oPos; 3730a0483764SConrad Meyer } 3731a0483764SConrad Meyer } 37320c16b537SWarner Losh 37330c16b537SWarner Losh /*====== Finalize ======*/ 37340c16b537SWarner Losh 37350c16b537SWarner Losh /*! ZSTD_flushStream() : 37360c16b537SWarner Losh * @return : amount of data remaining to flush */ 37370c16b537SWarner Losh size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 37380c16b537SWarner Losh { 37390c16b537SWarner Losh ZSTD_inBuffer input = { NULL, 0, 0 }; 3740a0483764SConrad Meyer return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush); 37410c16b537SWarner Losh } 37420c16b537SWarner Losh 37430c16b537SWarner Losh 37440c16b537SWarner Losh size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 37450c16b537SWarner Losh { 37460c16b537SWarner Losh ZSTD_inBuffer input = { NULL, 0, 0 }; 3747a0483764SConrad Meyer size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end); 37482b9c00cbSConrad Meyer FORWARD_IF_ERROR( remainingToFlush ); 3749a0483764SConrad Meyer if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */ 3750a0483764SConrad Meyer /* single thread mode : attempt to calculate remaining to flush more precisely */ 37510c16b537SWarner Losh { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; 3752*4d3f1eafSConrad Meyer size_t const checksumSize = (size_t)(zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4); 3753a0483764SConrad Meyer size_t const toFlush = remainingToFlush + lastBlockSize + checksumSize; 3754a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (unsigned)toFlush); 37550c16b537SWarner Losh return toFlush; 37560c16b537SWarner Losh } 37570c16b537SWarner Losh } 37580c16b537SWarner Losh 37590c16b537SWarner Losh 37600c16b537SWarner Losh /*-===== Pre-defined compression levels =====-*/ 37610c16b537SWarner Losh 37620c16b537SWarner Losh #define ZSTD_MAX_CLEVEL 22 37630c16b537SWarner Losh int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } 37640f743729SConrad Meyer int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; } 37650c16b537SWarner Losh 37660c16b537SWarner Losh static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { 37672b9c00cbSConrad Meyer { /* "default" - for any srcSize > 256 KB */ 37680c16b537SWarner Losh /* W, C, H, S, L, TL, strat */ 376919fcbaf1SConrad Meyer { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ 37700f743729SConrad Meyer { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ 3771a0483764SConrad Meyer { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ 3772a0483764SConrad Meyer { 21, 16, 17, 1, 5, 1, ZSTD_dfast }, /* level 3 */ 3773a0483764SConrad Meyer { 21, 18, 18, 1, 5, 1, ZSTD_dfast }, /* level 4 */ 3774a0483764SConrad Meyer { 21, 18, 19, 2, 5, 2, ZSTD_greedy }, /* level 5 */ 3775a0483764SConrad Meyer { 21, 19, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */ 3776a0483764SConrad Meyer { 21, 19, 19, 3, 5, 8, ZSTD_lazy }, /* level 7 */ 37770f743729SConrad Meyer { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ 37780f743729SConrad Meyer { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ 3779a0483764SConrad Meyer { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ 3780a0483764SConrad Meyer { 22, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ 3781a0483764SConrad Meyer { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ 3782a0483764SConrad Meyer { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 13 */ 3783a0483764SConrad Meyer { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ 3784a0483764SConrad Meyer { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ 3785a0483764SConrad Meyer { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ 3786a0483764SConrad Meyer { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ 3787a0483764SConrad Meyer { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ 3788a0483764SConrad Meyer { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ 3789a0483764SConrad Meyer { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ 3790a0483764SConrad Meyer { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ 3791a0483764SConrad Meyer { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ 37920c16b537SWarner Losh }, 37930c16b537SWarner Losh { /* for srcSize <= 256 KB */ 37940c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 379519fcbaf1SConrad Meyer { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 37960f743729SConrad Meyer { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ 37970f743729SConrad Meyer { 18, 14, 14, 1, 5, 1, ZSTD_dfast }, /* level 2 */ 37980f743729SConrad Meyer { 18, 16, 16, 1, 4, 1, ZSTD_dfast }, /* level 3 */ 37990f743729SConrad Meyer { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/ 38000f743729SConrad Meyer { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/ 38010f743729SConrad Meyer { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ 38020f743729SConrad Meyer { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ 38030f743729SConrad Meyer { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 38040f743729SConrad Meyer { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 38050f743729SConrad Meyer { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 3806a0483764SConrad Meyer { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ 3807a0483764SConrad Meyer { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ 3808a0483764SConrad Meyer { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ 3809a0483764SConrad Meyer { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ 3810a0483764SConrad Meyer { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ 3811a0483764SConrad Meyer { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ 3812a0483764SConrad Meyer { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ 3813a0483764SConrad Meyer { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ 3814a0483764SConrad Meyer { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ 3815a0483764SConrad Meyer { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ 3816a0483764SConrad Meyer { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ 3817a0483764SConrad Meyer { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ 38180c16b537SWarner Losh }, 38190c16b537SWarner Losh { /* for srcSize <= 128 KB */ 38200c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 38210f743729SConrad Meyer { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 38220f743729SConrad Meyer { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ 38230f743729SConrad Meyer { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ 38240f743729SConrad Meyer { 17, 15, 16, 2, 5, 1, ZSTD_dfast }, /* level 3 */ 38250f743729SConrad Meyer { 17, 17, 17, 2, 4, 1, ZSTD_dfast }, /* level 4 */ 38260f743729SConrad Meyer { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ 38270f743729SConrad Meyer { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ 38280f743729SConrad Meyer { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ 38290c16b537SWarner Losh { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 38300c16b537SWarner Losh { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 38310c16b537SWarner Losh { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 3832a0483764SConrad Meyer { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ 3833a0483764SConrad Meyer { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ 3834a0483764SConrad Meyer { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ 3835a0483764SConrad Meyer { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ 3836a0483764SConrad Meyer { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ 3837a0483764SConrad Meyer { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ 3838a0483764SConrad Meyer { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ 3839a0483764SConrad Meyer { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ 3840a0483764SConrad Meyer { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ 3841a0483764SConrad Meyer { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ 3842a0483764SConrad Meyer { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ 3843a0483764SConrad Meyer { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ 38440c16b537SWarner Losh }, 38450c16b537SWarner Losh { /* for srcSize <= 16 KB */ 38460c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 384719fcbaf1SConrad Meyer { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 38480f743729SConrad Meyer { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ 38490f743729SConrad Meyer { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ 3850a0483764SConrad Meyer { 14, 14, 15, 2, 4, 1, ZSTD_dfast }, /* level 3 */ 3851a0483764SConrad Meyer { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ 38520f743729SConrad Meyer { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ 38530f743729SConrad Meyer { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ 38540f743729SConrad Meyer { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ 38550f743729SConrad Meyer { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ 38560f743729SConrad Meyer { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ 38570f743729SConrad Meyer { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ 38580f743729SConrad Meyer { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ 3859a0483764SConrad Meyer { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ 3860a0483764SConrad Meyer { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ 3861a0483764SConrad Meyer { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ 3862a0483764SConrad Meyer { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ 3863a0483764SConrad Meyer { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ 3864a0483764SConrad Meyer { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ 3865a0483764SConrad Meyer { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ 3866a0483764SConrad Meyer { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ 3867a0483764SConrad Meyer { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ 3868a0483764SConrad Meyer { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ 3869a0483764SConrad Meyer { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ 38700c16b537SWarner Losh }, 38710c16b537SWarner Losh }; 38720c16b537SWarner Losh 38730c16b537SWarner Losh /*! ZSTD_getCParams() : 387419fcbaf1SConrad Meyer * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. 38750c16b537SWarner Losh * Size values are optional, provide 0 if not known or unused */ 38760c16b537SWarner Losh ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) 38770c16b537SWarner Losh { 38780c16b537SWarner Losh size_t const addedSize = srcSizeHint ? 0 : 500; 38792b9c00cbSConrad Meyer U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : ZSTD_CONTENTSIZE_UNKNOWN; /* intentional overflow for srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN */ 38802b9c00cbSConrad Meyer U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); 388119fcbaf1SConrad Meyer int row = compressionLevel; 388219fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_getCParams (cLevel=%i)", compressionLevel); 388319fcbaf1SConrad Meyer if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ 388419fcbaf1SConrad Meyer if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ 388519fcbaf1SConrad Meyer if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; 388619fcbaf1SConrad Meyer { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row]; 388719fcbaf1SConrad Meyer if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */ 38882b9c00cbSConrad Meyer return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); /* refine parameters based on srcSize & dictSize */ 3889a0483764SConrad Meyer } 38900c16b537SWarner Losh } 38910c16b537SWarner Losh 38920c16b537SWarner Losh /*! ZSTD_getParams() : 38932b9c00cbSConrad Meyer * same idea as ZSTD_getCParams() 38942b9c00cbSConrad Meyer * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). 38952b9c00cbSConrad Meyer * Fields of `ZSTD_frameParameters` are set to default values */ 38960c16b537SWarner Losh ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { 38970c16b537SWarner Losh ZSTD_parameters params; 38980c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize); 389919fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel); 39000c16b537SWarner Losh memset(¶ms, 0, sizeof(params)); 39010c16b537SWarner Losh params.cParams = cParams; 3902052d3c12SConrad Meyer params.fParams.contentSizeFlag = 1; 39030c16b537SWarner Losh return params; 39040c16b537SWarner Losh } 3905