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" 240c16b537SWarner Losh #include "zstd_fast.h" 250c16b537SWarner Losh #include "zstd_double_fast.h" 260c16b537SWarner Losh #include "zstd_lazy.h" 270c16b537SWarner Losh #include "zstd_opt.h" 280c16b537SWarner Losh #include "zstd_ldm.h" 290c16b537SWarner Losh 300c16b537SWarner Losh 310c16b537SWarner Losh /*-************************************* 320c16b537SWarner Losh * Helper functions 330c16b537SWarner Losh ***************************************/ 340c16b537SWarner Losh size_t ZSTD_compressBound(size_t srcSize) { 350c16b537SWarner Losh return ZSTD_COMPRESSBOUND(srcSize); 360c16b537SWarner Losh } 370c16b537SWarner Losh 380c16b537SWarner Losh 390c16b537SWarner Losh /*-************************************* 400c16b537SWarner Losh * Context memory management 410c16b537SWarner Losh ***************************************/ 420c16b537SWarner Losh struct ZSTD_CDict_s { 430c16b537SWarner Losh void* dictBuffer; 440c16b537SWarner Losh const void* dictContent; 450c16b537SWarner Losh size_t dictContentSize; 4619fcbaf1SConrad Meyer void* workspace; 4719fcbaf1SConrad Meyer size_t workspaceSize; 4819fcbaf1SConrad Meyer ZSTD_matchState_t matchState; 4919fcbaf1SConrad Meyer ZSTD_compressedBlockState_t cBlockState; 5019fcbaf1SConrad Meyer ZSTD_customMem customMem; 5119fcbaf1SConrad Meyer U32 dictID; 520c16b537SWarner Losh }; /* typedef'd to ZSTD_CDict within "zstd.h" */ 530c16b537SWarner Losh 540c16b537SWarner Losh ZSTD_CCtx* ZSTD_createCCtx(void) 550c16b537SWarner Losh { 560c16b537SWarner Losh return ZSTD_createCCtx_advanced(ZSTD_defaultCMem); 570c16b537SWarner Losh } 580c16b537SWarner Losh 590f743729SConrad Meyer static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager) 600f743729SConrad Meyer { 610f743729SConrad Meyer assert(cctx != NULL); 620f743729SConrad Meyer memset(cctx, 0, sizeof(*cctx)); 630f743729SConrad Meyer cctx->customMem = memManager; 640f743729SConrad Meyer cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); 65a0483764SConrad Meyer { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters); 660f743729SConrad Meyer assert(!ZSTD_isError(err)); 670f743729SConrad Meyer (void)err; 680f743729SConrad Meyer } 690f743729SConrad Meyer } 700f743729SConrad Meyer 710c16b537SWarner Losh ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) 720c16b537SWarner Losh { 7319fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(zcss_init==0); 7419fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); 750c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 760f743729SConrad Meyer { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem); 770c16b537SWarner Losh if (!cctx) return NULL; 780f743729SConrad Meyer ZSTD_initCCtx(cctx, customMem); 790c16b537SWarner Losh return cctx; 800c16b537SWarner Losh } 8119fcbaf1SConrad Meyer } 820c16b537SWarner Losh 830c16b537SWarner Losh ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize) 840c16b537SWarner Losh { 850c16b537SWarner Losh ZSTD_CCtx* const cctx = (ZSTD_CCtx*) workspace; 860c16b537SWarner Losh if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */ 870c16b537SWarner Losh if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */ 880c16b537SWarner Losh memset(workspace, 0, workspaceSize); /* may be a bit generous, could memset be smaller ? */ 890c16b537SWarner Losh cctx->staticSize = workspaceSize; 900c16b537SWarner Losh cctx->workSpace = (void*)(cctx+1); 910c16b537SWarner Losh cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx); 920c16b537SWarner Losh 9319fcbaf1SConrad Meyer /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ 9419fcbaf1SConrad Meyer if (cctx->workSpaceSize < HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t)) return NULL; 950c16b537SWarner Losh assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */ 9619fcbaf1SConrad Meyer cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)cctx->workSpace; 9719fcbaf1SConrad Meyer cctx->blockState.nextCBlock = cctx->blockState.prevCBlock + 1; 9819fcbaf1SConrad Meyer { 9919fcbaf1SConrad Meyer void* const ptr = cctx->blockState.nextCBlock + 1; 10019fcbaf1SConrad Meyer cctx->entropyWorkspace = (U32*)ptr; 10119fcbaf1SConrad Meyer } 10219fcbaf1SConrad Meyer cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); 1030c16b537SWarner Losh return cctx; 1040c16b537SWarner Losh } 1050c16b537SWarner Losh 106*2b9c00cbSConrad Meyer /** 107*2b9c00cbSConrad Meyer * Clears and frees all of the dictionaries in the CCtx. 108*2b9c00cbSConrad Meyer */ 109*2b9c00cbSConrad Meyer static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx) 110*2b9c00cbSConrad Meyer { 111*2b9c00cbSConrad Meyer ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem); 112*2b9c00cbSConrad Meyer ZSTD_freeCDict(cctx->localDict.cdict); 113*2b9c00cbSConrad Meyer memset(&cctx->localDict, 0, sizeof(cctx->localDict)); 114*2b9c00cbSConrad Meyer memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); 115*2b9c00cbSConrad Meyer cctx->cdict = NULL; 116*2b9c00cbSConrad Meyer } 117*2b9c00cbSConrad Meyer 118*2b9c00cbSConrad Meyer static size_t ZSTD_sizeof_localDict(ZSTD_localDict dict) 119*2b9c00cbSConrad Meyer { 120*2b9c00cbSConrad Meyer size_t const bufferSize = dict.dictBuffer != NULL ? dict.dictSize : 0; 121*2b9c00cbSConrad Meyer size_t const cdictSize = ZSTD_sizeof_CDict(dict.cdict); 122*2b9c00cbSConrad Meyer return bufferSize + cdictSize; 123*2b9c00cbSConrad Meyer } 124*2b9c00cbSConrad Meyer 1250f743729SConrad Meyer static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx) 1260c16b537SWarner Losh { 1270f743729SConrad Meyer assert(cctx != NULL); 1280f743729SConrad Meyer assert(cctx->staticSize == 0); 12919fcbaf1SConrad Meyer ZSTD_free(cctx->workSpace, cctx->customMem); cctx->workSpace = NULL; 130*2b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); 1310c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 13219fcbaf1SConrad Meyer ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL; 1330c16b537SWarner Losh #endif 1340f743729SConrad Meyer } 1350f743729SConrad Meyer 1360f743729SConrad Meyer size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) 1370f743729SConrad Meyer { 1380f743729SConrad Meyer if (cctx==NULL) return 0; /* support free on NULL */ 139*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->staticSize, memory_allocation, 140*2b9c00cbSConrad Meyer "not compatible with static CCtx"); 1410f743729SConrad Meyer ZSTD_freeCCtxContent(cctx); 1420c16b537SWarner Losh ZSTD_free(cctx, cctx->customMem); 1430f743729SConrad Meyer return 0; 1440c16b537SWarner Losh } 1450c16b537SWarner Losh 1460c16b537SWarner Losh 1470c16b537SWarner Losh static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx) 1480c16b537SWarner Losh { 1490c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 1500c16b537SWarner Losh return ZSTDMT_sizeof_CCtx(cctx->mtctx); 1510c16b537SWarner Losh #else 1520c16b537SWarner Losh (void)cctx; 1530c16b537SWarner Losh return 0; 1540c16b537SWarner Losh #endif 1550c16b537SWarner Losh } 1560c16b537SWarner Losh 1570c16b537SWarner Losh 1580c16b537SWarner Losh size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) 1590c16b537SWarner Losh { 1600c16b537SWarner Losh if (cctx==NULL) return 0; /* support sizeof on NULL */ 1610c16b537SWarner Losh return sizeof(*cctx) + cctx->workSpaceSize 162*2b9c00cbSConrad Meyer + ZSTD_sizeof_localDict(cctx->localDict) 1630c16b537SWarner Losh + ZSTD_sizeof_mtctx(cctx); 1640c16b537SWarner Losh } 1650c16b537SWarner Losh 1660c16b537SWarner Losh size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) 1670c16b537SWarner Losh { 1680c16b537SWarner Losh return ZSTD_sizeof_CCtx(zcs); /* same object */ 1690c16b537SWarner Losh } 1700c16b537SWarner Losh 1710c16b537SWarner Losh /* private API call, for dictBuilder only */ 1720c16b537SWarner Losh const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } 1730c16b537SWarner Losh 1740c16b537SWarner Losh static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( 1750c16b537SWarner Losh ZSTD_compressionParameters cParams) 1760c16b537SWarner Losh { 1770c16b537SWarner Losh ZSTD_CCtx_params cctxParams; 1780c16b537SWarner Losh memset(&cctxParams, 0, sizeof(cctxParams)); 1790c16b537SWarner Losh cctxParams.cParams = cParams; 18019fcbaf1SConrad Meyer cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 18119fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 18219fcbaf1SConrad Meyer cctxParams.fParams.contentSizeFlag = 1; 1830c16b537SWarner Losh return cctxParams; 1840c16b537SWarner Losh } 1850c16b537SWarner Losh 1860c16b537SWarner Losh static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced( 1870c16b537SWarner Losh ZSTD_customMem customMem) 1880c16b537SWarner Losh { 1890c16b537SWarner Losh ZSTD_CCtx_params* params; 1900c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 1910c16b537SWarner Losh params = (ZSTD_CCtx_params*)ZSTD_calloc( 1920c16b537SWarner Losh sizeof(ZSTD_CCtx_params), customMem); 1930c16b537SWarner Losh if (!params) { return NULL; } 1940c16b537SWarner Losh params->customMem = customMem; 1950c16b537SWarner Losh params->compressionLevel = ZSTD_CLEVEL_DEFAULT; 19619fcbaf1SConrad Meyer params->fParams.contentSizeFlag = 1; 1970c16b537SWarner Losh return params; 1980c16b537SWarner Losh } 1990c16b537SWarner Losh 2000c16b537SWarner Losh ZSTD_CCtx_params* ZSTD_createCCtxParams(void) 2010c16b537SWarner Losh { 2020c16b537SWarner Losh return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem); 2030c16b537SWarner Losh } 2040c16b537SWarner Losh 2050c16b537SWarner Losh size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) 2060c16b537SWarner Losh { 2070c16b537SWarner Losh if (params == NULL) { return 0; } 2080c16b537SWarner Losh ZSTD_free(params, params->customMem); 2090c16b537SWarner Losh return 0; 2100c16b537SWarner Losh } 2110c16b537SWarner Losh 21219fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params) 2130c16b537SWarner Losh { 21419fcbaf1SConrad Meyer return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); 2150c16b537SWarner Losh } 2160c16b537SWarner Losh 21719fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) { 218*2b9c00cbSConrad Meyer RETURN_ERROR_IF(!cctxParams, GENERIC); 2190c16b537SWarner Losh memset(cctxParams, 0, sizeof(*cctxParams)); 2200c16b537SWarner Losh cctxParams->compressionLevel = compressionLevel; 22119fcbaf1SConrad Meyer cctxParams->fParams.contentSizeFlag = 1; 2220c16b537SWarner Losh return 0; 2230c16b537SWarner Losh } 2240c16b537SWarner Losh 22519fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) 2260c16b537SWarner Losh { 227*2b9c00cbSConrad Meyer RETURN_ERROR_IF(!cctxParams, GENERIC); 228*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) ); 2290c16b537SWarner Losh memset(cctxParams, 0, sizeof(*cctxParams)); 2300c16b537SWarner Losh cctxParams->cParams = params.cParams; 2310c16b537SWarner Losh cctxParams->fParams = params.fParams; 23219fcbaf1SConrad Meyer cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 23319fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(params.cParams)); 2340c16b537SWarner Losh return 0; 2350c16b537SWarner Losh } 2360c16b537SWarner Losh 23719fcbaf1SConrad Meyer /* ZSTD_assignParamsToCCtxParams() : 23819fcbaf1SConrad Meyer * params is presumed valid at this stage */ 2390c16b537SWarner Losh static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( 2400c16b537SWarner Losh ZSTD_CCtx_params cctxParams, ZSTD_parameters params) 2410c16b537SWarner Losh { 2420c16b537SWarner Losh ZSTD_CCtx_params ret = cctxParams; 2430c16b537SWarner Losh ret.cParams = params.cParams; 2440c16b537SWarner Losh ret.fParams = params.fParams; 24519fcbaf1SConrad Meyer ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 24619fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(params.cParams)); 2470c16b537SWarner Losh return ret; 2480c16b537SWarner Losh } 2490c16b537SWarner Losh 250a0483764SConrad Meyer ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param) 251a0483764SConrad Meyer { 252a0483764SConrad Meyer ZSTD_bounds bounds = { 0, 0, 0 }; 253a0483764SConrad Meyer 254a0483764SConrad Meyer switch(param) 255a0483764SConrad Meyer { 256a0483764SConrad Meyer case ZSTD_c_compressionLevel: 257a0483764SConrad Meyer bounds.lowerBound = ZSTD_minCLevel(); 258a0483764SConrad Meyer bounds.upperBound = ZSTD_maxCLevel(); 259a0483764SConrad Meyer return bounds; 260a0483764SConrad Meyer 261a0483764SConrad Meyer case ZSTD_c_windowLog: 262a0483764SConrad Meyer bounds.lowerBound = ZSTD_WINDOWLOG_MIN; 263a0483764SConrad Meyer bounds.upperBound = ZSTD_WINDOWLOG_MAX; 264a0483764SConrad Meyer return bounds; 265a0483764SConrad Meyer 266a0483764SConrad Meyer case ZSTD_c_hashLog: 267a0483764SConrad Meyer bounds.lowerBound = ZSTD_HASHLOG_MIN; 268a0483764SConrad Meyer bounds.upperBound = ZSTD_HASHLOG_MAX; 269a0483764SConrad Meyer return bounds; 270a0483764SConrad Meyer 271a0483764SConrad Meyer case ZSTD_c_chainLog: 272a0483764SConrad Meyer bounds.lowerBound = ZSTD_CHAINLOG_MIN; 273a0483764SConrad Meyer bounds.upperBound = ZSTD_CHAINLOG_MAX; 274a0483764SConrad Meyer return bounds; 275a0483764SConrad Meyer 276a0483764SConrad Meyer case ZSTD_c_searchLog: 277a0483764SConrad Meyer bounds.lowerBound = ZSTD_SEARCHLOG_MIN; 278a0483764SConrad Meyer bounds.upperBound = ZSTD_SEARCHLOG_MAX; 279a0483764SConrad Meyer return bounds; 280a0483764SConrad Meyer 281a0483764SConrad Meyer case ZSTD_c_minMatch: 282a0483764SConrad Meyer bounds.lowerBound = ZSTD_MINMATCH_MIN; 283a0483764SConrad Meyer bounds.upperBound = ZSTD_MINMATCH_MAX; 284a0483764SConrad Meyer return bounds; 285a0483764SConrad Meyer 286a0483764SConrad Meyer case ZSTD_c_targetLength: 287a0483764SConrad Meyer bounds.lowerBound = ZSTD_TARGETLENGTH_MIN; 288a0483764SConrad Meyer bounds.upperBound = ZSTD_TARGETLENGTH_MAX; 289a0483764SConrad Meyer return bounds; 290a0483764SConrad Meyer 291a0483764SConrad Meyer case ZSTD_c_strategy: 292a0483764SConrad Meyer bounds.lowerBound = ZSTD_STRATEGY_MIN; 293a0483764SConrad Meyer bounds.upperBound = ZSTD_STRATEGY_MAX; 294a0483764SConrad Meyer return bounds; 295a0483764SConrad Meyer 296a0483764SConrad Meyer case ZSTD_c_contentSizeFlag: 297a0483764SConrad Meyer bounds.lowerBound = 0; 298a0483764SConrad Meyer bounds.upperBound = 1; 299a0483764SConrad Meyer return bounds; 300a0483764SConrad Meyer 301a0483764SConrad Meyer case ZSTD_c_checksumFlag: 302a0483764SConrad Meyer bounds.lowerBound = 0; 303a0483764SConrad Meyer bounds.upperBound = 1; 304a0483764SConrad Meyer return bounds; 305a0483764SConrad Meyer 306a0483764SConrad Meyer case ZSTD_c_dictIDFlag: 307a0483764SConrad Meyer bounds.lowerBound = 0; 308a0483764SConrad Meyer bounds.upperBound = 1; 309a0483764SConrad Meyer return bounds; 310a0483764SConrad Meyer 311a0483764SConrad Meyer case ZSTD_c_nbWorkers: 312a0483764SConrad Meyer bounds.lowerBound = 0; 313a0483764SConrad Meyer #ifdef ZSTD_MULTITHREAD 314a0483764SConrad Meyer bounds.upperBound = ZSTDMT_NBWORKERS_MAX; 315a0483764SConrad Meyer #else 316a0483764SConrad Meyer bounds.upperBound = 0; 317a0483764SConrad Meyer #endif 318a0483764SConrad Meyer return bounds; 319a0483764SConrad Meyer 320a0483764SConrad Meyer case ZSTD_c_jobSize: 321a0483764SConrad Meyer bounds.lowerBound = 0; 322a0483764SConrad Meyer #ifdef ZSTD_MULTITHREAD 323a0483764SConrad Meyer bounds.upperBound = ZSTDMT_JOBSIZE_MAX; 324a0483764SConrad Meyer #else 325a0483764SConrad Meyer bounds.upperBound = 0; 326a0483764SConrad Meyer #endif 327a0483764SConrad Meyer return bounds; 328a0483764SConrad Meyer 329a0483764SConrad Meyer case ZSTD_c_overlapLog: 330a0483764SConrad Meyer bounds.lowerBound = ZSTD_OVERLAPLOG_MIN; 331a0483764SConrad Meyer bounds.upperBound = ZSTD_OVERLAPLOG_MAX; 332a0483764SConrad Meyer return bounds; 333a0483764SConrad Meyer 334a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching: 335a0483764SConrad Meyer bounds.lowerBound = 0; 336a0483764SConrad Meyer bounds.upperBound = 1; 337a0483764SConrad Meyer return bounds; 338a0483764SConrad Meyer 339a0483764SConrad Meyer case ZSTD_c_ldmHashLog: 340a0483764SConrad Meyer bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN; 341a0483764SConrad Meyer bounds.upperBound = ZSTD_LDM_HASHLOG_MAX; 342a0483764SConrad Meyer return bounds; 343a0483764SConrad Meyer 344a0483764SConrad Meyer case ZSTD_c_ldmMinMatch: 345a0483764SConrad Meyer bounds.lowerBound = ZSTD_LDM_MINMATCH_MIN; 346a0483764SConrad Meyer bounds.upperBound = ZSTD_LDM_MINMATCH_MAX; 347a0483764SConrad Meyer return bounds; 348a0483764SConrad Meyer 349a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog: 350a0483764SConrad Meyer bounds.lowerBound = ZSTD_LDM_BUCKETSIZELOG_MIN; 351a0483764SConrad Meyer bounds.upperBound = ZSTD_LDM_BUCKETSIZELOG_MAX; 352a0483764SConrad Meyer return bounds; 353a0483764SConrad Meyer 354a0483764SConrad Meyer case ZSTD_c_ldmHashRateLog: 355a0483764SConrad Meyer bounds.lowerBound = ZSTD_LDM_HASHRATELOG_MIN; 356a0483764SConrad Meyer bounds.upperBound = ZSTD_LDM_HASHRATELOG_MAX; 357a0483764SConrad Meyer return bounds; 358a0483764SConrad Meyer 359a0483764SConrad Meyer /* experimental parameters */ 360a0483764SConrad Meyer case ZSTD_c_rsyncable: 361a0483764SConrad Meyer bounds.lowerBound = 0; 362a0483764SConrad Meyer bounds.upperBound = 1; 363a0483764SConrad Meyer return bounds; 364a0483764SConrad Meyer 365a0483764SConrad Meyer case ZSTD_c_forceMaxWindow : 366a0483764SConrad Meyer bounds.lowerBound = 0; 367a0483764SConrad Meyer bounds.upperBound = 1; 368a0483764SConrad Meyer return bounds; 369a0483764SConrad Meyer 370a0483764SConrad Meyer case ZSTD_c_format: 371a0483764SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless); 372a0483764SConrad Meyer bounds.lowerBound = ZSTD_f_zstd1; 373a0483764SConrad Meyer bounds.upperBound = ZSTD_f_zstd1_magicless; /* note : how to ensure at compile time that this is the highest value enum ? */ 374a0483764SConrad Meyer return bounds; 375a0483764SConrad Meyer 376a0483764SConrad Meyer case ZSTD_c_forceAttachDict: 377a0483764SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy); 378a0483764SConrad Meyer bounds.lowerBound = ZSTD_dictDefaultAttach; 379a0483764SConrad Meyer bounds.upperBound = ZSTD_dictForceCopy; /* note : how to ensure at compile time that this is the highest value enum ? */ 380a0483764SConrad Meyer return bounds; 381a0483764SConrad Meyer 382*2b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode: 383*2b9c00cbSConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed); 384*2b9c00cbSConrad Meyer bounds.lowerBound = ZSTD_lcm_auto; 385*2b9c00cbSConrad Meyer bounds.upperBound = ZSTD_lcm_uncompressed; 386*2b9c00cbSConrad Meyer return bounds; 387*2b9c00cbSConrad Meyer 388a0483764SConrad Meyer default: 389a0483764SConrad Meyer { ZSTD_bounds const boundError = { ERROR(parameter_unsupported), 0, 0 }; 390a0483764SConrad Meyer return boundError; 391a0483764SConrad Meyer } 392a0483764SConrad Meyer } 393a0483764SConrad Meyer } 394a0483764SConrad Meyer 395a0483764SConrad Meyer /* ZSTD_cParam_withinBounds: 396a0483764SConrad Meyer * @return 1 if value is within cParam bounds, 397a0483764SConrad Meyer * 0 otherwise */ 398a0483764SConrad Meyer static int ZSTD_cParam_withinBounds(ZSTD_cParameter cParam, int value) 399a0483764SConrad Meyer { 400a0483764SConrad Meyer ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); 401a0483764SConrad Meyer if (ZSTD_isError(bounds.error)) return 0; 402a0483764SConrad Meyer if (value < bounds.lowerBound) return 0; 403a0483764SConrad Meyer if (value > bounds.upperBound) return 0; 404a0483764SConrad Meyer return 1; 405a0483764SConrad Meyer } 406a0483764SConrad Meyer 407*2b9c00cbSConrad Meyer /* ZSTD_cParam_clampBounds: 408*2b9c00cbSConrad Meyer * Clamps the value into the bounded range. 409*2b9c00cbSConrad Meyer */ 410*2b9c00cbSConrad Meyer static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value) 411*2b9c00cbSConrad Meyer { 412*2b9c00cbSConrad Meyer ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); 413*2b9c00cbSConrad Meyer if (ZSTD_isError(bounds.error)) return bounds.error; 414*2b9c00cbSConrad Meyer if (*value < bounds.lowerBound) *value = bounds.lowerBound; 415*2b9c00cbSConrad Meyer if (*value > bounds.upperBound) *value = bounds.upperBound; 416*2b9c00cbSConrad Meyer return 0; 417*2b9c00cbSConrad Meyer } 418*2b9c00cbSConrad Meyer 419a0483764SConrad Meyer #define BOUNDCHECK(cParam, val) { \ 420*2b9c00cbSConrad Meyer RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \ 421*2b9c00cbSConrad Meyer parameter_outOfBound); \ 422*2b9c00cbSConrad Meyer } 4230c16b537SWarner Losh 42419fcbaf1SConrad Meyer 42519fcbaf1SConrad Meyer static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) 42619fcbaf1SConrad Meyer { 42719fcbaf1SConrad Meyer switch(param) 42819fcbaf1SConrad Meyer { 429a0483764SConrad Meyer case ZSTD_c_compressionLevel: 430a0483764SConrad Meyer case ZSTD_c_hashLog: 431a0483764SConrad Meyer case ZSTD_c_chainLog: 432a0483764SConrad Meyer case ZSTD_c_searchLog: 433a0483764SConrad Meyer case ZSTD_c_minMatch: 434a0483764SConrad Meyer case ZSTD_c_targetLength: 435a0483764SConrad Meyer case ZSTD_c_strategy: 43619fcbaf1SConrad Meyer return 1; 43719fcbaf1SConrad Meyer 438a0483764SConrad Meyer case ZSTD_c_format: 439a0483764SConrad Meyer case ZSTD_c_windowLog: 440a0483764SConrad Meyer case ZSTD_c_contentSizeFlag: 441a0483764SConrad Meyer case ZSTD_c_checksumFlag: 442a0483764SConrad Meyer case ZSTD_c_dictIDFlag: 443a0483764SConrad Meyer case ZSTD_c_forceMaxWindow : 444a0483764SConrad Meyer case ZSTD_c_nbWorkers: 445a0483764SConrad Meyer case ZSTD_c_jobSize: 446a0483764SConrad Meyer case ZSTD_c_overlapLog: 447a0483764SConrad Meyer case ZSTD_c_rsyncable: 448a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching: 449a0483764SConrad Meyer case ZSTD_c_ldmHashLog: 450a0483764SConrad Meyer case ZSTD_c_ldmMinMatch: 451a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog: 452a0483764SConrad Meyer case ZSTD_c_ldmHashRateLog: 453a0483764SConrad Meyer case ZSTD_c_forceAttachDict: 454*2b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode: 45519fcbaf1SConrad Meyer default: 45619fcbaf1SConrad Meyer return 0; 45719fcbaf1SConrad Meyer } 45819fcbaf1SConrad Meyer } 45919fcbaf1SConrad Meyer 460a0483764SConrad Meyer size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value) 4610c16b537SWarner Losh { 462a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setParameter (%i, %i)", (int)param, value); 46319fcbaf1SConrad Meyer if (cctx->streamStage != zcss_init) { 46419fcbaf1SConrad Meyer if (ZSTD_isUpdateAuthorized(param)) { 46519fcbaf1SConrad Meyer cctx->cParamsChanged = 1; 46619fcbaf1SConrad Meyer } else { 467*2b9c00cbSConrad Meyer RETURN_ERROR(stage_wrong); 46819fcbaf1SConrad Meyer } } 4690c16b537SWarner Losh 4700c16b537SWarner Losh switch(param) 4710c16b537SWarner Losh { 472*2b9c00cbSConrad Meyer case ZSTD_c_nbWorkers: 473*2b9c00cbSConrad Meyer RETURN_ERROR_IF((value!=0) && cctx->staticSize, parameter_unsupported, 474*2b9c00cbSConrad Meyer "MT not compatible with static alloc"); 475*2b9c00cbSConrad Meyer break; 4760c16b537SWarner Losh 477a0483764SConrad Meyer case ZSTD_c_compressionLevel: 478a0483764SConrad Meyer case ZSTD_c_windowLog: 479a0483764SConrad Meyer case ZSTD_c_hashLog: 480a0483764SConrad Meyer case ZSTD_c_chainLog: 481a0483764SConrad Meyer case ZSTD_c_searchLog: 482a0483764SConrad Meyer case ZSTD_c_minMatch: 483a0483764SConrad Meyer case ZSTD_c_targetLength: 484a0483764SConrad Meyer case ZSTD_c_strategy: 485*2b9c00cbSConrad Meyer case ZSTD_c_ldmHashRateLog: 486*2b9c00cbSConrad Meyer case ZSTD_c_format: 487a0483764SConrad Meyer case ZSTD_c_contentSizeFlag: 488a0483764SConrad Meyer case ZSTD_c_checksumFlag: 489a0483764SConrad Meyer case ZSTD_c_dictIDFlag: 490*2b9c00cbSConrad Meyer case ZSTD_c_forceMaxWindow: 491a0483764SConrad Meyer case ZSTD_c_forceAttachDict: 492*2b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode: 493a0483764SConrad Meyer case ZSTD_c_jobSize: 494a0483764SConrad Meyer case ZSTD_c_overlapLog: 495a0483764SConrad Meyer case ZSTD_c_rsyncable: 496a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching: 497a0483764SConrad Meyer case ZSTD_c_ldmHashLog: 498a0483764SConrad Meyer case ZSTD_c_ldmMinMatch: 499a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog: 500*2b9c00cbSConrad Meyer break; 5010c16b537SWarner Losh 502*2b9c00cbSConrad Meyer default: RETURN_ERROR(parameter_unsupported); 5030c16b537SWarner Losh } 504*2b9c00cbSConrad Meyer return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value); 5050c16b537SWarner Losh } 5060c16b537SWarner Losh 507*2b9c00cbSConrad Meyer size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams, 508a0483764SConrad Meyer ZSTD_cParameter param, int value) 5090c16b537SWarner Losh { 510*2b9c00cbSConrad Meyer DEBUGLOG(4, "ZSTD_CCtxParams_setParameter (%i, %i)", (int)param, value); 5110c16b537SWarner Losh switch(param) 5120c16b537SWarner Losh { 513a0483764SConrad Meyer case ZSTD_c_format : 514a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_format, value); 515052d3c12SConrad Meyer CCtxParams->format = (ZSTD_format_e)value; 516052d3c12SConrad Meyer return (size_t)CCtxParams->format; 5170c16b537SWarner Losh 518a0483764SConrad Meyer case ZSTD_c_compressionLevel : { 519*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); 520*2b9c00cbSConrad Meyer if (value) { /* 0 : does not change current level */ 521*2b9c00cbSConrad Meyer CCtxParams->compressionLevel = value; 52219fcbaf1SConrad Meyer } 52319fcbaf1SConrad Meyer if (CCtxParams->compressionLevel >= 0) return CCtxParams->compressionLevel; 52419fcbaf1SConrad Meyer return 0; /* return type (size_t) cannot represent negative values */ 52519fcbaf1SConrad Meyer } 5260c16b537SWarner Losh 527a0483764SConrad Meyer case ZSTD_c_windowLog : 528a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 529a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_windowLog, value); 530052d3c12SConrad Meyer CCtxParams->cParams.windowLog = value; 531052d3c12SConrad Meyer return CCtxParams->cParams.windowLog; 5320c16b537SWarner Losh 533a0483764SConrad Meyer case ZSTD_c_hashLog : 534a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 535a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_hashLog, value); 536052d3c12SConrad Meyer CCtxParams->cParams.hashLog = value; 537052d3c12SConrad Meyer return CCtxParams->cParams.hashLog; 5380c16b537SWarner Losh 539a0483764SConrad Meyer case ZSTD_c_chainLog : 540a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 541a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_chainLog, value); 542052d3c12SConrad Meyer CCtxParams->cParams.chainLog = value; 543052d3c12SConrad Meyer return CCtxParams->cParams.chainLog; 5440c16b537SWarner Losh 545a0483764SConrad Meyer case ZSTD_c_searchLog : 546a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 547a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_searchLog, value); 548052d3c12SConrad Meyer CCtxParams->cParams.searchLog = value; 549052d3c12SConrad Meyer return value; 5500c16b537SWarner Losh 551a0483764SConrad Meyer case ZSTD_c_minMatch : 552a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 553a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_minMatch, value); 554a0483764SConrad Meyer CCtxParams->cParams.minMatch = value; 555a0483764SConrad Meyer return CCtxParams->cParams.minMatch; 5560c16b537SWarner Losh 557a0483764SConrad Meyer case ZSTD_c_targetLength : 558a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_targetLength, value); 559052d3c12SConrad Meyer CCtxParams->cParams.targetLength = value; 560052d3c12SConrad Meyer return CCtxParams->cParams.targetLength; 5610c16b537SWarner Losh 562a0483764SConrad Meyer case ZSTD_c_strategy : 563a0483764SConrad Meyer if (value!=0) /* 0 => use default */ 564a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_strategy, value); 565052d3c12SConrad Meyer CCtxParams->cParams.strategy = (ZSTD_strategy)value; 566052d3c12SConrad Meyer return (size_t)CCtxParams->cParams.strategy; 5670c16b537SWarner Losh 568a0483764SConrad Meyer case ZSTD_c_contentSizeFlag : 5690c16b537SWarner Losh /* Content size written in frame header _when known_ (default:1) */ 570a0483764SConrad Meyer DEBUGLOG(4, "set content size flag = %u", (value!=0)); 571a0483764SConrad Meyer CCtxParams->fParams.contentSizeFlag = value != 0; 572052d3c12SConrad Meyer return CCtxParams->fParams.contentSizeFlag; 5730c16b537SWarner Losh 574a0483764SConrad Meyer case ZSTD_c_checksumFlag : 5750c16b537SWarner Losh /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ 576a0483764SConrad Meyer CCtxParams->fParams.checksumFlag = value != 0; 577052d3c12SConrad Meyer return CCtxParams->fParams.checksumFlag; 5780c16b537SWarner Losh 579a0483764SConrad Meyer case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ 580a0483764SConrad Meyer DEBUGLOG(4, "set dictIDFlag = %u", (value!=0)); 58119fcbaf1SConrad Meyer CCtxParams->fParams.noDictIDFlag = !value; 582052d3c12SConrad Meyer return !CCtxParams->fParams.noDictIDFlag; 5830c16b537SWarner Losh 584a0483764SConrad Meyer case ZSTD_c_forceMaxWindow : 585a0483764SConrad Meyer CCtxParams->forceWindow = (value != 0); 586052d3c12SConrad Meyer return CCtxParams->forceWindow; 5870c16b537SWarner Losh 588a0483764SConrad Meyer case ZSTD_c_forceAttachDict : { 589a0483764SConrad Meyer const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value; 590a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_forceAttachDict, pref); 591a0483764SConrad Meyer CCtxParams->attachDictPref = pref; 5920f743729SConrad Meyer return CCtxParams->attachDictPref; 593a0483764SConrad Meyer } 5940f743729SConrad Meyer 595*2b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode : { 596*2b9c00cbSConrad Meyer const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value; 597*2b9c00cbSConrad Meyer BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm); 598*2b9c00cbSConrad Meyer CCtxParams->literalCompressionMode = lcm; 599*2b9c00cbSConrad Meyer return CCtxParams->literalCompressionMode; 600*2b9c00cbSConrad Meyer } 601*2b9c00cbSConrad Meyer 602a0483764SConrad Meyer case ZSTD_c_nbWorkers : 6030c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 604*2b9c00cbSConrad Meyer RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 60519fcbaf1SConrad Meyer return 0; 6060c16b537SWarner Losh #else 607*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); 608*2b9c00cbSConrad Meyer CCtxParams->nbWorkers = value; 609*2b9c00cbSConrad Meyer return CCtxParams->nbWorkers; 6100c16b537SWarner Losh #endif 6110c16b537SWarner Losh 612a0483764SConrad Meyer case ZSTD_c_jobSize : 6130c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 614*2b9c00cbSConrad Meyer RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 615*2b9c00cbSConrad Meyer return 0; 6160c16b537SWarner Losh #else 617*2b9c00cbSConrad Meyer /* Adjust to the minimum non-default value. */ 618*2b9c00cbSConrad Meyer if (value != 0 && value < ZSTDMT_JOBSIZE_MIN) 619*2b9c00cbSConrad Meyer value = ZSTDMT_JOBSIZE_MIN; 620*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value)); 621*2b9c00cbSConrad Meyer assert(value >= 0); 622*2b9c00cbSConrad Meyer CCtxParams->jobSize = value; 623*2b9c00cbSConrad Meyer return CCtxParams->jobSize; 6240c16b537SWarner Losh #endif 6250c16b537SWarner Losh 626a0483764SConrad Meyer case ZSTD_c_overlapLog : 6270c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 628*2b9c00cbSConrad Meyer RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 629*2b9c00cbSConrad Meyer return 0; 6300c16b537SWarner Losh #else 631*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value)); 632*2b9c00cbSConrad Meyer CCtxParams->overlapLog = value; 633*2b9c00cbSConrad Meyer return CCtxParams->overlapLog; 6340c16b537SWarner Losh #endif 6350c16b537SWarner Losh 636a0483764SConrad Meyer case ZSTD_c_rsyncable : 637a0483764SConrad Meyer #ifndef ZSTD_MULTITHREAD 638*2b9c00cbSConrad Meyer RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading"); 639*2b9c00cbSConrad Meyer return 0; 640a0483764SConrad Meyer #else 641*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value)); 642*2b9c00cbSConrad Meyer CCtxParams->rsyncable = value; 643*2b9c00cbSConrad Meyer return CCtxParams->rsyncable; 644a0483764SConrad Meyer #endif 645a0483764SConrad Meyer 646a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching : 647a0483764SConrad Meyer CCtxParams->ldmParams.enableLdm = (value!=0); 64819fcbaf1SConrad Meyer return CCtxParams->ldmParams.enableLdm; 6490c16b537SWarner Losh 650a0483764SConrad Meyer case ZSTD_c_ldmHashLog : 651a0483764SConrad Meyer if (value!=0) /* 0 ==> auto */ 652a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_ldmHashLog, value); 653052d3c12SConrad Meyer CCtxParams->ldmParams.hashLog = value; 654052d3c12SConrad Meyer return CCtxParams->ldmParams.hashLog; 6550c16b537SWarner Losh 656a0483764SConrad Meyer case ZSTD_c_ldmMinMatch : 657a0483764SConrad Meyer if (value!=0) /* 0 ==> default */ 658a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_ldmMinMatch, value); 659052d3c12SConrad Meyer CCtxParams->ldmParams.minMatchLength = value; 660052d3c12SConrad Meyer return CCtxParams->ldmParams.minMatchLength; 6610c16b537SWarner Losh 662a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog : 663a0483764SConrad Meyer if (value!=0) /* 0 ==> default */ 664a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value); 665052d3c12SConrad Meyer CCtxParams->ldmParams.bucketSizeLog = value; 66619fcbaf1SConrad Meyer return CCtxParams->ldmParams.bucketSizeLog; 6670c16b537SWarner Losh 668a0483764SConrad Meyer case ZSTD_c_ldmHashRateLog : 669*2b9c00cbSConrad Meyer RETURN_ERROR_IF(value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN, 670*2b9c00cbSConrad Meyer parameter_outOfBound); 671a0483764SConrad Meyer CCtxParams->ldmParams.hashRateLog = value; 672a0483764SConrad Meyer return CCtxParams->ldmParams.hashRateLog; 6730c16b537SWarner Losh 674*2b9c00cbSConrad Meyer default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); 6750c16b537SWarner Losh } 6760c16b537SWarner Losh } 6770c16b537SWarner Losh 678a0483764SConrad Meyer size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value) 6790f743729SConrad Meyer { 680*2b9c00cbSConrad Meyer return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value); 6810f743729SConrad Meyer } 6820f743729SConrad Meyer 683*2b9c00cbSConrad Meyer size_t ZSTD_CCtxParams_getParameter( 684a0483764SConrad Meyer ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value) 6850f743729SConrad Meyer { 6860f743729SConrad Meyer switch(param) 6870f743729SConrad Meyer { 688a0483764SConrad Meyer case ZSTD_c_format : 6890f743729SConrad Meyer *value = CCtxParams->format; 6900f743729SConrad Meyer break; 691a0483764SConrad Meyer case ZSTD_c_compressionLevel : 6920f743729SConrad Meyer *value = CCtxParams->compressionLevel; 6930f743729SConrad Meyer break; 694a0483764SConrad Meyer case ZSTD_c_windowLog : 6950f743729SConrad Meyer *value = CCtxParams->cParams.windowLog; 6960f743729SConrad Meyer break; 697a0483764SConrad Meyer case ZSTD_c_hashLog : 6980f743729SConrad Meyer *value = CCtxParams->cParams.hashLog; 6990f743729SConrad Meyer break; 700a0483764SConrad Meyer case ZSTD_c_chainLog : 7010f743729SConrad Meyer *value = CCtxParams->cParams.chainLog; 7020f743729SConrad Meyer break; 703a0483764SConrad Meyer case ZSTD_c_searchLog : 7040f743729SConrad Meyer *value = CCtxParams->cParams.searchLog; 7050f743729SConrad Meyer break; 706a0483764SConrad Meyer case ZSTD_c_minMatch : 707a0483764SConrad Meyer *value = CCtxParams->cParams.minMatch; 7080f743729SConrad Meyer break; 709a0483764SConrad Meyer case ZSTD_c_targetLength : 7100f743729SConrad Meyer *value = CCtxParams->cParams.targetLength; 7110f743729SConrad Meyer break; 712a0483764SConrad Meyer case ZSTD_c_strategy : 7130f743729SConrad Meyer *value = (unsigned)CCtxParams->cParams.strategy; 7140f743729SConrad Meyer break; 715a0483764SConrad Meyer case ZSTD_c_contentSizeFlag : 7160f743729SConrad Meyer *value = CCtxParams->fParams.contentSizeFlag; 7170f743729SConrad Meyer break; 718a0483764SConrad Meyer case ZSTD_c_checksumFlag : 7190f743729SConrad Meyer *value = CCtxParams->fParams.checksumFlag; 7200f743729SConrad Meyer break; 721a0483764SConrad Meyer case ZSTD_c_dictIDFlag : 7220f743729SConrad Meyer *value = !CCtxParams->fParams.noDictIDFlag; 7230f743729SConrad Meyer break; 724a0483764SConrad Meyer case ZSTD_c_forceMaxWindow : 7250f743729SConrad Meyer *value = CCtxParams->forceWindow; 7260f743729SConrad Meyer break; 727a0483764SConrad Meyer case ZSTD_c_forceAttachDict : 7280f743729SConrad Meyer *value = CCtxParams->attachDictPref; 7290f743729SConrad Meyer break; 730*2b9c00cbSConrad Meyer case ZSTD_c_literalCompressionMode : 731*2b9c00cbSConrad Meyer *value = CCtxParams->literalCompressionMode; 732*2b9c00cbSConrad Meyer break; 733a0483764SConrad Meyer case ZSTD_c_nbWorkers : 7340f743729SConrad Meyer #ifndef ZSTD_MULTITHREAD 7350f743729SConrad Meyer assert(CCtxParams->nbWorkers == 0); 7360f743729SConrad Meyer #endif 7370f743729SConrad Meyer *value = CCtxParams->nbWorkers; 7380f743729SConrad Meyer break; 739a0483764SConrad Meyer case ZSTD_c_jobSize : 7400f743729SConrad Meyer #ifndef ZSTD_MULTITHREAD 741*2b9c00cbSConrad Meyer RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 7420f743729SConrad Meyer #else 743a0483764SConrad Meyer assert(CCtxParams->jobSize <= INT_MAX); 744a0483764SConrad Meyer *value = (int)CCtxParams->jobSize; 7450f743729SConrad Meyer break; 7460f743729SConrad Meyer #endif 747a0483764SConrad Meyer case ZSTD_c_overlapLog : 7480f743729SConrad Meyer #ifndef ZSTD_MULTITHREAD 749*2b9c00cbSConrad Meyer RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 7500f743729SConrad Meyer #else 751a0483764SConrad Meyer *value = CCtxParams->overlapLog; 7520f743729SConrad Meyer break; 7530f743729SConrad Meyer #endif 754a0483764SConrad Meyer case ZSTD_c_rsyncable : 755a0483764SConrad Meyer #ifndef ZSTD_MULTITHREAD 756*2b9c00cbSConrad Meyer RETURN_ERROR(parameter_unsupported, "not compiled with multithreading"); 757a0483764SConrad Meyer #else 758a0483764SConrad Meyer *value = CCtxParams->rsyncable; 759a0483764SConrad Meyer break; 760a0483764SConrad Meyer #endif 761a0483764SConrad Meyer case ZSTD_c_enableLongDistanceMatching : 7620f743729SConrad Meyer *value = CCtxParams->ldmParams.enableLdm; 7630f743729SConrad Meyer break; 764a0483764SConrad Meyer case ZSTD_c_ldmHashLog : 7650f743729SConrad Meyer *value = CCtxParams->ldmParams.hashLog; 7660f743729SConrad Meyer break; 767a0483764SConrad Meyer case ZSTD_c_ldmMinMatch : 7680f743729SConrad Meyer *value = CCtxParams->ldmParams.minMatchLength; 7690f743729SConrad Meyer break; 770a0483764SConrad Meyer case ZSTD_c_ldmBucketSizeLog : 7710f743729SConrad Meyer *value = CCtxParams->ldmParams.bucketSizeLog; 7720f743729SConrad Meyer break; 773a0483764SConrad Meyer case ZSTD_c_ldmHashRateLog : 774a0483764SConrad Meyer *value = CCtxParams->ldmParams.hashRateLog; 7750f743729SConrad Meyer break; 776*2b9c00cbSConrad Meyer default: RETURN_ERROR(parameter_unsupported, "unknown parameter"); 7770f743729SConrad Meyer } 7780f743729SConrad Meyer return 0; 7790f743729SConrad Meyer } 7800f743729SConrad Meyer 781052d3c12SConrad Meyer /** ZSTD_CCtx_setParametersUsingCCtxParams() : 782052d3c12SConrad Meyer * just applies `params` into `cctx` 783052d3c12SConrad Meyer * no action is performed, parameters are merely stored. 78419fcbaf1SConrad Meyer * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx. 78519fcbaf1SConrad Meyer * This is possible even if a compression is ongoing. 78619fcbaf1SConrad Meyer * In which case, new parameters will be applied on the fly, starting with next compression job. 7870c16b537SWarner Losh */ 7880c16b537SWarner Losh size_t ZSTD_CCtx_setParametersUsingCCtxParams( 7890c16b537SWarner Losh ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) 7900c16b537SWarner Losh { 7910f743729SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams"); 792*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 793*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->cdict, stage_wrong); 7940c16b537SWarner Losh 795052d3c12SConrad Meyer cctx->requestedParams = *params; 7960c16b537SWarner Losh return 0; 7970c16b537SWarner Losh } 7980c16b537SWarner Losh 7990c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) 8000c16b537SWarner Losh { 801052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize); 802*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 8030c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; 8040c16b537SWarner Losh return 0; 8050c16b537SWarner Losh } 8060c16b537SWarner Losh 807*2b9c00cbSConrad Meyer /** 808*2b9c00cbSConrad Meyer * Initializes the local dict using the requested parameters. 809*2b9c00cbSConrad Meyer * NOTE: This does not use the pledged src size, because it may be used for more 810*2b9c00cbSConrad Meyer * than one compression. 811*2b9c00cbSConrad Meyer */ 812*2b9c00cbSConrad Meyer static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx) 813*2b9c00cbSConrad Meyer { 814*2b9c00cbSConrad Meyer ZSTD_localDict* const dl = &cctx->localDict; 815*2b9c00cbSConrad Meyer ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams( 816*2b9c00cbSConrad Meyer &cctx->requestedParams, 0, dl->dictSize); 817*2b9c00cbSConrad Meyer if (dl->dict == NULL) { 818*2b9c00cbSConrad Meyer /* No local dictionary. */ 819*2b9c00cbSConrad Meyer assert(dl->dictBuffer == NULL); 820*2b9c00cbSConrad Meyer assert(dl->cdict == NULL); 821*2b9c00cbSConrad Meyer assert(dl->dictSize == 0); 822*2b9c00cbSConrad Meyer return 0; 823*2b9c00cbSConrad Meyer } 824*2b9c00cbSConrad Meyer if (dl->cdict != NULL) { 825*2b9c00cbSConrad Meyer assert(cctx->cdict == dl->cdict); 826*2b9c00cbSConrad Meyer /* Local dictionary already initialized. */ 827*2b9c00cbSConrad Meyer return 0; 828*2b9c00cbSConrad Meyer } 829*2b9c00cbSConrad Meyer assert(dl->dictSize > 0); 830*2b9c00cbSConrad Meyer assert(cctx->cdict == NULL); 831*2b9c00cbSConrad Meyer assert(cctx->prefixDict.dict == NULL); 832*2b9c00cbSConrad Meyer 833*2b9c00cbSConrad Meyer dl->cdict = ZSTD_createCDict_advanced( 834*2b9c00cbSConrad Meyer dl->dict, 835*2b9c00cbSConrad Meyer dl->dictSize, 836*2b9c00cbSConrad Meyer ZSTD_dlm_byRef, 837*2b9c00cbSConrad Meyer dl->dictContentType, 838*2b9c00cbSConrad Meyer cParams, 839*2b9c00cbSConrad Meyer cctx->customMem); 840*2b9c00cbSConrad Meyer RETURN_ERROR_IF(!dl->cdict, memory_allocation); 841*2b9c00cbSConrad Meyer cctx->cdict = dl->cdict; 842*2b9c00cbSConrad Meyer return 0; 843*2b9c00cbSConrad Meyer } 844*2b9c00cbSConrad Meyer 8450c16b537SWarner Losh size_t ZSTD_CCtx_loadDictionary_advanced( 8460c16b537SWarner Losh ZSTD_CCtx* cctx, const void* dict, size_t dictSize, 84719fcbaf1SConrad Meyer ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType) 8480c16b537SWarner Losh { 849*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 850*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->staticSize, memory_allocation, 851*2b9c00cbSConrad Meyer "no malloc for static CCtx"); 852052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); 853*2b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); /* in case one already exists */ 854*2b9c00cbSConrad Meyer if (dict == NULL || dictSize == 0) /* no dictionary mode */ 855*2b9c00cbSConrad Meyer return 0; 856*2b9c00cbSConrad Meyer if (dictLoadMethod == ZSTD_dlm_byRef) { 857*2b9c00cbSConrad Meyer cctx->localDict.dict = dict; 8580c16b537SWarner Losh } else { 859*2b9c00cbSConrad Meyer void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem); 860*2b9c00cbSConrad Meyer RETURN_ERROR_IF(!dictBuffer, memory_allocation); 861*2b9c00cbSConrad Meyer memcpy(dictBuffer, dict, dictSize); 862*2b9c00cbSConrad Meyer cctx->localDict.dictBuffer = dictBuffer; 863*2b9c00cbSConrad Meyer cctx->localDict.dict = dictBuffer; 8640c16b537SWarner Losh } 865*2b9c00cbSConrad Meyer cctx->localDict.dictSize = dictSize; 866*2b9c00cbSConrad Meyer cctx->localDict.dictContentType = dictContentType; 8670c16b537SWarner Losh return 0; 8680c16b537SWarner Losh } 8690c16b537SWarner Losh 8700c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( 8710c16b537SWarner Losh ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 8720c16b537SWarner Losh { 8730c16b537SWarner Losh return ZSTD_CCtx_loadDictionary_advanced( 87419fcbaf1SConrad Meyer cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); 8750c16b537SWarner Losh } 8760c16b537SWarner Losh 8770c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(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_byCopy, ZSTD_dct_auto); 8810c16b537SWarner Losh } 8820c16b537SWarner Losh 8830c16b537SWarner Losh 8840c16b537SWarner Losh size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 8850c16b537SWarner Losh { 886*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 887*2b9c00cbSConrad Meyer /* Free the existing local cdict (if any) to save memory. */ 888*2b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); 8890c16b537SWarner Losh cctx->cdict = cdict; 8900c16b537SWarner Losh return 0; 8910c16b537SWarner Losh } 8920c16b537SWarner Losh 8930c16b537SWarner Losh size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) 8940c16b537SWarner Losh { 89519fcbaf1SConrad Meyer return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent); 8960c16b537SWarner Losh } 8970c16b537SWarner Losh 8980c16b537SWarner Losh size_t ZSTD_CCtx_refPrefix_advanced( 89919fcbaf1SConrad Meyer ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) 9000c16b537SWarner Losh { 901*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 902*2b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); 9030c16b537SWarner Losh cctx->prefixDict.dict = prefix; 9040c16b537SWarner Losh cctx->prefixDict.dictSize = prefixSize; 90519fcbaf1SConrad Meyer cctx->prefixDict.dictContentType = dictContentType; 9060c16b537SWarner Losh return 0; 9070c16b537SWarner Losh } 9080c16b537SWarner Losh 9090f743729SConrad Meyer /*! ZSTD_CCtx_reset() : 9100f743729SConrad Meyer * Also dumps dictionary */ 911a0483764SConrad Meyer size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset) 9120c16b537SWarner Losh { 913a0483764SConrad Meyer if ( (reset == ZSTD_reset_session_only) 914a0483764SConrad Meyer || (reset == ZSTD_reset_session_and_parameters) ) { 9150c16b537SWarner Losh cctx->streamStage = zcss_init; 9160c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = 0; 9170c16b537SWarner Losh } 918a0483764SConrad Meyer if ( (reset == ZSTD_reset_parameters) 919a0483764SConrad Meyer || (reset == ZSTD_reset_session_and_parameters) ) { 920*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong); 921*2b9c00cbSConrad Meyer ZSTD_clearAllDicts(cctx); 9220f743729SConrad Meyer return ZSTD_CCtxParams_reset(&cctx->requestedParams); 9230c16b537SWarner Losh } 924a0483764SConrad Meyer return 0; 925a0483764SConrad Meyer } 926a0483764SConrad Meyer 9270c16b537SWarner Losh 9280c16b537SWarner Losh /** ZSTD_checkCParams() : 9290c16b537SWarner Losh control CParam values remain within authorized range. 9300c16b537SWarner Losh @return : 0, or an error code if one value is beyond authorized range */ 9310c16b537SWarner Losh size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) 9320c16b537SWarner Losh { 933a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_windowLog, cParams.windowLog); 934a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_chainLog, cParams.chainLog); 935a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_hashLog, cParams.hashLog); 936a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_searchLog, cParams.searchLog); 937a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_minMatch, cParams.minMatch); 938a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_targetLength,cParams.targetLength); 939a0483764SConrad Meyer BOUNDCHECK(ZSTD_c_strategy, cParams.strategy); 9400c16b537SWarner Losh return 0; 9410c16b537SWarner Losh } 9420c16b537SWarner Losh 9430c16b537SWarner Losh /** ZSTD_clampCParams() : 9440c16b537SWarner Losh * make CParam values within valid range. 9450c16b537SWarner Losh * @return : valid CParams */ 9460f743729SConrad Meyer static ZSTD_compressionParameters 9470f743729SConrad Meyer ZSTD_clampCParams(ZSTD_compressionParameters cParams) 9480c16b537SWarner Losh { 949a0483764SConrad Meyer # define CLAMP_TYPE(cParam, val, type) { \ 950a0483764SConrad Meyer ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \ 951a0483764SConrad Meyer if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \ 952a0483764SConrad Meyer else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \ 9530c16b537SWarner Losh } 954a0483764SConrad Meyer # define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, int) 955a0483764SConrad Meyer CLAMP(ZSTD_c_windowLog, cParams.windowLog); 956a0483764SConrad Meyer CLAMP(ZSTD_c_chainLog, cParams.chainLog); 957a0483764SConrad Meyer CLAMP(ZSTD_c_hashLog, cParams.hashLog); 958a0483764SConrad Meyer CLAMP(ZSTD_c_searchLog, cParams.searchLog); 959a0483764SConrad Meyer CLAMP(ZSTD_c_minMatch, cParams.minMatch); 960a0483764SConrad Meyer CLAMP(ZSTD_c_targetLength,cParams.targetLength); 961a0483764SConrad Meyer CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy); 9620c16b537SWarner Losh return cParams; 9630c16b537SWarner Losh } 9640c16b537SWarner Losh 9650c16b537SWarner Losh /** ZSTD_cycleLog() : 9660c16b537SWarner Losh * condition for correct operation : hashLog > 1 */ 9670c16b537SWarner Losh static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) 9680c16b537SWarner Losh { 9690c16b537SWarner Losh U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2); 9700c16b537SWarner Losh return hashLog - btScale; 9710c16b537SWarner Losh } 9720c16b537SWarner Losh 9730c16b537SWarner Losh /** ZSTD_adjustCParams_internal() : 974*2b9c00cbSConrad Meyer * optimize `cPar` for a specified input (`srcSize` and `dictSize`). 975*2b9c00cbSConrad Meyer * mostly downsize to reduce memory consumption and initialization latency. 976*2b9c00cbSConrad Meyer * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known. 977*2b9c00cbSConrad Meyer * note : for the time being, `srcSize==0` means "unknown" too, for compatibility with older convention. 978*2b9c00cbSConrad Meyer * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */ 9790f743729SConrad Meyer static ZSTD_compressionParameters 9800f743729SConrad Meyer ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, 9810f743729SConrad Meyer unsigned long long srcSize, 9820f743729SConrad Meyer size_t dictSize) 9830c16b537SWarner Losh { 9840c16b537SWarner Losh static const U64 minSrcSize = 513; /* (1<<9) + 1 */ 9850c16b537SWarner Losh static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); 9860c16b537SWarner Losh assert(ZSTD_checkCParams(cPar)==0); 9870c16b537SWarner Losh 988*2b9c00cbSConrad Meyer if (dictSize && (srcSize+1<2) /* ZSTD_CONTENTSIZE_UNKNOWN and 0 mean "unknown" */ ) 9890c16b537SWarner Losh srcSize = minSrcSize; /* presumed small when there is a dictionary */ 9900c16b537SWarner Losh else if (srcSize == 0) 9910c16b537SWarner Losh srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */ 9920c16b537SWarner Losh 9930c16b537SWarner Losh /* resize windowLog if input is small enough, to use less memory */ 9940c16b537SWarner Losh if ( (srcSize < maxWindowResize) 9950c16b537SWarner Losh && (dictSize < maxWindowResize) ) { 9960c16b537SWarner Losh U32 const tSize = (U32)(srcSize + dictSize); 9970c16b537SWarner Losh static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN; 9980c16b537SWarner Losh U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN : 9990c16b537SWarner Losh ZSTD_highbit32(tSize-1) + 1; 10000c16b537SWarner Losh if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; 10010c16b537SWarner Losh } 10020f743729SConrad Meyer if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1; 10030c16b537SWarner Losh { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); 10040c16b537SWarner Losh if (cycleLog > cPar.windowLog) 10050c16b537SWarner Losh cPar.chainLog -= (cycleLog - cPar.windowLog); 10060c16b537SWarner Losh } 10070c16b537SWarner Losh 10080c16b537SWarner Losh if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) 1009*2b9c00cbSConrad Meyer cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */ 10100c16b537SWarner Losh 10110c16b537SWarner Losh return cPar; 10120c16b537SWarner Losh } 10130c16b537SWarner Losh 10140f743729SConrad Meyer ZSTD_compressionParameters 10150f743729SConrad Meyer ZSTD_adjustCParams(ZSTD_compressionParameters cPar, 10160f743729SConrad Meyer unsigned long long srcSize, 10170f743729SConrad Meyer size_t dictSize) 10180c16b537SWarner Losh { 1019*2b9c00cbSConrad Meyer cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */ 10200c16b537SWarner Losh return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); 10210c16b537SWarner Losh } 10220c16b537SWarner Losh 10230f743729SConrad Meyer ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( 10240f743729SConrad Meyer const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize) 10250f743729SConrad Meyer { 10260f743729SConrad Meyer ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize); 10270f743729SConrad Meyer if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; 10280f743729SConrad Meyer if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog; 10290f743729SConrad Meyer if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog; 10300f743729SConrad Meyer if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog; 10310f743729SConrad Meyer if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog; 1032a0483764SConrad Meyer if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch; 10330f743729SConrad Meyer if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength; 10340f743729SConrad Meyer if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy; 10350f743729SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 10360f743729SConrad Meyer return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize); 10370f743729SConrad Meyer } 10380f743729SConrad Meyer 10390f743729SConrad Meyer static size_t 10400f743729SConrad Meyer ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, 10410f743729SConrad Meyer const U32 forCCtx) 104219fcbaf1SConrad Meyer { 104319fcbaf1SConrad Meyer size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); 104419fcbaf1SConrad Meyer size_t const hSize = ((size_t)1) << cParams->hashLog; 1045a0483764SConrad Meyer U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 104619fcbaf1SConrad Meyer size_t const h3Size = ((size_t)1) << hashLog3; 104719fcbaf1SConrad Meyer size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 104819fcbaf1SConrad Meyer size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32) 104919fcbaf1SConrad Meyer + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t)); 1050a0483764SConrad Meyer size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt)) 105119fcbaf1SConrad Meyer ? optPotentialSpace 105219fcbaf1SConrad Meyer : 0; 105319fcbaf1SConrad Meyer DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u", 105419fcbaf1SConrad Meyer (U32)chainSize, (U32)hSize, (U32)h3Size); 105519fcbaf1SConrad Meyer return tableSpace + optSpace; 105619fcbaf1SConrad Meyer } 105719fcbaf1SConrad Meyer 10580c16b537SWarner Losh size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) 10590c16b537SWarner Losh { 1060*2b9c00cbSConrad Meyer RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); 10610c16b537SWarner Losh { ZSTD_compressionParameters const cParams = 106219fcbaf1SConrad Meyer ZSTD_getCParamsFromCCtxParams(params, 0, 0); 10630c16b537SWarner Losh size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); 1064a0483764SConrad Meyer U32 const divider = (cParams.minMatch==3) ? 3 : 4; 10650c16b537SWarner Losh size_t const maxNbSeq = blockSize / divider; 10660f743729SConrad Meyer size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq; 106719fcbaf1SConrad Meyer size_t const entropySpace = HUF_WORKSPACE_SIZE; 106819fcbaf1SConrad Meyer size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t); 106919fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1); 10700c16b537SWarner Losh 107119fcbaf1SConrad Meyer size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams); 107219fcbaf1SConrad Meyer size_t const ldmSeqSpace = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq); 10730c16b537SWarner Losh 107419fcbaf1SConrad Meyer size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace + 107519fcbaf1SConrad Meyer matchStateSize + ldmSpace + ldmSeqSpace; 10760c16b537SWarner Losh 10770c16b537SWarner Losh DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx)); 10780c16b537SWarner Losh DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace); 10790c16b537SWarner Losh return sizeof(ZSTD_CCtx) + neededSpace; 10800c16b537SWarner Losh } 10810c16b537SWarner Losh } 10820c16b537SWarner Losh 10830c16b537SWarner Losh size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) 10840c16b537SWarner Losh { 10850c16b537SWarner Losh ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); 10860c16b537SWarner Losh return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms); 10870c16b537SWarner Losh } 10880c16b537SWarner Losh 108919fcbaf1SConrad Meyer static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) 10900c16b537SWarner Losh { 10910c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); 10920c16b537SWarner Losh return ZSTD_estimateCCtxSize_usingCParams(cParams); 10930c16b537SWarner Losh } 10940c16b537SWarner Losh 109519fcbaf1SConrad Meyer size_t ZSTD_estimateCCtxSize(int compressionLevel) 109619fcbaf1SConrad Meyer { 109719fcbaf1SConrad Meyer int level; 109819fcbaf1SConrad Meyer size_t memBudget = 0; 1099a0483764SConrad Meyer for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { 110019fcbaf1SConrad Meyer size_t const newMB = ZSTD_estimateCCtxSize_internal(level); 110119fcbaf1SConrad Meyer if (newMB > memBudget) memBudget = newMB; 110219fcbaf1SConrad Meyer } 110319fcbaf1SConrad Meyer return memBudget; 110419fcbaf1SConrad Meyer } 110519fcbaf1SConrad Meyer 11060c16b537SWarner Losh size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) 11070c16b537SWarner Losh { 1108*2b9c00cbSConrad Meyer RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only."); 1109*2b9c00cbSConrad Meyer { ZSTD_compressionParameters const cParams = 1110*2b9c00cbSConrad Meyer ZSTD_getCParamsFromCCtxParams(params, 0, 0); 1111*2b9c00cbSConrad Meyer size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params); 1112*2b9c00cbSConrad Meyer size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); 1113*2b9c00cbSConrad Meyer size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize; 11140c16b537SWarner Losh size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; 11150c16b537SWarner Losh size_t const streamingSize = inBuffSize + outBuffSize; 11160c16b537SWarner Losh 11170c16b537SWarner Losh return CCtxSize + streamingSize; 11180c16b537SWarner Losh } 11190c16b537SWarner Losh } 11200c16b537SWarner Losh 11210c16b537SWarner Losh size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) 11220c16b537SWarner Losh { 11230c16b537SWarner Losh ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); 11240c16b537SWarner Losh return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms); 11250c16b537SWarner Losh } 11260c16b537SWarner Losh 11270f743729SConrad Meyer static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) 11280f743729SConrad Meyer { 11290c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); 11300c16b537SWarner Losh return ZSTD_estimateCStreamSize_usingCParams(cParams); 11310c16b537SWarner Losh } 11320c16b537SWarner Losh 11330f743729SConrad Meyer size_t ZSTD_estimateCStreamSize(int compressionLevel) 11340f743729SConrad Meyer { 113519fcbaf1SConrad Meyer int level; 113619fcbaf1SConrad Meyer size_t memBudget = 0; 1137a0483764SConrad Meyer for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) { 113819fcbaf1SConrad Meyer size_t const newMB = ZSTD_estimateCStreamSize_internal(level); 113919fcbaf1SConrad Meyer if (newMB > memBudget) memBudget = newMB; 114019fcbaf1SConrad Meyer } 114119fcbaf1SConrad Meyer return memBudget; 114219fcbaf1SConrad Meyer } 114319fcbaf1SConrad Meyer 114419fcbaf1SConrad Meyer /* ZSTD_getFrameProgression(): 114519fcbaf1SConrad Meyer * tells how much data has been consumed (input) and produced (output) for current frame. 114619fcbaf1SConrad Meyer * able to count progression inside worker threads (non-blocking mode). 114719fcbaf1SConrad Meyer */ 114819fcbaf1SConrad Meyer ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx) 114919fcbaf1SConrad Meyer { 115019fcbaf1SConrad Meyer #ifdef ZSTD_MULTITHREAD 115119fcbaf1SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 115219fcbaf1SConrad Meyer return ZSTDMT_getFrameProgression(cctx->mtctx); 115319fcbaf1SConrad Meyer } 115419fcbaf1SConrad Meyer #endif 115519fcbaf1SConrad Meyer { ZSTD_frameProgression fp; 115619fcbaf1SConrad Meyer size_t const buffered = (cctx->inBuff == NULL) ? 0 : 115719fcbaf1SConrad Meyer cctx->inBuffPos - cctx->inToCompress; 115819fcbaf1SConrad Meyer if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress); 115919fcbaf1SConrad Meyer assert(buffered <= ZSTD_BLOCKSIZE_MAX); 116019fcbaf1SConrad Meyer fp.ingested = cctx->consumedSrcSize + buffered; 116119fcbaf1SConrad Meyer fp.consumed = cctx->consumedSrcSize; 116219fcbaf1SConrad Meyer fp.produced = cctx->producedCSize; 11630f743729SConrad Meyer fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */ 11640f743729SConrad Meyer fp.currentJobID = 0; 11650f743729SConrad Meyer fp.nbActiveWorkers = 0; 116619fcbaf1SConrad Meyer return fp; 116719fcbaf1SConrad Meyer } } 116819fcbaf1SConrad Meyer 11690f743729SConrad Meyer /*! ZSTD_toFlushNow() 11700f743729SConrad Meyer * Only useful for multithreading scenarios currently (nbWorkers >= 1). 11710f743729SConrad Meyer */ 11720f743729SConrad Meyer size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx) 11730f743729SConrad Meyer { 11740f743729SConrad Meyer #ifdef ZSTD_MULTITHREAD 11750f743729SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 11760f743729SConrad Meyer return ZSTDMT_toFlushNow(cctx->mtctx); 11770f743729SConrad Meyer } 11780f743729SConrad Meyer #endif 11790f743729SConrad Meyer (void)cctx; 11800f743729SConrad 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 */ 11810f743729SConrad Meyer } 11820f743729SConrad Meyer 11830f743729SConrad Meyer 118419fcbaf1SConrad Meyer 11850c16b537SWarner Losh static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1, 11860c16b537SWarner Losh ZSTD_compressionParameters cParams2) 11870c16b537SWarner Losh { 1188052d3c12SConrad Meyer return (cParams1.hashLog == cParams2.hashLog) 11890c16b537SWarner Losh & (cParams1.chainLog == cParams2.chainLog) 11900c16b537SWarner Losh & (cParams1.strategy == cParams2.strategy) /* opt parser space */ 1191a0483764SConrad Meyer & ((cParams1.minMatch==3) == (cParams2.minMatch==3)); /* hashlog3 space */ 11920c16b537SWarner Losh } 11930c16b537SWarner Losh 11940f743729SConrad Meyer static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1, 11950f743729SConrad Meyer ZSTD_compressionParameters cParams2) 11960f743729SConrad Meyer { 11970f743729SConrad Meyer (void)cParams1; 11980f743729SConrad Meyer (void)cParams2; 11990f743729SConrad Meyer assert(cParams1.windowLog == cParams2.windowLog); 12000f743729SConrad Meyer assert(cParams1.chainLog == cParams2.chainLog); 12010f743729SConrad Meyer assert(cParams1.hashLog == cParams2.hashLog); 12020f743729SConrad Meyer assert(cParams1.searchLog == cParams2.searchLog); 1203a0483764SConrad Meyer assert(cParams1.minMatch == cParams2.minMatch); 12040f743729SConrad Meyer assert(cParams1.targetLength == cParams2.targetLength); 12050f743729SConrad Meyer assert(cParams1.strategy == cParams2.strategy); 12060f743729SConrad Meyer } 12070f743729SConrad Meyer 12080c16b537SWarner Losh /** The parameters are equivalent if ldm is not enabled in both sets or 12090c16b537SWarner Losh * all the parameters are equivalent. */ 12100c16b537SWarner Losh static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1, 12110c16b537SWarner Losh ldmParams_t ldmParams2) 12120c16b537SWarner Losh { 12130c16b537SWarner Losh return (!ldmParams1.enableLdm && !ldmParams2.enableLdm) || 12140c16b537SWarner Losh (ldmParams1.enableLdm == ldmParams2.enableLdm && 12150c16b537SWarner Losh ldmParams1.hashLog == ldmParams2.hashLog && 12160c16b537SWarner Losh ldmParams1.bucketSizeLog == ldmParams2.bucketSizeLog && 12170c16b537SWarner Losh ldmParams1.minMatchLength == ldmParams2.minMatchLength && 1218a0483764SConrad Meyer ldmParams1.hashRateLog == ldmParams2.hashRateLog); 12190c16b537SWarner Losh } 12200c16b537SWarner Losh 1221052d3c12SConrad Meyer typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e; 1222052d3c12SConrad Meyer 1223052d3c12SConrad Meyer /* ZSTD_sufficientBuff() : 1224052d3c12SConrad Meyer * check internal buffers exist for streaming if buffPol == ZSTDb_buffered . 1225052d3c12SConrad Meyer * Note : they are assumed to be correctly sized if ZSTD_equivalentCParams()==1 */ 12260f743729SConrad Meyer static U32 ZSTD_sufficientBuff(size_t bufferSize1, size_t maxNbSeq1, 12270f743729SConrad Meyer size_t maxNbLit1, 1228052d3c12SConrad Meyer ZSTD_buffered_policy_e buffPol2, 1229052d3c12SConrad Meyer ZSTD_compressionParameters cParams2, 1230052d3c12SConrad Meyer U64 pledgedSrcSize) 1231052d3c12SConrad Meyer { 1232052d3c12SConrad Meyer size_t const windowSize2 = MAX(1, (size_t)MIN(((U64)1 << cParams2.windowLog), pledgedSrcSize)); 1233052d3c12SConrad Meyer size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2); 1234a0483764SConrad Meyer size_t const maxNbSeq2 = blockSize2 / ((cParams2.minMatch == 3) ? 3 : 4); 12350f743729SConrad Meyer size_t const maxNbLit2 = blockSize2; 1236052d3c12SConrad Meyer size_t const neededBufferSize2 = (buffPol2==ZSTDb_buffered) ? windowSize2 + blockSize2 : 0; 12370f743729SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff: is neededBufferSize2=%u <= bufferSize1=%u", 12380f743729SConrad Meyer (U32)neededBufferSize2, (U32)bufferSize1); 12390f743729SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbSeq2=%u <= maxNbSeq1=%u", 12400f743729SConrad Meyer (U32)maxNbSeq2, (U32)maxNbSeq1); 12410f743729SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbLit2=%u <= maxNbLit1=%u", 12420f743729SConrad Meyer (U32)maxNbLit2, (U32)maxNbLit1); 12430f743729SConrad Meyer return (maxNbLit2 <= maxNbLit1) 12440f743729SConrad Meyer & (maxNbSeq2 <= maxNbSeq1) 1245052d3c12SConrad Meyer & (neededBufferSize2 <= bufferSize1); 1246052d3c12SConrad Meyer } 1247052d3c12SConrad Meyer 12480c16b537SWarner Losh /** Equivalence for resetCCtx purposes */ 12490c16b537SWarner Losh static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1, 1250052d3c12SConrad Meyer ZSTD_CCtx_params params2, 12510f743729SConrad Meyer size_t buffSize1, 12520f743729SConrad Meyer size_t maxNbSeq1, size_t maxNbLit1, 1253052d3c12SConrad Meyer ZSTD_buffered_policy_e buffPol2, 1254052d3c12SConrad Meyer U64 pledgedSrcSize) 12550c16b537SWarner Losh { 1256052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentParams: pledgedSrcSize=%u", (U32)pledgedSrcSize); 12570f743729SConrad Meyer if (!ZSTD_equivalentCParams(params1.cParams, params2.cParams)) { 12580f743729SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentCParams() == 0"); 12590f743729SConrad Meyer return 0; 12600f743729SConrad Meyer } 12610f743729SConrad Meyer if (!ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams)) { 12620f743729SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentLdmParams() == 0"); 12630f743729SConrad Meyer return 0; 12640f743729SConrad Meyer } 12650f743729SConrad Meyer if (!ZSTD_sufficientBuff(buffSize1, maxNbSeq1, maxNbLit1, buffPol2, 12660f743729SConrad Meyer params2.cParams, pledgedSrcSize)) { 12670f743729SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff() == 0"); 12680f743729SConrad Meyer return 0; 12690f743729SConrad Meyer } 12700f743729SConrad Meyer return 1; 12710c16b537SWarner Losh } 12720c16b537SWarner Losh 127319fcbaf1SConrad Meyer static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) 127419fcbaf1SConrad Meyer { 127519fcbaf1SConrad Meyer int i; 127619fcbaf1SConrad Meyer for (i = 0; i < ZSTD_REP_NUM; ++i) 127719fcbaf1SConrad Meyer bs->rep[i] = repStartValue[i]; 12780f743729SConrad Meyer bs->entropy.huf.repeatMode = HUF_repeat_none; 12790f743729SConrad Meyer bs->entropy.fse.offcode_repeatMode = FSE_repeat_none; 12800f743729SConrad Meyer bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none; 12810f743729SConrad Meyer bs->entropy.fse.litlength_repeatMode = FSE_repeat_none; 128219fcbaf1SConrad Meyer } 128319fcbaf1SConrad Meyer 128419fcbaf1SConrad Meyer /*! ZSTD_invalidateMatchState() 128519fcbaf1SConrad Meyer * Invalidate all the matches in the match finder tables. 128619fcbaf1SConrad Meyer * Requires nextSrc and base to be set (can be NULL). 128719fcbaf1SConrad Meyer */ 128819fcbaf1SConrad Meyer static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms) 128919fcbaf1SConrad Meyer { 129019fcbaf1SConrad Meyer ZSTD_window_clear(&ms->window); 129119fcbaf1SConrad Meyer 1292a0483764SConrad Meyer ms->nextToUpdate = ms->window.dictLimit; 1293a0483764SConrad Meyer ms->nextToUpdate3 = ms->window.dictLimit; 129419fcbaf1SConrad Meyer ms->loadedDictEnd = 0; 129519fcbaf1SConrad Meyer ms->opt.litLengthSum = 0; /* force reset of btopt stats */ 12960f743729SConrad Meyer ms->dictMatchState = NULL; 129719fcbaf1SConrad Meyer } 129819fcbaf1SConrad Meyer 12990c16b537SWarner Losh /*! ZSTD_continueCCtx() : 13000c16b537SWarner Losh * reuse CCtx without reset (note : requires no dictionary) */ 13010c16b537SWarner Losh static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize) 13020c16b537SWarner Losh { 1303052d3c12SConrad Meyer size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); 1304052d3c12SConrad Meyer size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); 130519fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_continueCCtx: re-use context in place"); 1306052d3c12SConrad Meyer 1307052d3c12SConrad Meyer cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */ 13080c16b537SWarner Losh cctx->appliedParams = params; 13090f743729SConrad Meyer cctx->blockState.matchState.cParams = params.cParams; 13100c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; 13110c16b537SWarner Losh cctx->consumedSrcSize = 0; 131219fcbaf1SConrad Meyer cctx->producedCSize = 0; 13130c16b537SWarner Losh if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) 13140c16b537SWarner Losh cctx->appliedParams.fParams.contentSizeFlag = 0; 13150c16b537SWarner Losh DEBUGLOG(4, "pledged content size : %u ; flag : %u", 13160c16b537SWarner Losh (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag); 13170c16b537SWarner Losh cctx->stage = ZSTDcs_init; 13180c16b537SWarner Losh cctx->dictID = 0; 131919fcbaf1SConrad Meyer if (params.ldmParams.enableLdm) 132019fcbaf1SConrad Meyer ZSTD_window_clear(&cctx->ldmState.window); 132119fcbaf1SConrad Meyer ZSTD_referenceExternalSequences(cctx, NULL, 0); 132219fcbaf1SConrad Meyer ZSTD_invalidateMatchState(&cctx->blockState.matchState); 132319fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(cctx->blockState.prevCBlock); 13240c16b537SWarner Losh XXH64_reset(&cctx->xxhState, 0); 13250c16b537SWarner Losh return 0; 13260c16b537SWarner Losh } 13270c16b537SWarner Losh 13280c16b537SWarner Losh typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e; 13290c16b537SWarner Losh 13300f743729SConrad Meyer static void* 13310f743729SConrad Meyer ZSTD_reset_matchState(ZSTD_matchState_t* ms, 13320f743729SConrad Meyer void* ptr, 13330f743729SConrad Meyer const ZSTD_compressionParameters* cParams, 13340f743729SConrad Meyer ZSTD_compResetPolicy_e const crp, U32 const forCCtx) 133519fcbaf1SConrad Meyer { 133619fcbaf1SConrad Meyer size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); 133719fcbaf1SConrad Meyer size_t const hSize = ((size_t)1) << cParams->hashLog; 1338a0483764SConrad Meyer U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 133919fcbaf1SConrad Meyer size_t const h3Size = ((size_t)1) << hashLog3; 134019fcbaf1SConrad Meyer size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 134119fcbaf1SConrad Meyer 134219fcbaf1SConrad Meyer assert(((size_t)ptr & 3) == 0); 134319fcbaf1SConrad Meyer 134419fcbaf1SConrad Meyer ms->hashLog3 = hashLog3; 134519fcbaf1SConrad Meyer memset(&ms->window, 0, sizeof(ms->window)); 13460f743729SConrad Meyer ms->window.dictLimit = 1; /* start from 1, so that 1st position is valid */ 13470f743729SConrad Meyer ms->window.lowLimit = 1; /* it ensures first and later CCtx usages compress the same */ 13480f743729SConrad Meyer ms->window.nextSrc = ms->window.base + 1; /* see issue #1241 */ 134919fcbaf1SConrad Meyer ZSTD_invalidateMatchState(ms); 135019fcbaf1SConrad Meyer 135119fcbaf1SConrad Meyer /* opt parser space */ 1352a0483764SConrad Meyer if (forCCtx && (cParams->strategy >= ZSTD_btopt)) { 135319fcbaf1SConrad Meyer DEBUGLOG(4, "reserving optimal parser space"); 1354a0483764SConrad Meyer ms->opt.litFreq = (unsigned*)ptr; 135519fcbaf1SConrad Meyer ms->opt.litLengthFreq = ms->opt.litFreq + (1<<Litbits); 135619fcbaf1SConrad Meyer ms->opt.matchLengthFreq = ms->opt.litLengthFreq + (MaxLL+1); 135719fcbaf1SConrad Meyer ms->opt.offCodeFreq = ms->opt.matchLengthFreq + (MaxML+1); 135819fcbaf1SConrad Meyer ptr = ms->opt.offCodeFreq + (MaxOff+1); 135919fcbaf1SConrad Meyer ms->opt.matchTable = (ZSTD_match_t*)ptr; 136019fcbaf1SConrad Meyer ptr = ms->opt.matchTable + ZSTD_OPT_NUM+1; 136119fcbaf1SConrad Meyer ms->opt.priceTable = (ZSTD_optimal_t*)ptr; 136219fcbaf1SConrad Meyer ptr = ms->opt.priceTable + ZSTD_OPT_NUM+1; 136319fcbaf1SConrad Meyer } 136419fcbaf1SConrad Meyer 136519fcbaf1SConrad Meyer /* table Space */ 136619fcbaf1SConrad Meyer DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset); 136719fcbaf1SConrad Meyer assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ 136819fcbaf1SConrad Meyer if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */ 136919fcbaf1SConrad Meyer ms->hashTable = (U32*)(ptr); 137019fcbaf1SConrad Meyer ms->chainTable = ms->hashTable + hSize; 137119fcbaf1SConrad Meyer ms->hashTable3 = ms->chainTable + chainSize; 137219fcbaf1SConrad Meyer ptr = ms->hashTable3 + h3Size; 137319fcbaf1SConrad Meyer 13740f743729SConrad Meyer ms->cParams = *cParams; 13750f743729SConrad Meyer 137619fcbaf1SConrad Meyer assert(((size_t)ptr & 3) == 0); 137719fcbaf1SConrad Meyer return ptr; 137819fcbaf1SConrad Meyer } 137919fcbaf1SConrad Meyer 13800f743729SConrad Meyer #define ZSTD_WORKSPACETOOLARGE_FACTOR 3 /* define "workspace is too large" as this number of times larger than needed */ 13810f743729SConrad Meyer #define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 /* when workspace is continuously too large 13820f743729SConrad Meyer * during at least this number of times, 13830f743729SConrad Meyer * context's memory usage is considered wasteful, 13840f743729SConrad Meyer * because it's sized to handle a worst case scenario which rarely happens. 13850f743729SConrad Meyer * In which case, resize it down to free some memory */ 13860f743729SConrad Meyer 13870c16b537SWarner Losh /*! ZSTD_resetCCtx_internal() : 13880c16b537SWarner Losh note : `params` are assumed fully validated at this stage */ 13890c16b537SWarner Losh static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, 13900f743729SConrad Meyer ZSTD_CCtx_params params, 13910f743729SConrad Meyer U64 pledgedSrcSize, 13920c16b537SWarner Losh ZSTD_compResetPolicy_e const crp, 13930c16b537SWarner Losh ZSTD_buffered_policy_e const zbuff) 13940c16b537SWarner Losh { 1395052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u", 1396052d3c12SConrad Meyer (U32)pledgedSrcSize, params.cParams.windowLog); 13970c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 13980c16b537SWarner Losh 13990c16b537SWarner Losh if (crp == ZSTDcrp_continue) { 1400052d3c12SConrad Meyer if (ZSTD_equivalentParams(zc->appliedParams, params, 14010f743729SConrad Meyer zc->inBuffSize, 14020f743729SConrad Meyer zc->seqStore.maxNbSeq, zc->seqStore.maxNbLit, 1403052d3c12SConrad Meyer zbuff, pledgedSrcSize)) { 14040f743729SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%zu)", 14050f743729SConrad Meyer zc->appliedParams.cParams.windowLog, zc->blockSize); 14060f743729SConrad Meyer zc->workSpaceOversizedDuration += (zc->workSpaceOversizedDuration > 0); /* if it was too large, it still is */ 14070f743729SConrad Meyer if (zc->workSpaceOversizedDuration <= ZSTD_WORKSPACETOOLARGE_MAXDURATION) 14080c16b537SWarner Losh return ZSTD_continueCCtx(zc, params, pledgedSrcSize); 14090c16b537SWarner Losh } } 1410052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx"); 14110c16b537SWarner Losh 14120c16b537SWarner Losh if (params.ldmParams.enableLdm) { 14130c16b537SWarner Losh /* Adjust long distance matching parameters */ 141419fcbaf1SConrad Meyer ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); 14150c16b537SWarner Losh assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); 1416a0483764SConrad Meyer assert(params.ldmParams.hashRateLog < 32); 1417a0483764SConrad Meyer zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength); 14180c16b537SWarner Losh } 14190c16b537SWarner Losh 1420052d3c12SConrad Meyer { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); 1421052d3c12SConrad Meyer size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); 1422a0483764SConrad Meyer U32 const divider = (params.cParams.minMatch==3) ? 3 : 4; 14230c16b537SWarner Losh size_t const maxNbSeq = blockSize / divider; 14240f743729SConrad Meyer size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq; 14250c16b537SWarner Losh size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0; 1426052d3c12SConrad Meyer size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0; 142719fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1); 142819fcbaf1SConrad Meyer size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize); 14290f743729SConrad Meyer void* ptr; /* used to partition workSpace */ 14300c16b537SWarner Losh 14310c16b537SWarner Losh /* Check if workSpace is large enough, alloc a new one if needed */ 143219fcbaf1SConrad Meyer { size_t const entropySpace = HUF_WORKSPACE_SIZE; 143319fcbaf1SConrad Meyer size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t); 14340c16b537SWarner Losh size_t const bufferSpace = buffInSize + buffOutSize; 143519fcbaf1SConrad Meyer size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams); 143619fcbaf1SConrad Meyer size_t const ldmSeqSpace = maxNbLdmSeq * sizeof(rawSeq); 143719fcbaf1SConrad Meyer 143819fcbaf1SConrad Meyer size_t const neededSpace = entropySpace + blockStateSpace + ldmSpace + 143919fcbaf1SConrad Meyer ldmSeqSpace + matchStateSize + tokenSpace + 144019fcbaf1SConrad Meyer bufferSpace; 14410c16b537SWarner Losh 14420f743729SConrad Meyer int const workSpaceTooSmall = zc->workSpaceSize < neededSpace; 14430f743729SConrad Meyer int const workSpaceTooLarge = zc->workSpaceSize > ZSTD_WORKSPACETOOLARGE_FACTOR * neededSpace; 14440f743729SConrad Meyer int const workSpaceWasteful = workSpaceTooLarge && (zc->workSpaceOversizedDuration > ZSTD_WORKSPACETOOLARGE_MAXDURATION); 14450f743729SConrad Meyer zc->workSpaceOversizedDuration = workSpaceTooLarge ? zc->workSpaceOversizedDuration+1 : 0; 14460f743729SConrad Meyer 14470f743729SConrad Meyer DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers", 14480f743729SConrad Meyer neededSpace>>10, matchStateSize>>10, bufferSpace>>10); 14490f743729SConrad Meyer DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); 14500f743729SConrad Meyer 14510f743729SConrad Meyer if (workSpaceTooSmall || workSpaceWasteful) { 14520f743729SConrad Meyer DEBUGLOG(4, "Need to resize workSpaceSize from %zuKB to %zuKB", 14530f743729SConrad Meyer zc->workSpaceSize >> 10, 14540f743729SConrad Meyer neededSpace >> 10); 1455*2b9c00cbSConrad Meyer 1456*2b9c00cbSConrad Meyer RETURN_ERROR_IF(zc->staticSize, memory_allocation, "static cctx : no resize"); 14570c16b537SWarner Losh 14580c16b537SWarner Losh zc->workSpaceSize = 0; 14590c16b537SWarner Losh ZSTD_free(zc->workSpace, zc->customMem); 14600c16b537SWarner Losh zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem); 1461*2b9c00cbSConrad Meyer RETURN_ERROR_IF(zc->workSpace == NULL, memory_allocation); 14620c16b537SWarner Losh zc->workSpaceSize = neededSpace; 14630f743729SConrad Meyer zc->workSpaceOversizedDuration = 0; 14640c16b537SWarner Losh 14650f743729SConrad Meyer /* Statically sized space. 14660f743729SConrad Meyer * entropyWorkspace never moves, 14670f743729SConrad Meyer * though prev/next block swap places */ 14680c16b537SWarner Losh assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */ 146919fcbaf1SConrad Meyer assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_compressedBlockState_t)); 147019fcbaf1SConrad Meyer zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)zc->workSpace; 147119fcbaf1SConrad Meyer zc->blockState.nextCBlock = zc->blockState.prevCBlock + 1; 147219fcbaf1SConrad Meyer ptr = zc->blockState.nextCBlock + 1; 147319fcbaf1SConrad Meyer zc->entropyWorkspace = (U32*)ptr; 14740c16b537SWarner Losh } } 14750c16b537SWarner Losh 14760c16b537SWarner Losh /* init params */ 14770c16b537SWarner Losh zc->appliedParams = params; 14780f743729SConrad Meyer zc->blockState.matchState.cParams = params.cParams; 14790c16b537SWarner Losh zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; 14800c16b537SWarner Losh zc->consumedSrcSize = 0; 148119fcbaf1SConrad Meyer zc->producedCSize = 0; 14820c16b537SWarner Losh if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) 14830c16b537SWarner Losh zc->appliedParams.fParams.contentSizeFlag = 0; 1484052d3c12SConrad Meyer DEBUGLOG(4, "pledged content size : %u ; flag : %u", 1485a0483764SConrad Meyer (unsigned)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag); 14860c16b537SWarner Losh zc->blockSize = blockSize; 14870c16b537SWarner Losh 14880c16b537SWarner Losh XXH64_reset(&zc->xxhState, 0); 14890c16b537SWarner Losh zc->stage = ZSTDcs_init; 14900c16b537SWarner Losh zc->dictID = 0; 14910c16b537SWarner Losh 149219fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock); 14930c16b537SWarner Losh 149419fcbaf1SConrad Meyer ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32; 14950c16b537SWarner Losh 14960c16b537SWarner Losh /* ldm hash table */ 14970c16b537SWarner Losh /* initialize bucketOffsets table later for pointer alignment */ 14980c16b537SWarner Losh if (params.ldmParams.enableLdm) { 14990c16b537SWarner Losh size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog; 15000c16b537SWarner Losh memset(ptr, 0, ldmHSize * sizeof(ldmEntry_t)); 15010c16b537SWarner Losh assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ 15020c16b537SWarner Losh zc->ldmState.hashTable = (ldmEntry_t*)ptr; 15030c16b537SWarner Losh ptr = zc->ldmState.hashTable + ldmHSize; 150419fcbaf1SConrad Meyer zc->ldmSequences = (rawSeq*)ptr; 150519fcbaf1SConrad Meyer ptr = zc->ldmSequences + maxNbLdmSeq; 150619fcbaf1SConrad Meyer zc->maxNbLdmSequences = maxNbLdmSeq; 15070c16b537SWarner Losh 150819fcbaf1SConrad Meyer memset(&zc->ldmState.window, 0, sizeof(zc->ldmState.window)); 150919fcbaf1SConrad Meyer } 15100c16b537SWarner Losh assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ 151119fcbaf1SConrad Meyer 151219fcbaf1SConrad Meyer ptr = ZSTD_reset_matchState(&zc->blockState.matchState, ptr, ¶ms.cParams, crp, /* forCCtx */ 1); 15130c16b537SWarner Losh 15140c16b537SWarner Losh /* sequences storage */ 15150f743729SConrad Meyer zc->seqStore.maxNbSeq = maxNbSeq; 15160c16b537SWarner Losh zc->seqStore.sequencesStart = (seqDef*)ptr; 15170c16b537SWarner Losh ptr = zc->seqStore.sequencesStart + maxNbSeq; 15180c16b537SWarner Losh zc->seqStore.llCode = (BYTE*) ptr; 15190c16b537SWarner Losh zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq; 15200c16b537SWarner Losh zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq; 15210c16b537SWarner Losh zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq; 15220f743729SConrad Meyer /* ZSTD_wildcopy() is used to copy into the literals buffer, 15230f743729SConrad Meyer * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes. 15240f743729SConrad Meyer */ 15250f743729SConrad Meyer zc->seqStore.maxNbLit = blockSize; 15260f743729SConrad Meyer ptr = zc->seqStore.litStart + blockSize + WILDCOPY_OVERLENGTH; 15270c16b537SWarner Losh 15280c16b537SWarner Losh /* ldm bucketOffsets table */ 15290c16b537SWarner Losh if (params.ldmParams.enableLdm) { 15300c16b537SWarner Losh size_t const ldmBucketSize = 15310c16b537SWarner Losh ((size_t)1) << (params.ldmParams.hashLog - 15320c16b537SWarner Losh params.ldmParams.bucketSizeLog); 15330c16b537SWarner Losh memset(ptr, 0, ldmBucketSize); 15340c16b537SWarner Losh zc->ldmState.bucketOffsets = (BYTE*)ptr; 15350c16b537SWarner Losh ptr = zc->ldmState.bucketOffsets + ldmBucketSize; 153619fcbaf1SConrad Meyer ZSTD_window_clear(&zc->ldmState.window); 15370c16b537SWarner Losh } 153819fcbaf1SConrad Meyer ZSTD_referenceExternalSequences(zc, NULL, 0); 15390c16b537SWarner Losh 15400c16b537SWarner Losh /* buffers */ 15410c16b537SWarner Losh zc->inBuffSize = buffInSize; 15420c16b537SWarner Losh zc->inBuff = (char*)ptr; 15430c16b537SWarner Losh zc->outBuffSize = buffOutSize; 15440c16b537SWarner Losh zc->outBuff = zc->inBuff + buffInSize; 15450c16b537SWarner Losh 15460c16b537SWarner Losh return 0; 15470c16b537SWarner Losh } 15480c16b537SWarner Losh } 15490c16b537SWarner Losh 15500c16b537SWarner Losh /* ZSTD_invalidateRepCodes() : 15510c16b537SWarner Losh * ensures next compression will not use repcodes from previous block. 15520c16b537SWarner Losh * Note : only works with regular variant; 15530c16b537SWarner Losh * do not use with extDict variant ! */ 15540c16b537SWarner Losh void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) { 15550c16b537SWarner Losh int i; 155619fcbaf1SConrad Meyer for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0; 155719fcbaf1SConrad Meyer assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window)); 15580c16b537SWarner Losh } 15590c16b537SWarner Losh 15600f743729SConrad Meyer /* These are the approximate sizes for each strategy past which copying the 15610f743729SConrad Meyer * dictionary tables into the working context is faster than using them 15620f743729SConrad Meyer * in-place. 15630f743729SConrad Meyer */ 1564a0483764SConrad Meyer static const size_t attachDictSizeCutoffs[ZSTD_STRATEGY_MAX+1] = { 15650f743729SConrad Meyer 8 KB, /* unused */ 15660f743729SConrad Meyer 8 KB, /* ZSTD_fast */ 15670f743729SConrad Meyer 16 KB, /* ZSTD_dfast */ 15680f743729SConrad Meyer 32 KB, /* ZSTD_greedy */ 15690f743729SConrad Meyer 32 KB, /* ZSTD_lazy */ 15700f743729SConrad Meyer 32 KB, /* ZSTD_lazy2 */ 15710f743729SConrad Meyer 32 KB, /* ZSTD_btlazy2 */ 15720f743729SConrad Meyer 32 KB, /* ZSTD_btopt */ 1573a0483764SConrad Meyer 8 KB, /* ZSTD_btultra */ 1574a0483764SConrad Meyer 8 KB /* ZSTD_btultra2 */ 15750f743729SConrad Meyer }; 15760f743729SConrad Meyer 15770f743729SConrad Meyer static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, 15780f743729SConrad Meyer ZSTD_CCtx_params params, 15790f743729SConrad Meyer U64 pledgedSrcSize) 15800f743729SConrad Meyer { 15810f743729SConrad Meyer size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy]; 15820f743729SConrad Meyer return ( pledgedSrcSize <= cutoff 15830f743729SConrad Meyer || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN 15840f743729SConrad Meyer || params.attachDictPref == ZSTD_dictForceAttach ) 15850f743729SConrad Meyer && params.attachDictPref != ZSTD_dictForceCopy 15860f743729SConrad Meyer && !params.forceWindow; /* dictMatchState isn't correctly 15870f743729SConrad Meyer * handled in _enforceMaxDist */ 15880f743729SConrad Meyer } 15890f743729SConrad Meyer 15900f743729SConrad Meyer static size_t ZSTD_resetCCtx_byAttachingCDict( 15910f743729SConrad Meyer ZSTD_CCtx* cctx, 159219fcbaf1SConrad Meyer const ZSTD_CDict* cdict, 15930f743729SConrad Meyer ZSTD_CCtx_params params, 159419fcbaf1SConrad Meyer U64 pledgedSrcSize, 159519fcbaf1SConrad Meyer ZSTD_buffered_policy_e zbuff) 159619fcbaf1SConrad Meyer { 15970f743729SConrad Meyer { 15980f743729SConrad Meyer const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; 15990f743729SConrad Meyer unsigned const windowLog = params.cParams.windowLog; 16000f743729SConrad Meyer assert(windowLog != 0); 16010f743729SConrad Meyer /* Resize working context table params for input only, since the dict 16020f743729SConrad Meyer * has its own tables. */ 16030f743729SConrad Meyer params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0); 16040f743729SConrad Meyer params.cParams.windowLog = windowLog; 16050f743729SConrad Meyer ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 16060f743729SConrad Meyer ZSTDcrp_continue, zbuff); 16070f743729SConrad Meyer assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); 16080f743729SConrad Meyer } 16090f743729SConrad Meyer 16100f743729SConrad Meyer { 16110f743729SConrad Meyer const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc 16120f743729SConrad Meyer - cdict->matchState.window.base); 16130f743729SConrad Meyer const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit; 16140f743729SConrad Meyer if (cdictLen == 0) { 16150f743729SConrad Meyer /* don't even attach dictionaries with no contents */ 16160f743729SConrad Meyer DEBUGLOG(4, "skipping attaching empty dictionary"); 16170f743729SConrad Meyer } else { 16180f743729SConrad Meyer DEBUGLOG(4, "attaching dictionary into context"); 16190f743729SConrad Meyer cctx->blockState.matchState.dictMatchState = &cdict->matchState; 16200f743729SConrad Meyer 16210f743729SConrad Meyer /* prep working match state so dict matches never have negative indices 16220f743729SConrad Meyer * when they are translated to the working context's index space. */ 16230f743729SConrad Meyer if (cctx->blockState.matchState.window.dictLimit < cdictEnd) { 16240f743729SConrad Meyer cctx->blockState.matchState.window.nextSrc = 16250f743729SConrad Meyer cctx->blockState.matchState.window.base + cdictEnd; 16260f743729SConrad Meyer ZSTD_window_clear(&cctx->blockState.matchState.window); 16270f743729SConrad Meyer } 16280f743729SConrad Meyer cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit; 16290f743729SConrad Meyer } 16300f743729SConrad Meyer } 16310f743729SConrad Meyer 16320f743729SConrad Meyer cctx->dictID = cdict->dictID; 16330f743729SConrad Meyer 16340f743729SConrad Meyer /* copy block state */ 16350f743729SConrad Meyer memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 16360f743729SConrad Meyer 16370f743729SConrad Meyer return 0; 16380f743729SConrad Meyer } 16390f743729SConrad Meyer 16400f743729SConrad Meyer static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, 16410f743729SConrad Meyer const ZSTD_CDict* cdict, 16420f743729SConrad Meyer ZSTD_CCtx_params params, 16430f743729SConrad Meyer U64 pledgedSrcSize, 16440f743729SConrad Meyer ZSTD_buffered_policy_e zbuff) 16450f743729SConrad Meyer { 16460f743729SConrad Meyer const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; 16470f743729SConrad Meyer 16480f743729SConrad Meyer DEBUGLOG(4, "copying dictionary into context"); 16490f743729SConrad Meyer 16500f743729SConrad Meyer { unsigned const windowLog = params.cParams.windowLog; 16510f743729SConrad Meyer assert(windowLog != 0); 165219fcbaf1SConrad Meyer /* Copy only compression parameters related to tables. */ 16530f743729SConrad Meyer params.cParams = *cdict_cParams; 16540f743729SConrad Meyer params.cParams.windowLog = windowLog; 165519fcbaf1SConrad Meyer ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 165619fcbaf1SConrad Meyer ZSTDcrp_noMemset, zbuff); 16570f743729SConrad Meyer assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); 16580f743729SConrad Meyer assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog); 16590f743729SConrad Meyer assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog); 166019fcbaf1SConrad Meyer } 166119fcbaf1SConrad Meyer 166219fcbaf1SConrad Meyer /* copy tables */ 16630f743729SConrad Meyer { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog); 16640f743729SConrad Meyer size_t const hSize = (size_t)1 << cdict_cParams->hashLog; 166519fcbaf1SConrad Meyer size_t const tableSpace = (chainSize + hSize) * sizeof(U32); 166619fcbaf1SConrad Meyer assert((U32*)cctx->blockState.matchState.chainTable == (U32*)cctx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */ 166719fcbaf1SConrad Meyer assert((U32*)cctx->blockState.matchState.hashTable3 == (U32*)cctx->blockState.matchState.chainTable + chainSize); 166819fcbaf1SConrad Meyer assert((U32*)cdict->matchState.chainTable == (U32*)cdict->matchState.hashTable + hSize); /* chainTable must follow hashTable */ 166919fcbaf1SConrad Meyer assert((U32*)cdict->matchState.hashTable3 == (U32*)cdict->matchState.chainTable + chainSize); 167019fcbaf1SConrad Meyer memcpy(cctx->blockState.matchState.hashTable, cdict->matchState.hashTable, tableSpace); /* presumes all tables follow each other */ 167119fcbaf1SConrad Meyer } 16720f743729SConrad Meyer 167319fcbaf1SConrad Meyer /* Zero the hashTable3, since the cdict never fills it */ 167419fcbaf1SConrad Meyer { size_t const h3Size = (size_t)1 << cctx->blockState.matchState.hashLog3; 167519fcbaf1SConrad Meyer assert(cdict->matchState.hashLog3 == 0); 167619fcbaf1SConrad Meyer memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); 167719fcbaf1SConrad Meyer } 167819fcbaf1SConrad Meyer 167919fcbaf1SConrad Meyer /* copy dictionary offsets */ 16800f743729SConrad Meyer { ZSTD_matchState_t const* srcMatchState = &cdict->matchState; 168119fcbaf1SConrad Meyer ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState; 168219fcbaf1SConrad Meyer dstMatchState->window = srcMatchState->window; 168319fcbaf1SConrad Meyer dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 168419fcbaf1SConrad Meyer dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3; 168519fcbaf1SConrad Meyer dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 168619fcbaf1SConrad Meyer } 16870f743729SConrad Meyer 168819fcbaf1SConrad Meyer cctx->dictID = cdict->dictID; 168919fcbaf1SConrad Meyer 169019fcbaf1SConrad Meyer /* copy block state */ 169119fcbaf1SConrad Meyer memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 169219fcbaf1SConrad Meyer 169319fcbaf1SConrad Meyer return 0; 169419fcbaf1SConrad Meyer } 16950c16b537SWarner Losh 16960f743729SConrad Meyer /* We have a choice between copying the dictionary context into the working 16970f743729SConrad Meyer * context, or referencing the dictionary context from the working context 16980f743729SConrad Meyer * in-place. We decide here which strategy to use. */ 16990f743729SConrad Meyer static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx, 17000f743729SConrad Meyer const ZSTD_CDict* cdict, 17010f743729SConrad Meyer ZSTD_CCtx_params params, 17020f743729SConrad Meyer U64 pledgedSrcSize, 17030f743729SConrad Meyer ZSTD_buffered_policy_e zbuff) 17040f743729SConrad Meyer { 17050f743729SConrad Meyer 1706a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)", 1707a0483764SConrad Meyer (unsigned)pledgedSrcSize); 17080f743729SConrad Meyer 17090f743729SConrad Meyer if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) { 17100f743729SConrad Meyer return ZSTD_resetCCtx_byAttachingCDict( 17110f743729SConrad Meyer cctx, cdict, params, pledgedSrcSize, zbuff); 17120f743729SConrad Meyer } else { 17130f743729SConrad Meyer return ZSTD_resetCCtx_byCopyingCDict( 17140f743729SConrad Meyer cctx, cdict, params, pledgedSrcSize, zbuff); 17150f743729SConrad Meyer } 17160f743729SConrad Meyer } 17170f743729SConrad Meyer 17180c16b537SWarner Losh /*! ZSTD_copyCCtx_internal() : 17190c16b537SWarner Losh * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 17200c16b537SWarner Losh * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 1721052d3c12SConrad Meyer * The "context", in this case, refers to the hash and chain tables, 1722052d3c12SConrad Meyer * entropy tables, and dictionary references. 1723052d3c12SConrad Meyer * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx. 17240c16b537SWarner Losh * @return : 0, or an error code */ 17250c16b537SWarner Losh static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, 17260c16b537SWarner Losh const ZSTD_CCtx* srcCCtx, 17270c16b537SWarner Losh ZSTD_frameParameters fParams, 1728052d3c12SConrad Meyer U64 pledgedSrcSize, 17290c16b537SWarner Losh ZSTD_buffered_policy_e zbuff) 17300c16b537SWarner Losh { 17310c16b537SWarner Losh DEBUGLOG(5, "ZSTD_copyCCtx_internal"); 1732*2b9c00cbSConrad Meyer RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong); 17330c16b537SWarner Losh 17340c16b537SWarner Losh memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); 17350c16b537SWarner Losh { ZSTD_CCtx_params params = dstCCtx->requestedParams; 17360c16b537SWarner Losh /* Copy only compression parameters related to tables. */ 17370c16b537SWarner Losh params.cParams = srcCCtx->appliedParams.cParams; 17380c16b537SWarner Losh params.fParams = fParams; 17390c16b537SWarner Losh ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, 17400c16b537SWarner Losh ZSTDcrp_noMemset, zbuff); 174119fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog); 174219fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy); 174319fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog); 174419fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog); 174519fcbaf1SConrad Meyer assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3); 17460c16b537SWarner Losh } 17470c16b537SWarner Losh 17480c16b537SWarner Losh /* copy tables */ 17490c16b537SWarner Losh { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog); 17500c16b537SWarner Losh size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; 175119fcbaf1SConrad Meyer size_t const h3Size = (size_t)1 << srcCCtx->blockState.matchState.hashLog3; 17520c16b537SWarner Losh size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 175319fcbaf1SConrad Meyer assert((U32*)dstCCtx->blockState.matchState.chainTable == (U32*)dstCCtx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */ 175419fcbaf1SConrad Meyer assert((U32*)dstCCtx->blockState.matchState.hashTable3 == (U32*)dstCCtx->blockState.matchState.chainTable + chainSize); 175519fcbaf1SConrad Meyer memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, tableSpace); /* presumes all tables follow each other */ 17560c16b537SWarner Losh } 17570c16b537SWarner Losh 17580c16b537SWarner Losh /* copy dictionary offsets */ 175919fcbaf1SConrad Meyer { 17600f743729SConrad Meyer const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState; 176119fcbaf1SConrad Meyer ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState; 176219fcbaf1SConrad Meyer dstMatchState->window = srcMatchState->window; 176319fcbaf1SConrad Meyer dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 176419fcbaf1SConrad Meyer dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3; 176519fcbaf1SConrad Meyer dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 176619fcbaf1SConrad Meyer } 17670c16b537SWarner Losh dstCCtx->dictID = srcCCtx->dictID; 17680c16b537SWarner Losh 176919fcbaf1SConrad Meyer /* copy block state */ 177019fcbaf1SConrad Meyer memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); 17710c16b537SWarner Losh 17720c16b537SWarner Losh return 0; 17730c16b537SWarner Losh } 17740c16b537SWarner Losh 17750c16b537SWarner Losh /*! ZSTD_copyCCtx() : 17760c16b537SWarner Losh * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 17770c16b537SWarner Losh * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 17780c16b537SWarner Losh * pledgedSrcSize==0 means "unknown". 17790c16b537SWarner Losh * @return : 0, or an error code */ 17800c16b537SWarner Losh size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) 17810c16b537SWarner Losh { 17820c16b537SWarner Losh ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 17830c16b537SWarner Losh ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0); 17840c16b537SWarner Losh ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); 1785052d3c12SConrad Meyer if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; 1786052d3c12SConrad Meyer fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN); 17870c16b537SWarner Losh 1788052d3c12SConrad Meyer return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, 178919fcbaf1SConrad Meyer fParams, pledgedSrcSize, 1790052d3c12SConrad Meyer zbuff); 17910c16b537SWarner Losh } 17920c16b537SWarner Losh 17930c16b537SWarner Losh 179419fcbaf1SConrad Meyer #define ZSTD_ROWSIZE 16 17950c16b537SWarner Losh /*! ZSTD_reduceTable() : 179619fcbaf1SConrad Meyer * reduce table indexes by `reducerValue`, or squash to zero. 179719fcbaf1SConrad Meyer * PreserveMark preserves "unsorted mark" for btlazy2 strategy. 179819fcbaf1SConrad Meyer * It must be set to a clear 0/1 value, to remove branch during inlining. 179919fcbaf1SConrad Meyer * Presume table size is a multiple of ZSTD_ROWSIZE 180019fcbaf1SConrad Meyer * to help auto-vectorization */ 180119fcbaf1SConrad Meyer FORCE_INLINE_TEMPLATE void 180219fcbaf1SConrad Meyer ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark) 18030c16b537SWarner Losh { 180419fcbaf1SConrad Meyer int const nbRows = (int)size / ZSTD_ROWSIZE; 180519fcbaf1SConrad Meyer int cellNb = 0; 180619fcbaf1SConrad Meyer int rowNb; 180719fcbaf1SConrad Meyer assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */ 180819fcbaf1SConrad Meyer assert(size < (1U<<31)); /* can be casted to int */ 180919fcbaf1SConrad Meyer for (rowNb=0 ; rowNb < nbRows ; rowNb++) { 181019fcbaf1SConrad Meyer int column; 181119fcbaf1SConrad Meyer for (column=0; column<ZSTD_ROWSIZE; column++) { 181219fcbaf1SConrad Meyer if (preserveMark) { 181319fcbaf1SConrad Meyer U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0; 181419fcbaf1SConrad Meyer table[cellNb] += adder; 18150c16b537SWarner Losh } 181619fcbaf1SConrad Meyer if (table[cellNb] < reducerValue) table[cellNb] = 0; 181719fcbaf1SConrad Meyer else table[cellNb] -= reducerValue; 181819fcbaf1SConrad Meyer cellNb++; 181919fcbaf1SConrad Meyer } } 18200c16b537SWarner Losh } 18210c16b537SWarner Losh 182219fcbaf1SConrad Meyer static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue) 18230c16b537SWarner Losh { 182419fcbaf1SConrad Meyer ZSTD_reduceTable_internal(table, size, reducerValue, 0); 18250c16b537SWarner Losh } 182619fcbaf1SConrad Meyer 182719fcbaf1SConrad Meyer static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue) 182819fcbaf1SConrad Meyer { 182919fcbaf1SConrad Meyer ZSTD_reduceTable_internal(table, size, reducerValue, 1); 18300c16b537SWarner Losh } 18310c16b537SWarner Losh 18320c16b537SWarner Losh /*! ZSTD_reduceIndex() : 18330c16b537SWarner Losh * rescale all indexes to avoid future overflow (indexes are U32) */ 18340c16b537SWarner Losh static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) 18350c16b537SWarner Losh { 183619fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &zc->blockState.matchState; 18370c16b537SWarner Losh { U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog; 183819fcbaf1SConrad Meyer ZSTD_reduceTable(ms->hashTable, hSize, reducerValue); 18390c16b537SWarner Losh } 184019fcbaf1SConrad Meyer 184119fcbaf1SConrad Meyer if (zc->appliedParams.cParams.strategy != ZSTD_fast) { 184219fcbaf1SConrad Meyer U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog; 184319fcbaf1SConrad Meyer if (zc->appliedParams.cParams.strategy == ZSTD_btlazy2) 184419fcbaf1SConrad Meyer ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue); 184519fcbaf1SConrad Meyer else 184619fcbaf1SConrad Meyer ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue); 184719fcbaf1SConrad Meyer } 184819fcbaf1SConrad Meyer 184919fcbaf1SConrad Meyer if (ms->hashLog3) { 185019fcbaf1SConrad Meyer U32 const h3Size = (U32)1 << ms->hashLog3; 185119fcbaf1SConrad Meyer ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue); 18520c16b537SWarner Losh } 18530c16b537SWarner Losh } 18540c16b537SWarner Losh 18550c16b537SWarner Losh 18560c16b537SWarner Losh /*-******************************************************* 18570c16b537SWarner Losh * Block entropic compression 18580c16b537SWarner Losh *********************************************************/ 18590c16b537SWarner Losh 18600c16b537SWarner Losh /* See doc/zstd_compression_format.md for detailed format description */ 18610c16b537SWarner Losh 18620f743729SConrad Meyer static size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) 18630c16b537SWarner Losh { 18640f743729SConrad Meyer U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3); 1865*2b9c00cbSConrad Meyer RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity, 1866*2b9c00cbSConrad Meyer dstSize_tooSmall); 18670f743729SConrad Meyer MEM_writeLE24(dst, cBlockHeader24); 18680c16b537SWarner Losh memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize); 18690c16b537SWarner Losh return ZSTD_blockHeaderSize + srcSize; 18700c16b537SWarner Losh } 18710c16b537SWarner Losh 18720c16b537SWarner Losh static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize) 18730c16b537SWarner Losh { 18740c16b537SWarner Losh BYTE* const ostart = (BYTE* const)dst; 18750c16b537SWarner Losh U32 const flSize = 1 + (srcSize>31) + (srcSize>4095); 18760c16b537SWarner Losh 1877*2b9c00cbSConrad Meyer RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall); 18780c16b537SWarner Losh 18790c16b537SWarner Losh switch(flSize) 18800c16b537SWarner Losh { 18810c16b537SWarner Losh case 1: /* 2 - 1 - 5 */ 18820c16b537SWarner Losh ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3)); 18830c16b537SWarner Losh break; 18840c16b537SWarner Losh case 2: /* 2 - 2 - 12 */ 18850c16b537SWarner Losh MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4))); 18860c16b537SWarner Losh break; 18870c16b537SWarner Losh case 3: /* 2 - 2 - 20 */ 18880c16b537SWarner Losh MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4))); 18890c16b537SWarner Losh break; 18900c16b537SWarner Losh default: /* not necessary : flSize is {1,2,3} */ 18910c16b537SWarner Losh assert(0); 18920c16b537SWarner Losh } 18930c16b537SWarner Losh 18940c16b537SWarner Losh memcpy(ostart + flSize, src, srcSize); 18950c16b537SWarner Losh return srcSize + flSize; 18960c16b537SWarner Losh } 18970c16b537SWarner Losh 18980c16b537SWarner Losh static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize) 18990c16b537SWarner Losh { 19000c16b537SWarner Losh BYTE* const ostart = (BYTE* const)dst; 19010c16b537SWarner Losh U32 const flSize = 1 + (srcSize>31) + (srcSize>4095); 19020c16b537SWarner Losh 19030c16b537SWarner Losh (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */ 19040c16b537SWarner Losh 19050c16b537SWarner Losh switch(flSize) 19060c16b537SWarner Losh { 19070c16b537SWarner Losh case 1: /* 2 - 1 - 5 */ 19080c16b537SWarner Losh ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3)); 19090c16b537SWarner Losh break; 19100c16b537SWarner Losh case 2: /* 2 - 2 - 12 */ 19110c16b537SWarner Losh MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4))); 19120c16b537SWarner Losh break; 19130c16b537SWarner Losh case 3: /* 2 - 2 - 20 */ 19140c16b537SWarner Losh MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4))); 19150c16b537SWarner Losh break; 19160c16b537SWarner Losh default: /* not necessary : flSize is {1,2,3} */ 19170c16b537SWarner Losh assert(0); 19180c16b537SWarner Losh } 19190c16b537SWarner Losh 19200c16b537SWarner Losh ostart[flSize] = *(const BYTE*)src; 19210c16b537SWarner Losh return flSize+1; 19220c16b537SWarner Losh } 19230c16b537SWarner Losh 19240c16b537SWarner Losh 19250f743729SConrad Meyer /* ZSTD_minGain() : 19260f743729SConrad Meyer * minimum compression required 19270f743729SConrad Meyer * to generate a compress block or a compressed literals section. 19280f743729SConrad Meyer * note : use same formula for both situations */ 19290f743729SConrad Meyer static size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat) 19300f743729SConrad Meyer { 1931a0483764SConrad Meyer U32 const minlog = (strat>=ZSTD_btultra) ? (U32)(strat) - 1 : 6; 1932a0483764SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_btultra == 8); 1933a0483764SConrad Meyer assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); 19340f743729SConrad Meyer return (srcSize >> minlog) + 2; 19350f743729SConrad Meyer } 19360c16b537SWarner Losh 19370f743729SConrad Meyer static size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, 19380f743729SConrad Meyer ZSTD_hufCTables_t* nextHuf, 193919fcbaf1SConrad Meyer ZSTD_strategy strategy, int disableLiteralCompression, 19400c16b537SWarner Losh void* dst, size_t dstCapacity, 194119fcbaf1SConrad Meyer const void* src, size_t srcSize, 1942a0483764SConrad Meyer void* workspace, size_t wkspSize, 1943a0483764SConrad Meyer const int bmi2) 19440c16b537SWarner Losh { 19450f743729SConrad Meyer size_t const minGain = ZSTD_minGain(srcSize, strategy); 19460c16b537SWarner Losh size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); 19470c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 19480c16b537SWarner Losh U32 singleStream = srcSize < 256; 19490c16b537SWarner Losh symbolEncodingType_e hType = set_compressed; 19500c16b537SWarner Losh size_t cLitSize; 19510c16b537SWarner Losh 195219fcbaf1SConrad Meyer DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i)", 195319fcbaf1SConrad Meyer disableLiteralCompression); 195419fcbaf1SConrad Meyer 195519fcbaf1SConrad Meyer /* Prepare nextEntropy assuming reusing the existing table */ 19560f743729SConrad Meyer memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 195719fcbaf1SConrad Meyer 195819fcbaf1SConrad Meyer if (disableLiteralCompression) 195919fcbaf1SConrad Meyer return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 19600c16b537SWarner Losh 19610c16b537SWarner Losh /* small ? don't even attempt compression (speed opt) */ 196219fcbaf1SConrad Meyer # define COMPRESS_LITERALS_SIZE_MIN 63 19630f743729SConrad Meyer { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; 19640c16b537SWarner Losh if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 19650c16b537SWarner Losh } 19660c16b537SWarner Losh 1967*2b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression"); 19680f743729SConrad Meyer { HUF_repeat repeat = prevHuf->repeatMode; 19690c16b537SWarner Losh int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0; 19700c16b537SWarner Losh if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1; 19710c16b537SWarner Losh cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, 1972a0483764SConrad Meyer workspace, wkspSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2) 19730c16b537SWarner Losh : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, 1974a0483764SConrad Meyer workspace, wkspSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2); 197519fcbaf1SConrad Meyer if (repeat != HUF_repeat_none) { 197619fcbaf1SConrad Meyer /* reused the existing table */ 197719fcbaf1SConrad Meyer hType = set_repeat; 197819fcbaf1SConrad Meyer } 19790c16b537SWarner Losh } 19800c16b537SWarner Losh 19810c16b537SWarner Losh if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) { 19820f743729SConrad Meyer memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 19830c16b537SWarner Losh return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 19840c16b537SWarner Losh } 19850c16b537SWarner Losh if (cLitSize==1) { 19860f743729SConrad Meyer memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 19870c16b537SWarner Losh return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); 19880c16b537SWarner Losh } 19890c16b537SWarner Losh 199019fcbaf1SConrad Meyer if (hType == set_compressed) { 199119fcbaf1SConrad Meyer /* using a newly constructed table */ 19920f743729SConrad Meyer nextHuf->repeatMode = HUF_repeat_check; 199319fcbaf1SConrad Meyer } 199419fcbaf1SConrad Meyer 19950c16b537SWarner Losh /* Build header */ 19960c16b537SWarner Losh switch(lhSize) 19970c16b537SWarner Losh { 19980c16b537SWarner Losh case 3: /* 2 - 2 - 10 - 10 */ 19990c16b537SWarner Losh { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14); 20000c16b537SWarner Losh MEM_writeLE24(ostart, lhc); 20010c16b537SWarner Losh break; 20020c16b537SWarner Losh } 20030c16b537SWarner Losh case 4: /* 2 - 2 - 14 - 14 */ 20040c16b537SWarner Losh { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18); 20050c16b537SWarner Losh MEM_writeLE32(ostart, lhc); 20060c16b537SWarner Losh break; 20070c16b537SWarner Losh } 20080c16b537SWarner Losh case 5: /* 2 - 2 - 18 - 18 */ 20090c16b537SWarner Losh { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22); 20100c16b537SWarner Losh MEM_writeLE32(ostart, lhc); 20110c16b537SWarner Losh ostart[4] = (BYTE)(cLitSize >> 10); 20120c16b537SWarner Losh break; 20130c16b537SWarner Losh } 20140c16b537SWarner Losh default: /* not possible : lhSize is {3,4,5} */ 20150c16b537SWarner Losh assert(0); 20160c16b537SWarner Losh } 20170c16b537SWarner Losh return lhSize+cLitSize; 20180c16b537SWarner Losh } 20190c16b537SWarner Losh 20200c16b537SWarner Losh 20210c16b537SWarner Losh void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) 20220c16b537SWarner Losh { 20230c16b537SWarner Losh const seqDef* const sequences = seqStorePtr->sequencesStart; 20240c16b537SWarner Losh BYTE* const llCodeTable = seqStorePtr->llCode; 20250c16b537SWarner Losh BYTE* const ofCodeTable = seqStorePtr->ofCode; 20260c16b537SWarner Losh BYTE* const mlCodeTable = seqStorePtr->mlCode; 20270c16b537SWarner Losh U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 20280c16b537SWarner Losh U32 u; 20290f743729SConrad Meyer assert(nbSeq <= seqStorePtr->maxNbSeq); 20300c16b537SWarner Losh for (u=0; u<nbSeq; u++) { 20310c16b537SWarner Losh U32 const llv = sequences[u].litLength; 20320c16b537SWarner Losh U32 const mlv = sequences[u].matchLength; 2033052d3c12SConrad Meyer llCodeTable[u] = (BYTE)ZSTD_LLcode(llv); 20340c16b537SWarner Losh ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset); 2035052d3c12SConrad Meyer mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv); 20360c16b537SWarner Losh } 20370c16b537SWarner Losh if (seqStorePtr->longLengthID==1) 20380c16b537SWarner Losh llCodeTable[seqStorePtr->longLengthPos] = MaxLL; 20390c16b537SWarner Losh if (seqStorePtr->longLengthID==2) 20400c16b537SWarner Losh mlCodeTable[seqStorePtr->longLengthPos] = MaxML; 20410c16b537SWarner Losh } 20420c16b537SWarner Losh 20430f743729SConrad Meyer 20440f743729SConrad Meyer /** 20450f743729SConrad Meyer * -log2(x / 256) lookup table for x in [0, 256). 20460f743729SConrad Meyer * If x == 0: Return 0 20470f743729SConrad Meyer * Else: Return floor(-log2(x / 256) * 256) 20480f743729SConrad Meyer */ 2049*2b9c00cbSConrad Meyer static unsigned const kInverseProbabilityLog256[256] = { 20500f743729SConrad Meyer 0, 2048, 1792, 1642, 1536, 1453, 1386, 1329, 1280, 1236, 1197, 1162, 20510f743729SConrad Meyer 1130, 1100, 1073, 1047, 1024, 1001, 980, 960, 941, 923, 906, 889, 20520f743729SConrad Meyer 874, 859, 844, 830, 817, 804, 791, 779, 768, 756, 745, 734, 20530f743729SConrad Meyer 724, 714, 704, 694, 685, 676, 667, 658, 650, 642, 633, 626, 20540f743729SConrad Meyer 618, 610, 603, 595, 588, 581, 574, 567, 561, 554, 548, 542, 20550f743729SConrad Meyer 535, 529, 523, 517, 512, 506, 500, 495, 489, 484, 478, 473, 20560f743729SConrad Meyer 468, 463, 458, 453, 448, 443, 438, 434, 429, 424, 420, 415, 20570f743729SConrad Meyer 411, 407, 402, 398, 394, 390, 386, 382, 377, 373, 370, 366, 20580f743729SConrad Meyer 362, 358, 354, 350, 347, 343, 339, 336, 332, 329, 325, 322, 20590f743729SConrad Meyer 318, 315, 311, 308, 305, 302, 298, 295, 292, 289, 286, 282, 20600f743729SConrad Meyer 279, 276, 273, 270, 267, 264, 261, 258, 256, 253, 250, 247, 20610f743729SConrad Meyer 244, 241, 239, 236, 233, 230, 228, 225, 222, 220, 217, 215, 20620f743729SConrad Meyer 212, 209, 207, 204, 202, 199, 197, 194, 192, 190, 187, 185, 20630f743729SConrad Meyer 182, 180, 178, 175, 173, 171, 168, 166, 164, 162, 159, 157, 20640f743729SConrad Meyer 155, 153, 151, 149, 146, 144, 142, 140, 138, 136, 134, 132, 20650f743729SConrad Meyer 130, 128, 126, 123, 121, 119, 117, 115, 114, 112, 110, 108, 20660f743729SConrad Meyer 106, 104, 102, 100, 98, 96, 94, 93, 91, 89, 87, 85, 20670f743729SConrad Meyer 83, 82, 80, 78, 76, 74, 73, 71, 69, 67, 66, 64, 20680f743729SConrad Meyer 62, 61, 59, 57, 55, 54, 52, 50, 49, 47, 46, 44, 20690f743729SConrad Meyer 42, 41, 39, 37, 36, 34, 33, 31, 30, 28, 26, 25, 20700f743729SConrad Meyer 23, 22, 20, 19, 17, 16, 14, 13, 11, 10, 8, 7, 20710f743729SConrad Meyer 5, 4, 2, 1, 20720f743729SConrad Meyer }; 20730f743729SConrad Meyer 20740f743729SConrad Meyer 20750f743729SConrad Meyer /** 20760f743729SConrad Meyer * Returns the cost in bits of encoding the distribution described by count 20770f743729SConrad Meyer * using the entropy bound. 20780f743729SConrad Meyer */ 20790f743729SConrad Meyer static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t const total) 20800f743729SConrad Meyer { 20810f743729SConrad Meyer unsigned cost = 0; 20820f743729SConrad Meyer unsigned s; 20830f743729SConrad Meyer for (s = 0; s <= max; ++s) { 20840f743729SConrad Meyer unsigned norm = (unsigned)((256 * count[s]) / total); 20850f743729SConrad Meyer if (count[s] != 0 && norm == 0) 20860f743729SConrad Meyer norm = 1; 20870f743729SConrad Meyer assert(count[s] < total); 2088*2b9c00cbSConrad Meyer cost += count[s] * kInverseProbabilityLog256[norm]; 20890f743729SConrad Meyer } 20900f743729SConrad Meyer return cost >> 8; 20910f743729SConrad Meyer } 20920f743729SConrad Meyer 20930f743729SConrad Meyer 20940f743729SConrad Meyer /** 20950f743729SConrad Meyer * Returns the cost in bits of encoding the distribution in count using the 20960f743729SConrad Meyer * table described by norm. The max symbol support by norm is assumed >= max. 20970f743729SConrad Meyer * norm must be valid for every symbol with non-zero probability in count. 20980f743729SConrad Meyer */ 20990f743729SConrad Meyer static size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog, 21000f743729SConrad Meyer unsigned const* count, unsigned const max) 21010f743729SConrad Meyer { 21020f743729SConrad Meyer unsigned const shift = 8 - accuracyLog; 21030f743729SConrad Meyer size_t cost = 0; 21040f743729SConrad Meyer unsigned s; 21050f743729SConrad Meyer assert(accuracyLog <= 8); 21060f743729SConrad Meyer for (s = 0; s <= max; ++s) { 21070f743729SConrad Meyer unsigned const normAcc = norm[s] != -1 ? norm[s] : 1; 21080f743729SConrad Meyer unsigned const norm256 = normAcc << shift; 21090f743729SConrad Meyer assert(norm256 > 0); 21100f743729SConrad Meyer assert(norm256 < 256); 2111*2b9c00cbSConrad Meyer cost += count[s] * kInverseProbabilityLog256[norm256]; 21120f743729SConrad Meyer } 21130f743729SConrad Meyer return cost >> 8; 21140f743729SConrad Meyer } 21150f743729SConrad Meyer 21160f743729SConrad Meyer 21170f743729SConrad Meyer static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) { 21180f743729SConrad Meyer void const* ptr = ctable; 21190f743729SConrad Meyer U16 const* u16ptr = (U16 const*)ptr; 21200f743729SConrad Meyer U32 const maxSymbolValue = MEM_read16(u16ptr + 1); 21210f743729SConrad Meyer return maxSymbolValue; 21220f743729SConrad Meyer } 21230f743729SConrad Meyer 21240f743729SConrad Meyer 21250f743729SConrad Meyer /** 21260f743729SConrad Meyer * Returns the cost in bits of encoding the distribution in count using ctable. 21270f743729SConrad Meyer * Returns an error if ctable cannot represent all the symbols in count. 21280f743729SConrad Meyer */ 21290f743729SConrad Meyer static size_t ZSTD_fseBitCost( 21300f743729SConrad Meyer FSE_CTable const* ctable, 21310f743729SConrad Meyer unsigned const* count, 21320f743729SConrad Meyer unsigned const max) 21330f743729SConrad Meyer { 21340f743729SConrad Meyer unsigned const kAccuracyLog = 8; 21350f743729SConrad Meyer size_t cost = 0; 21360f743729SConrad Meyer unsigned s; 21370f743729SConrad Meyer FSE_CState_t cstate; 21380f743729SConrad Meyer FSE_initCState(&cstate, ctable); 2139*2b9c00cbSConrad Meyer RETURN_ERROR_IF(ZSTD_getFSEMaxSymbolValue(ctable) < max, GENERIC, 2140*2b9c00cbSConrad Meyer "Repeat FSE_CTable has maxSymbolValue %u < %u", 21410f743729SConrad Meyer ZSTD_getFSEMaxSymbolValue(ctable), max); 21420f743729SConrad Meyer for (s = 0; s <= max; ++s) { 21430f743729SConrad Meyer unsigned const tableLog = cstate.stateLog; 21440f743729SConrad Meyer unsigned const badCost = (tableLog + 1) << kAccuracyLog; 21450f743729SConrad Meyer unsigned const bitCost = FSE_bitCost(cstate.symbolTT, tableLog, s, kAccuracyLog); 21460f743729SConrad Meyer if (count[s] == 0) 21470f743729SConrad Meyer continue; 2148*2b9c00cbSConrad Meyer RETURN_ERROR_IF(bitCost >= badCost, GENERIC, 2149*2b9c00cbSConrad Meyer "Repeat FSE_CTable has Prob[%u] == 0", s); 21500f743729SConrad Meyer cost += count[s] * bitCost; 21510f743729SConrad Meyer } 21520f743729SConrad Meyer return cost >> kAccuracyLog; 21530f743729SConrad Meyer } 21540f743729SConrad Meyer 21550f743729SConrad Meyer /** 21560f743729SConrad Meyer * Returns the cost in bytes of encoding the normalized count header. 21570f743729SConrad Meyer * Returns an error if any of the helper functions return an error. 21580f743729SConrad Meyer */ 21590f743729SConrad Meyer static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max, 21600f743729SConrad Meyer size_t const nbSeq, unsigned const FSELog) 21610f743729SConrad Meyer { 21620f743729SConrad Meyer BYTE wksp[FSE_NCOUNTBOUND]; 21630f743729SConrad Meyer S16 norm[MaxSeq + 1]; 21640f743729SConrad Meyer const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); 2165*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq, max)); 21660f743729SConrad Meyer return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog); 21670f743729SConrad Meyer } 21680f743729SConrad Meyer 21690f743729SConrad Meyer 21700c16b537SWarner Losh typedef enum { 21710c16b537SWarner Losh ZSTD_defaultDisallowed = 0, 21720c16b537SWarner Losh ZSTD_defaultAllowed = 1 21730c16b537SWarner Losh } ZSTD_defaultPolicy_e; 21740c16b537SWarner Losh 21750f743729SConrad Meyer MEM_STATIC symbolEncodingType_e 21760f743729SConrad Meyer ZSTD_selectEncodingType( 21770f743729SConrad Meyer FSE_repeat* repeatMode, unsigned const* count, unsigned const max, 21780f743729SConrad Meyer size_t const mostFrequent, size_t nbSeq, unsigned const FSELog, 21790f743729SConrad Meyer FSE_CTable const* prevCTable, 21800f743729SConrad Meyer short const* defaultNorm, U32 defaultNormLog, 21810f743729SConrad Meyer ZSTD_defaultPolicy_e const isDefaultAllowed, 21820f743729SConrad Meyer ZSTD_strategy const strategy) 21830c16b537SWarner Losh { 21840c16b537SWarner Losh ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0); 21850f743729SConrad Meyer if (mostFrequent == nbSeq) { 21860f743729SConrad Meyer *repeatMode = FSE_repeat_none; 21870f743729SConrad Meyer if (isDefaultAllowed && nbSeq <= 2) { 21880c16b537SWarner Losh /* Prefer set_basic over set_rle when there are 2 or less symbols, 21890c16b537SWarner Losh * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol. 21900c16b537SWarner Losh * If basic encoding isn't possible, always choose RLE. 21910c16b537SWarner Losh */ 21920f743729SConrad Meyer DEBUGLOG(5, "Selected set_basic"); 21930f743729SConrad Meyer return set_basic; 21940f743729SConrad Meyer } 21950f743729SConrad Meyer DEBUGLOG(5, "Selected set_rle"); 21960c16b537SWarner Losh return set_rle; 21970c16b537SWarner Losh } 21980f743729SConrad Meyer if (strategy < ZSTD_lazy) { 21990f743729SConrad Meyer if (isDefaultAllowed) { 22000f743729SConrad Meyer size_t const staticFse_nbSeq_max = 1000; 22010f743729SConrad Meyer size_t const mult = 10 - strategy; 22020f743729SConrad Meyer size_t const baseLog = 3; 22030f743729SConrad Meyer size_t const dynamicFse_nbSeq_min = (((size_t)1 << defaultNormLog) * mult) >> baseLog; /* 28-36 for offset, 56-72 for lengths */ 22040f743729SConrad Meyer assert(defaultNormLog >= 5 && defaultNormLog <= 6); /* xx_DEFAULTNORMLOG */ 22050f743729SConrad Meyer assert(mult <= 9 && mult >= 7); 22060f743729SConrad Meyer if ( (*repeatMode == FSE_repeat_valid) 22070f743729SConrad Meyer && (nbSeq < staticFse_nbSeq_max) ) { 2208052d3c12SConrad Meyer DEBUGLOG(5, "Selected set_repeat"); 22090c16b537SWarner Losh return set_repeat; 22100c16b537SWarner Losh } 22110f743729SConrad Meyer if ( (nbSeq < dynamicFse_nbSeq_min) 22120f743729SConrad Meyer || (mostFrequent < (nbSeq >> (defaultNormLog-1))) ) { 2213052d3c12SConrad Meyer DEBUGLOG(5, "Selected set_basic"); 2214052d3c12SConrad Meyer /* The format allows default tables to be repeated, but it isn't useful. 2215052d3c12SConrad Meyer * When using simple heuristics to select encoding type, we don't want 2216052d3c12SConrad Meyer * to confuse these tables with dictionaries. When running more careful 2217052d3c12SConrad Meyer * analysis, we don't need to waste time checking both repeating tables 2218052d3c12SConrad Meyer * and default tables. 2219052d3c12SConrad Meyer */ 2220052d3c12SConrad Meyer *repeatMode = FSE_repeat_none; 22210c16b537SWarner Losh return set_basic; 22220c16b537SWarner Losh } 22230f743729SConrad Meyer } 22240f743729SConrad Meyer } else { 22250f743729SConrad Meyer size_t const basicCost = isDefaultAllowed ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, count, max) : ERROR(GENERIC); 22260f743729SConrad Meyer size_t const repeatCost = *repeatMode != FSE_repeat_none ? ZSTD_fseBitCost(prevCTable, count, max) : ERROR(GENERIC); 22270f743729SConrad Meyer size_t const NCountCost = ZSTD_NCountCost(count, max, nbSeq, FSELog); 22280f743729SConrad Meyer size_t const compressedCost = (NCountCost << 3) + ZSTD_entropyCost(count, max, nbSeq); 22290f743729SConrad Meyer 22300f743729SConrad Meyer if (isDefaultAllowed) { 22310f743729SConrad Meyer assert(!ZSTD_isError(basicCost)); 22320f743729SConrad Meyer assert(!(*repeatMode == FSE_repeat_valid && ZSTD_isError(repeatCost))); 22330f743729SConrad Meyer } 22340f743729SConrad Meyer assert(!ZSTD_isError(NCountCost)); 22350f743729SConrad Meyer assert(compressedCost < ERROR(maxCode)); 22360f743729SConrad Meyer DEBUGLOG(5, "Estimated bit costs: basic=%u\trepeat=%u\tcompressed=%u", 2237a0483764SConrad Meyer (unsigned)basicCost, (unsigned)repeatCost, (unsigned)compressedCost); 22380f743729SConrad Meyer if (basicCost <= repeatCost && basicCost <= compressedCost) { 22390f743729SConrad Meyer DEBUGLOG(5, "Selected set_basic"); 22400f743729SConrad Meyer assert(isDefaultAllowed); 22410f743729SConrad Meyer *repeatMode = FSE_repeat_none; 22420f743729SConrad Meyer return set_basic; 22430f743729SConrad Meyer } 22440f743729SConrad Meyer if (repeatCost <= compressedCost) { 22450f743729SConrad Meyer DEBUGLOG(5, "Selected set_repeat"); 22460f743729SConrad Meyer assert(!ZSTD_isError(repeatCost)); 22470f743729SConrad Meyer return set_repeat; 22480f743729SConrad Meyer } 22490f743729SConrad Meyer assert(compressedCost < basicCost && compressedCost < repeatCost); 22500f743729SConrad Meyer } 2251052d3c12SConrad Meyer DEBUGLOG(5, "Selected set_compressed"); 22520c16b537SWarner Losh *repeatMode = FSE_repeat_check; 22530c16b537SWarner Losh return set_compressed; 22540c16b537SWarner Losh } 22550c16b537SWarner Losh 22560f743729SConrad Meyer MEM_STATIC size_t 22570f743729SConrad Meyer ZSTD_buildCTable(void* dst, size_t dstCapacity, 225819fcbaf1SConrad Meyer FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type, 2259a0483764SConrad Meyer unsigned* count, U32 max, 22600f743729SConrad Meyer const BYTE* codeTable, size_t nbSeq, 22610f743729SConrad Meyer const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax, 22620f743729SConrad Meyer const FSE_CTable* prevCTable, size_t prevCTableSize, 22630c16b537SWarner Losh void* workspace, size_t workspaceSize) 22640c16b537SWarner Losh { 22650c16b537SWarner Losh BYTE* op = (BYTE*)dst; 22660f743729SConrad Meyer const BYTE* const oend = op + dstCapacity; 2267a0483764SConrad Meyer DEBUGLOG(6, "ZSTD_buildCTable (dstCapacity=%u)", (unsigned)dstCapacity); 22680c16b537SWarner Losh 22690c16b537SWarner Losh switch (type) { 22700c16b537SWarner Losh case set_rle: 2271*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(FSE_buildCTable_rle(nextCTable, (BYTE)max)); 2272*2b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity==0, dstSize_tooSmall); 2273a0483764SConrad Meyer *op = codeTable[0]; 22740c16b537SWarner Losh return 1; 22750c16b537SWarner Losh case set_repeat: 227619fcbaf1SConrad Meyer memcpy(nextCTable, prevCTable, prevCTableSize); 22770c16b537SWarner Losh return 0; 22780c16b537SWarner Losh case set_basic: 2279*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */ 22800c16b537SWarner Losh return 0; 22810c16b537SWarner Losh case set_compressed: { 22820c16b537SWarner Losh S16 norm[MaxSeq + 1]; 22830c16b537SWarner Losh size_t nbSeq_1 = nbSeq; 22840c16b537SWarner Losh const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); 22850c16b537SWarner Losh if (count[codeTable[nbSeq-1]] > 1) { 22860c16b537SWarner Losh count[codeTable[nbSeq-1]]--; 22870c16b537SWarner Losh nbSeq_1--; 22880c16b537SWarner Losh } 22890c16b537SWarner Losh assert(nbSeq_1 > 1); 2290*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max)); 22910c16b537SWarner Losh { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */ 2292*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(NCountSize); 2293*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, workspace, workspaceSize)); 22940c16b537SWarner Losh return NCountSize; 22950c16b537SWarner Losh } 22960c16b537SWarner Losh } 2297*2b9c00cbSConrad Meyer default: assert(0); RETURN_ERROR(GENERIC); 22980c16b537SWarner Losh } 22990c16b537SWarner Losh } 23000c16b537SWarner Losh 230119fcbaf1SConrad Meyer FORCE_INLINE_TEMPLATE size_t 230219fcbaf1SConrad Meyer ZSTD_encodeSequences_body( 2303052d3c12SConrad Meyer void* dst, size_t dstCapacity, 23040c16b537SWarner Losh FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 23050c16b537SWarner Losh FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 23060c16b537SWarner Losh FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 23070c16b537SWarner Losh seqDef const* sequences, size_t nbSeq, int longOffsets) 23080c16b537SWarner Losh { 23090c16b537SWarner Losh BIT_CStream_t blockStream; 23100c16b537SWarner Losh FSE_CState_t stateMatchLength; 23110c16b537SWarner Losh FSE_CState_t stateOffsetBits; 23120c16b537SWarner Losh FSE_CState_t stateLitLength; 23130c16b537SWarner Losh 2314*2b9c00cbSConrad Meyer RETURN_ERROR_IF( 2315*2b9c00cbSConrad Meyer ERR_isError(BIT_initCStream(&blockStream, dst, dstCapacity)), 2316*2b9c00cbSConrad Meyer dstSize_tooSmall, "not enough space remaining"); 2317a0483764SConrad Meyer DEBUGLOG(6, "available space for bitstream : %i (dstCapacity=%u)", 2318a0483764SConrad Meyer (int)(blockStream.endPtr - blockStream.startPtr), 2319a0483764SConrad Meyer (unsigned)dstCapacity); 23200c16b537SWarner Losh 23210c16b537SWarner Losh /* first symbols */ 23220c16b537SWarner Losh FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]); 23230c16b537SWarner Losh FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]); 23240c16b537SWarner Losh FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]); 23250c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]); 23260c16b537SWarner Losh if (MEM_32bits()) BIT_flushBits(&blockStream); 23270c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]); 23280c16b537SWarner Losh if (MEM_32bits()) BIT_flushBits(&blockStream); 23290c16b537SWarner Losh if (longOffsets) { 23300c16b537SWarner Losh U32 const ofBits = ofCodeTable[nbSeq-1]; 23310c16b537SWarner Losh int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); 23320c16b537SWarner Losh if (extraBits) { 23330c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits); 23340c16b537SWarner Losh BIT_flushBits(&blockStream); 23350c16b537SWarner Losh } 23360c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits, 23370c16b537SWarner Losh ofBits - extraBits); 23380c16b537SWarner Losh } else { 23390c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]); 23400c16b537SWarner Losh } 23410c16b537SWarner Losh BIT_flushBits(&blockStream); 23420c16b537SWarner Losh 23430c16b537SWarner Losh { size_t n; 23440c16b537SWarner Losh for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */ 23450c16b537SWarner Losh BYTE const llCode = llCodeTable[n]; 23460c16b537SWarner Losh BYTE const ofCode = ofCodeTable[n]; 23470c16b537SWarner Losh BYTE const mlCode = mlCodeTable[n]; 23480c16b537SWarner Losh U32 const llBits = LL_bits[llCode]; 2349052d3c12SConrad Meyer U32 const ofBits = ofCode; 23500c16b537SWarner Losh U32 const mlBits = ML_bits[mlCode]; 2351052d3c12SConrad Meyer DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u", 2352a0483764SConrad Meyer (unsigned)sequences[n].litLength, 2353a0483764SConrad Meyer (unsigned)sequences[n].matchLength + MINMATCH, 2354a0483764SConrad Meyer (unsigned)sequences[n].offset); 235519fcbaf1SConrad Meyer /* 32b*/ /* 64b*/ 23560c16b537SWarner Losh /* (7)*/ /* (7)*/ 23570c16b537SWarner Losh FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */ 23580c16b537SWarner Losh FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */ 23590c16b537SWarner Losh if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/ 23600c16b537SWarner Losh FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */ 23610c16b537SWarner Losh if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog))) 23620c16b537SWarner Losh BIT_flushBits(&blockStream); /* (7)*/ 23630c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].litLength, llBits); 23640c16b537SWarner Losh if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream); 23650c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].matchLength, mlBits); 23660c16b537SWarner Losh if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream); 23670c16b537SWarner Losh if (longOffsets) { 23680c16b537SWarner Losh int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); 23690c16b537SWarner Losh if (extraBits) { 23700c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].offset, extraBits); 23710c16b537SWarner Losh BIT_flushBits(&blockStream); /* (7)*/ 23720c16b537SWarner Losh } 23730c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].offset >> extraBits, 23740c16b537SWarner Losh ofBits - extraBits); /* 31 */ 23750c16b537SWarner Losh } else { 23760c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */ 23770c16b537SWarner Losh } 23780c16b537SWarner Losh BIT_flushBits(&blockStream); /* (7)*/ 2379a0483764SConrad Meyer DEBUGLOG(7, "remaining space : %i", (int)(blockStream.endPtr - blockStream.ptr)); 23800c16b537SWarner Losh } } 23810c16b537SWarner Losh 238219fcbaf1SConrad Meyer DEBUGLOG(6, "ZSTD_encodeSequences: flushing ML state with %u bits", stateMatchLength.stateLog); 23830c16b537SWarner Losh FSE_flushCState(&blockStream, &stateMatchLength); 238419fcbaf1SConrad Meyer DEBUGLOG(6, "ZSTD_encodeSequences: flushing Off state with %u bits", stateOffsetBits.stateLog); 23850c16b537SWarner Losh FSE_flushCState(&blockStream, &stateOffsetBits); 238619fcbaf1SConrad Meyer DEBUGLOG(6, "ZSTD_encodeSequences: flushing LL state with %u bits", stateLitLength.stateLog); 23870c16b537SWarner Losh FSE_flushCState(&blockStream, &stateLitLength); 23880c16b537SWarner Losh 23890c16b537SWarner Losh { size_t const streamSize = BIT_closeCStream(&blockStream); 2390*2b9c00cbSConrad Meyer RETURN_ERROR_IF(streamSize==0, dstSize_tooSmall, "not enough space"); 23910c16b537SWarner Losh return streamSize; 23920c16b537SWarner Losh } 23930c16b537SWarner Losh } 23940c16b537SWarner Losh 239519fcbaf1SConrad Meyer static size_t 239619fcbaf1SConrad Meyer ZSTD_encodeSequences_default( 239719fcbaf1SConrad Meyer void* dst, size_t dstCapacity, 239819fcbaf1SConrad Meyer FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 239919fcbaf1SConrad Meyer FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 240019fcbaf1SConrad Meyer FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 240119fcbaf1SConrad Meyer seqDef const* sequences, size_t nbSeq, int longOffsets) 24020c16b537SWarner Losh { 240319fcbaf1SConrad Meyer return ZSTD_encodeSequences_body(dst, dstCapacity, 240419fcbaf1SConrad Meyer CTable_MatchLength, mlCodeTable, 240519fcbaf1SConrad Meyer CTable_OffsetBits, ofCodeTable, 240619fcbaf1SConrad Meyer CTable_LitLength, llCodeTable, 240719fcbaf1SConrad Meyer sequences, nbSeq, longOffsets); 240819fcbaf1SConrad Meyer } 240919fcbaf1SConrad Meyer 241019fcbaf1SConrad Meyer 241119fcbaf1SConrad Meyer #if DYNAMIC_BMI2 241219fcbaf1SConrad Meyer 241319fcbaf1SConrad Meyer static TARGET_ATTRIBUTE("bmi2") size_t 241419fcbaf1SConrad Meyer ZSTD_encodeSequences_bmi2( 241519fcbaf1SConrad Meyer void* dst, size_t dstCapacity, 241619fcbaf1SConrad Meyer FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 241719fcbaf1SConrad Meyer FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 241819fcbaf1SConrad Meyer FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 241919fcbaf1SConrad Meyer seqDef const* sequences, size_t nbSeq, int longOffsets) 242019fcbaf1SConrad Meyer { 242119fcbaf1SConrad Meyer return ZSTD_encodeSequences_body(dst, dstCapacity, 242219fcbaf1SConrad Meyer CTable_MatchLength, mlCodeTable, 242319fcbaf1SConrad Meyer CTable_OffsetBits, ofCodeTable, 242419fcbaf1SConrad Meyer CTable_LitLength, llCodeTable, 242519fcbaf1SConrad Meyer sequences, nbSeq, longOffsets); 242619fcbaf1SConrad Meyer } 242719fcbaf1SConrad Meyer 242819fcbaf1SConrad Meyer #endif 242919fcbaf1SConrad Meyer 24300f743729SConrad Meyer static size_t ZSTD_encodeSequences( 243119fcbaf1SConrad Meyer void* dst, size_t dstCapacity, 243219fcbaf1SConrad Meyer FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 243319fcbaf1SConrad Meyer FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 243419fcbaf1SConrad Meyer FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 243519fcbaf1SConrad Meyer seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2) 243619fcbaf1SConrad Meyer { 2437a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_encodeSequences: dstCapacity = %u", (unsigned)dstCapacity); 243819fcbaf1SConrad Meyer #if DYNAMIC_BMI2 243919fcbaf1SConrad Meyer if (bmi2) { 244019fcbaf1SConrad Meyer return ZSTD_encodeSequences_bmi2(dst, dstCapacity, 244119fcbaf1SConrad Meyer CTable_MatchLength, mlCodeTable, 244219fcbaf1SConrad Meyer CTable_OffsetBits, ofCodeTable, 244319fcbaf1SConrad Meyer CTable_LitLength, llCodeTable, 244419fcbaf1SConrad Meyer sequences, nbSeq, longOffsets); 244519fcbaf1SConrad Meyer } 244619fcbaf1SConrad Meyer #endif 244719fcbaf1SConrad Meyer (void)bmi2; 244819fcbaf1SConrad Meyer return ZSTD_encodeSequences_default(dst, dstCapacity, 244919fcbaf1SConrad Meyer CTable_MatchLength, mlCodeTable, 245019fcbaf1SConrad Meyer CTable_OffsetBits, ofCodeTable, 245119fcbaf1SConrad Meyer CTable_LitLength, llCodeTable, 245219fcbaf1SConrad Meyer sequences, nbSeq, longOffsets); 245319fcbaf1SConrad Meyer } 245419fcbaf1SConrad Meyer 2455*2b9c00cbSConrad Meyer static int ZSTD_disableLiteralsCompression(const ZSTD_CCtx_params* cctxParams) 2456*2b9c00cbSConrad Meyer { 2457*2b9c00cbSConrad Meyer switch (cctxParams->literalCompressionMode) { 2458*2b9c00cbSConrad Meyer case ZSTD_lcm_huffman: 2459*2b9c00cbSConrad Meyer return 0; 2460*2b9c00cbSConrad Meyer case ZSTD_lcm_uncompressed: 2461*2b9c00cbSConrad Meyer return 1; 2462*2b9c00cbSConrad Meyer default: 2463*2b9c00cbSConrad Meyer assert(0 /* impossible: pre-validated */); 2464*2b9c00cbSConrad Meyer /* fall-through */ 2465*2b9c00cbSConrad Meyer case ZSTD_lcm_auto: 2466*2b9c00cbSConrad Meyer return (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0); 2467*2b9c00cbSConrad Meyer } 2468*2b9c00cbSConrad Meyer } 2469*2b9c00cbSConrad Meyer 2470a0483764SConrad Meyer /* ZSTD_compressSequences_internal(): 2471a0483764SConrad Meyer * actually compresses both literals and sequences */ 2472a0483764SConrad Meyer MEM_STATIC size_t 2473a0483764SConrad Meyer ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, 2474a0483764SConrad Meyer const ZSTD_entropyCTables_t* prevEntropy, 247519fcbaf1SConrad Meyer ZSTD_entropyCTables_t* nextEntropy, 2476a0483764SConrad Meyer const ZSTD_CCtx_params* cctxParams, 2477a0483764SConrad Meyer void* dst, size_t dstCapacity, 2478a0483764SConrad Meyer void* workspace, size_t wkspSize, 247919fcbaf1SConrad Meyer const int bmi2) 248019fcbaf1SConrad Meyer { 248119fcbaf1SConrad Meyer const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; 24820f743729SConrad Meyer ZSTD_strategy const strategy = cctxParams->cParams.strategy; 2483a0483764SConrad Meyer unsigned count[MaxSeq+1]; 24840f743729SConrad Meyer FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable; 24850f743729SConrad Meyer FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable; 24860f743729SConrad Meyer FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable; 24870c16b537SWarner Losh U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ 24880c16b537SWarner Losh const seqDef* const sequences = seqStorePtr->sequencesStart; 24890c16b537SWarner Losh const BYTE* const ofCodeTable = seqStorePtr->ofCode; 24900c16b537SWarner Losh const BYTE* const llCodeTable = seqStorePtr->llCode; 24910c16b537SWarner Losh const BYTE* const mlCodeTable = seqStorePtr->mlCode; 24920c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 24930c16b537SWarner Losh BYTE* const oend = ostart + dstCapacity; 24940c16b537SWarner Losh BYTE* op = ostart; 24950c16b537SWarner Losh size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart; 24960c16b537SWarner Losh BYTE* seqHead; 24970f743729SConrad Meyer BYTE* lastNCount = NULL; 24980c16b537SWarner Losh 249919fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 2500a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressSequences_internal"); 25010c16b537SWarner Losh 25020c16b537SWarner Losh /* Compress literals */ 25030c16b537SWarner Losh { const BYTE* const literals = seqStorePtr->litStart; 25040c16b537SWarner Losh size_t const litSize = seqStorePtr->lit - literals; 25050c16b537SWarner Losh size_t const cSize = ZSTD_compressLiterals( 25060f743729SConrad Meyer &prevEntropy->huf, &nextEntropy->huf, 2507*2b9c00cbSConrad Meyer cctxParams->cParams.strategy, 2508*2b9c00cbSConrad Meyer ZSTD_disableLiteralsCompression(cctxParams), 250919fcbaf1SConrad Meyer op, dstCapacity, 251019fcbaf1SConrad Meyer literals, litSize, 2511a0483764SConrad Meyer workspace, wkspSize, 2512a0483764SConrad Meyer bmi2); 2513*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 2514052d3c12SConrad Meyer assert(cSize <= dstCapacity); 25150c16b537SWarner Losh op += cSize; 25160c16b537SWarner Losh } 25170c16b537SWarner Losh 25180c16b537SWarner Losh /* Sequences Header */ 2519*2b9c00cbSConrad Meyer RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/, 2520*2b9c00cbSConrad Meyer dstSize_tooSmall); 2521052d3c12SConrad Meyer if (nbSeq < 0x7F) 2522052d3c12SConrad Meyer *op++ = (BYTE)nbSeq; 2523052d3c12SConrad Meyer else if (nbSeq < LONGNBSEQ) 2524052d3c12SConrad Meyer op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; 2525052d3c12SConrad Meyer else 2526052d3c12SConrad Meyer op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; 252719fcbaf1SConrad Meyer if (nbSeq==0) { 25280f743729SConrad Meyer /* Copy the old tables over as if we repeated them */ 25290f743729SConrad Meyer memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); 253019fcbaf1SConrad Meyer return op - ostart; 253119fcbaf1SConrad Meyer } 25320c16b537SWarner Losh 25330c16b537SWarner Losh /* seqHead : flags for FSE encoding type */ 25340c16b537SWarner Losh seqHead = op++; 25350c16b537SWarner Losh 25360c16b537SWarner Losh /* convert length/distances into codes */ 25370c16b537SWarner Losh ZSTD_seqToCodes(seqStorePtr); 2538052d3c12SConrad Meyer /* build CTable for Literal Lengths */ 2539a0483764SConrad Meyer { unsigned max = MaxLL; 2540a0483764SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ 2541052d3c12SConrad Meyer DEBUGLOG(5, "Building LL table"); 25420f743729SConrad Meyer nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode; 2543a0483764SConrad Meyer LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode, 2544a0483764SConrad Meyer count, max, mostFrequent, nbSeq, 2545a0483764SConrad Meyer LLFSELog, prevEntropy->fse.litlengthCTable, 2546a0483764SConrad Meyer LL_defaultNorm, LL_defaultNormLog, 2547a0483764SConrad Meyer ZSTD_defaultAllowed, strategy); 25480f743729SConrad Meyer assert(set_basic < set_compressed && set_rle < set_compressed); 25490f743729SConrad Meyer assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 25500c16b537SWarner Losh { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, 25510c16b537SWarner Losh count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL, 25520f743729SConrad Meyer prevEntropy->fse.litlengthCTable, sizeof(prevEntropy->fse.litlengthCTable), 2553a0483764SConrad Meyer workspace, wkspSize); 2554*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(countSize); 25550f743729SConrad Meyer if (LLtype == set_compressed) 25560f743729SConrad Meyer lastNCount = op; 25570c16b537SWarner Losh op += countSize; 25580c16b537SWarner Losh } } 2559052d3c12SConrad Meyer /* build CTable for Offsets */ 2560a0483764SConrad Meyer { unsigned max = MaxOff; 2561a0483764SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ 25620c16b537SWarner Losh /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ 2563052d3c12SConrad Meyer ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; 2564052d3c12SConrad Meyer DEBUGLOG(5, "Building OF table"); 25650f743729SConrad Meyer nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode; 2566a0483764SConrad Meyer Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode, 2567a0483764SConrad Meyer count, max, mostFrequent, nbSeq, 2568a0483764SConrad Meyer OffFSELog, prevEntropy->fse.offcodeCTable, 2569a0483764SConrad Meyer OF_defaultNorm, OF_defaultNormLog, 2570a0483764SConrad Meyer defaultPolicy, strategy); 25710f743729SConrad Meyer assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 25720c16b537SWarner Losh { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, 25730c16b537SWarner Losh count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, 25740f743729SConrad Meyer prevEntropy->fse.offcodeCTable, sizeof(prevEntropy->fse.offcodeCTable), 2575a0483764SConrad Meyer workspace, wkspSize); 2576*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(countSize); 25770f743729SConrad Meyer if (Offtype == set_compressed) 25780f743729SConrad Meyer lastNCount = op; 25790c16b537SWarner Losh op += countSize; 25800c16b537SWarner Losh } } 2581052d3c12SConrad Meyer /* build CTable for MatchLengths */ 2582a0483764SConrad Meyer { unsigned max = MaxML; 2583a0483764SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace, wkspSize); /* can't fail */ 2584a0483764SConrad Meyer DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op)); 25850f743729SConrad Meyer nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode; 2586a0483764SConrad Meyer MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode, 2587a0483764SConrad Meyer count, max, mostFrequent, nbSeq, 2588a0483764SConrad Meyer MLFSELog, prevEntropy->fse.matchlengthCTable, 2589a0483764SConrad Meyer ML_defaultNorm, ML_defaultNormLog, 2590a0483764SConrad Meyer ZSTD_defaultAllowed, strategy); 25910f743729SConrad Meyer assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 25920c16b537SWarner Losh { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, 25930c16b537SWarner Losh count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML, 25940f743729SConrad Meyer prevEntropy->fse.matchlengthCTable, sizeof(prevEntropy->fse.matchlengthCTable), 2595a0483764SConrad Meyer workspace, wkspSize); 2596*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(countSize); 25970f743729SConrad Meyer if (MLtype == set_compressed) 25980f743729SConrad Meyer lastNCount = op; 25990c16b537SWarner Losh op += countSize; 26000c16b537SWarner Losh } } 26010c16b537SWarner Losh 26020c16b537SWarner Losh *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); 26030c16b537SWarner Losh 2604052d3c12SConrad Meyer { size_t const bitstreamSize = ZSTD_encodeSequences( 2605052d3c12SConrad Meyer op, oend - op, 26060c16b537SWarner Losh CTable_MatchLength, mlCodeTable, 26070c16b537SWarner Losh CTable_OffsetBits, ofCodeTable, 26080c16b537SWarner Losh CTable_LitLength, llCodeTable, 2609052d3c12SConrad Meyer sequences, nbSeq, 261019fcbaf1SConrad Meyer longOffsets, bmi2); 2611*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(bitstreamSize); 2612052d3c12SConrad Meyer op += bitstreamSize; 26130f743729SConrad Meyer /* zstd versions <= 1.3.4 mistakenly report corruption when 2614*2b9c00cbSConrad Meyer * FSE_readNCount() receives a buffer < 4 bytes. 26150f743729SConrad Meyer * Fixed by https://github.com/facebook/zstd/pull/1146. 26160f743729SConrad Meyer * This can happen when the last set_compressed table present is 2 26170f743729SConrad Meyer * bytes and the bitstream is only one byte. 26180f743729SConrad Meyer * In this exceedingly rare case, we will simply emit an uncompressed 26190f743729SConrad Meyer * block, since it isn't worth optimizing. 26200f743729SConrad Meyer */ 26210f743729SConrad Meyer if (lastNCount && (op - lastNCount) < 4) { 26220f743729SConrad Meyer /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ 26230f743729SConrad Meyer assert(op - lastNCount == 3); 26240f743729SConrad Meyer DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " 26250f743729SConrad Meyer "emitting an uncompressed block."); 26260f743729SConrad Meyer return 0; 26270f743729SConrad Meyer } 26280c16b537SWarner Losh } 26290c16b537SWarner Losh 2630a0483764SConrad Meyer DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart)); 26310c16b537SWarner Losh return op - ostart; 26320c16b537SWarner Losh } 26330c16b537SWarner Losh 2634a0483764SConrad Meyer MEM_STATIC size_t 2635a0483764SConrad Meyer ZSTD_compressSequences(seqStore_t* seqStorePtr, 26360f743729SConrad Meyer const ZSTD_entropyCTables_t* prevEntropy, 263719fcbaf1SConrad Meyer ZSTD_entropyCTables_t* nextEntropy, 26380f743729SConrad Meyer const ZSTD_CCtx_params* cctxParams, 26390c16b537SWarner Losh void* dst, size_t dstCapacity, 2640a0483764SConrad Meyer size_t srcSize, 2641a0483764SConrad Meyer void* workspace, size_t wkspSize, 2642a0483764SConrad Meyer int bmi2) 26430c16b537SWarner Losh { 264419fcbaf1SConrad Meyer size_t const cSize = ZSTD_compressSequences_internal( 2645a0483764SConrad Meyer seqStorePtr, prevEntropy, nextEntropy, cctxParams, 2646a0483764SConrad Meyer dst, dstCapacity, 2647a0483764SConrad Meyer workspace, wkspSize, bmi2); 26480f743729SConrad Meyer if (cSize == 0) return 0; 264919fcbaf1SConrad Meyer /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block. 265019fcbaf1SConrad Meyer * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block. 26510c16b537SWarner Losh */ 265219fcbaf1SConrad Meyer if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) 265319fcbaf1SConrad Meyer return 0; /* block not compressed */ 2654*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 265519fcbaf1SConrad Meyer 265619fcbaf1SConrad Meyer /* Check compressibility */ 26570f743729SConrad Meyer { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy); 265819fcbaf1SConrad Meyer if (cSize >= maxCSize) return 0; /* block not compressed */ 265919fcbaf1SConrad Meyer } 266019fcbaf1SConrad Meyer 26610c16b537SWarner Losh return cSize; 26620c16b537SWarner Losh } 26630c16b537SWarner Losh 26640c16b537SWarner Losh /* ZSTD_selectBlockCompressor() : 26650c16b537SWarner Losh * Not static, but internal use only (used by long distance matcher) 26660c16b537SWarner Losh * assumption : strat is a valid strategy */ 26670f743729SConrad Meyer ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode) 26680c16b537SWarner Losh { 2669a0483764SConrad Meyer static const ZSTD_blockCompressor blockCompressor[3][ZSTD_STRATEGY_MAX+1] = { 26700c16b537SWarner Losh { ZSTD_compressBlock_fast /* default for 0 */, 26710f743729SConrad Meyer ZSTD_compressBlock_fast, 26720f743729SConrad Meyer ZSTD_compressBlock_doubleFast, 26730f743729SConrad Meyer ZSTD_compressBlock_greedy, 26740f743729SConrad Meyer ZSTD_compressBlock_lazy, 26750f743729SConrad Meyer ZSTD_compressBlock_lazy2, 26760f743729SConrad Meyer ZSTD_compressBlock_btlazy2, 26770f743729SConrad Meyer ZSTD_compressBlock_btopt, 2678a0483764SConrad Meyer ZSTD_compressBlock_btultra, 2679a0483764SConrad Meyer ZSTD_compressBlock_btultra2 }, 26800c16b537SWarner Losh { ZSTD_compressBlock_fast_extDict /* default for 0 */, 26810f743729SConrad Meyer ZSTD_compressBlock_fast_extDict, 26820f743729SConrad Meyer ZSTD_compressBlock_doubleFast_extDict, 26830f743729SConrad Meyer ZSTD_compressBlock_greedy_extDict, 26840f743729SConrad Meyer ZSTD_compressBlock_lazy_extDict, 26850f743729SConrad Meyer ZSTD_compressBlock_lazy2_extDict, 26860f743729SConrad Meyer ZSTD_compressBlock_btlazy2_extDict, 26870f743729SConrad Meyer ZSTD_compressBlock_btopt_extDict, 2688a0483764SConrad Meyer ZSTD_compressBlock_btultra_extDict, 26890f743729SConrad Meyer ZSTD_compressBlock_btultra_extDict }, 26900f743729SConrad Meyer { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */, 26910f743729SConrad Meyer ZSTD_compressBlock_fast_dictMatchState, 26920f743729SConrad Meyer ZSTD_compressBlock_doubleFast_dictMatchState, 26930f743729SConrad Meyer ZSTD_compressBlock_greedy_dictMatchState, 26940f743729SConrad Meyer ZSTD_compressBlock_lazy_dictMatchState, 26950f743729SConrad Meyer ZSTD_compressBlock_lazy2_dictMatchState, 26960f743729SConrad Meyer ZSTD_compressBlock_btlazy2_dictMatchState, 26970f743729SConrad Meyer ZSTD_compressBlock_btopt_dictMatchState, 2698a0483764SConrad Meyer ZSTD_compressBlock_btultra_dictMatchState, 26990f743729SConrad Meyer ZSTD_compressBlock_btultra_dictMatchState } 27000c16b537SWarner Losh }; 27010f743729SConrad Meyer ZSTD_blockCompressor selectedCompressor; 27020c16b537SWarner Losh ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); 2703052d3c12SConrad Meyer 2704a0483764SConrad Meyer assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat)); 2705a0483764SConrad Meyer selectedCompressor = blockCompressor[(int)dictMode][(int)strat]; 27060f743729SConrad Meyer assert(selectedCompressor != NULL); 27070f743729SConrad Meyer return selectedCompressor; 27080c16b537SWarner Losh } 27090c16b537SWarner Losh 27100c16b537SWarner Losh static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, 27110c16b537SWarner Losh const BYTE* anchor, size_t lastLLSize) 27120c16b537SWarner Losh { 27130c16b537SWarner Losh memcpy(seqStorePtr->lit, anchor, lastLLSize); 27140c16b537SWarner Losh seqStorePtr->lit += lastLLSize; 27150c16b537SWarner Losh } 27160c16b537SWarner Losh 27170f743729SConrad Meyer void ZSTD_resetSeqStore(seqStore_t* ssPtr) 2718052d3c12SConrad Meyer { 2719052d3c12SConrad Meyer ssPtr->lit = ssPtr->litStart; 2720052d3c12SConrad Meyer ssPtr->sequences = ssPtr->sequencesStart; 2721052d3c12SConrad Meyer ssPtr->longLengthID = 0; 2722052d3c12SConrad Meyer } 2723052d3c12SConrad Meyer 272419fcbaf1SConrad Meyer static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, 272519fcbaf1SConrad Meyer void* dst, size_t dstCapacity, 272619fcbaf1SConrad Meyer const void* src, size_t srcSize) 27270c16b537SWarner Losh { 272819fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &zc->blockState.matchState; 27290f743729SConrad Meyer size_t cSize; 2730a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", 2731a0483764SConrad Meyer (unsigned)dstCapacity, (unsigned)ms->window.dictLimit, (unsigned)ms->nextToUpdate); 27320f743729SConrad Meyer assert(srcSize <= ZSTD_BLOCKSIZE_MAX); 27330f743729SConrad Meyer 27340f743729SConrad Meyer /* Assert that we have correctly flushed the ctx params into the ms's copy */ 27350f743729SConrad Meyer ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); 27360f743729SConrad Meyer 273719fcbaf1SConrad Meyer if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) { 2738a0483764SConrad Meyer ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch); 27390f743729SConrad Meyer cSize = 0; 27400f743729SConrad Meyer goto out; /* don't even attempt compression below a certain srcSize */ 274119fcbaf1SConrad Meyer } 2742052d3c12SConrad Meyer ZSTD_resetSeqStore(&(zc->seqStore)); 2743*2b9c00cbSConrad Meyer /* required for optimal parser to read stats from dictionary */ 2744*2b9c00cbSConrad Meyer ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy; 2745*2b9c00cbSConrad Meyer /* tell the optimal parser how we expect to compress literals */ 2746*2b9c00cbSConrad Meyer ms->opt.literalCompressionMode = zc->appliedParams.literalCompressionMode; 27470f743729SConrad Meyer 27480f743729SConrad Meyer /* a gap between an attached dict and the current window is not safe, 2749a0483764SConrad Meyer * they must remain adjacent, 2750a0483764SConrad Meyer * and when that stops being the case, the dict must be unset */ 27510f743729SConrad Meyer assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit); 2752052d3c12SConrad Meyer 2753052d3c12SConrad Meyer /* limited update after a very long match */ 275419fcbaf1SConrad Meyer { const BYTE* const base = ms->window.base; 27550c16b537SWarner Losh const BYTE* const istart = (const BYTE*)src; 27560c16b537SWarner Losh const U32 current = (U32)(istart-base); 27570f743729SConrad Meyer if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */ 275819fcbaf1SConrad Meyer if (current > ms->nextToUpdate + 384) 275919fcbaf1SConrad Meyer ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384)); 2760052d3c12SConrad Meyer } 276119fcbaf1SConrad Meyer 276219fcbaf1SConrad Meyer /* select and store sequences */ 27630f743729SConrad Meyer { ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms); 276419fcbaf1SConrad Meyer size_t lastLLSize; 276519fcbaf1SConrad Meyer { int i; 276619fcbaf1SConrad Meyer for (i = 0; i < ZSTD_REP_NUM; ++i) 276719fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i]; 2768052d3c12SConrad Meyer } 276919fcbaf1SConrad Meyer if (zc->externSeqStore.pos < zc->externSeqStore.size) { 277019fcbaf1SConrad Meyer assert(!zc->appliedParams.ldmParams.enableLdm); 277119fcbaf1SConrad Meyer /* Updates ldmSeqStore.pos */ 277219fcbaf1SConrad Meyer lastLLSize = 277319fcbaf1SConrad Meyer ZSTD_ldm_blockCompress(&zc->externSeqStore, 277419fcbaf1SConrad Meyer ms, &zc->seqStore, 277519fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep, 27760f743729SConrad Meyer src, srcSize); 277719fcbaf1SConrad Meyer assert(zc->externSeqStore.pos <= zc->externSeqStore.size); 277819fcbaf1SConrad Meyer } else if (zc->appliedParams.ldmParams.enableLdm) { 277919fcbaf1SConrad Meyer rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0}; 278019fcbaf1SConrad Meyer 278119fcbaf1SConrad Meyer ldmSeqStore.seq = zc->ldmSequences; 278219fcbaf1SConrad Meyer ldmSeqStore.capacity = zc->maxNbLdmSequences; 278319fcbaf1SConrad Meyer /* Updates ldmSeqStore.size */ 2784*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore, 278519fcbaf1SConrad Meyer &zc->appliedParams.ldmParams, 278619fcbaf1SConrad Meyer src, srcSize)); 278719fcbaf1SConrad Meyer /* Updates ldmSeqStore.pos */ 278819fcbaf1SConrad Meyer lastLLSize = 278919fcbaf1SConrad Meyer ZSTD_ldm_blockCompress(&ldmSeqStore, 279019fcbaf1SConrad Meyer ms, &zc->seqStore, 279119fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep, 27920f743729SConrad Meyer src, srcSize); 279319fcbaf1SConrad Meyer assert(ldmSeqStore.pos == ldmSeqStore.size); 279419fcbaf1SConrad Meyer } else { /* not long range mode */ 27950f743729SConrad Meyer ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode); 27960f743729SConrad Meyer lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); 279719fcbaf1SConrad Meyer } 279819fcbaf1SConrad Meyer { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; 279919fcbaf1SConrad Meyer ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize); 280019fcbaf1SConrad Meyer } } 280119fcbaf1SConrad Meyer 280219fcbaf1SConrad Meyer /* encode sequences and literals */ 28030f743729SConrad Meyer cSize = ZSTD_compressSequences(&zc->seqStore, 280419fcbaf1SConrad Meyer &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, 280519fcbaf1SConrad Meyer &zc->appliedParams, 280619fcbaf1SConrad Meyer dst, dstCapacity, 2807a0483764SConrad Meyer srcSize, 2808a0483764SConrad Meyer zc->entropyWorkspace, HUF_WORKSPACE_SIZE /* statically allocated in resetCCtx */, 2809a0483764SConrad Meyer zc->bmi2); 28100f743729SConrad Meyer 28110f743729SConrad Meyer out: 28120f743729SConrad Meyer if (!ZSTD_isError(cSize) && cSize != 0) { 28130f743729SConrad Meyer /* confirm repcodes and entropy tables when emitting a compressed block */ 28140f743729SConrad Meyer ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock; 281519fcbaf1SConrad Meyer zc->blockState.prevCBlock = zc->blockState.nextCBlock; 281619fcbaf1SConrad Meyer zc->blockState.nextCBlock = tmp; 281719fcbaf1SConrad Meyer } 28180f743729SConrad Meyer /* We check that dictionaries have offset codes available for the first 28190f743729SConrad Meyer * block. After the first block, the offcode table might not have large 28200f743729SConrad Meyer * enough codes to represent the offsets in the data. 28210f743729SConrad Meyer */ 28220f743729SConrad Meyer if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) 28230f743729SConrad Meyer zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; 28240f743729SConrad Meyer 282519fcbaf1SConrad Meyer return cSize; 282619fcbaf1SConrad Meyer } 28270c16b537SWarner Losh 28280c16b537SWarner Losh 28290c16b537SWarner Losh /*! ZSTD_compress_frameChunk() : 28300c16b537SWarner Losh * Compress a chunk of data into one or multiple blocks. 28310c16b537SWarner Losh * All blocks will be terminated, all input will be consumed. 28320c16b537SWarner Losh * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content. 28330c16b537SWarner Losh * Frame is supposed already started (header already produced) 28340c16b537SWarner Losh * @return : compressed size, or an error code 28350c16b537SWarner Losh */ 28360c16b537SWarner Losh static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, 28370c16b537SWarner Losh void* dst, size_t dstCapacity, 28380c16b537SWarner Losh const void* src, size_t srcSize, 28390c16b537SWarner Losh U32 lastFrameChunk) 28400c16b537SWarner Losh { 28410c16b537SWarner Losh size_t blockSize = cctx->blockSize; 28420c16b537SWarner Losh size_t remaining = srcSize; 28430c16b537SWarner Losh const BYTE* ip = (const BYTE*)src; 28440c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 28450c16b537SWarner Losh BYTE* op = ostart; 28460c16b537SWarner Losh U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; 2847052d3c12SConrad Meyer assert(cctx->appliedParams.cParams.windowLog <= 31); 28480c16b537SWarner Losh 2849a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize); 28500c16b537SWarner Losh if (cctx->appliedParams.fParams.checksumFlag && srcSize) 28510c16b537SWarner Losh XXH64_update(&cctx->xxhState, src, srcSize); 28520c16b537SWarner Losh 28530c16b537SWarner Losh while (remaining) { 285419fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 28550c16b537SWarner Losh U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); 28560c16b537SWarner Losh 2857*2b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE, 2858*2b9c00cbSConrad Meyer dstSize_tooSmall, 2859*2b9c00cbSConrad Meyer "not enough space to store compressed block"); 28600c16b537SWarner Losh if (remaining < blockSize) blockSize = remaining; 28610c16b537SWarner Losh 286219fcbaf1SConrad Meyer if (ZSTD_window_needOverflowCorrection(ms->window, ip + blockSize)) { 286319fcbaf1SConrad Meyer U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy); 286419fcbaf1SConrad Meyer U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); 28650c16b537SWarner Losh ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); 28660c16b537SWarner Losh ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); 28670c16b537SWarner Losh ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); 28680c16b537SWarner Losh ZSTD_reduceIndex(cctx, correction); 286919fcbaf1SConrad Meyer if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; 287019fcbaf1SConrad Meyer else ms->nextToUpdate -= correction; 287119fcbaf1SConrad Meyer ms->loadedDictEnd = 0; 28720f743729SConrad Meyer ms->dictMatchState = NULL; 28730c16b537SWarner Losh } 28740f743729SConrad Meyer ZSTD_window_enforceMaxDist(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); 287519fcbaf1SConrad Meyer if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; 28760c16b537SWarner Losh 2877052d3c12SConrad Meyer { size_t cSize = ZSTD_compressBlock_internal(cctx, 2878052d3c12SConrad Meyer op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, 2879052d3c12SConrad Meyer ip, blockSize); 2880*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 28810c16b537SWarner Losh 28820c16b537SWarner Losh if (cSize == 0) { /* block is not compressible */ 28830f743729SConrad Meyer cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); 2884*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 28850c16b537SWarner Losh } else { 28860c16b537SWarner Losh U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); 28870c16b537SWarner Losh MEM_writeLE24(op, cBlockHeader24); 28880c16b537SWarner Losh cSize += ZSTD_blockHeaderSize; 28890c16b537SWarner Losh } 28900c16b537SWarner Losh 28910c16b537SWarner Losh ip += blockSize; 2892052d3c12SConrad Meyer assert(remaining >= blockSize); 2893052d3c12SConrad Meyer remaining -= blockSize; 28940c16b537SWarner Losh op += cSize; 2895052d3c12SConrad Meyer assert(dstCapacity >= cSize); 2896052d3c12SConrad Meyer dstCapacity -= cSize; 2897052d3c12SConrad Meyer DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u", 2898a0483764SConrad Meyer (unsigned)cSize); 2899052d3c12SConrad Meyer } } 29000c16b537SWarner Losh 29010c16b537SWarner Losh if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending; 29020c16b537SWarner Losh return op-ostart; 29030c16b537SWarner Losh } 29040c16b537SWarner Losh 29050c16b537SWarner Losh 29060c16b537SWarner Losh static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, 29070c16b537SWarner Losh ZSTD_CCtx_params params, U64 pledgedSrcSize, U32 dictID) 29080c16b537SWarner Losh { BYTE* const op = (BYTE*)dst; 29090c16b537SWarner Losh U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */ 29100c16b537SWarner Losh U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */ 29110c16b537SWarner Losh U32 const checksumFlag = params.fParams.checksumFlag>0; 29120c16b537SWarner Losh U32 const windowSize = (U32)1 << params.cParams.windowLog; 29130c16b537SWarner Losh U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize); 29140c16b537SWarner Losh BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3); 29150c16b537SWarner Losh U32 const fcsCode = params.fParams.contentSizeFlag ? 29160c16b537SWarner Losh (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */ 2917*2b9c00cbSConrad Meyer BYTE const frameHeaderDescriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) ); 29180c16b537SWarner Losh size_t pos=0; 29190c16b537SWarner Losh 29200f743729SConrad Meyer assert(!(params.fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)); 2921*2b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall); 29220c16b537SWarner Losh DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", 2923a0483764SConrad Meyer !params.fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode); 29240c16b537SWarner Losh 29250c16b537SWarner Losh if (params.format == ZSTD_f_zstd1) { 29260c16b537SWarner Losh MEM_writeLE32(dst, ZSTD_MAGICNUMBER); 29270c16b537SWarner Losh pos = 4; 29280c16b537SWarner Losh } 2929*2b9c00cbSConrad Meyer op[pos++] = frameHeaderDescriptionByte; 29300c16b537SWarner Losh if (!singleSegment) op[pos++] = windowLogByte; 29310c16b537SWarner Losh switch(dictIDSizeCode) 29320c16b537SWarner Losh { 29330c16b537SWarner Losh default: assert(0); /* impossible */ 29340c16b537SWarner Losh case 0 : break; 29350c16b537SWarner Losh case 1 : op[pos] = (BYTE)(dictID); pos++; break; 29360c16b537SWarner Losh case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; 29370c16b537SWarner Losh case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break; 29380c16b537SWarner Losh } 29390c16b537SWarner Losh switch(fcsCode) 29400c16b537SWarner Losh { 29410c16b537SWarner Losh default: assert(0); /* impossible */ 29420c16b537SWarner Losh case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; 29430c16b537SWarner Losh case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; 29440c16b537SWarner Losh case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; 29450c16b537SWarner Losh case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break; 29460c16b537SWarner Losh } 29470c16b537SWarner Losh return pos; 29480c16b537SWarner Losh } 29490c16b537SWarner Losh 295019fcbaf1SConrad Meyer /* ZSTD_writeLastEmptyBlock() : 295119fcbaf1SConrad Meyer * output an empty Block with end-of-frame mark to complete a frame 295219fcbaf1SConrad Meyer * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h)) 2953*2b9c00cbSConrad Meyer * or an error code if `dstCapacity` is too small (<ZSTD_blockHeaderSize) 295419fcbaf1SConrad Meyer */ 295519fcbaf1SConrad Meyer size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) 295619fcbaf1SConrad Meyer { 2957*2b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall); 295819fcbaf1SConrad Meyer { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */ 295919fcbaf1SConrad Meyer MEM_writeLE24(dst, cBlockHeader24); 296019fcbaf1SConrad Meyer return ZSTD_blockHeaderSize; 296119fcbaf1SConrad Meyer } 296219fcbaf1SConrad Meyer } 296319fcbaf1SConrad Meyer 296419fcbaf1SConrad Meyer size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) 296519fcbaf1SConrad Meyer { 2966*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong); 2967*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm, 2968*2b9c00cbSConrad Meyer parameter_unsupported); 296919fcbaf1SConrad Meyer cctx->externSeqStore.seq = seq; 297019fcbaf1SConrad Meyer cctx->externSeqStore.size = nbSeq; 297119fcbaf1SConrad Meyer cctx->externSeqStore.capacity = nbSeq; 297219fcbaf1SConrad Meyer cctx->externSeqStore.pos = 0; 297319fcbaf1SConrad Meyer return 0; 297419fcbaf1SConrad Meyer } 297519fcbaf1SConrad Meyer 29760c16b537SWarner Losh 29770c16b537SWarner Losh static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, 29780c16b537SWarner Losh void* dst, size_t dstCapacity, 29790c16b537SWarner Losh const void* src, size_t srcSize, 29800c16b537SWarner Losh U32 frame, U32 lastFrameChunk) 29810c16b537SWarner Losh { 29820f743729SConrad Meyer ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 29830c16b537SWarner Losh size_t fhSize = 0; 29840c16b537SWarner Losh 298519fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u", 2986a0483764SConrad Meyer cctx->stage, (unsigned)srcSize); 2987*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->stage==ZSTDcs_created, stage_wrong, 2988*2b9c00cbSConrad Meyer "missing init (ZSTD_compressBegin)"); 29890c16b537SWarner Losh 29900c16b537SWarner Losh if (frame && (cctx->stage==ZSTDcs_init)) { 29910c16b537SWarner Losh fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 29920c16b537SWarner Losh cctx->pledgedSrcSizePlusOne-1, cctx->dictID); 2993*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(fhSize); 29940c16b537SWarner Losh dstCapacity -= fhSize; 29950c16b537SWarner Losh dst = (char*)dst + fhSize; 29960c16b537SWarner Losh cctx->stage = ZSTDcs_ongoing; 29970c16b537SWarner Losh } 29980c16b537SWarner Losh 2999052d3c12SConrad Meyer if (!srcSize) return fhSize; /* do not generate an empty block if no input */ 3000052d3c12SConrad Meyer 300119fcbaf1SConrad Meyer if (!ZSTD_window_update(&ms->window, src, srcSize)) { 300219fcbaf1SConrad Meyer ms->nextToUpdate = ms->window.dictLimit; 30030c16b537SWarner Losh } 30040f743729SConrad Meyer if (cctx->appliedParams.ldmParams.enableLdm) { 300519fcbaf1SConrad Meyer ZSTD_window_update(&cctx->ldmState.window, src, srcSize); 30060f743729SConrad Meyer } 30070f743729SConrad Meyer 30080f743729SConrad Meyer if (!frame) { 30090f743729SConrad Meyer /* overflow check and correction for block mode */ 30100f743729SConrad Meyer if (ZSTD_window_needOverflowCorrection(ms->window, (const char*)src + srcSize)) { 30110f743729SConrad Meyer U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy); 30120f743729SConrad Meyer U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, 1 << cctx->appliedParams.cParams.windowLog, src); 30130f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); 30140f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); 30150f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); 30160f743729SConrad Meyer ZSTD_reduceIndex(cctx, correction); 30170f743729SConrad Meyer if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; 30180f743729SConrad Meyer else ms->nextToUpdate -= correction; 30190f743729SConrad Meyer ms->loadedDictEnd = 0; 30200f743729SConrad Meyer ms->dictMatchState = NULL; 30210f743729SConrad Meyer } 30220f743729SConrad Meyer } 30230c16b537SWarner Losh 3024a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (unsigned)cctx->blockSize); 3025052d3c12SConrad Meyer { size_t const cSize = frame ? 30260c16b537SWarner Losh ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : 30270c16b537SWarner Losh ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize); 3028*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 30290c16b537SWarner Losh cctx->consumedSrcSize += srcSize; 303019fcbaf1SConrad Meyer cctx->producedCSize += (cSize + fhSize); 30310f743729SConrad Meyer assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); 30320f743729SConrad Meyer if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ 30330f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); 3034*2b9c00cbSConrad Meyer RETURN_ERROR_IF( 3035*2b9c00cbSConrad Meyer cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne, 3036*2b9c00cbSConrad Meyer srcSize_wrong, 3037*2b9c00cbSConrad Meyer "error : pledgedSrcSize = %u, while realSrcSize >= %u", 3038*2b9c00cbSConrad Meyer (unsigned)cctx->pledgedSrcSizePlusOne-1, 3039*2b9c00cbSConrad Meyer (unsigned)cctx->consumedSrcSize); 304019fcbaf1SConrad Meyer } 30410c16b537SWarner Losh return cSize + fhSize; 3042052d3c12SConrad Meyer } 30430c16b537SWarner Losh } 30440c16b537SWarner Losh 30450c16b537SWarner Losh size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, 30460c16b537SWarner Losh void* dst, size_t dstCapacity, 30470c16b537SWarner Losh const void* src, size_t srcSize) 30480c16b537SWarner Losh { 3049a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize); 30500c16b537SWarner Losh return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */); 30510c16b537SWarner Losh } 30520c16b537SWarner Losh 30530c16b537SWarner Losh 30540c16b537SWarner Losh size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) 30550c16b537SWarner Losh { 305619fcbaf1SConrad Meyer ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams; 305719fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 30580c16b537SWarner Losh return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog); 30590c16b537SWarner Losh } 30600c16b537SWarner Losh 30610c16b537SWarner Losh size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) 30620c16b537SWarner Losh { 30630c16b537SWarner Losh size_t const blockSizeMax = ZSTD_getBlockSize(cctx); 3064*2b9c00cbSConrad Meyer RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong); 30650f743729SConrad Meyer 30660c16b537SWarner Losh return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); 30670c16b537SWarner Losh } 30680c16b537SWarner Losh 30690c16b537SWarner Losh /*! ZSTD_loadDictionaryContent() : 30700c16b537SWarner Losh * @return : 0, or an error code 30710c16b537SWarner Losh */ 30720f743729SConrad Meyer static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, 30730f743729SConrad Meyer ZSTD_CCtx_params const* params, 30740f743729SConrad Meyer const void* src, size_t srcSize, 30750f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm) 30760c16b537SWarner Losh { 30770c16b537SWarner Losh const BYTE* const ip = (const BYTE*) src; 30780c16b537SWarner Losh const BYTE* const iend = ip + srcSize; 30790c16b537SWarner Losh 308019fcbaf1SConrad Meyer ZSTD_window_update(&ms->window, src, srcSize); 308119fcbaf1SConrad Meyer ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); 30820c16b537SWarner Losh 30830f743729SConrad Meyer /* Assert that we the ms params match the params we're being given */ 30840f743729SConrad Meyer ZSTD_assertEqualCParams(params->cParams, ms->cParams); 30850f743729SConrad Meyer 30860c16b537SWarner Losh if (srcSize <= HASH_READ_SIZE) return 0; 30870c16b537SWarner Losh 308819fcbaf1SConrad Meyer switch(params->cParams.strategy) 30890c16b537SWarner Losh { 30900c16b537SWarner Losh case ZSTD_fast: 30910f743729SConrad Meyer ZSTD_fillHashTable(ms, iend, dtlm); 30920c16b537SWarner Losh break; 30930c16b537SWarner Losh case ZSTD_dfast: 30940f743729SConrad Meyer ZSTD_fillDoubleHashTable(ms, iend, dtlm); 30950c16b537SWarner Losh break; 30960c16b537SWarner Losh 30970c16b537SWarner Losh case ZSTD_greedy: 30980c16b537SWarner Losh case ZSTD_lazy: 30990c16b537SWarner Losh case ZSTD_lazy2: 31000c16b537SWarner Losh if (srcSize >= HASH_READ_SIZE) 31010f743729SConrad Meyer ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE); 31020c16b537SWarner Losh break; 31030c16b537SWarner Losh 310419fcbaf1SConrad Meyer case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ 31050c16b537SWarner Losh case ZSTD_btopt: 31060c16b537SWarner Losh case ZSTD_btultra: 3107a0483764SConrad Meyer case ZSTD_btultra2: 31080c16b537SWarner Losh if (srcSize >= HASH_READ_SIZE) 31090f743729SConrad Meyer ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend); 31100c16b537SWarner Losh break; 31110c16b537SWarner Losh 31120c16b537SWarner Losh default: 31130c16b537SWarner Losh assert(0); /* not possible : not a valid strategy id */ 31140c16b537SWarner Losh } 31150c16b537SWarner Losh 311619fcbaf1SConrad Meyer ms->nextToUpdate = (U32)(iend - ms->window.base); 31170c16b537SWarner Losh return 0; 31180c16b537SWarner Losh } 31190c16b537SWarner Losh 31200c16b537SWarner Losh 31210c16b537SWarner Losh /* Dictionaries that assign zero probability to symbols that show up causes problems 31220c16b537SWarner Losh when FSE encoding. Refuse dictionaries that assign zero probability to symbols 31230c16b537SWarner Losh that we may encounter during compression. 31240c16b537SWarner Losh NOTE: This behavior is not standard and could be improved in the future. */ 31250c16b537SWarner Losh static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) { 31260c16b537SWarner Losh U32 s; 3127*2b9c00cbSConrad Meyer RETURN_ERROR_IF(dictMaxSymbolValue < maxSymbolValue, dictionary_corrupted); 31280c16b537SWarner Losh for (s = 0; s <= maxSymbolValue; ++s) { 3129*2b9c00cbSConrad Meyer RETURN_ERROR_IF(normalizedCounter[s] == 0, dictionary_corrupted); 31300c16b537SWarner Losh } 31310c16b537SWarner Losh return 0; 31320c16b537SWarner Losh } 31330c16b537SWarner Losh 31340c16b537SWarner Losh 31350c16b537SWarner Losh /* Dictionary format : 31360c16b537SWarner Losh * See : 31370c16b537SWarner Losh * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format 31380c16b537SWarner Losh */ 31390c16b537SWarner Losh /*! ZSTD_loadZstdDictionary() : 314019fcbaf1SConrad Meyer * @return : dictID, or an error code 31410c16b537SWarner Losh * assumptions : magic number supposed already checked 31420c16b537SWarner Losh * dictSize supposed > 8 31430c16b537SWarner Losh */ 31440f743729SConrad Meyer static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, 31450f743729SConrad Meyer ZSTD_matchState_t* ms, 31460f743729SConrad Meyer ZSTD_CCtx_params const* params, 31470f743729SConrad Meyer const void* dict, size_t dictSize, 31480f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 31490f743729SConrad Meyer void* workspace) 31500c16b537SWarner Losh { 31510c16b537SWarner Losh const BYTE* dictPtr = (const BYTE*)dict; 31520c16b537SWarner Losh const BYTE* const dictEnd = dictPtr + dictSize; 31530c16b537SWarner Losh short offcodeNCount[MaxOff+1]; 31540c16b537SWarner Losh unsigned offcodeMaxValue = MaxOff; 315519fcbaf1SConrad Meyer size_t dictID; 31560c16b537SWarner Losh 315719fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 31580f743729SConrad Meyer assert(dictSize > 8); 31590f743729SConrad Meyer assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); 31600c16b537SWarner Losh 31610c16b537SWarner Losh dictPtr += 4; /* skip magic number */ 316219fcbaf1SConrad Meyer dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr); 31630c16b537SWarner Losh dictPtr += 4; 31640c16b537SWarner Losh 31650c16b537SWarner Losh { unsigned maxSymbolValue = 255; 31660f743729SConrad Meyer size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr); 3167*2b9c00cbSConrad Meyer RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted); 3168*2b9c00cbSConrad Meyer RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted); 31690c16b537SWarner Losh dictPtr += hufHeaderSize; 31700c16b537SWarner Losh } 31710c16b537SWarner Losh 31720c16b537SWarner Losh { unsigned offcodeLog; 31730c16b537SWarner Losh size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); 3174*2b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted); 3175*2b9c00cbSConrad Meyer RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted); 31760c16b537SWarner Losh /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ 31770f743729SConrad Meyer /* fill all offset symbols to avoid garbage at end of table */ 3178*2b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 3179*2b9c00cbSConrad Meyer bs->entropy.fse.offcodeCTable, 3180a0483764SConrad Meyer offcodeNCount, MaxOff, offcodeLog, 3181*2b9c00cbSConrad Meyer workspace, HUF_WORKSPACE_SIZE)), 31820c16b537SWarner Losh dictionary_corrupted); 31830c16b537SWarner Losh dictPtr += offcodeHeaderSize; 31840c16b537SWarner Losh } 31850c16b537SWarner Losh 31860c16b537SWarner Losh { short matchlengthNCount[MaxML+1]; 31870c16b537SWarner Losh unsigned matchlengthMaxValue = MaxML, matchlengthLog; 31880c16b537SWarner Losh size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); 3189*2b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted); 3190*2b9c00cbSConrad Meyer RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted); 31910c16b537SWarner Losh /* Every match length code must have non-zero probability */ 3192*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML)); 3193*2b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 3194*2b9c00cbSConrad Meyer bs->entropy.fse.matchlengthCTable, 3195a0483764SConrad Meyer matchlengthNCount, matchlengthMaxValue, matchlengthLog, 3196*2b9c00cbSConrad Meyer workspace, HUF_WORKSPACE_SIZE)), 31970c16b537SWarner Losh dictionary_corrupted); 31980c16b537SWarner Losh dictPtr += matchlengthHeaderSize; 31990c16b537SWarner Losh } 32000c16b537SWarner Losh 32010c16b537SWarner Losh { short litlengthNCount[MaxLL+1]; 32020c16b537SWarner Losh unsigned litlengthMaxValue = MaxLL, litlengthLog; 32030c16b537SWarner Losh size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); 3204*2b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted); 3205*2b9c00cbSConrad Meyer RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted); 32060c16b537SWarner Losh /* Every literal length code must have non-zero probability */ 3207*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL)); 3208*2b9c00cbSConrad Meyer RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp( 3209*2b9c00cbSConrad Meyer bs->entropy.fse.litlengthCTable, 3210a0483764SConrad Meyer litlengthNCount, litlengthMaxValue, litlengthLog, 3211*2b9c00cbSConrad Meyer workspace, HUF_WORKSPACE_SIZE)), 32120c16b537SWarner Losh dictionary_corrupted); 32130c16b537SWarner Losh dictPtr += litlengthHeaderSize; 32140c16b537SWarner Losh } 32150c16b537SWarner Losh 3216*2b9c00cbSConrad Meyer RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted); 321719fcbaf1SConrad Meyer bs->rep[0] = MEM_readLE32(dictPtr+0); 321819fcbaf1SConrad Meyer bs->rep[1] = MEM_readLE32(dictPtr+4); 321919fcbaf1SConrad Meyer bs->rep[2] = MEM_readLE32(dictPtr+8); 32200c16b537SWarner Losh dictPtr += 12; 32210c16b537SWarner Losh 32220c16b537SWarner Losh { size_t const dictContentSize = (size_t)(dictEnd - dictPtr); 32230c16b537SWarner Losh U32 offcodeMax = MaxOff; 32240c16b537SWarner Losh if (dictContentSize <= ((U32)-1) - 128 KB) { 32250c16b537SWarner Losh U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ 32260c16b537SWarner Losh offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ 32270c16b537SWarner Losh } 32280c16b537SWarner Losh /* All offset values <= dictContentSize + 128 KB must be representable */ 3229*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff))); 32300c16b537SWarner Losh /* All repCodes must be <= dictContentSize and != 0*/ 32310c16b537SWarner Losh { U32 u; 32320c16b537SWarner Losh for (u=0; u<3; u++) { 3233*2b9c00cbSConrad Meyer RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted); 3234*2b9c00cbSConrad Meyer RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted); 32350c16b537SWarner Losh } } 32360c16b537SWarner Losh 32370f743729SConrad Meyer bs->entropy.huf.repeatMode = HUF_repeat_valid; 32380f743729SConrad Meyer bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid; 32390f743729SConrad Meyer bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid; 32400f743729SConrad Meyer bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid; 3241*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize, dtlm)); 324219fcbaf1SConrad Meyer return dictID; 32430c16b537SWarner Losh } 32440c16b537SWarner Losh } 32450c16b537SWarner Losh 32460c16b537SWarner Losh /** ZSTD_compress_insertDictionary() : 324719fcbaf1SConrad Meyer * @return : dictID, or an error code */ 32480f743729SConrad Meyer static size_t 32490f743729SConrad Meyer ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, 32500f743729SConrad Meyer ZSTD_matchState_t* ms, 32510f743729SConrad Meyer const ZSTD_CCtx_params* params, 32520c16b537SWarner Losh const void* dict, size_t dictSize, 325319fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 32540f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 325519fcbaf1SConrad Meyer void* workspace) 32560c16b537SWarner Losh { 3257052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); 32580c16b537SWarner Losh if ((dict==NULL) || (dictSize<=8)) return 0; 32590c16b537SWarner Losh 326019fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(bs); 326119fcbaf1SConrad Meyer 32620c16b537SWarner Losh /* dict restricted modes */ 326319fcbaf1SConrad Meyer if (dictContentType == ZSTD_dct_rawContent) 32640f743729SConrad Meyer return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm); 32650c16b537SWarner Losh 32660c16b537SWarner Losh if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { 326719fcbaf1SConrad Meyer if (dictContentType == ZSTD_dct_auto) { 3268052d3c12SConrad Meyer DEBUGLOG(4, "raw content dictionary detected"); 32690f743729SConrad Meyer return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm); 32700c16b537SWarner Losh } 3271*2b9c00cbSConrad Meyer RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong); 32720c16b537SWarner Losh assert(0); /* impossible */ 32730c16b537SWarner Losh } 32740c16b537SWarner Losh 32750c16b537SWarner Losh /* dict as full zstd dictionary */ 32760f743729SConrad Meyer return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, dtlm, workspace); 32770c16b537SWarner Losh } 32780c16b537SWarner Losh 32790c16b537SWarner Losh /*! ZSTD_compressBegin_internal() : 32800c16b537SWarner Losh * @return : 0, or an error code */ 32810f743729SConrad Meyer static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, 32820c16b537SWarner Losh const void* dict, size_t dictSize, 328319fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 32840f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 32850c16b537SWarner Losh const ZSTD_CDict* cdict, 32860c16b537SWarner Losh ZSTD_CCtx_params params, U64 pledgedSrcSize, 32870c16b537SWarner Losh ZSTD_buffered_policy_e zbuff) 32880c16b537SWarner Losh { 3289052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params.cParams.windowLog); 32900c16b537SWarner Losh /* params are supposed to be fully validated at this point */ 32910c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 32920c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 32930c16b537SWarner Losh 32940c16b537SWarner Losh if (cdict && cdict->dictContentSize>0) { 32950f743729SConrad Meyer return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff); 32960c16b537SWarner Losh } 32970c16b537SWarner Losh 3298*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 32990c16b537SWarner Losh ZSTDcrp_continue, zbuff) ); 330019fcbaf1SConrad Meyer { 330119fcbaf1SConrad Meyer size_t const dictID = ZSTD_compress_insertDictionary( 330219fcbaf1SConrad Meyer cctx->blockState.prevCBlock, &cctx->blockState.matchState, 33030f743729SConrad Meyer ¶ms, dict, dictSize, dictContentType, dtlm, cctx->entropyWorkspace); 3304*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(dictID); 330519fcbaf1SConrad Meyer assert(dictID <= (size_t)(U32)-1); 330619fcbaf1SConrad Meyer cctx->dictID = (U32)dictID; 330719fcbaf1SConrad Meyer } 330819fcbaf1SConrad Meyer return 0; 33090c16b537SWarner Losh } 33100c16b537SWarner Losh 3311052d3c12SConrad Meyer size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, 33120c16b537SWarner Losh const void* dict, size_t dictSize, 331319fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 33140f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 3315052d3c12SConrad Meyer const ZSTD_CDict* cdict, 33160c16b537SWarner Losh ZSTD_CCtx_params params, 33170c16b537SWarner Losh unsigned long long pledgedSrcSize) 33180c16b537SWarner Losh { 3319052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params.cParams.windowLog); 33200c16b537SWarner Losh /* compression parameters verification and optimization */ 3321*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) ); 3322052d3c12SConrad Meyer return ZSTD_compressBegin_internal(cctx, 33230f743729SConrad Meyer dict, dictSize, dictContentType, dtlm, 3324052d3c12SConrad Meyer cdict, 33250c16b537SWarner Losh params, pledgedSrcSize, 33260c16b537SWarner Losh ZSTDb_not_buffered); 33270c16b537SWarner Losh } 33280c16b537SWarner Losh 33290c16b537SWarner Losh /*! ZSTD_compressBegin_advanced() : 33300c16b537SWarner Losh * @return : 0, or an error code */ 33310c16b537SWarner Losh size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, 33320c16b537SWarner Losh const void* dict, size_t dictSize, 33330c16b537SWarner Losh ZSTD_parameters params, unsigned long long pledgedSrcSize) 33340c16b537SWarner Losh { 33350c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 33360c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 3337052d3c12SConrad Meyer return ZSTD_compressBegin_advanced_internal(cctx, 33380f743729SConrad Meyer dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, 3339052d3c12SConrad Meyer NULL /*cdict*/, 3340052d3c12SConrad Meyer cctxParams, pledgedSrcSize); 33410c16b537SWarner Losh } 33420c16b537SWarner Losh 33430c16b537SWarner Losh size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) 33440c16b537SWarner Losh { 334519fcbaf1SConrad Meyer ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); 33460c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 33470c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 3348a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize); 33490f743729SConrad Meyer return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, 3350052d3c12SConrad Meyer cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); 33510c16b537SWarner Losh } 33520c16b537SWarner Losh 33530c16b537SWarner Losh size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) 33540c16b537SWarner Losh { 33550c16b537SWarner Losh return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); 33560c16b537SWarner Losh } 33570c16b537SWarner Losh 33580c16b537SWarner Losh 33590c16b537SWarner Losh /*! ZSTD_writeEpilogue() : 33600c16b537SWarner Losh * Ends a frame. 33610c16b537SWarner Losh * @return : nb of bytes written into dst (or an error code) */ 33620c16b537SWarner Losh static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) 33630c16b537SWarner Losh { 33640c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 33650c16b537SWarner Losh BYTE* op = ostart; 33660c16b537SWarner Losh size_t fhSize = 0; 33670c16b537SWarner Losh 336819fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_writeEpilogue"); 3369*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing"); 33700c16b537SWarner Losh 33710c16b537SWarner Losh /* special case : empty frame */ 33720c16b537SWarner Losh if (cctx->stage == ZSTDcs_init) { 33730c16b537SWarner Losh fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0); 3374*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(fhSize); 33750c16b537SWarner Losh dstCapacity -= fhSize; 33760c16b537SWarner Losh op += fhSize; 33770c16b537SWarner Losh cctx->stage = ZSTDcs_ongoing; 33780c16b537SWarner Losh } 33790c16b537SWarner Losh 33800c16b537SWarner Losh if (cctx->stage != ZSTDcs_ending) { 33810c16b537SWarner Losh /* write one last empty block, make it the "last" block */ 33820c16b537SWarner Losh U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0; 3383*2b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall); 33840c16b537SWarner Losh MEM_writeLE32(op, cBlockHeader24); 33850c16b537SWarner Losh op += ZSTD_blockHeaderSize; 33860c16b537SWarner Losh dstCapacity -= ZSTD_blockHeaderSize; 33870c16b537SWarner Losh } 33880c16b537SWarner Losh 33890c16b537SWarner Losh if (cctx->appliedParams.fParams.checksumFlag) { 33900c16b537SWarner Losh U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); 3391*2b9c00cbSConrad Meyer RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall); 3392a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum); 33930c16b537SWarner Losh MEM_writeLE32(op, checksum); 33940c16b537SWarner Losh op += 4; 33950c16b537SWarner Losh } 33960c16b537SWarner Losh 33970c16b537SWarner Losh cctx->stage = ZSTDcs_created; /* return to "created but no init" status */ 33980c16b537SWarner Losh return op-ostart; 33990c16b537SWarner Losh } 34000c16b537SWarner Losh 34010c16b537SWarner Losh size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, 34020c16b537SWarner Losh void* dst, size_t dstCapacity, 34030c16b537SWarner Losh const void* src, size_t srcSize) 34040c16b537SWarner Losh { 34050c16b537SWarner Losh size_t endResult; 34060c16b537SWarner Losh size_t const cSize = ZSTD_compressContinue_internal(cctx, 34070c16b537SWarner Losh dst, dstCapacity, src, srcSize, 34080c16b537SWarner Losh 1 /* frame mode */, 1 /* last chunk */); 3409*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 34100c16b537SWarner Losh endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); 3411*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(endResult); 34120f743729SConrad Meyer assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); 34130f743729SConrad Meyer if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ 34140f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); 34150c16b537SWarner Losh DEBUGLOG(4, "end of frame : controlling src size"); 3416*2b9c00cbSConrad Meyer RETURN_ERROR_IF( 3417*2b9c00cbSConrad Meyer cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1, 3418*2b9c00cbSConrad Meyer srcSize_wrong, 3419*2b9c00cbSConrad Meyer "error : pledgedSrcSize = %u, while realSrcSize = %u", 3420*2b9c00cbSConrad Meyer (unsigned)cctx->pledgedSrcSizePlusOne-1, 3421*2b9c00cbSConrad Meyer (unsigned)cctx->consumedSrcSize); 3422*2b9c00cbSConrad Meyer } 34230c16b537SWarner Losh return cSize + endResult; 34240c16b537SWarner Losh } 34250c16b537SWarner Losh 34260c16b537SWarner Losh 34270c16b537SWarner Losh static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, 34280c16b537SWarner Losh void* dst, size_t dstCapacity, 34290c16b537SWarner Losh const void* src, size_t srcSize, 34300c16b537SWarner Losh const void* dict,size_t dictSize, 34310c16b537SWarner Losh ZSTD_parameters params) 34320c16b537SWarner Losh { 34330c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 34340c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 3435052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_internal"); 34360c16b537SWarner Losh return ZSTD_compress_advanced_internal(cctx, 34370c16b537SWarner Losh dst, dstCapacity, 34380c16b537SWarner Losh src, srcSize, 34390c16b537SWarner Losh dict, dictSize, 34400c16b537SWarner Losh cctxParams); 34410c16b537SWarner Losh } 34420c16b537SWarner Losh 34430f743729SConrad Meyer size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, 34440c16b537SWarner Losh void* dst, size_t dstCapacity, 34450c16b537SWarner Losh const void* src, size_t srcSize, 34460c16b537SWarner Losh const void* dict,size_t dictSize, 34470c16b537SWarner Losh ZSTD_parameters params) 34480c16b537SWarner Losh { 3449052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_advanced"); 3450*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams)); 34510f743729SConrad Meyer return ZSTD_compress_internal(cctx, 34520f743729SConrad Meyer dst, dstCapacity, 34530f743729SConrad Meyer src, srcSize, 34540f743729SConrad Meyer dict, dictSize, 34550f743729SConrad Meyer params); 34560c16b537SWarner Losh } 34570c16b537SWarner Losh 34580c16b537SWarner Losh /* Internal */ 34590c16b537SWarner Losh size_t ZSTD_compress_advanced_internal( 34600c16b537SWarner Losh ZSTD_CCtx* cctx, 34610c16b537SWarner Losh void* dst, size_t dstCapacity, 34620c16b537SWarner Losh const void* src, size_t srcSize, 34630c16b537SWarner Losh const void* dict,size_t dictSize, 34640c16b537SWarner Losh ZSTD_CCtx_params params) 34650c16b537SWarner Losh { 3466a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize); 3467*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, 34680f743729SConrad Meyer dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, 34690c16b537SWarner Losh params, srcSize, ZSTDb_not_buffered) ); 34700c16b537SWarner Losh return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 34710c16b537SWarner Losh } 34720c16b537SWarner Losh 34730f743729SConrad Meyer size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, 34740f743729SConrad Meyer void* dst, size_t dstCapacity, 34750f743729SConrad Meyer const void* src, size_t srcSize, 34760f743729SConrad Meyer const void* dict, size_t dictSize, 34770f743729SConrad Meyer int compressionLevel) 34780c16b537SWarner Losh { 34790f743729SConrad Meyer ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize + (!srcSize), dict ? dictSize : 0); 348019fcbaf1SConrad Meyer ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 348119fcbaf1SConrad Meyer assert(params.fParams.contentSizeFlag == 1); 348219fcbaf1SConrad Meyer return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, cctxParams); 34830c16b537SWarner Losh } 34840c16b537SWarner Losh 34850f743729SConrad Meyer size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, 34860f743729SConrad Meyer void* dst, size_t dstCapacity, 34870f743729SConrad Meyer const void* src, size_t srcSize, 34880f743729SConrad Meyer int compressionLevel) 34890c16b537SWarner Losh { 3490a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (unsigned)srcSize); 34910f743729SConrad Meyer assert(cctx != NULL); 349219fcbaf1SConrad Meyer return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel); 34930c16b537SWarner Losh } 34940c16b537SWarner Losh 34950f743729SConrad Meyer size_t ZSTD_compress(void* dst, size_t dstCapacity, 34960f743729SConrad Meyer const void* src, size_t srcSize, 34970f743729SConrad Meyer int compressionLevel) 34980c16b537SWarner Losh { 34990c16b537SWarner Losh size_t result; 35000c16b537SWarner Losh ZSTD_CCtx ctxBody; 35010f743729SConrad Meyer ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem); 35020c16b537SWarner Losh result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); 35030f743729SConrad Meyer ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */ 35040c16b537SWarner Losh return result; 35050c16b537SWarner Losh } 35060c16b537SWarner Losh 35070c16b537SWarner Losh 35080c16b537SWarner Losh /* ===== Dictionary API ===== */ 35090c16b537SWarner Losh 35100c16b537SWarner Losh /*! ZSTD_estimateCDictSize_advanced() : 35110c16b537SWarner Losh * Estimate amount of memory that will be needed to create a dictionary with following arguments */ 35120c16b537SWarner Losh size_t ZSTD_estimateCDictSize_advanced( 35130c16b537SWarner Losh size_t dictSize, ZSTD_compressionParameters cParams, 35140c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod) 35150c16b537SWarner Losh { 3516a0483764SConrad Meyer DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict)); 351719fcbaf1SConrad Meyer return sizeof(ZSTD_CDict) + HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) 35180c16b537SWarner Losh + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); 35190c16b537SWarner Losh } 35200c16b537SWarner Losh 35210c16b537SWarner Losh size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) 35220c16b537SWarner Losh { 35230c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 35240c16b537SWarner Losh return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); 35250c16b537SWarner Losh } 35260c16b537SWarner Losh 35270c16b537SWarner Losh size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) 35280c16b537SWarner Losh { 35290c16b537SWarner Losh if (cdict==NULL) return 0; /* support sizeof on NULL */ 3530a0483764SConrad Meyer DEBUGLOG(5, "sizeof(*cdict) : %u", (unsigned)sizeof(*cdict)); 353119fcbaf1SConrad Meyer return cdict->workspaceSize + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict); 35320c16b537SWarner Losh } 35330c16b537SWarner Losh 35340c16b537SWarner Losh static size_t ZSTD_initCDict_internal( 35350c16b537SWarner Losh ZSTD_CDict* cdict, 35360c16b537SWarner Losh const void* dictBuffer, size_t dictSize, 35370c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 353819fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 35390c16b537SWarner Losh ZSTD_compressionParameters cParams) 35400c16b537SWarner Losh { 3541a0483764SConrad Meyer DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType); 354219fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 35430f743729SConrad Meyer cdict->matchState.cParams = cParams; 35440c16b537SWarner Losh if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { 35450c16b537SWarner Losh cdict->dictBuffer = NULL; 35460c16b537SWarner Losh cdict->dictContent = dictBuffer; 35470c16b537SWarner Losh } else { 354819fcbaf1SConrad Meyer void* const internalBuffer = ZSTD_malloc(dictSize, cdict->customMem); 35490c16b537SWarner Losh cdict->dictBuffer = internalBuffer; 35500c16b537SWarner Losh cdict->dictContent = internalBuffer; 3551*2b9c00cbSConrad Meyer RETURN_ERROR_IF(!internalBuffer, memory_allocation); 35520c16b537SWarner Losh memcpy(internalBuffer, dictBuffer, dictSize); 35530c16b537SWarner Losh } 35540c16b537SWarner Losh cdict->dictContentSize = dictSize; 35550c16b537SWarner Losh 355619fcbaf1SConrad Meyer /* Reset the state to no dictionary */ 355719fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(&cdict->cBlockState); 355819fcbaf1SConrad Meyer { void* const end = ZSTD_reset_matchState( 355919fcbaf1SConrad Meyer &cdict->matchState, 356019fcbaf1SConrad Meyer (U32*)cdict->workspace + HUF_WORKSPACE_SIZE_U32, 356119fcbaf1SConrad Meyer &cParams, ZSTDcrp_continue, /* forCCtx */ 0); 356219fcbaf1SConrad Meyer assert(end == (char*)cdict->workspace + cdict->workspaceSize); 356319fcbaf1SConrad Meyer (void)end; 356419fcbaf1SConrad Meyer } 356519fcbaf1SConrad Meyer /* (Maybe) load the dictionary 356619fcbaf1SConrad Meyer * Skips loading the dictionary if it is <= 8 bytes. 356719fcbaf1SConrad Meyer */ 356819fcbaf1SConrad Meyer { ZSTD_CCtx_params params; 356919fcbaf1SConrad Meyer memset(¶ms, 0, sizeof(params)); 357019fcbaf1SConrad Meyer params.compressionLevel = ZSTD_CLEVEL_DEFAULT; 357119fcbaf1SConrad Meyer params.fParams.contentSizeFlag = 1; 357219fcbaf1SConrad Meyer params.cParams = cParams; 357319fcbaf1SConrad Meyer { size_t const dictID = ZSTD_compress_insertDictionary( 357419fcbaf1SConrad Meyer &cdict->cBlockState, &cdict->matchState, ¶ms, 357519fcbaf1SConrad Meyer cdict->dictContent, cdict->dictContentSize, 35760f743729SConrad Meyer dictContentType, ZSTD_dtlm_full, cdict->workspace); 3577*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(dictID); 357819fcbaf1SConrad Meyer assert(dictID <= (size_t)(U32)-1); 357919fcbaf1SConrad Meyer cdict->dictID = (U32)dictID; 358019fcbaf1SConrad Meyer } 35810c16b537SWarner Losh } 35820c16b537SWarner Losh 35830c16b537SWarner Losh return 0; 35840c16b537SWarner Losh } 35850c16b537SWarner Losh 35860c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, 35870c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 358819fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 35890c16b537SWarner Losh ZSTD_compressionParameters cParams, ZSTD_customMem customMem) 35900c16b537SWarner Losh { 3591a0483764SConrad Meyer DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (unsigned)dictContentType); 35920c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 35930c16b537SWarner Losh 35940c16b537SWarner Losh { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); 359519fcbaf1SConrad Meyer size_t const workspaceSize = HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); 359619fcbaf1SConrad Meyer void* const workspace = ZSTD_malloc(workspaceSize, customMem); 35970c16b537SWarner Losh 359819fcbaf1SConrad Meyer if (!cdict || !workspace) { 35990c16b537SWarner Losh ZSTD_free(cdict, customMem); 360019fcbaf1SConrad Meyer ZSTD_free(workspace, customMem); 36010c16b537SWarner Losh return NULL; 36020c16b537SWarner Losh } 360319fcbaf1SConrad Meyer cdict->customMem = customMem; 360419fcbaf1SConrad Meyer cdict->workspace = workspace; 360519fcbaf1SConrad Meyer cdict->workspaceSize = workspaceSize; 36060c16b537SWarner Losh if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 36070c16b537SWarner Losh dictBuffer, dictSize, 360819fcbaf1SConrad Meyer dictLoadMethod, dictContentType, 36090c16b537SWarner Losh cParams) )) { 36100c16b537SWarner Losh ZSTD_freeCDict(cdict); 36110c16b537SWarner Losh return NULL; 36120c16b537SWarner Losh } 36130c16b537SWarner Losh 36140c16b537SWarner Losh return cdict; 36150c16b537SWarner Losh } 36160c16b537SWarner Losh } 36170c16b537SWarner Losh 36180c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) 36190c16b537SWarner Losh { 36200c16b537SWarner Losh ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 36210c16b537SWarner Losh return ZSTD_createCDict_advanced(dict, dictSize, 362219fcbaf1SConrad Meyer ZSTD_dlm_byCopy, ZSTD_dct_auto, 36230c16b537SWarner Losh cParams, ZSTD_defaultCMem); 36240c16b537SWarner Losh } 36250c16b537SWarner Losh 36260c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) 36270c16b537SWarner Losh { 36280c16b537SWarner Losh ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 36290c16b537SWarner Losh return ZSTD_createCDict_advanced(dict, dictSize, 363019fcbaf1SConrad Meyer ZSTD_dlm_byRef, ZSTD_dct_auto, 36310c16b537SWarner Losh cParams, ZSTD_defaultCMem); 36320c16b537SWarner Losh } 36330c16b537SWarner Losh 36340c16b537SWarner Losh size_t ZSTD_freeCDict(ZSTD_CDict* cdict) 36350c16b537SWarner Losh { 36360c16b537SWarner Losh if (cdict==NULL) return 0; /* support free on NULL */ 363719fcbaf1SConrad Meyer { ZSTD_customMem const cMem = cdict->customMem; 363819fcbaf1SConrad Meyer ZSTD_free(cdict->workspace, cMem); 36390c16b537SWarner Losh ZSTD_free(cdict->dictBuffer, cMem); 36400c16b537SWarner Losh ZSTD_free(cdict, cMem); 36410c16b537SWarner Losh return 0; 36420c16b537SWarner Losh } 36430c16b537SWarner Losh } 36440c16b537SWarner Losh 36450c16b537SWarner Losh /*! ZSTD_initStaticCDict_advanced() : 36460c16b537SWarner Losh * Generate a digested dictionary in provided memory area. 36470c16b537SWarner Losh * workspace: The memory area to emplace the dictionary into. 36480c16b537SWarner Losh * Provided pointer must 8-bytes aligned. 36490c16b537SWarner Losh * It must outlive dictionary usage. 36500c16b537SWarner Losh * workspaceSize: Use ZSTD_estimateCDictSize() 36510c16b537SWarner Losh * to determine how large workspace must be. 36520c16b537SWarner Losh * cParams : use ZSTD_getCParams() to transform a compression level 36530c16b537SWarner Losh * into its relevants cParams. 36540c16b537SWarner Losh * @return : pointer to ZSTD_CDict*, or NULL if error (size too small) 36550c16b537SWarner Losh * Note : there is no corresponding "free" function. 36560c16b537SWarner Losh * Since workspace was allocated externally, it must be freed externally. 36570c16b537SWarner Losh */ 365819fcbaf1SConrad Meyer const ZSTD_CDict* ZSTD_initStaticCDict( 365919fcbaf1SConrad Meyer void* workspace, size_t workspaceSize, 36600c16b537SWarner Losh const void* dict, size_t dictSize, 36610c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 366219fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 36630c16b537SWarner Losh ZSTD_compressionParameters cParams) 36640c16b537SWarner Losh { 366519fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); 36660c16b537SWarner Losh size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize) 366719fcbaf1SConrad Meyer + HUF_WORKSPACE_SIZE + matchStateSize; 36680c16b537SWarner Losh ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; 36690c16b537SWarner Losh void* ptr; 36700c16b537SWarner Losh if ((size_t)workspace & 7) return NULL; /* 8-aligned */ 3671052d3c12SConrad Meyer DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u", 3672a0483764SConrad Meyer (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize)); 36730c16b537SWarner Losh if (workspaceSize < neededSize) return NULL; 36740c16b537SWarner Losh 36750c16b537SWarner Losh if (dictLoadMethod == ZSTD_dlm_byCopy) { 36760c16b537SWarner Losh memcpy(cdict+1, dict, dictSize); 36770c16b537SWarner Losh dict = cdict+1; 36780c16b537SWarner Losh ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize; 36790c16b537SWarner Losh } else { 36800c16b537SWarner Losh ptr = cdict+1; 36810c16b537SWarner Losh } 368219fcbaf1SConrad Meyer cdict->workspace = ptr; 368319fcbaf1SConrad Meyer cdict->workspaceSize = HUF_WORKSPACE_SIZE + matchStateSize; 36840c16b537SWarner Losh 36850c16b537SWarner Losh if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 36860c16b537SWarner Losh dict, dictSize, 368719fcbaf1SConrad Meyer ZSTD_dlm_byRef, dictContentType, 36880c16b537SWarner Losh cParams) )) 36890c16b537SWarner Losh return NULL; 36900c16b537SWarner Losh 36910c16b537SWarner Losh return cdict; 36920c16b537SWarner Losh } 36930c16b537SWarner Losh 369419fcbaf1SConrad Meyer ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) 369519fcbaf1SConrad Meyer { 369619fcbaf1SConrad Meyer assert(cdict != NULL); 36970f743729SConrad Meyer return cdict->matchState.cParams; 36980c16b537SWarner Losh } 36990c16b537SWarner Losh 37000c16b537SWarner Losh /* ZSTD_compressBegin_usingCDict_advanced() : 37010c16b537SWarner Losh * cdict must be != NULL */ 37020c16b537SWarner Losh size_t ZSTD_compressBegin_usingCDict_advanced( 37030c16b537SWarner Losh ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, 37040c16b537SWarner Losh ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) 37050c16b537SWarner Losh { 3706052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced"); 3707*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cdict==NULL, dictionary_wrong); 37080c16b537SWarner Losh { ZSTD_CCtx_params params = cctx->requestedParams; 37090c16b537SWarner Losh params.cParams = ZSTD_getCParamsFromCDict(cdict); 371019fcbaf1SConrad Meyer /* Increase window log to fit the entire dictionary and source if the 371119fcbaf1SConrad Meyer * source size is known. Limit the increase to 19, which is the 371219fcbaf1SConrad Meyer * window log for compression level 1 with the largest source size. 371319fcbaf1SConrad Meyer */ 371419fcbaf1SConrad Meyer if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { 371519fcbaf1SConrad Meyer U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); 371619fcbaf1SConrad Meyer U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; 371719fcbaf1SConrad Meyer params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog); 371819fcbaf1SConrad Meyer } 37190c16b537SWarner Losh params.fParams = fParams; 37200c16b537SWarner Losh return ZSTD_compressBegin_internal(cctx, 37210f743729SConrad Meyer NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, 37220c16b537SWarner Losh cdict, 37230c16b537SWarner Losh params, pledgedSrcSize, 37240c16b537SWarner Losh ZSTDb_not_buffered); 37250c16b537SWarner Losh } 37260c16b537SWarner Losh } 37270c16b537SWarner Losh 37280c16b537SWarner Losh /* ZSTD_compressBegin_usingCDict() : 37290c16b537SWarner Losh * pledgedSrcSize=0 means "unknown" 37300c16b537SWarner Losh * if pledgedSrcSize>0, it will enable contentSizeFlag */ 37310c16b537SWarner Losh size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 37320c16b537SWarner Losh { 37330c16b537SWarner Losh ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 3734052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); 37350f743729SConrad Meyer return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); 37360c16b537SWarner Losh } 37370c16b537SWarner Losh 37380c16b537SWarner Losh size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, 37390c16b537SWarner Losh void* dst, size_t dstCapacity, 37400c16b537SWarner Losh const void* src, size_t srcSize, 37410c16b537SWarner Losh const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) 37420c16b537SWarner Losh { 3743*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */ 37440c16b537SWarner Losh return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 37450c16b537SWarner Losh } 37460c16b537SWarner Losh 37470c16b537SWarner Losh /*! ZSTD_compress_usingCDict() : 37480c16b537SWarner Losh * Compression using a digested Dictionary. 37490c16b537SWarner Losh * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times. 37500c16b537SWarner Losh * Note that compression parameters are decided at CDict creation time 37510c16b537SWarner Losh * while frame parameters are hardcoded */ 37520c16b537SWarner Losh size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, 37530c16b537SWarner Losh void* dst, size_t dstCapacity, 37540c16b537SWarner Losh const void* src, size_t srcSize, 37550c16b537SWarner Losh const ZSTD_CDict* cdict) 37560c16b537SWarner Losh { 37570c16b537SWarner Losh ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 37580c16b537SWarner Losh return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); 37590c16b537SWarner Losh } 37600c16b537SWarner Losh 37610c16b537SWarner Losh 37620c16b537SWarner Losh 37630c16b537SWarner Losh /* ****************************************************************** 37640c16b537SWarner Losh * Streaming 37650c16b537SWarner Losh ********************************************************************/ 37660c16b537SWarner Losh 37670c16b537SWarner Losh ZSTD_CStream* ZSTD_createCStream(void) 37680c16b537SWarner Losh { 3769052d3c12SConrad Meyer DEBUGLOG(3, "ZSTD_createCStream"); 37700c16b537SWarner Losh return ZSTD_createCStream_advanced(ZSTD_defaultCMem); 37710c16b537SWarner Losh } 37720c16b537SWarner Losh 37730c16b537SWarner Losh ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize) 37740c16b537SWarner Losh { 37750c16b537SWarner Losh return ZSTD_initStaticCCtx(workspace, workspaceSize); 37760c16b537SWarner Losh } 37770c16b537SWarner Losh 37780c16b537SWarner Losh ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem) 37790c16b537SWarner Losh { /* CStream and CCtx are now same object */ 37800c16b537SWarner Losh return ZSTD_createCCtx_advanced(customMem); 37810c16b537SWarner Losh } 37820c16b537SWarner Losh 37830c16b537SWarner Losh size_t ZSTD_freeCStream(ZSTD_CStream* zcs) 37840c16b537SWarner Losh { 37850c16b537SWarner Losh return ZSTD_freeCCtx(zcs); /* same object */ 37860c16b537SWarner Losh } 37870c16b537SWarner Losh 37880c16b537SWarner Losh 37890c16b537SWarner Losh 37900c16b537SWarner Losh /*====== Initialization ======*/ 37910c16b537SWarner Losh 37920c16b537SWarner Losh size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; } 37930c16b537SWarner Losh 37940c16b537SWarner Losh size_t ZSTD_CStreamOutSize(void) 37950c16b537SWarner Losh { 37960c16b537SWarner Losh return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; 37970c16b537SWarner Losh } 37980c16b537SWarner Losh 379919fcbaf1SConrad Meyer static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx, 380019fcbaf1SConrad Meyer const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType, 3801052d3c12SConrad Meyer const ZSTD_CDict* const cdict, 38020f743729SConrad Meyer ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize) 38030c16b537SWarner Losh { 38040f743729SConrad Meyer DEBUGLOG(4, "ZSTD_resetCStream_internal"); 38050f743729SConrad Meyer /* Finalize the compression parameters */ 38060f743729SConrad Meyer params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, dictSize); 38070c16b537SWarner Losh /* params are supposed to be fully validated at this point */ 38080c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 38090c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 38100c16b537SWarner Losh 3811*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx, 38120f743729SConrad Meyer dict, dictSize, dictContentType, ZSTD_dtlm_fast, 38130c16b537SWarner Losh cdict, 38140c16b537SWarner Losh params, pledgedSrcSize, 38150c16b537SWarner Losh ZSTDb_buffered) ); 38160c16b537SWarner Losh 381719fcbaf1SConrad Meyer cctx->inToCompress = 0; 381819fcbaf1SConrad Meyer cctx->inBuffPos = 0; 381919fcbaf1SConrad Meyer cctx->inBuffTarget = cctx->blockSize 382019fcbaf1SConrad 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 */ 382119fcbaf1SConrad Meyer cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; 382219fcbaf1SConrad Meyer cctx->streamStage = zcss_load; 382319fcbaf1SConrad Meyer cctx->frameEnded = 0; 38240c16b537SWarner Losh return 0; /* ready to go */ 38250c16b537SWarner Losh } 38260c16b537SWarner Losh 3827052d3c12SConrad Meyer /* ZSTD_resetCStream(): 3828052d3c12SConrad Meyer * pledgedSrcSize == 0 means "unknown" */ 3829*2b9c00cbSConrad Meyer size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pss) 38300c16b537SWarner Losh { 3831*2b9c00cbSConrad Meyer /* temporary : 0 interpreted as "unknown" during transition period. 3832*2b9c00cbSConrad Meyer * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. 3833*2b9c00cbSConrad Meyer * 0 will be interpreted as "empty" in the future. 3834*2b9c00cbSConrad Meyer */ 3835*2b9c00cbSConrad Meyer U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 3836a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize); 3837*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 3838*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 3839*2b9c00cbSConrad Meyer return 0; 38400c16b537SWarner Losh } 38410c16b537SWarner Losh 38420c16b537SWarner Losh /*! ZSTD_initCStream_internal() : 3843052d3c12SConrad Meyer * Note : for lib/compress only. Used by zstdmt_compress.c. 38440c16b537SWarner Losh * Assumption 1 : params are valid 38450c16b537SWarner Losh * Assumption 2 : either dict, or cdict, is defined, not both */ 38460c16b537SWarner Losh size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, 38470c16b537SWarner Losh const void* dict, size_t dictSize, const ZSTD_CDict* cdict, 38480c16b537SWarner Losh ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) 38490c16b537SWarner Losh { 38500c16b537SWarner Losh DEBUGLOG(4, "ZSTD_initCStream_internal"); 3851*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 3852*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 38530c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 3854*2b9c00cbSConrad Meyer zcs->requestedParams = params; 38550c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 3856*2b9c00cbSConrad Meyer if (dict) { 3857*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); 38580c16b537SWarner Losh } else { 3859*2b9c00cbSConrad Meyer /* Dictionary is cleared if !cdict */ 3860*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); 38610c16b537SWarner Losh } 3862*2b9c00cbSConrad Meyer return 0; 38630c16b537SWarner Losh } 38640c16b537SWarner Losh 38650c16b537SWarner Losh /* ZSTD_initCStream_usingCDict_advanced() : 38660c16b537SWarner Losh * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ 38670c16b537SWarner Losh size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, 38680c16b537SWarner Losh const ZSTD_CDict* cdict, 38690c16b537SWarner Losh ZSTD_frameParameters fParams, 38700c16b537SWarner Losh unsigned long long pledgedSrcSize) 3871052d3c12SConrad Meyer { 3872052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced"); 3873*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 3874*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 3875*2b9c00cbSConrad Meyer zcs->requestedParams.fParams = fParams; 3876*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); 3877*2b9c00cbSConrad Meyer return 0; 38780c16b537SWarner Losh } 38790c16b537SWarner Losh 38800c16b537SWarner Losh /* note : cdict must outlive compression session */ 38810c16b537SWarner Losh size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict) 38820c16b537SWarner Losh { 3883052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingCDict"); 3884*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 3885*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) ); 3886*2b9c00cbSConrad Meyer return 0; 38870c16b537SWarner Losh } 38880c16b537SWarner Losh 388919fcbaf1SConrad Meyer 3890052d3c12SConrad Meyer /* ZSTD_initCStream_advanced() : 389119fcbaf1SConrad Meyer * pledgedSrcSize must be exact. 3892052d3c12SConrad Meyer * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. 3893052d3c12SConrad Meyer * dict is loaded with default parameters ZSTD_dm_auto and ZSTD_dlm_byCopy. */ 38940c16b537SWarner Losh size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, 38950c16b537SWarner Losh const void* dict, size_t dictSize, 3896*2b9c00cbSConrad Meyer ZSTD_parameters params, unsigned long long pss) 38970c16b537SWarner Losh { 3898*2b9c00cbSConrad Meyer /* for compatibility with older programs relying on this behavior. 3899*2b9c00cbSConrad Meyer * Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. 3900*2b9c00cbSConrad Meyer * This line will be removed in the future. 3901*2b9c00cbSConrad Meyer */ 3902*2b9c00cbSConrad Meyer U64 const pledgedSrcSize = (pss==0 && params.fParams.contentSizeFlag==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 3903*2b9c00cbSConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_advanced"); 3904*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 3905*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 3906*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) ); 39070f743729SConrad Meyer zcs->requestedParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); 3908*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); 3909*2b9c00cbSConrad Meyer return 0; 391019fcbaf1SConrad Meyer } 39110c16b537SWarner Losh 39120c16b537SWarner Losh size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) 39130c16b537SWarner Losh { 3914*2b9c00cbSConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingDict"); 3915*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 3916*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); 3917*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) ); 3918*2b9c00cbSConrad Meyer return 0; 39190c16b537SWarner Losh } 39200c16b537SWarner Losh 3921052d3c12SConrad Meyer size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss) 39220c16b537SWarner Losh { 3923*2b9c00cbSConrad Meyer /* temporary : 0 interpreted as "unknown" during transition period. 3924*2b9c00cbSConrad Meyer * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. 3925*2b9c00cbSConrad Meyer * 0 will be interpreted as "empty" in the future. 3926*2b9c00cbSConrad Meyer */ 3927*2b9c00cbSConrad Meyer U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; 3928*2b9c00cbSConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_srcSize"); 3929*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 3930*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) ); 3931*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); 3932*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) ); 3933*2b9c00cbSConrad Meyer return 0; 39340c16b537SWarner Losh } 39350c16b537SWarner Losh 39360c16b537SWarner Losh size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) 39370c16b537SWarner Losh { 3938052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream"); 3939*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) ); 3940*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) ); 3941*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) ); 3942*2b9c00cbSConrad Meyer return 0; 39430c16b537SWarner Losh } 39440c16b537SWarner Losh 39450c16b537SWarner Losh /*====== Compression ======*/ 39460c16b537SWarner Losh 3947a0483764SConrad Meyer static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx) 3948a0483764SConrad Meyer { 3949a0483764SConrad Meyer size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos; 3950a0483764SConrad Meyer if (hintInSize==0) hintInSize = cctx->blockSize; 3951a0483764SConrad Meyer return hintInSize; 3952a0483764SConrad Meyer } 3953a0483764SConrad Meyer 3954a0483764SConrad Meyer static size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, 39550c16b537SWarner Losh const void* src, size_t srcSize) 39560c16b537SWarner Losh { 39570c16b537SWarner Losh size_t const length = MIN(dstCapacity, srcSize); 39580c16b537SWarner Losh if (length) memcpy(dst, src, length); 39590c16b537SWarner Losh return length; 39600c16b537SWarner Losh } 39610c16b537SWarner Losh 39620c16b537SWarner Losh /** ZSTD_compressStream_generic(): 3963a0483764SConrad Meyer * internal function for all *compressStream*() variants 396419fcbaf1SConrad Meyer * non-static, because can be called from zstdmt_compress.c 39650c16b537SWarner Losh * @return : hint size for next input */ 3966*2b9c00cbSConrad Meyer static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, 39670c16b537SWarner Losh ZSTD_outBuffer* output, 39680c16b537SWarner Losh ZSTD_inBuffer* input, 39690c16b537SWarner Losh ZSTD_EndDirective const flushMode) 39700c16b537SWarner Losh { 39710c16b537SWarner Losh const char* const istart = (const char*)input->src; 39720c16b537SWarner Losh const char* const iend = istart + input->size; 39730c16b537SWarner Losh const char* ip = istart + input->pos; 39740c16b537SWarner Losh char* const ostart = (char*)output->dst; 39750c16b537SWarner Losh char* const oend = ostart + output->size; 39760c16b537SWarner Losh char* op = ostart + output->pos; 39770c16b537SWarner Losh U32 someMoreWork = 1; 39780c16b537SWarner Losh 39790c16b537SWarner Losh /* check expectations */ 3980a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode); 39810c16b537SWarner Losh assert(zcs->inBuff != NULL); 39820c16b537SWarner Losh assert(zcs->inBuffSize > 0); 39830c16b537SWarner Losh assert(zcs->outBuff != NULL); 39840c16b537SWarner Losh assert(zcs->outBuffSize > 0); 39850c16b537SWarner Losh assert(output->pos <= output->size); 39860c16b537SWarner Losh assert(input->pos <= input->size); 39870c16b537SWarner Losh 39880c16b537SWarner Losh while (someMoreWork) { 39890c16b537SWarner Losh switch(zcs->streamStage) 39900c16b537SWarner Losh { 39910c16b537SWarner Losh case zcss_init: 3992*2b9c00cbSConrad Meyer RETURN_ERROR(init_missing, "call ZSTD_initCStream() first!"); 39930c16b537SWarner Losh 39940c16b537SWarner Losh case zcss_load: 39950c16b537SWarner Losh if ( (flushMode == ZSTD_e_end) 39960c16b537SWarner Losh && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */ 39970c16b537SWarner Losh && (zcs->inBuffPos == 0) ) { 39980c16b537SWarner Losh /* shortcut to compression pass directly into output buffer */ 39990c16b537SWarner Losh size_t const cSize = ZSTD_compressEnd(zcs, 40000c16b537SWarner Losh op, oend-op, ip, iend-ip); 4001a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize); 4002*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 40030c16b537SWarner Losh ip = iend; 40040c16b537SWarner Losh op += cSize; 40050c16b537SWarner Losh zcs->frameEnded = 1; 4006a0483764SConrad Meyer ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 40070c16b537SWarner Losh someMoreWork = 0; break; 40080c16b537SWarner Losh } 40090c16b537SWarner Losh /* complete loading into inBuffer */ 40100c16b537SWarner Losh { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; 40110c16b537SWarner Losh size_t const loaded = ZSTD_limitCopy( 40120c16b537SWarner Losh zcs->inBuff + zcs->inBuffPos, toLoad, 40130c16b537SWarner Losh ip, iend-ip); 40140c16b537SWarner Losh zcs->inBuffPos += loaded; 40150c16b537SWarner Losh ip += loaded; 40160c16b537SWarner Losh if ( (flushMode == ZSTD_e_continue) 40170c16b537SWarner Losh && (zcs->inBuffPos < zcs->inBuffTarget) ) { 40180c16b537SWarner Losh /* not enough input to fill full block : stop here */ 40190c16b537SWarner Losh someMoreWork = 0; break; 40200c16b537SWarner Losh } 40210c16b537SWarner Losh if ( (flushMode == ZSTD_e_flush) 40220c16b537SWarner Losh && (zcs->inBuffPos == zcs->inToCompress) ) { 40230c16b537SWarner Losh /* empty */ 40240c16b537SWarner Losh someMoreWork = 0; break; 40250c16b537SWarner Losh } 40260c16b537SWarner Losh } 40270c16b537SWarner Losh /* compress current block (note : this stage cannot be stopped in the middle) */ 40280c16b537SWarner Losh DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode); 40290c16b537SWarner Losh { void* cDst; 40300c16b537SWarner Losh size_t cSize; 40310c16b537SWarner Losh size_t const iSize = zcs->inBuffPos - zcs->inToCompress; 40320c16b537SWarner Losh size_t oSize = oend-op; 40330c16b537SWarner Losh unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); 40340c16b537SWarner Losh if (oSize >= ZSTD_compressBound(iSize)) 40350c16b537SWarner Losh cDst = op; /* compress into output buffer, to skip flush stage */ 40360c16b537SWarner Losh else 40370c16b537SWarner Losh cDst = zcs->outBuff, oSize = zcs->outBuffSize; 40380c16b537SWarner Losh cSize = lastBlock ? 40390c16b537SWarner Losh ZSTD_compressEnd(zcs, cDst, oSize, 40400c16b537SWarner Losh zcs->inBuff + zcs->inToCompress, iSize) : 40410c16b537SWarner Losh ZSTD_compressContinue(zcs, cDst, oSize, 40420c16b537SWarner Losh zcs->inBuff + zcs->inToCompress, iSize); 4043*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(cSize); 40440c16b537SWarner Losh zcs->frameEnded = lastBlock; 40450c16b537SWarner Losh /* prepare next block */ 40460c16b537SWarner Losh zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; 40470c16b537SWarner Losh if (zcs->inBuffTarget > zcs->inBuffSize) 40480c16b537SWarner Losh zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; 40490c16b537SWarner Losh DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", 4050a0483764SConrad Meyer (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize); 40510c16b537SWarner Losh if (!lastBlock) 40520c16b537SWarner Losh assert(zcs->inBuffTarget <= zcs->inBuffSize); 40530c16b537SWarner Losh zcs->inToCompress = zcs->inBuffPos; 40540c16b537SWarner Losh if (cDst == op) { /* no need to flush */ 40550c16b537SWarner Losh op += cSize; 40560c16b537SWarner Losh if (zcs->frameEnded) { 40570c16b537SWarner Losh DEBUGLOG(5, "Frame completed directly in outBuffer"); 40580c16b537SWarner Losh someMoreWork = 0; 4059a0483764SConrad Meyer ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 40600c16b537SWarner Losh } 40610c16b537SWarner Losh break; 40620c16b537SWarner Losh } 40630c16b537SWarner Losh zcs->outBuffContentSize = cSize; 40640c16b537SWarner Losh zcs->outBuffFlushedSize = 0; 40650c16b537SWarner Losh zcs->streamStage = zcss_flush; /* pass-through to flush stage */ 40660c16b537SWarner Losh } 40670c16b537SWarner Losh /* fall-through */ 40680c16b537SWarner Losh case zcss_flush: 40690c16b537SWarner Losh DEBUGLOG(5, "flush stage"); 40700c16b537SWarner Losh { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; 40710c16b537SWarner Losh size_t const flushed = ZSTD_limitCopy(op, oend-op, 40720c16b537SWarner Losh zcs->outBuff + zcs->outBuffFlushedSize, toFlush); 40730c16b537SWarner Losh DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u", 4074a0483764SConrad Meyer (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed); 40750c16b537SWarner Losh op += flushed; 40760c16b537SWarner Losh zcs->outBuffFlushedSize += flushed; 40770c16b537SWarner Losh if (toFlush!=flushed) { 40780c16b537SWarner Losh /* flush not fully completed, presumably because dst is too small */ 40790c16b537SWarner Losh assert(op==oend); 40800c16b537SWarner Losh someMoreWork = 0; 40810c16b537SWarner Losh break; 40820c16b537SWarner Losh } 40830c16b537SWarner Losh zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; 40840c16b537SWarner Losh if (zcs->frameEnded) { 40850c16b537SWarner Losh DEBUGLOG(5, "Frame completed on flush"); 40860c16b537SWarner Losh someMoreWork = 0; 4087a0483764SConrad Meyer ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only); 40880c16b537SWarner Losh break; 40890c16b537SWarner Losh } 40900c16b537SWarner Losh zcs->streamStage = zcss_load; 40910c16b537SWarner Losh break; 40920c16b537SWarner Losh } 40930c16b537SWarner Losh 40940c16b537SWarner Losh default: /* impossible */ 40950c16b537SWarner Losh assert(0); 40960c16b537SWarner Losh } 40970c16b537SWarner Losh } 40980c16b537SWarner Losh 40990c16b537SWarner Losh input->pos = ip - istart; 41000c16b537SWarner Losh output->pos = op - ostart; 41010c16b537SWarner Losh if (zcs->frameEnded) return 0; 4102a0483764SConrad Meyer return ZSTD_nextInputSizeHint(zcs); 41030c16b537SWarner Losh } 4104a0483764SConrad Meyer 4105a0483764SConrad Meyer static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx) 4106a0483764SConrad Meyer { 4107a0483764SConrad Meyer #ifdef ZSTD_MULTITHREAD 4108a0483764SConrad Meyer if (cctx->appliedParams.nbWorkers >= 1) { 4109a0483764SConrad Meyer assert(cctx->mtctx != NULL); 4110a0483764SConrad Meyer return ZSTDMT_nextInputSizeHint(cctx->mtctx); 4111a0483764SConrad Meyer } 4112a0483764SConrad Meyer #endif 4113a0483764SConrad Meyer return ZSTD_nextInputSizeHint(cctx); 4114a0483764SConrad Meyer 41150c16b537SWarner Losh } 41160c16b537SWarner Losh 41170c16b537SWarner Losh size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) 41180c16b537SWarner Losh { 4119*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) ); 4120a0483764SConrad Meyer return ZSTD_nextInputSizeHint_MTorST(zcs); 41210c16b537SWarner Losh } 41220c16b537SWarner Losh 41230c16b537SWarner Losh 4124a0483764SConrad Meyer size_t ZSTD_compressStream2( ZSTD_CCtx* cctx, 41250c16b537SWarner Losh ZSTD_outBuffer* output, 41260c16b537SWarner Losh ZSTD_inBuffer* input, 41270c16b537SWarner Losh ZSTD_EndDirective endOp) 41280c16b537SWarner Losh { 4129a0483764SConrad Meyer DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp); 41300c16b537SWarner Losh /* check conditions */ 4131*2b9c00cbSConrad Meyer RETURN_ERROR_IF(output->pos > output->size, GENERIC); 4132*2b9c00cbSConrad Meyer RETURN_ERROR_IF(input->pos > input->size, GENERIC); 41330c16b537SWarner Losh assert(cctx!=NULL); 41340c16b537SWarner Losh 41350c16b537SWarner Losh /* transparent initialization stage */ 41360c16b537SWarner Losh if (cctx->streamStage == zcss_init) { 41370c16b537SWarner Losh ZSTD_CCtx_params params = cctx->requestedParams; 4138052d3c12SConrad Meyer ZSTD_prefixDict const prefixDict = cctx->prefixDict; 4139*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) ); /* Init the local dict if present. */ 41400c16b537SWarner Losh memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ 41410c16b537SWarner Losh assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ 4142a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage"); 4143052d3c12SConrad Meyer if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */ 4144052d3c12SConrad Meyer params.cParams = ZSTD_getCParamsFromCCtxParams( 414519fcbaf1SConrad Meyer &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); 41460c16b537SWarner Losh 41470f743729SConrad Meyer 41480c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 414919fcbaf1SConrad Meyer if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { 415019fcbaf1SConrad Meyer params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ 415119fcbaf1SConrad Meyer } 415219fcbaf1SConrad Meyer if (params.nbWorkers > 0) { 415319fcbaf1SConrad Meyer /* mt context creation */ 41540f743729SConrad Meyer if (cctx->mtctx == NULL) { 4155a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_compressStream2: creating new mtctx for nbWorkers=%u", 415619fcbaf1SConrad Meyer params.nbWorkers); 415719fcbaf1SConrad Meyer cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbWorkers, cctx->customMem); 4158*2b9c00cbSConrad Meyer RETURN_ERROR_IF(cctx->mtctx == NULL, memory_allocation); 41590c16b537SWarner Losh } 416019fcbaf1SConrad Meyer /* mt compression */ 416119fcbaf1SConrad Meyer DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); 4162*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTDMT_initCStream_internal( 41630c16b537SWarner Losh cctx->mtctx, 416419fcbaf1SConrad Meyer prefixDict.dict, prefixDict.dictSize, ZSTD_dct_rawContent, 41650c16b537SWarner Losh cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); 41660c16b537SWarner Losh cctx->streamStage = zcss_load; 416719fcbaf1SConrad Meyer cctx->appliedParams.nbWorkers = params.nbWorkers; 41680c16b537SWarner Losh } else 41690c16b537SWarner Losh #endif 4170*2b9c00cbSConrad Meyer { FORWARD_IF_ERROR( ZSTD_resetCStream_internal(cctx, 417119fcbaf1SConrad Meyer prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, 417219fcbaf1SConrad Meyer cctx->cdict, 417319fcbaf1SConrad Meyer params, cctx->pledgedSrcSizePlusOne-1) ); 4174052d3c12SConrad Meyer assert(cctx->streamStage == zcss_load); 417519fcbaf1SConrad Meyer assert(cctx->appliedParams.nbWorkers == 0); 41760c16b537SWarner Losh } } 4177a0483764SConrad Meyer /* end of transparent initialization stage */ 41780c16b537SWarner Losh 41790c16b537SWarner Losh /* compression stage */ 41800c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 418119fcbaf1SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 4182*2b9c00cbSConrad Meyer int const forceMaxProgress = (endOp == ZSTD_e_flush || endOp == ZSTD_e_end); 4183*2b9c00cbSConrad Meyer size_t flushMin; 4184*2b9c00cbSConrad Meyer assert(forceMaxProgress || endOp == ZSTD_e_continue /* Protection for a new flush type */); 418519fcbaf1SConrad Meyer if (cctx->cParamsChanged) { 418619fcbaf1SConrad Meyer ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams); 418719fcbaf1SConrad Meyer cctx->cParamsChanged = 0; 418819fcbaf1SConrad Meyer } 4189*2b9c00cbSConrad Meyer do { 4190*2b9c00cbSConrad Meyer flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); 41910c16b537SWarner Losh if ( ZSTD_isError(flushMin) 41920c16b537SWarner Losh || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ 4193a0483764SConrad Meyer ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); 41940c16b537SWarner Losh } 4195*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(flushMin); 4196*2b9c00cbSConrad Meyer } while (forceMaxProgress && flushMin != 0 && output->pos < output->size); 4197a0483764SConrad Meyer DEBUGLOG(5, "completed ZSTD_compressStream2 delegating to ZSTDMT_compressStream_generic"); 4198*2b9c00cbSConrad Meyer /* Either we don't require maximum forward progress, we've finished the 4199*2b9c00cbSConrad Meyer * flush, or we are out of output space. 4200*2b9c00cbSConrad Meyer */ 4201*2b9c00cbSConrad Meyer assert(!forceMaxProgress || flushMin == 0 || output->pos == output->size); 42020c16b537SWarner Losh return flushMin; 4203*2b9c00cbSConrad Meyer } 42040c16b537SWarner Losh #endif 4205*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) ); 4206a0483764SConrad Meyer DEBUGLOG(5, "completed ZSTD_compressStream2"); 42070c16b537SWarner Losh return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ 42080c16b537SWarner Losh } 42090c16b537SWarner Losh 4210a0483764SConrad Meyer size_t ZSTD_compressStream2_simpleArgs ( 42110c16b537SWarner Losh ZSTD_CCtx* cctx, 42120c16b537SWarner Losh void* dst, size_t dstCapacity, size_t* dstPos, 42130c16b537SWarner Losh const void* src, size_t srcSize, size_t* srcPos, 42140c16b537SWarner Losh ZSTD_EndDirective endOp) 42150c16b537SWarner Losh { 42160c16b537SWarner Losh ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; 42170c16b537SWarner Losh ZSTD_inBuffer input = { src, srcSize, *srcPos }; 4218a0483764SConrad Meyer /* ZSTD_compressStream2() will check validity of dstPos and srcPos */ 4219a0483764SConrad Meyer size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp); 42200c16b537SWarner Losh *dstPos = output.pos; 42210c16b537SWarner Losh *srcPos = input.pos; 42220c16b537SWarner Losh return cErr; 42230c16b537SWarner Losh } 42240c16b537SWarner Losh 4225a0483764SConrad Meyer size_t ZSTD_compress2(ZSTD_CCtx* cctx, 4226a0483764SConrad Meyer void* dst, size_t dstCapacity, 4227a0483764SConrad Meyer const void* src, size_t srcSize) 4228a0483764SConrad Meyer { 4229a0483764SConrad Meyer ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only); 4230a0483764SConrad Meyer { size_t oPos = 0; 4231a0483764SConrad Meyer size_t iPos = 0; 4232a0483764SConrad Meyer size_t const result = ZSTD_compressStream2_simpleArgs(cctx, 4233a0483764SConrad Meyer dst, dstCapacity, &oPos, 4234a0483764SConrad Meyer src, srcSize, &iPos, 4235a0483764SConrad Meyer ZSTD_e_end); 4236*2b9c00cbSConrad Meyer FORWARD_IF_ERROR(result); 4237a0483764SConrad Meyer if (result != 0) { /* compression not completed, due to lack of output space */ 4238a0483764SConrad Meyer assert(oPos == dstCapacity); 4239*2b9c00cbSConrad Meyer RETURN_ERROR(dstSize_tooSmall); 4240a0483764SConrad Meyer } 4241a0483764SConrad Meyer assert(iPos == srcSize); /* all input is expected consumed */ 4242a0483764SConrad Meyer return oPos; 4243a0483764SConrad Meyer } 4244a0483764SConrad Meyer } 42450c16b537SWarner Losh 42460c16b537SWarner Losh /*====== Finalize ======*/ 42470c16b537SWarner Losh 42480c16b537SWarner Losh /*! ZSTD_flushStream() : 42490c16b537SWarner Losh * @return : amount of data remaining to flush */ 42500c16b537SWarner Losh size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 42510c16b537SWarner Losh { 42520c16b537SWarner Losh ZSTD_inBuffer input = { NULL, 0, 0 }; 4253a0483764SConrad Meyer return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush); 42540c16b537SWarner Losh } 42550c16b537SWarner Losh 42560c16b537SWarner Losh 42570c16b537SWarner Losh size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 42580c16b537SWarner Losh { 42590c16b537SWarner Losh ZSTD_inBuffer input = { NULL, 0, 0 }; 4260a0483764SConrad Meyer size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end); 4261*2b9c00cbSConrad Meyer FORWARD_IF_ERROR( remainingToFlush ); 4262a0483764SConrad Meyer if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush; /* minimal estimation */ 4263a0483764SConrad Meyer /* single thread mode : attempt to calculate remaining to flush more precisely */ 42640c16b537SWarner Losh { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; 42650c16b537SWarner Losh size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4; 4266a0483764SConrad Meyer size_t const toFlush = remainingToFlush + lastBlockSize + checksumSize; 4267a0483764SConrad Meyer DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (unsigned)toFlush); 42680c16b537SWarner Losh return toFlush; 42690c16b537SWarner Losh } 42700c16b537SWarner Losh } 42710c16b537SWarner Losh 42720c16b537SWarner Losh 42730c16b537SWarner Losh /*-===== Pre-defined compression levels =====-*/ 42740c16b537SWarner Losh 42750c16b537SWarner Losh #define ZSTD_MAX_CLEVEL 22 42760c16b537SWarner Losh int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } 42770f743729SConrad Meyer int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; } 42780c16b537SWarner Losh 42790c16b537SWarner Losh static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { 4280*2b9c00cbSConrad Meyer { /* "default" - for any srcSize > 256 KB */ 42810c16b537SWarner Losh /* W, C, H, S, L, TL, strat */ 428219fcbaf1SConrad Meyer { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ 42830f743729SConrad Meyer { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ 4284a0483764SConrad Meyer { 20, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ 4285a0483764SConrad Meyer { 21, 16, 17, 1, 5, 1, ZSTD_dfast }, /* level 3 */ 4286a0483764SConrad Meyer { 21, 18, 18, 1, 5, 1, ZSTD_dfast }, /* level 4 */ 4287a0483764SConrad Meyer { 21, 18, 19, 2, 5, 2, ZSTD_greedy }, /* level 5 */ 4288a0483764SConrad Meyer { 21, 19, 19, 3, 5, 4, ZSTD_greedy }, /* level 6 */ 4289a0483764SConrad Meyer { 21, 19, 19, 3, 5, 8, ZSTD_lazy }, /* level 7 */ 42900f743729SConrad Meyer { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ 42910f743729SConrad Meyer { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ 4292a0483764SConrad Meyer { 22, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ 4293a0483764SConrad Meyer { 22, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ 4294a0483764SConrad Meyer { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ 4295a0483764SConrad Meyer { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 13 */ 4296a0483764SConrad Meyer { 22, 22, 23, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ 4297a0483764SConrad Meyer { 22, 23, 23, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ 4298a0483764SConrad Meyer { 22, 22, 22, 5, 5, 48, ZSTD_btopt }, /* level 16 */ 4299a0483764SConrad Meyer { 23, 23, 22, 5, 4, 64, ZSTD_btopt }, /* level 17 */ 4300a0483764SConrad Meyer { 23, 23, 22, 6, 3, 64, ZSTD_btultra }, /* level 18 */ 4301a0483764SConrad Meyer { 23, 24, 22, 7, 3,256, ZSTD_btultra2}, /* level 19 */ 4302a0483764SConrad Meyer { 25, 25, 23, 7, 3,256, ZSTD_btultra2}, /* level 20 */ 4303a0483764SConrad Meyer { 26, 26, 24, 7, 3,512, ZSTD_btultra2}, /* level 21 */ 4304a0483764SConrad Meyer { 27, 27, 25, 9, 3,999, ZSTD_btultra2}, /* level 22 */ 43050c16b537SWarner Losh }, 43060c16b537SWarner Losh { /* for srcSize <= 256 KB */ 43070c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 430819fcbaf1SConrad Meyer { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 43090f743729SConrad Meyer { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ 43100f743729SConrad Meyer { 18, 14, 14, 1, 5, 1, ZSTD_dfast }, /* level 2 */ 43110f743729SConrad Meyer { 18, 16, 16, 1, 4, 1, ZSTD_dfast }, /* level 3 */ 43120f743729SConrad Meyer { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/ 43130f743729SConrad Meyer { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/ 43140f743729SConrad Meyer { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ 43150f743729SConrad Meyer { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ 43160f743729SConrad Meyer { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 43170f743729SConrad Meyer { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 43180f743729SConrad Meyer { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 4319a0483764SConrad Meyer { 18, 18, 19, 5, 4, 12, ZSTD_btlazy2 }, /* level 11.*/ 4320a0483764SConrad Meyer { 18, 19, 19, 7, 4, 12, ZSTD_btlazy2 }, /* level 12.*/ 4321a0483764SConrad Meyer { 18, 18, 19, 4, 4, 16, ZSTD_btopt }, /* level 13 */ 4322a0483764SConrad Meyer { 18, 18, 19, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ 4323a0483764SConrad Meyer { 18, 18, 19, 6, 3,128, ZSTD_btopt }, /* level 15.*/ 4324a0483764SConrad Meyer { 18, 19, 19, 6, 3,128, ZSTD_btultra }, /* level 16.*/ 4325a0483764SConrad Meyer { 18, 19, 19, 8, 3,256, ZSTD_btultra }, /* level 17.*/ 4326a0483764SConrad Meyer { 18, 19, 19, 6, 3,128, ZSTD_btultra2}, /* level 18.*/ 4327a0483764SConrad Meyer { 18, 19, 19, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ 4328a0483764SConrad Meyer { 18, 19, 19, 10, 3,512, ZSTD_btultra2}, /* level 20.*/ 4329a0483764SConrad Meyer { 18, 19, 19, 12, 3,512, ZSTD_btultra2}, /* level 21.*/ 4330a0483764SConrad Meyer { 18, 19, 19, 13, 3,999, ZSTD_btultra2}, /* level 22.*/ 43310c16b537SWarner Losh }, 43320c16b537SWarner Losh { /* for srcSize <= 128 KB */ 43330c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 43340f743729SConrad Meyer { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 43350f743729SConrad Meyer { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ 43360f743729SConrad Meyer { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ 43370f743729SConrad Meyer { 17, 15, 16, 2, 5, 1, ZSTD_dfast }, /* level 3 */ 43380f743729SConrad Meyer { 17, 17, 17, 2, 4, 1, ZSTD_dfast }, /* level 4 */ 43390f743729SConrad Meyer { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ 43400f743729SConrad Meyer { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ 43410f743729SConrad Meyer { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ 43420c16b537SWarner Losh { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 43430c16b537SWarner Losh { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 43440c16b537SWarner Losh { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 4345a0483764SConrad Meyer { 17, 17, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 11 */ 4346a0483764SConrad Meyer { 17, 18, 17, 7, 4, 12, ZSTD_btlazy2 }, /* level 12 */ 4347a0483764SConrad Meyer { 17, 18, 17, 3, 4, 12, ZSTD_btopt }, /* level 13.*/ 4348a0483764SConrad Meyer { 17, 18, 17, 4, 3, 32, ZSTD_btopt }, /* level 14.*/ 4349a0483764SConrad Meyer { 17, 18, 17, 6, 3,256, ZSTD_btopt }, /* level 15.*/ 4350a0483764SConrad Meyer { 17, 18, 17, 6, 3,128, ZSTD_btultra }, /* level 16.*/ 4351a0483764SConrad Meyer { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 17.*/ 4352a0483764SConrad Meyer { 17, 18, 17, 10, 3,512, ZSTD_btultra }, /* level 18.*/ 4353a0483764SConrad Meyer { 17, 18, 17, 5, 3,256, ZSTD_btultra2}, /* level 19.*/ 4354a0483764SConrad Meyer { 17, 18, 17, 7, 3,512, ZSTD_btultra2}, /* level 20.*/ 4355a0483764SConrad Meyer { 17, 18, 17, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ 4356a0483764SConrad Meyer { 17, 18, 17, 11, 3,999, ZSTD_btultra2}, /* level 22.*/ 43570c16b537SWarner Losh }, 43580c16b537SWarner Losh { /* for srcSize <= 16 KB */ 43590c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 436019fcbaf1SConrad Meyer { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 43610f743729SConrad Meyer { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ 43620f743729SConrad Meyer { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ 4363a0483764SConrad Meyer { 14, 14, 15, 2, 4, 1, ZSTD_dfast }, /* level 3 */ 4364a0483764SConrad Meyer { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4 */ 43650f743729SConrad Meyer { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ 43660f743729SConrad Meyer { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ 43670f743729SConrad Meyer { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ 43680f743729SConrad Meyer { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ 43690f743729SConrad Meyer { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ 43700f743729SConrad Meyer { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ 43710f743729SConrad Meyer { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ 4372a0483764SConrad Meyer { 14, 15, 14, 4, 3, 24, ZSTD_btopt }, /* level 12.*/ 4373a0483764SConrad Meyer { 14, 15, 14, 5, 3, 32, ZSTD_btultra }, /* level 13.*/ 4374a0483764SConrad Meyer { 14, 15, 15, 6, 3, 64, ZSTD_btultra }, /* level 14.*/ 4375a0483764SConrad Meyer { 14, 15, 15, 7, 3,256, ZSTD_btultra }, /* level 15.*/ 4376a0483764SConrad Meyer { 14, 15, 15, 5, 3, 48, ZSTD_btultra2}, /* level 16.*/ 4377a0483764SConrad Meyer { 14, 15, 15, 6, 3,128, ZSTD_btultra2}, /* level 17.*/ 4378a0483764SConrad Meyer { 14, 15, 15, 7, 3,256, ZSTD_btultra2}, /* level 18.*/ 4379a0483764SConrad Meyer { 14, 15, 15, 8, 3,256, ZSTD_btultra2}, /* level 19.*/ 4380a0483764SConrad Meyer { 14, 15, 15, 8, 3,512, ZSTD_btultra2}, /* level 20.*/ 4381a0483764SConrad Meyer { 14, 15, 15, 9, 3,512, ZSTD_btultra2}, /* level 21.*/ 4382a0483764SConrad Meyer { 14, 15, 15, 10, 3,999, ZSTD_btultra2}, /* level 22.*/ 43830c16b537SWarner Losh }, 43840c16b537SWarner Losh }; 43850c16b537SWarner Losh 43860c16b537SWarner Losh /*! ZSTD_getCParams() : 438719fcbaf1SConrad Meyer * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. 43880c16b537SWarner Losh * Size values are optional, provide 0 if not known or unused */ 43890c16b537SWarner Losh ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) 43900c16b537SWarner Losh { 43910c16b537SWarner Losh size_t const addedSize = srcSizeHint ? 0 : 500; 4392*2b9c00cbSConrad Meyer U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : ZSTD_CONTENTSIZE_UNKNOWN; /* intentional overflow for srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN */ 4393*2b9c00cbSConrad Meyer U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); 439419fcbaf1SConrad Meyer int row = compressionLevel; 439519fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_getCParams (cLevel=%i)", compressionLevel); 439619fcbaf1SConrad Meyer if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ 439719fcbaf1SConrad Meyer if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ 439819fcbaf1SConrad Meyer if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; 439919fcbaf1SConrad Meyer { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row]; 440019fcbaf1SConrad Meyer if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */ 4401*2b9c00cbSConrad Meyer return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); /* refine parameters based on srcSize & dictSize */ 4402a0483764SConrad Meyer } 44030c16b537SWarner Losh } 44040c16b537SWarner Losh 44050c16b537SWarner Losh /*! ZSTD_getParams() : 4406*2b9c00cbSConrad Meyer * same idea as ZSTD_getCParams() 4407*2b9c00cbSConrad Meyer * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`). 4408*2b9c00cbSConrad Meyer * Fields of `ZSTD_frameParameters` are set to default values */ 44090c16b537SWarner Losh ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { 44100c16b537SWarner Losh ZSTD_parameters params; 44110c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize); 441219fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel); 44130c16b537SWarner Losh memset(¶ms, 0, sizeof(params)); 44140c16b537SWarner Losh params.cParams = cParams; 4415052d3c12SConrad Meyer params.fParams.contentSizeFlag = 1; 44160c16b537SWarner Losh return params; 44170c16b537SWarner Losh } 4418