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 ***************************************/ 140c16b537SWarner Losh #include <string.h> /* memset */ 1519fcbaf1SConrad Meyer #include "cpu.h" 160c16b537SWarner Losh #include "mem.h" 17*0f743729SConrad Meyer #include "hist.h" /* HIST_countFast_wksp */ 180c16b537SWarner Losh #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */ 190c16b537SWarner Losh #include "fse.h" 200c16b537SWarner Losh #define HUF_STATIC_LINKING_ONLY 210c16b537SWarner Losh #include "huf.h" 22052d3c12SConrad Meyer #include "zstd_compress_internal.h" 230c16b537SWarner Losh #include "zstd_fast.h" 240c16b537SWarner Losh #include "zstd_double_fast.h" 250c16b537SWarner Losh #include "zstd_lazy.h" 260c16b537SWarner Losh #include "zstd_opt.h" 270c16b537SWarner Losh #include "zstd_ldm.h" 280c16b537SWarner Losh 290c16b537SWarner Losh 300c16b537SWarner Losh /*-************************************* 310c16b537SWarner Losh * Helper functions 320c16b537SWarner Losh ***************************************/ 330c16b537SWarner Losh size_t ZSTD_compressBound(size_t srcSize) { 340c16b537SWarner Losh return ZSTD_COMPRESSBOUND(srcSize); 350c16b537SWarner Losh } 360c16b537SWarner Losh 370c16b537SWarner Losh 380c16b537SWarner Losh /*-************************************* 390c16b537SWarner Losh * Context memory management 400c16b537SWarner Losh ***************************************/ 410c16b537SWarner Losh struct ZSTD_CDict_s { 420c16b537SWarner Losh void* dictBuffer; 430c16b537SWarner Losh const void* dictContent; 440c16b537SWarner Losh size_t dictContentSize; 4519fcbaf1SConrad Meyer void* workspace; 4619fcbaf1SConrad Meyer size_t workspaceSize; 4719fcbaf1SConrad Meyer ZSTD_matchState_t matchState; 4819fcbaf1SConrad Meyer ZSTD_compressedBlockState_t cBlockState; 4919fcbaf1SConrad Meyer ZSTD_customMem customMem; 5019fcbaf1SConrad Meyer U32 dictID; 510c16b537SWarner Losh }; /* typedef'd to ZSTD_CDict within "zstd.h" */ 520c16b537SWarner Losh 530c16b537SWarner Losh ZSTD_CCtx* ZSTD_createCCtx(void) 540c16b537SWarner Losh { 550c16b537SWarner Losh return ZSTD_createCCtx_advanced(ZSTD_defaultCMem); 560c16b537SWarner Losh } 570c16b537SWarner Losh 58*0f743729SConrad Meyer static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager) 59*0f743729SConrad Meyer { 60*0f743729SConrad Meyer assert(cctx != NULL); 61*0f743729SConrad Meyer memset(cctx, 0, sizeof(*cctx)); 62*0f743729SConrad Meyer cctx->customMem = memManager; 63*0f743729SConrad Meyer cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); 64*0f743729SConrad Meyer { size_t const err = ZSTD_CCtx_resetParameters(cctx); 65*0f743729SConrad Meyer assert(!ZSTD_isError(err)); 66*0f743729SConrad Meyer (void)err; 67*0f743729SConrad Meyer } 68*0f743729SConrad Meyer } 69*0f743729SConrad Meyer 700c16b537SWarner Losh ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) 710c16b537SWarner Losh { 7219fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(zcss_init==0); 7319fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); 740c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 75*0f743729SConrad Meyer { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem); 760c16b537SWarner Losh if (!cctx) return NULL; 77*0f743729SConrad Meyer ZSTD_initCCtx(cctx, customMem); 780c16b537SWarner Losh return cctx; 790c16b537SWarner Losh } 8019fcbaf1SConrad Meyer } 810c16b537SWarner Losh 820c16b537SWarner Losh ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize) 830c16b537SWarner Losh { 840c16b537SWarner Losh ZSTD_CCtx* const cctx = (ZSTD_CCtx*) workspace; 850c16b537SWarner Losh if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */ 860c16b537SWarner Losh if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */ 870c16b537SWarner Losh memset(workspace, 0, workspaceSize); /* may be a bit generous, could memset be smaller ? */ 880c16b537SWarner Losh cctx->staticSize = workspaceSize; 890c16b537SWarner Losh cctx->workSpace = (void*)(cctx+1); 900c16b537SWarner Losh cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx); 910c16b537SWarner Losh 9219fcbaf1SConrad Meyer /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ 9319fcbaf1SConrad Meyer if (cctx->workSpaceSize < HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t)) return NULL; 940c16b537SWarner Losh assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */ 9519fcbaf1SConrad Meyer cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)cctx->workSpace; 9619fcbaf1SConrad Meyer cctx->blockState.nextCBlock = cctx->blockState.prevCBlock + 1; 9719fcbaf1SConrad Meyer { 9819fcbaf1SConrad Meyer void* const ptr = cctx->blockState.nextCBlock + 1; 9919fcbaf1SConrad Meyer cctx->entropyWorkspace = (U32*)ptr; 10019fcbaf1SConrad Meyer } 10119fcbaf1SConrad Meyer cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); 1020c16b537SWarner Losh return cctx; 1030c16b537SWarner Losh } 1040c16b537SWarner Losh 105*0f743729SConrad Meyer static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx) 1060c16b537SWarner Losh { 107*0f743729SConrad Meyer assert(cctx != NULL); 108*0f743729SConrad Meyer assert(cctx->staticSize == 0); 10919fcbaf1SConrad Meyer ZSTD_free(cctx->workSpace, cctx->customMem); cctx->workSpace = NULL; 11019fcbaf1SConrad Meyer ZSTD_freeCDict(cctx->cdictLocal); cctx->cdictLocal = NULL; 1110c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 11219fcbaf1SConrad Meyer ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL; 1130c16b537SWarner Losh #endif 114*0f743729SConrad Meyer } 115*0f743729SConrad Meyer 116*0f743729SConrad Meyer size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) 117*0f743729SConrad Meyer { 118*0f743729SConrad Meyer if (cctx==NULL) return 0; /* support free on NULL */ 119*0f743729SConrad Meyer if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */ 120*0f743729SConrad Meyer ZSTD_freeCCtxContent(cctx); 1210c16b537SWarner Losh ZSTD_free(cctx, cctx->customMem); 122*0f743729SConrad Meyer return 0; 1230c16b537SWarner Losh } 1240c16b537SWarner Losh 1250c16b537SWarner Losh 1260c16b537SWarner Losh static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx) 1270c16b537SWarner Losh { 1280c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 1290c16b537SWarner Losh return ZSTDMT_sizeof_CCtx(cctx->mtctx); 1300c16b537SWarner Losh #else 1310c16b537SWarner Losh (void) cctx; 1320c16b537SWarner Losh return 0; 1330c16b537SWarner Losh #endif 1340c16b537SWarner Losh } 1350c16b537SWarner Losh 1360c16b537SWarner Losh 1370c16b537SWarner Losh size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) 1380c16b537SWarner Losh { 1390c16b537SWarner Losh if (cctx==NULL) return 0; /* support sizeof on NULL */ 1400c16b537SWarner Losh return sizeof(*cctx) + cctx->workSpaceSize 1410c16b537SWarner Losh + ZSTD_sizeof_CDict(cctx->cdictLocal) 1420c16b537SWarner Losh + ZSTD_sizeof_mtctx(cctx); 1430c16b537SWarner Losh } 1440c16b537SWarner Losh 1450c16b537SWarner Losh size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) 1460c16b537SWarner Losh { 1470c16b537SWarner Losh return ZSTD_sizeof_CCtx(zcs); /* same object */ 1480c16b537SWarner Losh } 1490c16b537SWarner Losh 1500c16b537SWarner Losh /* private API call, for dictBuilder only */ 1510c16b537SWarner Losh const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } 1520c16b537SWarner Losh 1530c16b537SWarner Losh static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( 1540c16b537SWarner Losh ZSTD_compressionParameters cParams) 1550c16b537SWarner Losh { 1560c16b537SWarner Losh ZSTD_CCtx_params cctxParams; 1570c16b537SWarner Losh memset(&cctxParams, 0, sizeof(cctxParams)); 1580c16b537SWarner Losh cctxParams.cParams = cParams; 15919fcbaf1SConrad Meyer cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 16019fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 16119fcbaf1SConrad Meyer cctxParams.fParams.contentSizeFlag = 1; 1620c16b537SWarner Losh return cctxParams; 1630c16b537SWarner Losh } 1640c16b537SWarner Losh 1650c16b537SWarner Losh static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced( 1660c16b537SWarner Losh ZSTD_customMem customMem) 1670c16b537SWarner Losh { 1680c16b537SWarner Losh ZSTD_CCtx_params* params; 1690c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 1700c16b537SWarner Losh params = (ZSTD_CCtx_params*)ZSTD_calloc( 1710c16b537SWarner Losh sizeof(ZSTD_CCtx_params), customMem); 1720c16b537SWarner Losh if (!params) { return NULL; } 1730c16b537SWarner Losh params->customMem = customMem; 1740c16b537SWarner Losh params->compressionLevel = ZSTD_CLEVEL_DEFAULT; 17519fcbaf1SConrad Meyer params->fParams.contentSizeFlag = 1; 1760c16b537SWarner Losh return params; 1770c16b537SWarner Losh } 1780c16b537SWarner Losh 1790c16b537SWarner Losh ZSTD_CCtx_params* ZSTD_createCCtxParams(void) 1800c16b537SWarner Losh { 1810c16b537SWarner Losh return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem); 1820c16b537SWarner Losh } 1830c16b537SWarner Losh 1840c16b537SWarner Losh size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) 1850c16b537SWarner Losh { 1860c16b537SWarner Losh if (params == NULL) { return 0; } 1870c16b537SWarner Losh ZSTD_free(params, params->customMem); 1880c16b537SWarner Losh return 0; 1890c16b537SWarner Losh } 1900c16b537SWarner Losh 19119fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params) 1920c16b537SWarner Losh { 19319fcbaf1SConrad Meyer return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); 1940c16b537SWarner Losh } 1950c16b537SWarner Losh 19619fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) { 1970c16b537SWarner Losh if (!cctxParams) { return ERROR(GENERIC); } 1980c16b537SWarner Losh memset(cctxParams, 0, sizeof(*cctxParams)); 1990c16b537SWarner Losh cctxParams->compressionLevel = compressionLevel; 20019fcbaf1SConrad Meyer cctxParams->fParams.contentSizeFlag = 1; 2010c16b537SWarner Losh return 0; 2020c16b537SWarner Losh } 2030c16b537SWarner Losh 20419fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) 2050c16b537SWarner Losh { 2060c16b537SWarner Losh if (!cctxParams) { return ERROR(GENERIC); } 2070c16b537SWarner Losh CHECK_F( ZSTD_checkCParams(params.cParams) ); 2080c16b537SWarner Losh memset(cctxParams, 0, sizeof(*cctxParams)); 2090c16b537SWarner Losh cctxParams->cParams = params.cParams; 2100c16b537SWarner Losh cctxParams->fParams = params.fParams; 21119fcbaf1SConrad Meyer cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 21219fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(params.cParams)); 2130c16b537SWarner Losh return 0; 2140c16b537SWarner Losh } 2150c16b537SWarner Losh 21619fcbaf1SConrad Meyer /* ZSTD_assignParamsToCCtxParams() : 21719fcbaf1SConrad Meyer * params is presumed valid at this stage */ 2180c16b537SWarner Losh static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( 2190c16b537SWarner Losh ZSTD_CCtx_params cctxParams, ZSTD_parameters params) 2200c16b537SWarner Losh { 2210c16b537SWarner Losh ZSTD_CCtx_params ret = cctxParams; 2220c16b537SWarner Losh ret.cParams = params.cParams; 2230c16b537SWarner Losh ret.fParams = params.fParams; 22419fcbaf1SConrad Meyer ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 22519fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(params.cParams)); 2260c16b537SWarner Losh return ret; 2270c16b537SWarner Losh } 2280c16b537SWarner Losh 2290c16b537SWarner Losh #define CLAMPCHECK(val,min,max) { \ 2300c16b537SWarner Losh if (((val)<(min)) | ((val)>(max))) { \ 2310c16b537SWarner Losh return ERROR(parameter_outOfBound); \ 2320c16b537SWarner Losh } } 2330c16b537SWarner Losh 23419fcbaf1SConrad Meyer 23519fcbaf1SConrad Meyer static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) 23619fcbaf1SConrad Meyer { 23719fcbaf1SConrad Meyer switch(param) 23819fcbaf1SConrad Meyer { 23919fcbaf1SConrad Meyer case ZSTD_p_compressionLevel: 24019fcbaf1SConrad Meyer case ZSTD_p_hashLog: 24119fcbaf1SConrad Meyer case ZSTD_p_chainLog: 24219fcbaf1SConrad Meyer case ZSTD_p_searchLog: 24319fcbaf1SConrad Meyer case ZSTD_p_minMatch: 24419fcbaf1SConrad Meyer case ZSTD_p_targetLength: 24519fcbaf1SConrad Meyer case ZSTD_p_compressionStrategy: 24619fcbaf1SConrad Meyer return 1; 24719fcbaf1SConrad Meyer 24819fcbaf1SConrad Meyer case ZSTD_p_format: 24919fcbaf1SConrad Meyer case ZSTD_p_windowLog: 25019fcbaf1SConrad Meyer case ZSTD_p_contentSizeFlag: 25119fcbaf1SConrad Meyer case ZSTD_p_checksumFlag: 25219fcbaf1SConrad Meyer case ZSTD_p_dictIDFlag: 25319fcbaf1SConrad Meyer case ZSTD_p_forceMaxWindow : 25419fcbaf1SConrad Meyer case ZSTD_p_nbWorkers: 25519fcbaf1SConrad Meyer case ZSTD_p_jobSize: 25619fcbaf1SConrad Meyer case ZSTD_p_overlapSizeLog: 25719fcbaf1SConrad Meyer case ZSTD_p_enableLongDistanceMatching: 25819fcbaf1SConrad Meyer case ZSTD_p_ldmHashLog: 25919fcbaf1SConrad Meyer case ZSTD_p_ldmMinMatch: 26019fcbaf1SConrad Meyer case ZSTD_p_ldmBucketSizeLog: 26119fcbaf1SConrad Meyer case ZSTD_p_ldmHashEveryLog: 262*0f743729SConrad Meyer case ZSTD_p_forceAttachDict: 26319fcbaf1SConrad Meyer default: 26419fcbaf1SConrad Meyer return 0; 26519fcbaf1SConrad Meyer } 26619fcbaf1SConrad Meyer } 26719fcbaf1SConrad Meyer 2680c16b537SWarner Losh size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value) 2690c16b537SWarner Losh { 270052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setParameter (%u, %u)", (U32)param, value); 27119fcbaf1SConrad Meyer if (cctx->streamStage != zcss_init) { 27219fcbaf1SConrad Meyer if (ZSTD_isUpdateAuthorized(param)) { 27319fcbaf1SConrad Meyer cctx->cParamsChanged = 1; 27419fcbaf1SConrad Meyer } else { 27519fcbaf1SConrad Meyer return ERROR(stage_wrong); 27619fcbaf1SConrad Meyer } } 2770c16b537SWarner Losh 2780c16b537SWarner Losh switch(param) 2790c16b537SWarner Losh { 2800c16b537SWarner Losh case ZSTD_p_format : 2810c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 2820c16b537SWarner Losh 2830c16b537SWarner Losh case ZSTD_p_compressionLevel: 2840c16b537SWarner Losh if (cctx->cdict) return ERROR(stage_wrong); 2850c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 2860c16b537SWarner Losh 2870c16b537SWarner Losh case ZSTD_p_windowLog: 2880c16b537SWarner Losh case ZSTD_p_hashLog: 2890c16b537SWarner Losh case ZSTD_p_chainLog: 2900c16b537SWarner Losh case ZSTD_p_searchLog: 2910c16b537SWarner Losh case ZSTD_p_minMatch: 2920c16b537SWarner Losh case ZSTD_p_targetLength: 2930c16b537SWarner Losh case ZSTD_p_compressionStrategy: 2940c16b537SWarner Losh if (cctx->cdict) return ERROR(stage_wrong); 2950c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 2960c16b537SWarner Losh 2970c16b537SWarner Losh case ZSTD_p_contentSizeFlag: 2980c16b537SWarner Losh case ZSTD_p_checksumFlag: 2990c16b537SWarner Losh case ZSTD_p_dictIDFlag: 3000c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 3010c16b537SWarner Losh 3020c16b537SWarner Losh case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize, 303052d3c12SConrad Meyer * even when referencing into Dictionary content. 3040c16b537SWarner Losh * default : 0 when using a CDict, 1 when using a Prefix */ 3050c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 3060c16b537SWarner Losh 307*0f743729SConrad Meyer case ZSTD_p_forceAttachDict: 308*0f743729SConrad Meyer return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 309*0f743729SConrad Meyer 31019fcbaf1SConrad Meyer case ZSTD_p_nbWorkers: 31119fcbaf1SConrad Meyer if ((value>0) && cctx->staticSize) { 3120c16b537SWarner Losh return ERROR(parameter_unsupported); /* MT not compatible with static alloc */ 3130c16b537SWarner Losh } 3140c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 3150c16b537SWarner Losh 3160c16b537SWarner Losh case ZSTD_p_jobSize: 3170c16b537SWarner Losh case ZSTD_p_overlapSizeLog: 3180c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 3190c16b537SWarner Losh 3200c16b537SWarner Losh case ZSTD_p_enableLongDistanceMatching: 3210c16b537SWarner Losh case ZSTD_p_ldmHashLog: 3220c16b537SWarner Losh case ZSTD_p_ldmMinMatch: 3230c16b537SWarner Losh case ZSTD_p_ldmBucketSizeLog: 3240c16b537SWarner Losh case ZSTD_p_ldmHashEveryLog: 3250c16b537SWarner Losh if (cctx->cdict) return ERROR(stage_wrong); 3260c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 3270c16b537SWarner Losh 3280c16b537SWarner Losh default: return ERROR(parameter_unsupported); 3290c16b537SWarner Losh } 3300c16b537SWarner Losh } 3310c16b537SWarner Losh 3320c16b537SWarner Losh size_t ZSTD_CCtxParam_setParameter( 333052d3c12SConrad Meyer ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, unsigned value) 3340c16b537SWarner Losh { 335052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtxParam_setParameter (%u, %u)", (U32)param, value); 3360c16b537SWarner Losh switch(param) 3370c16b537SWarner Losh { 3380c16b537SWarner Losh case ZSTD_p_format : 3390c16b537SWarner Losh if (value > (unsigned)ZSTD_f_zstd1_magicless) 3400c16b537SWarner Losh return ERROR(parameter_unsupported); 341052d3c12SConrad Meyer CCtxParams->format = (ZSTD_format_e)value; 342052d3c12SConrad Meyer return (size_t)CCtxParams->format; 3430c16b537SWarner Losh 34419fcbaf1SConrad Meyer case ZSTD_p_compressionLevel : { 34519fcbaf1SConrad Meyer int cLevel = (int)value; /* cast expected to restore negative sign */ 34619fcbaf1SConrad Meyer if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel(); 34719fcbaf1SConrad Meyer if (cLevel) { /* 0 : does not change current level */ 34819fcbaf1SConrad Meyer CCtxParams->compressionLevel = cLevel; 34919fcbaf1SConrad Meyer } 35019fcbaf1SConrad Meyer if (CCtxParams->compressionLevel >= 0) return CCtxParams->compressionLevel; 35119fcbaf1SConrad Meyer return 0; /* return type (size_t) cannot represent negative values */ 35219fcbaf1SConrad Meyer } 3530c16b537SWarner Losh 3540c16b537SWarner Losh case ZSTD_p_windowLog : 35519fcbaf1SConrad Meyer if (value>0) /* 0 => use default */ 3560c16b537SWarner Losh CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); 357052d3c12SConrad Meyer CCtxParams->cParams.windowLog = value; 358052d3c12SConrad Meyer return CCtxParams->cParams.windowLog; 3590c16b537SWarner Losh 3600c16b537SWarner Losh case ZSTD_p_hashLog : 36119fcbaf1SConrad Meyer if (value>0) /* 0 => use default */ 3620c16b537SWarner Losh CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); 363052d3c12SConrad Meyer CCtxParams->cParams.hashLog = value; 364052d3c12SConrad Meyer return CCtxParams->cParams.hashLog; 3650c16b537SWarner Losh 3660c16b537SWarner Losh case ZSTD_p_chainLog : 36719fcbaf1SConrad Meyer if (value>0) /* 0 => use default */ 3680c16b537SWarner Losh CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); 369052d3c12SConrad Meyer CCtxParams->cParams.chainLog = value; 370052d3c12SConrad Meyer return CCtxParams->cParams.chainLog; 3710c16b537SWarner Losh 3720c16b537SWarner Losh case ZSTD_p_searchLog : 37319fcbaf1SConrad Meyer if (value>0) /* 0 => use default */ 3740c16b537SWarner Losh CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); 375052d3c12SConrad Meyer CCtxParams->cParams.searchLog = value; 376052d3c12SConrad Meyer return value; 3770c16b537SWarner Losh 3780c16b537SWarner Losh case ZSTD_p_minMatch : 37919fcbaf1SConrad Meyer if (value>0) /* 0 => use default */ 3800c16b537SWarner Losh CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); 381052d3c12SConrad Meyer CCtxParams->cParams.searchLength = value; 382052d3c12SConrad Meyer return CCtxParams->cParams.searchLength; 3830c16b537SWarner Losh 3840c16b537SWarner Losh case ZSTD_p_targetLength : 38519fcbaf1SConrad Meyer /* all values are valid. 0 => use default */ 386052d3c12SConrad Meyer CCtxParams->cParams.targetLength = value; 387052d3c12SConrad Meyer return CCtxParams->cParams.targetLength; 3880c16b537SWarner Losh 3890c16b537SWarner Losh case ZSTD_p_compressionStrategy : 39019fcbaf1SConrad Meyer if (value>0) /* 0 => use default */ 3910c16b537SWarner Losh CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra); 392052d3c12SConrad Meyer CCtxParams->cParams.strategy = (ZSTD_strategy)value; 393052d3c12SConrad Meyer return (size_t)CCtxParams->cParams.strategy; 3940c16b537SWarner Losh 3950c16b537SWarner Losh case ZSTD_p_contentSizeFlag : 3960c16b537SWarner Losh /* Content size written in frame header _when known_ (default:1) */ 397052d3c12SConrad Meyer DEBUGLOG(4, "set content size flag = %u", (value>0)); 398052d3c12SConrad Meyer CCtxParams->fParams.contentSizeFlag = value > 0; 399052d3c12SConrad Meyer return CCtxParams->fParams.contentSizeFlag; 4000c16b537SWarner Losh 4010c16b537SWarner Losh case ZSTD_p_checksumFlag : 4020c16b537SWarner Losh /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ 403052d3c12SConrad Meyer CCtxParams->fParams.checksumFlag = value > 0; 404052d3c12SConrad Meyer return CCtxParams->fParams.checksumFlag; 4050c16b537SWarner Losh 4060c16b537SWarner Losh case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ 407052d3c12SConrad Meyer DEBUGLOG(4, "set dictIDFlag = %u", (value>0)); 40819fcbaf1SConrad Meyer CCtxParams->fParams.noDictIDFlag = !value; 409052d3c12SConrad Meyer return !CCtxParams->fParams.noDictIDFlag; 4100c16b537SWarner Losh 4110c16b537SWarner Losh case ZSTD_p_forceMaxWindow : 412052d3c12SConrad Meyer CCtxParams->forceWindow = (value > 0); 413052d3c12SConrad Meyer return CCtxParams->forceWindow; 4140c16b537SWarner Losh 415*0f743729SConrad Meyer case ZSTD_p_forceAttachDict : 416*0f743729SConrad Meyer CCtxParams->attachDictPref = value ? 417*0f743729SConrad Meyer (value > 0 ? ZSTD_dictForceAttach : ZSTD_dictForceCopy) : 418*0f743729SConrad Meyer ZSTD_dictDefaultAttach; 419*0f743729SConrad Meyer return CCtxParams->attachDictPref; 420*0f743729SConrad Meyer 42119fcbaf1SConrad Meyer case ZSTD_p_nbWorkers : 4220c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 42319fcbaf1SConrad Meyer if (value>0) return ERROR(parameter_unsupported); 42419fcbaf1SConrad Meyer return 0; 4250c16b537SWarner Losh #else 42619fcbaf1SConrad Meyer return ZSTDMT_CCtxParam_setNbWorkers(CCtxParams, value); 4270c16b537SWarner Losh #endif 4280c16b537SWarner Losh 4290c16b537SWarner Losh case ZSTD_p_jobSize : 4300c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 4310c16b537SWarner Losh return ERROR(parameter_unsupported); 4320c16b537SWarner Losh #else 433052d3c12SConrad Meyer return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_jobSize, value); 4340c16b537SWarner Losh #endif 4350c16b537SWarner Losh 4360c16b537SWarner Losh case ZSTD_p_overlapSizeLog : 4370c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 4380c16b537SWarner Losh return ERROR(parameter_unsupported); 4390c16b537SWarner Losh #else 440052d3c12SConrad Meyer return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_overlapSectionLog, value); 4410c16b537SWarner Losh #endif 4420c16b537SWarner Losh 4430c16b537SWarner Losh case ZSTD_p_enableLongDistanceMatching : 44419fcbaf1SConrad Meyer CCtxParams->ldmParams.enableLdm = (value>0); 44519fcbaf1SConrad Meyer return CCtxParams->ldmParams.enableLdm; 4460c16b537SWarner Losh 4470c16b537SWarner Losh case ZSTD_p_ldmHashLog : 44819fcbaf1SConrad Meyer if (value>0) /* 0 ==> auto */ 4490c16b537SWarner Losh CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); 450052d3c12SConrad Meyer CCtxParams->ldmParams.hashLog = value; 451052d3c12SConrad Meyer return CCtxParams->ldmParams.hashLog; 4520c16b537SWarner Losh 4530c16b537SWarner Losh case ZSTD_p_ldmMinMatch : 45419fcbaf1SConrad Meyer if (value>0) /* 0 ==> default */ 4550c16b537SWarner Losh CLAMPCHECK(value, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX); 456052d3c12SConrad Meyer CCtxParams->ldmParams.minMatchLength = value; 457052d3c12SConrad Meyer return CCtxParams->ldmParams.minMatchLength; 4580c16b537SWarner Losh 4590c16b537SWarner Losh case ZSTD_p_ldmBucketSizeLog : 46019fcbaf1SConrad Meyer if (value > ZSTD_LDM_BUCKETSIZELOG_MAX) 4610c16b537SWarner Losh return ERROR(parameter_outOfBound); 462052d3c12SConrad Meyer CCtxParams->ldmParams.bucketSizeLog = value; 46319fcbaf1SConrad Meyer return CCtxParams->ldmParams.bucketSizeLog; 4640c16b537SWarner Losh 4650c16b537SWarner Losh case ZSTD_p_ldmHashEveryLog : 46619fcbaf1SConrad Meyer if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN) 4670c16b537SWarner Losh return ERROR(parameter_outOfBound); 468052d3c12SConrad Meyer CCtxParams->ldmParams.hashEveryLog = value; 46919fcbaf1SConrad Meyer return CCtxParams->ldmParams.hashEveryLog; 4700c16b537SWarner Losh 4710c16b537SWarner Losh default: return ERROR(parameter_unsupported); 4720c16b537SWarner Losh } 4730c16b537SWarner Losh } 4740c16b537SWarner Losh 475*0f743729SConrad Meyer size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned* value) 476*0f743729SConrad Meyer { 477*0f743729SConrad Meyer return ZSTD_CCtxParam_getParameter(&cctx->requestedParams, param, value); 478*0f743729SConrad Meyer } 479*0f743729SConrad Meyer 480*0f743729SConrad Meyer size_t ZSTD_CCtxParam_getParameter( 481*0f743729SConrad Meyer ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, unsigned* value) 482*0f743729SConrad Meyer { 483*0f743729SConrad Meyer switch(param) 484*0f743729SConrad Meyer { 485*0f743729SConrad Meyer case ZSTD_p_format : 486*0f743729SConrad Meyer *value = CCtxParams->format; 487*0f743729SConrad Meyer break; 488*0f743729SConrad Meyer case ZSTD_p_compressionLevel : 489*0f743729SConrad Meyer *value = CCtxParams->compressionLevel; 490*0f743729SConrad Meyer break; 491*0f743729SConrad Meyer case ZSTD_p_windowLog : 492*0f743729SConrad Meyer *value = CCtxParams->cParams.windowLog; 493*0f743729SConrad Meyer break; 494*0f743729SConrad Meyer case ZSTD_p_hashLog : 495*0f743729SConrad Meyer *value = CCtxParams->cParams.hashLog; 496*0f743729SConrad Meyer break; 497*0f743729SConrad Meyer case ZSTD_p_chainLog : 498*0f743729SConrad Meyer *value = CCtxParams->cParams.chainLog; 499*0f743729SConrad Meyer break; 500*0f743729SConrad Meyer case ZSTD_p_searchLog : 501*0f743729SConrad Meyer *value = CCtxParams->cParams.searchLog; 502*0f743729SConrad Meyer break; 503*0f743729SConrad Meyer case ZSTD_p_minMatch : 504*0f743729SConrad Meyer *value = CCtxParams->cParams.searchLength; 505*0f743729SConrad Meyer break; 506*0f743729SConrad Meyer case ZSTD_p_targetLength : 507*0f743729SConrad Meyer *value = CCtxParams->cParams.targetLength; 508*0f743729SConrad Meyer break; 509*0f743729SConrad Meyer case ZSTD_p_compressionStrategy : 510*0f743729SConrad Meyer *value = (unsigned)CCtxParams->cParams.strategy; 511*0f743729SConrad Meyer break; 512*0f743729SConrad Meyer case ZSTD_p_contentSizeFlag : 513*0f743729SConrad Meyer *value = CCtxParams->fParams.contentSizeFlag; 514*0f743729SConrad Meyer break; 515*0f743729SConrad Meyer case ZSTD_p_checksumFlag : 516*0f743729SConrad Meyer *value = CCtxParams->fParams.checksumFlag; 517*0f743729SConrad Meyer break; 518*0f743729SConrad Meyer case ZSTD_p_dictIDFlag : 519*0f743729SConrad Meyer *value = !CCtxParams->fParams.noDictIDFlag; 520*0f743729SConrad Meyer break; 521*0f743729SConrad Meyer case ZSTD_p_forceMaxWindow : 522*0f743729SConrad Meyer *value = CCtxParams->forceWindow; 523*0f743729SConrad Meyer break; 524*0f743729SConrad Meyer case ZSTD_p_forceAttachDict : 525*0f743729SConrad Meyer *value = CCtxParams->attachDictPref; 526*0f743729SConrad Meyer break; 527*0f743729SConrad Meyer case ZSTD_p_nbWorkers : 528*0f743729SConrad Meyer #ifndef ZSTD_MULTITHREAD 529*0f743729SConrad Meyer assert(CCtxParams->nbWorkers == 0); 530*0f743729SConrad Meyer #endif 531*0f743729SConrad Meyer *value = CCtxParams->nbWorkers; 532*0f743729SConrad Meyer break; 533*0f743729SConrad Meyer case ZSTD_p_jobSize : 534*0f743729SConrad Meyer #ifndef ZSTD_MULTITHREAD 535*0f743729SConrad Meyer return ERROR(parameter_unsupported); 536*0f743729SConrad Meyer #else 537*0f743729SConrad Meyer *value = CCtxParams->jobSize; 538*0f743729SConrad Meyer break; 539*0f743729SConrad Meyer #endif 540*0f743729SConrad Meyer case ZSTD_p_overlapSizeLog : 541*0f743729SConrad Meyer #ifndef ZSTD_MULTITHREAD 542*0f743729SConrad Meyer return ERROR(parameter_unsupported); 543*0f743729SConrad Meyer #else 544*0f743729SConrad Meyer *value = CCtxParams->overlapSizeLog; 545*0f743729SConrad Meyer break; 546*0f743729SConrad Meyer #endif 547*0f743729SConrad Meyer case ZSTD_p_enableLongDistanceMatching : 548*0f743729SConrad Meyer *value = CCtxParams->ldmParams.enableLdm; 549*0f743729SConrad Meyer break; 550*0f743729SConrad Meyer case ZSTD_p_ldmHashLog : 551*0f743729SConrad Meyer *value = CCtxParams->ldmParams.hashLog; 552*0f743729SConrad Meyer break; 553*0f743729SConrad Meyer case ZSTD_p_ldmMinMatch : 554*0f743729SConrad Meyer *value = CCtxParams->ldmParams.minMatchLength; 555*0f743729SConrad Meyer break; 556*0f743729SConrad Meyer case ZSTD_p_ldmBucketSizeLog : 557*0f743729SConrad Meyer *value = CCtxParams->ldmParams.bucketSizeLog; 558*0f743729SConrad Meyer break; 559*0f743729SConrad Meyer case ZSTD_p_ldmHashEveryLog : 560*0f743729SConrad Meyer *value = CCtxParams->ldmParams.hashEveryLog; 561*0f743729SConrad Meyer break; 562*0f743729SConrad Meyer default: return ERROR(parameter_unsupported); 563*0f743729SConrad Meyer } 564*0f743729SConrad Meyer return 0; 565*0f743729SConrad Meyer } 566*0f743729SConrad Meyer 567052d3c12SConrad Meyer /** ZSTD_CCtx_setParametersUsingCCtxParams() : 568052d3c12SConrad Meyer * just applies `params` into `cctx` 569052d3c12SConrad Meyer * no action is performed, parameters are merely stored. 57019fcbaf1SConrad Meyer * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx. 57119fcbaf1SConrad Meyer * This is possible even if a compression is ongoing. 57219fcbaf1SConrad Meyer * In which case, new parameters will be applied on the fly, starting with next compression job. 5730c16b537SWarner Losh */ 5740c16b537SWarner Losh size_t ZSTD_CCtx_setParametersUsingCCtxParams( 5750c16b537SWarner Losh ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) 5760c16b537SWarner Losh { 577*0f743729SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams"); 5780c16b537SWarner Losh if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); 5790c16b537SWarner Losh if (cctx->cdict) return ERROR(stage_wrong); 5800c16b537SWarner Losh 581052d3c12SConrad Meyer cctx->requestedParams = *params; 5820c16b537SWarner Losh return 0; 5830c16b537SWarner Losh } 5840c16b537SWarner Losh 5850c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) 5860c16b537SWarner Losh { 587052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize); 5880c16b537SWarner Losh if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); 5890c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; 5900c16b537SWarner Losh return 0; 5910c16b537SWarner Losh } 5920c16b537SWarner Losh 5930c16b537SWarner Losh size_t ZSTD_CCtx_loadDictionary_advanced( 5940c16b537SWarner Losh ZSTD_CCtx* cctx, const void* dict, size_t dictSize, 59519fcbaf1SConrad Meyer ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType) 5960c16b537SWarner Losh { 5970c16b537SWarner Losh if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); 5980c16b537SWarner Losh if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */ 599052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); 6000c16b537SWarner Losh ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */ 6010c16b537SWarner Losh if (dict==NULL || dictSize==0) { /* no dictionary mode */ 6020c16b537SWarner Losh cctx->cdictLocal = NULL; 6030c16b537SWarner Losh cctx->cdict = NULL; 6040c16b537SWarner Losh } else { 6050c16b537SWarner Losh ZSTD_compressionParameters const cParams = 60619fcbaf1SConrad Meyer ZSTD_getCParamsFromCCtxParams(&cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, dictSize); 6070c16b537SWarner Losh cctx->cdictLocal = ZSTD_createCDict_advanced( 6080c16b537SWarner Losh dict, dictSize, 60919fcbaf1SConrad Meyer dictLoadMethod, dictContentType, 6100c16b537SWarner Losh cParams, cctx->customMem); 6110c16b537SWarner Losh cctx->cdict = cctx->cdictLocal; 6120c16b537SWarner Losh if (cctx->cdictLocal == NULL) 6130c16b537SWarner Losh return ERROR(memory_allocation); 6140c16b537SWarner Losh } 6150c16b537SWarner Losh return 0; 6160c16b537SWarner Losh } 6170c16b537SWarner Losh 6180c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( 6190c16b537SWarner Losh ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 6200c16b537SWarner Losh { 6210c16b537SWarner Losh return ZSTD_CCtx_loadDictionary_advanced( 62219fcbaf1SConrad Meyer cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); 6230c16b537SWarner Losh } 6240c16b537SWarner Losh 6250c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 6260c16b537SWarner Losh { 6270c16b537SWarner Losh return ZSTD_CCtx_loadDictionary_advanced( 62819fcbaf1SConrad Meyer cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); 6290c16b537SWarner Losh } 6300c16b537SWarner Losh 6310c16b537SWarner Losh 6320c16b537SWarner Losh size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 6330c16b537SWarner Losh { 6340c16b537SWarner Losh if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); 6350c16b537SWarner Losh cctx->cdict = cdict; 6360c16b537SWarner Losh memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* exclusive */ 6370c16b537SWarner Losh return 0; 6380c16b537SWarner Losh } 6390c16b537SWarner Losh 6400c16b537SWarner Losh size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) 6410c16b537SWarner Losh { 64219fcbaf1SConrad Meyer return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent); 6430c16b537SWarner Losh } 6440c16b537SWarner Losh 6450c16b537SWarner Losh size_t ZSTD_CCtx_refPrefix_advanced( 64619fcbaf1SConrad Meyer ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) 6470c16b537SWarner Losh { 6480c16b537SWarner Losh if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); 6490c16b537SWarner Losh cctx->cdict = NULL; /* prefix discards any prior cdict */ 6500c16b537SWarner Losh cctx->prefixDict.dict = prefix; 6510c16b537SWarner Losh cctx->prefixDict.dictSize = prefixSize; 65219fcbaf1SConrad Meyer cctx->prefixDict.dictContentType = dictContentType; 6530c16b537SWarner Losh return 0; 6540c16b537SWarner Losh } 6550c16b537SWarner Losh 656*0f743729SConrad Meyer /*! ZSTD_CCtx_reset() : 657*0f743729SConrad Meyer * Also dumps dictionary */ 658*0f743729SConrad Meyer void ZSTD_CCtx_reset(ZSTD_CCtx* cctx) 6590c16b537SWarner Losh { 6600c16b537SWarner Losh cctx->streamStage = zcss_init; 6610c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = 0; 6620c16b537SWarner Losh } 6630c16b537SWarner Losh 664*0f743729SConrad Meyer size_t ZSTD_CCtx_resetParameters(ZSTD_CCtx* cctx) 6650c16b537SWarner Losh { 666*0f743729SConrad Meyer if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); 6670c16b537SWarner Losh cctx->cdict = NULL; 668*0f743729SConrad Meyer return ZSTD_CCtxParams_reset(&cctx->requestedParams); 6690c16b537SWarner Losh } 6700c16b537SWarner Losh 6710c16b537SWarner Losh /** ZSTD_checkCParams() : 6720c16b537SWarner Losh control CParam values remain within authorized range. 6730c16b537SWarner Losh @return : 0, or an error code if one value is beyond authorized range */ 6740c16b537SWarner Losh size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) 6750c16b537SWarner Losh { 6760c16b537SWarner Losh CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); 6770c16b537SWarner Losh CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); 6780c16b537SWarner Losh CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); 6790c16b537SWarner Losh CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); 6800c16b537SWarner Losh CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); 681*0f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_TARGETLENGTH_MIN == 0); 682*0f743729SConrad Meyer if (cParams.targetLength > ZSTD_TARGETLENGTH_MAX) 683*0f743729SConrad Meyer return ERROR(parameter_outOfBound); 6840c16b537SWarner Losh if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) 6850c16b537SWarner Losh return ERROR(parameter_unsupported); 6860c16b537SWarner Losh return 0; 6870c16b537SWarner Losh } 6880c16b537SWarner Losh 6890c16b537SWarner Losh /** ZSTD_clampCParams() : 6900c16b537SWarner Losh * make CParam values within valid range. 6910c16b537SWarner Losh * @return : valid CParams */ 692*0f743729SConrad Meyer static ZSTD_compressionParameters 693*0f743729SConrad Meyer ZSTD_clampCParams(ZSTD_compressionParameters cParams) 6940c16b537SWarner Losh { 6950c16b537SWarner Losh # define CLAMP(val,min,max) { \ 6960c16b537SWarner Losh if (val<min) val=min; \ 6970c16b537SWarner Losh else if (val>max) val=max; \ 6980c16b537SWarner Losh } 6990c16b537SWarner Losh CLAMP(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); 7000c16b537SWarner Losh CLAMP(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); 7010c16b537SWarner Losh CLAMP(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); 7020c16b537SWarner Losh CLAMP(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); 7030c16b537SWarner Losh CLAMP(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); 704*0f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_TARGETLENGTH_MIN == 0); 705*0f743729SConrad Meyer if (cParams.targetLength > ZSTD_TARGETLENGTH_MAX) 706*0f743729SConrad Meyer cParams.targetLength = ZSTD_TARGETLENGTH_MAX; 707*0f743729SConrad Meyer CLAMP(cParams.strategy, ZSTD_fast, ZSTD_btultra); 7080c16b537SWarner Losh return cParams; 7090c16b537SWarner Losh } 7100c16b537SWarner Losh 7110c16b537SWarner Losh /** ZSTD_cycleLog() : 7120c16b537SWarner Losh * condition for correct operation : hashLog > 1 */ 7130c16b537SWarner Losh static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) 7140c16b537SWarner Losh { 7150c16b537SWarner Losh U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2); 7160c16b537SWarner Losh return hashLog - btScale; 7170c16b537SWarner Losh } 7180c16b537SWarner Losh 7190c16b537SWarner Losh /** ZSTD_adjustCParams_internal() : 7200c16b537SWarner Losh optimize `cPar` for a given input (`srcSize` and `dictSize`). 7210c16b537SWarner Losh mostly downsizing to reduce memory consumption and initialization latency. 7220c16b537SWarner Losh Both `srcSize` and `dictSize` are optional (use 0 if unknown). 723*0f743729SConrad Meyer Note : cPar is assumed validated. Use ZSTD_checkCParams() to ensure this condition. */ 724*0f743729SConrad Meyer static ZSTD_compressionParameters 725*0f743729SConrad Meyer ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, 726*0f743729SConrad Meyer unsigned long long srcSize, 727*0f743729SConrad Meyer size_t dictSize) 7280c16b537SWarner Losh { 7290c16b537SWarner Losh static const U64 minSrcSize = 513; /* (1<<9) + 1 */ 7300c16b537SWarner Losh static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); 7310c16b537SWarner Losh assert(ZSTD_checkCParams(cPar)==0); 7320c16b537SWarner Losh 7330c16b537SWarner Losh if (dictSize && (srcSize+1<2) /* srcSize unknown */ ) 7340c16b537SWarner Losh srcSize = minSrcSize; /* presumed small when there is a dictionary */ 7350c16b537SWarner Losh else if (srcSize == 0) 7360c16b537SWarner Losh srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */ 7370c16b537SWarner Losh 7380c16b537SWarner Losh /* resize windowLog if input is small enough, to use less memory */ 7390c16b537SWarner Losh if ( (srcSize < maxWindowResize) 7400c16b537SWarner Losh && (dictSize < maxWindowResize) ) { 7410c16b537SWarner Losh U32 const tSize = (U32)(srcSize + dictSize); 7420c16b537SWarner Losh static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN; 7430c16b537SWarner Losh U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN : 7440c16b537SWarner Losh ZSTD_highbit32(tSize-1) + 1; 7450c16b537SWarner Losh if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; 7460c16b537SWarner Losh } 747*0f743729SConrad Meyer if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1; 7480c16b537SWarner Losh { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); 7490c16b537SWarner Losh if (cycleLog > cPar.windowLog) 7500c16b537SWarner Losh cPar.chainLog -= (cycleLog - cPar.windowLog); 7510c16b537SWarner Losh } 7520c16b537SWarner Losh 7530c16b537SWarner Losh if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) 7540c16b537SWarner Losh cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ 7550c16b537SWarner Losh 7560c16b537SWarner Losh return cPar; 7570c16b537SWarner Losh } 7580c16b537SWarner Losh 759*0f743729SConrad Meyer ZSTD_compressionParameters 760*0f743729SConrad Meyer ZSTD_adjustCParams(ZSTD_compressionParameters cPar, 761*0f743729SConrad Meyer unsigned long long srcSize, 762*0f743729SConrad Meyer size_t dictSize) 7630c16b537SWarner Losh { 7640c16b537SWarner Losh cPar = ZSTD_clampCParams(cPar); 7650c16b537SWarner Losh return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); 7660c16b537SWarner Losh } 7670c16b537SWarner Losh 768*0f743729SConrad Meyer ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( 769*0f743729SConrad Meyer const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize) 770*0f743729SConrad Meyer { 771*0f743729SConrad Meyer ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize); 772*0f743729SConrad Meyer if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; 773*0f743729SConrad Meyer if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog; 774*0f743729SConrad Meyer if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog; 775*0f743729SConrad Meyer if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog; 776*0f743729SConrad Meyer if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog; 777*0f743729SConrad Meyer if (CCtxParams->cParams.searchLength) cParams.searchLength = CCtxParams->cParams.searchLength; 778*0f743729SConrad Meyer if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength; 779*0f743729SConrad Meyer if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy; 780*0f743729SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 781*0f743729SConrad Meyer return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize); 782*0f743729SConrad Meyer } 783*0f743729SConrad Meyer 784*0f743729SConrad Meyer static size_t 785*0f743729SConrad Meyer ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams, 786*0f743729SConrad Meyer const U32 forCCtx) 78719fcbaf1SConrad Meyer { 78819fcbaf1SConrad Meyer size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); 78919fcbaf1SConrad Meyer size_t const hSize = ((size_t)1) << cParams->hashLog; 79019fcbaf1SConrad Meyer U32 const hashLog3 = (forCCtx && cParams->searchLength==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 79119fcbaf1SConrad Meyer size_t const h3Size = ((size_t)1) << hashLog3; 79219fcbaf1SConrad Meyer size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 79319fcbaf1SConrad Meyer size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32) 79419fcbaf1SConrad Meyer + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t)); 79519fcbaf1SConrad Meyer size_t const optSpace = (forCCtx && ((cParams->strategy == ZSTD_btopt) || 79619fcbaf1SConrad Meyer (cParams->strategy == ZSTD_btultra))) 79719fcbaf1SConrad Meyer ? optPotentialSpace 79819fcbaf1SConrad Meyer : 0; 79919fcbaf1SConrad Meyer DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u", 80019fcbaf1SConrad Meyer (U32)chainSize, (U32)hSize, (U32)h3Size); 80119fcbaf1SConrad Meyer return tableSpace + optSpace; 80219fcbaf1SConrad Meyer } 80319fcbaf1SConrad Meyer 8040c16b537SWarner Losh size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) 8050c16b537SWarner Losh { 8060c16b537SWarner Losh /* Estimate CCtx size is supported for single-threaded compression only. */ 80719fcbaf1SConrad Meyer if (params->nbWorkers > 0) { return ERROR(GENERIC); } 8080c16b537SWarner Losh { ZSTD_compressionParameters const cParams = 80919fcbaf1SConrad Meyer ZSTD_getCParamsFromCCtxParams(params, 0, 0); 8100c16b537SWarner Losh size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); 8110c16b537SWarner Losh U32 const divider = (cParams.searchLength==3) ? 3 : 4; 8120c16b537SWarner Losh size_t const maxNbSeq = blockSize / divider; 813*0f743729SConrad Meyer size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq; 81419fcbaf1SConrad Meyer size_t const entropySpace = HUF_WORKSPACE_SIZE; 81519fcbaf1SConrad Meyer size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t); 81619fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1); 8170c16b537SWarner Losh 81819fcbaf1SConrad Meyer size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams); 81919fcbaf1SConrad Meyer size_t const ldmSeqSpace = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq); 8200c16b537SWarner Losh 82119fcbaf1SConrad Meyer size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace + 82219fcbaf1SConrad Meyer matchStateSize + ldmSpace + ldmSeqSpace; 8230c16b537SWarner Losh 8240c16b537SWarner Losh DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx)); 8250c16b537SWarner Losh DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace); 8260c16b537SWarner Losh return sizeof(ZSTD_CCtx) + neededSpace; 8270c16b537SWarner Losh } 8280c16b537SWarner Losh } 8290c16b537SWarner Losh 8300c16b537SWarner Losh size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) 8310c16b537SWarner Losh { 8320c16b537SWarner Losh ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); 8330c16b537SWarner Losh return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms); 8340c16b537SWarner Losh } 8350c16b537SWarner Losh 83619fcbaf1SConrad Meyer static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) 8370c16b537SWarner Losh { 8380c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); 8390c16b537SWarner Losh return ZSTD_estimateCCtxSize_usingCParams(cParams); 8400c16b537SWarner Losh } 8410c16b537SWarner Losh 84219fcbaf1SConrad Meyer size_t ZSTD_estimateCCtxSize(int compressionLevel) 84319fcbaf1SConrad Meyer { 84419fcbaf1SConrad Meyer int level; 84519fcbaf1SConrad Meyer size_t memBudget = 0; 84619fcbaf1SConrad Meyer for (level=1; level<=compressionLevel; level++) { 84719fcbaf1SConrad Meyer size_t const newMB = ZSTD_estimateCCtxSize_internal(level); 84819fcbaf1SConrad Meyer if (newMB > memBudget) memBudget = newMB; 84919fcbaf1SConrad Meyer } 85019fcbaf1SConrad Meyer return memBudget; 85119fcbaf1SConrad Meyer } 85219fcbaf1SConrad Meyer 8530c16b537SWarner Losh size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) 8540c16b537SWarner Losh { 85519fcbaf1SConrad Meyer if (params->nbWorkers > 0) { return ERROR(GENERIC); } 8560c16b537SWarner Losh { size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params); 8570c16b537SWarner Losh size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog); 8580c16b537SWarner Losh size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize; 8590c16b537SWarner Losh size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; 8600c16b537SWarner Losh size_t const streamingSize = inBuffSize + outBuffSize; 8610c16b537SWarner Losh 8620c16b537SWarner Losh return CCtxSize + streamingSize; 8630c16b537SWarner Losh } 8640c16b537SWarner Losh } 8650c16b537SWarner Losh 8660c16b537SWarner Losh size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) 8670c16b537SWarner Losh { 8680c16b537SWarner Losh ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); 8690c16b537SWarner Losh return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms); 8700c16b537SWarner Losh } 8710c16b537SWarner Losh 872*0f743729SConrad Meyer static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) 873*0f743729SConrad Meyer { 8740c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); 8750c16b537SWarner Losh return ZSTD_estimateCStreamSize_usingCParams(cParams); 8760c16b537SWarner Losh } 8770c16b537SWarner Losh 878*0f743729SConrad Meyer size_t ZSTD_estimateCStreamSize(int compressionLevel) 879*0f743729SConrad Meyer { 88019fcbaf1SConrad Meyer int level; 88119fcbaf1SConrad Meyer size_t memBudget = 0; 88219fcbaf1SConrad Meyer for (level=1; level<=compressionLevel; level++) { 88319fcbaf1SConrad Meyer size_t const newMB = ZSTD_estimateCStreamSize_internal(level); 88419fcbaf1SConrad Meyer if (newMB > memBudget) memBudget = newMB; 88519fcbaf1SConrad Meyer } 88619fcbaf1SConrad Meyer return memBudget; 88719fcbaf1SConrad Meyer } 88819fcbaf1SConrad Meyer 88919fcbaf1SConrad Meyer /* ZSTD_getFrameProgression(): 89019fcbaf1SConrad Meyer * tells how much data has been consumed (input) and produced (output) for current frame. 89119fcbaf1SConrad Meyer * able to count progression inside worker threads (non-blocking mode). 89219fcbaf1SConrad Meyer */ 89319fcbaf1SConrad Meyer ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx) 89419fcbaf1SConrad Meyer { 89519fcbaf1SConrad Meyer #ifdef ZSTD_MULTITHREAD 89619fcbaf1SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 89719fcbaf1SConrad Meyer return ZSTDMT_getFrameProgression(cctx->mtctx); 89819fcbaf1SConrad Meyer } 89919fcbaf1SConrad Meyer #endif 90019fcbaf1SConrad Meyer { ZSTD_frameProgression fp; 90119fcbaf1SConrad Meyer size_t const buffered = (cctx->inBuff == NULL) ? 0 : 90219fcbaf1SConrad Meyer cctx->inBuffPos - cctx->inToCompress; 90319fcbaf1SConrad Meyer if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress); 90419fcbaf1SConrad Meyer assert(buffered <= ZSTD_BLOCKSIZE_MAX); 90519fcbaf1SConrad Meyer fp.ingested = cctx->consumedSrcSize + buffered; 90619fcbaf1SConrad Meyer fp.consumed = cctx->consumedSrcSize; 90719fcbaf1SConrad Meyer fp.produced = cctx->producedCSize; 908*0f743729SConrad Meyer fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */ 909*0f743729SConrad Meyer fp.currentJobID = 0; 910*0f743729SConrad Meyer fp.nbActiveWorkers = 0; 91119fcbaf1SConrad Meyer return fp; 91219fcbaf1SConrad Meyer } } 91319fcbaf1SConrad Meyer 914*0f743729SConrad Meyer /*! ZSTD_toFlushNow() 915*0f743729SConrad Meyer * Only useful for multithreading scenarios currently (nbWorkers >= 1). 916*0f743729SConrad Meyer */ 917*0f743729SConrad Meyer size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx) 918*0f743729SConrad Meyer { 919*0f743729SConrad Meyer #ifdef ZSTD_MULTITHREAD 920*0f743729SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 921*0f743729SConrad Meyer return ZSTDMT_toFlushNow(cctx->mtctx); 922*0f743729SConrad Meyer } 923*0f743729SConrad Meyer #endif 924*0f743729SConrad Meyer (void)cctx; 925*0f743729SConrad 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 */ 926*0f743729SConrad Meyer } 927*0f743729SConrad Meyer 928*0f743729SConrad Meyer 92919fcbaf1SConrad Meyer 9300c16b537SWarner Losh static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1, 9310c16b537SWarner Losh ZSTD_compressionParameters cParams2) 9320c16b537SWarner Losh { 933052d3c12SConrad Meyer return (cParams1.hashLog == cParams2.hashLog) 9340c16b537SWarner Losh & (cParams1.chainLog == cParams2.chainLog) 9350c16b537SWarner Losh & (cParams1.strategy == cParams2.strategy) /* opt parser space */ 9360c16b537SWarner Losh & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */ 9370c16b537SWarner Losh } 9380c16b537SWarner Losh 939*0f743729SConrad Meyer static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1, 940*0f743729SConrad Meyer ZSTD_compressionParameters cParams2) 941*0f743729SConrad Meyer { 942*0f743729SConrad Meyer (void)cParams1; 943*0f743729SConrad Meyer (void)cParams2; 944*0f743729SConrad Meyer assert(cParams1.windowLog == cParams2.windowLog); 945*0f743729SConrad Meyer assert(cParams1.chainLog == cParams2.chainLog); 946*0f743729SConrad Meyer assert(cParams1.hashLog == cParams2.hashLog); 947*0f743729SConrad Meyer assert(cParams1.searchLog == cParams2.searchLog); 948*0f743729SConrad Meyer assert(cParams1.searchLength == cParams2.searchLength); 949*0f743729SConrad Meyer assert(cParams1.targetLength == cParams2.targetLength); 950*0f743729SConrad Meyer assert(cParams1.strategy == cParams2.strategy); 951*0f743729SConrad Meyer } 952*0f743729SConrad Meyer 9530c16b537SWarner Losh /** The parameters are equivalent if ldm is not enabled in both sets or 9540c16b537SWarner Losh * all the parameters are equivalent. */ 9550c16b537SWarner Losh static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1, 9560c16b537SWarner Losh ldmParams_t ldmParams2) 9570c16b537SWarner Losh { 9580c16b537SWarner Losh return (!ldmParams1.enableLdm && !ldmParams2.enableLdm) || 9590c16b537SWarner Losh (ldmParams1.enableLdm == ldmParams2.enableLdm && 9600c16b537SWarner Losh ldmParams1.hashLog == ldmParams2.hashLog && 9610c16b537SWarner Losh ldmParams1.bucketSizeLog == ldmParams2.bucketSizeLog && 9620c16b537SWarner Losh ldmParams1.minMatchLength == ldmParams2.minMatchLength && 9630c16b537SWarner Losh ldmParams1.hashEveryLog == ldmParams2.hashEveryLog); 9640c16b537SWarner Losh } 9650c16b537SWarner Losh 966052d3c12SConrad Meyer typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e; 967052d3c12SConrad Meyer 968052d3c12SConrad Meyer /* ZSTD_sufficientBuff() : 969052d3c12SConrad Meyer * check internal buffers exist for streaming if buffPol == ZSTDb_buffered . 970052d3c12SConrad Meyer * Note : they are assumed to be correctly sized if ZSTD_equivalentCParams()==1 */ 971*0f743729SConrad Meyer static U32 ZSTD_sufficientBuff(size_t bufferSize1, size_t maxNbSeq1, 972*0f743729SConrad Meyer size_t maxNbLit1, 973052d3c12SConrad Meyer ZSTD_buffered_policy_e buffPol2, 974052d3c12SConrad Meyer ZSTD_compressionParameters cParams2, 975052d3c12SConrad Meyer U64 pledgedSrcSize) 976052d3c12SConrad Meyer { 977052d3c12SConrad Meyer size_t const windowSize2 = MAX(1, (size_t)MIN(((U64)1 << cParams2.windowLog), pledgedSrcSize)); 978052d3c12SConrad Meyer size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2); 979*0f743729SConrad Meyer size_t const maxNbSeq2 = blockSize2 / ((cParams2.searchLength == 3) ? 3 : 4); 980*0f743729SConrad Meyer size_t const maxNbLit2 = blockSize2; 981052d3c12SConrad Meyer size_t const neededBufferSize2 = (buffPol2==ZSTDb_buffered) ? windowSize2 + blockSize2 : 0; 982*0f743729SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff: is neededBufferSize2=%u <= bufferSize1=%u", 983*0f743729SConrad Meyer (U32)neededBufferSize2, (U32)bufferSize1); 984*0f743729SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbSeq2=%u <= maxNbSeq1=%u", 985*0f743729SConrad Meyer (U32)maxNbSeq2, (U32)maxNbSeq1); 986*0f743729SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbLit2=%u <= maxNbLit1=%u", 987*0f743729SConrad Meyer (U32)maxNbLit2, (U32)maxNbLit1); 988*0f743729SConrad Meyer return (maxNbLit2 <= maxNbLit1) 989*0f743729SConrad Meyer & (maxNbSeq2 <= maxNbSeq1) 990052d3c12SConrad Meyer & (neededBufferSize2 <= bufferSize1); 991052d3c12SConrad Meyer } 992052d3c12SConrad Meyer 9930c16b537SWarner Losh /** Equivalence for resetCCtx purposes */ 9940c16b537SWarner Losh static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1, 995052d3c12SConrad Meyer ZSTD_CCtx_params params2, 996*0f743729SConrad Meyer size_t buffSize1, 997*0f743729SConrad Meyer size_t maxNbSeq1, size_t maxNbLit1, 998052d3c12SConrad Meyer ZSTD_buffered_policy_e buffPol2, 999052d3c12SConrad Meyer U64 pledgedSrcSize) 10000c16b537SWarner Losh { 1001052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentParams: pledgedSrcSize=%u", (U32)pledgedSrcSize); 1002*0f743729SConrad Meyer if (!ZSTD_equivalentCParams(params1.cParams, params2.cParams)) { 1003*0f743729SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentCParams() == 0"); 1004*0f743729SConrad Meyer return 0; 1005*0f743729SConrad Meyer } 1006*0f743729SConrad Meyer if (!ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams)) { 1007*0f743729SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentLdmParams() == 0"); 1008*0f743729SConrad Meyer return 0; 1009*0f743729SConrad Meyer } 1010*0f743729SConrad Meyer if (!ZSTD_sufficientBuff(buffSize1, maxNbSeq1, maxNbLit1, buffPol2, 1011*0f743729SConrad Meyer params2.cParams, pledgedSrcSize)) { 1012*0f743729SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff() == 0"); 1013*0f743729SConrad Meyer return 0; 1014*0f743729SConrad Meyer } 1015*0f743729SConrad Meyer return 1; 10160c16b537SWarner Losh } 10170c16b537SWarner Losh 101819fcbaf1SConrad Meyer static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) 101919fcbaf1SConrad Meyer { 102019fcbaf1SConrad Meyer int i; 102119fcbaf1SConrad Meyer for (i = 0; i < ZSTD_REP_NUM; ++i) 102219fcbaf1SConrad Meyer bs->rep[i] = repStartValue[i]; 1023*0f743729SConrad Meyer bs->entropy.huf.repeatMode = HUF_repeat_none; 1024*0f743729SConrad Meyer bs->entropy.fse.offcode_repeatMode = FSE_repeat_none; 1025*0f743729SConrad Meyer bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none; 1026*0f743729SConrad Meyer bs->entropy.fse.litlength_repeatMode = FSE_repeat_none; 102719fcbaf1SConrad Meyer } 102819fcbaf1SConrad Meyer 102919fcbaf1SConrad Meyer /*! ZSTD_invalidateMatchState() 103019fcbaf1SConrad Meyer * Invalidate all the matches in the match finder tables. 103119fcbaf1SConrad Meyer * Requires nextSrc and base to be set (can be NULL). 103219fcbaf1SConrad Meyer */ 103319fcbaf1SConrad Meyer static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms) 103419fcbaf1SConrad Meyer { 103519fcbaf1SConrad Meyer ZSTD_window_clear(&ms->window); 103619fcbaf1SConrad Meyer 103719fcbaf1SConrad Meyer ms->nextToUpdate = ms->window.dictLimit + 1; 1038*0f743729SConrad Meyer ms->nextToUpdate3 = ms->window.dictLimit + 1; 103919fcbaf1SConrad Meyer ms->loadedDictEnd = 0; 104019fcbaf1SConrad Meyer ms->opt.litLengthSum = 0; /* force reset of btopt stats */ 1041*0f743729SConrad Meyer ms->dictMatchState = NULL; 104219fcbaf1SConrad Meyer } 104319fcbaf1SConrad Meyer 10440c16b537SWarner Losh /*! ZSTD_continueCCtx() : 10450c16b537SWarner Losh * reuse CCtx without reset (note : requires no dictionary) */ 10460c16b537SWarner Losh static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize) 10470c16b537SWarner Losh { 1048052d3c12SConrad Meyer size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); 1049052d3c12SConrad Meyer size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); 105019fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_continueCCtx: re-use context in place"); 1051052d3c12SConrad Meyer 1052052d3c12SConrad Meyer cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */ 10530c16b537SWarner Losh cctx->appliedParams = params; 1054*0f743729SConrad Meyer cctx->blockState.matchState.cParams = params.cParams; 10550c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; 10560c16b537SWarner Losh cctx->consumedSrcSize = 0; 105719fcbaf1SConrad Meyer cctx->producedCSize = 0; 10580c16b537SWarner Losh if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) 10590c16b537SWarner Losh cctx->appliedParams.fParams.contentSizeFlag = 0; 10600c16b537SWarner Losh DEBUGLOG(4, "pledged content size : %u ; flag : %u", 10610c16b537SWarner Losh (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag); 10620c16b537SWarner Losh cctx->stage = ZSTDcs_init; 10630c16b537SWarner Losh cctx->dictID = 0; 106419fcbaf1SConrad Meyer if (params.ldmParams.enableLdm) 106519fcbaf1SConrad Meyer ZSTD_window_clear(&cctx->ldmState.window); 106619fcbaf1SConrad Meyer ZSTD_referenceExternalSequences(cctx, NULL, 0); 106719fcbaf1SConrad Meyer ZSTD_invalidateMatchState(&cctx->blockState.matchState); 106819fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(cctx->blockState.prevCBlock); 10690c16b537SWarner Losh XXH64_reset(&cctx->xxhState, 0); 10700c16b537SWarner Losh return 0; 10710c16b537SWarner Losh } 10720c16b537SWarner Losh 10730c16b537SWarner Losh typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e; 10740c16b537SWarner Losh 1075*0f743729SConrad Meyer static void* 1076*0f743729SConrad Meyer ZSTD_reset_matchState(ZSTD_matchState_t* ms, 1077*0f743729SConrad Meyer void* ptr, 1078*0f743729SConrad Meyer const ZSTD_compressionParameters* cParams, 1079*0f743729SConrad Meyer ZSTD_compResetPolicy_e const crp, U32 const forCCtx) 108019fcbaf1SConrad Meyer { 108119fcbaf1SConrad Meyer size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); 108219fcbaf1SConrad Meyer size_t const hSize = ((size_t)1) << cParams->hashLog; 108319fcbaf1SConrad Meyer U32 const hashLog3 = (forCCtx && cParams->searchLength==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 108419fcbaf1SConrad Meyer size_t const h3Size = ((size_t)1) << hashLog3; 108519fcbaf1SConrad Meyer size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 108619fcbaf1SConrad Meyer 108719fcbaf1SConrad Meyer assert(((size_t)ptr & 3) == 0); 108819fcbaf1SConrad Meyer 108919fcbaf1SConrad Meyer ms->hashLog3 = hashLog3; 109019fcbaf1SConrad Meyer memset(&ms->window, 0, sizeof(ms->window)); 1091*0f743729SConrad Meyer ms->window.dictLimit = 1; /* start from 1, so that 1st position is valid */ 1092*0f743729SConrad Meyer ms->window.lowLimit = 1; /* it ensures first and later CCtx usages compress the same */ 1093*0f743729SConrad Meyer ms->window.nextSrc = ms->window.base + 1; /* see issue #1241 */ 109419fcbaf1SConrad Meyer ZSTD_invalidateMatchState(ms); 109519fcbaf1SConrad Meyer 109619fcbaf1SConrad Meyer /* opt parser space */ 109719fcbaf1SConrad Meyer if (forCCtx && ((cParams->strategy == ZSTD_btopt) | (cParams->strategy == ZSTD_btultra))) { 109819fcbaf1SConrad Meyer DEBUGLOG(4, "reserving optimal parser space"); 109919fcbaf1SConrad Meyer ms->opt.litFreq = (U32*)ptr; 110019fcbaf1SConrad Meyer ms->opt.litLengthFreq = ms->opt.litFreq + (1<<Litbits); 110119fcbaf1SConrad Meyer ms->opt.matchLengthFreq = ms->opt.litLengthFreq + (MaxLL+1); 110219fcbaf1SConrad Meyer ms->opt.offCodeFreq = ms->opt.matchLengthFreq + (MaxML+1); 110319fcbaf1SConrad Meyer ptr = ms->opt.offCodeFreq + (MaxOff+1); 110419fcbaf1SConrad Meyer ms->opt.matchTable = (ZSTD_match_t*)ptr; 110519fcbaf1SConrad Meyer ptr = ms->opt.matchTable + ZSTD_OPT_NUM+1; 110619fcbaf1SConrad Meyer ms->opt.priceTable = (ZSTD_optimal_t*)ptr; 110719fcbaf1SConrad Meyer ptr = ms->opt.priceTable + ZSTD_OPT_NUM+1; 110819fcbaf1SConrad Meyer } 110919fcbaf1SConrad Meyer 111019fcbaf1SConrad Meyer /* table Space */ 111119fcbaf1SConrad Meyer DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset); 111219fcbaf1SConrad Meyer assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ 111319fcbaf1SConrad Meyer if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */ 111419fcbaf1SConrad Meyer ms->hashTable = (U32*)(ptr); 111519fcbaf1SConrad Meyer ms->chainTable = ms->hashTable + hSize; 111619fcbaf1SConrad Meyer ms->hashTable3 = ms->chainTable + chainSize; 111719fcbaf1SConrad Meyer ptr = ms->hashTable3 + h3Size; 111819fcbaf1SConrad Meyer 1119*0f743729SConrad Meyer ms->cParams = *cParams; 1120*0f743729SConrad Meyer 112119fcbaf1SConrad Meyer assert(((size_t)ptr & 3) == 0); 112219fcbaf1SConrad Meyer return ptr; 112319fcbaf1SConrad Meyer } 112419fcbaf1SConrad Meyer 1125*0f743729SConrad Meyer #define ZSTD_WORKSPACETOOLARGE_FACTOR 3 /* define "workspace is too large" as this number of times larger than needed */ 1126*0f743729SConrad Meyer #define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 /* when workspace is continuously too large 1127*0f743729SConrad Meyer * during at least this number of times, 1128*0f743729SConrad Meyer * context's memory usage is considered wasteful, 1129*0f743729SConrad Meyer * because it's sized to handle a worst case scenario which rarely happens. 1130*0f743729SConrad Meyer * In which case, resize it down to free some memory */ 1131*0f743729SConrad Meyer 11320c16b537SWarner Losh /*! ZSTD_resetCCtx_internal() : 11330c16b537SWarner Losh note : `params` are assumed fully validated at this stage */ 11340c16b537SWarner Losh static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, 1135*0f743729SConrad Meyer ZSTD_CCtx_params params, 1136*0f743729SConrad Meyer U64 pledgedSrcSize, 11370c16b537SWarner Losh ZSTD_compResetPolicy_e const crp, 11380c16b537SWarner Losh ZSTD_buffered_policy_e const zbuff) 11390c16b537SWarner Losh { 1140052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u", 1141052d3c12SConrad Meyer (U32)pledgedSrcSize, params.cParams.windowLog); 11420c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 11430c16b537SWarner Losh 11440c16b537SWarner Losh if (crp == ZSTDcrp_continue) { 1145052d3c12SConrad Meyer if (ZSTD_equivalentParams(zc->appliedParams, params, 1146*0f743729SConrad Meyer zc->inBuffSize, 1147*0f743729SConrad Meyer zc->seqStore.maxNbSeq, zc->seqStore.maxNbLit, 1148052d3c12SConrad Meyer zbuff, pledgedSrcSize)) { 1149*0f743729SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%zu)", 1150*0f743729SConrad Meyer zc->appliedParams.cParams.windowLog, zc->blockSize); 1151*0f743729SConrad Meyer zc->workSpaceOversizedDuration += (zc->workSpaceOversizedDuration > 0); /* if it was too large, it still is */ 1152*0f743729SConrad Meyer if (zc->workSpaceOversizedDuration <= ZSTD_WORKSPACETOOLARGE_MAXDURATION) 11530c16b537SWarner Losh return ZSTD_continueCCtx(zc, params, pledgedSrcSize); 11540c16b537SWarner Losh } } 1155052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx"); 11560c16b537SWarner Losh 11570c16b537SWarner Losh if (params.ldmParams.enableLdm) { 11580c16b537SWarner Losh /* Adjust long distance matching parameters */ 115919fcbaf1SConrad Meyer ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); 11600c16b537SWarner Losh assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); 11610c16b537SWarner Losh assert(params.ldmParams.hashEveryLog < 32); 1162*0f743729SConrad Meyer zc->ldmState.hashPower = ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength); 11630c16b537SWarner Losh } 11640c16b537SWarner Losh 1165052d3c12SConrad Meyer { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); 1166052d3c12SConrad Meyer size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); 11670c16b537SWarner Losh U32 const divider = (params.cParams.searchLength==3) ? 3 : 4; 11680c16b537SWarner Losh size_t const maxNbSeq = blockSize / divider; 1169*0f743729SConrad Meyer size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq; 11700c16b537SWarner Losh size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0; 1171052d3c12SConrad Meyer size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0; 117219fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1); 117319fcbaf1SConrad Meyer size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize); 1174*0f743729SConrad Meyer void* ptr; /* used to partition workSpace */ 11750c16b537SWarner Losh 11760c16b537SWarner Losh /* Check if workSpace is large enough, alloc a new one if needed */ 117719fcbaf1SConrad Meyer { size_t const entropySpace = HUF_WORKSPACE_SIZE; 117819fcbaf1SConrad Meyer size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t); 11790c16b537SWarner Losh size_t const bufferSpace = buffInSize + buffOutSize; 118019fcbaf1SConrad Meyer size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams); 118119fcbaf1SConrad Meyer size_t const ldmSeqSpace = maxNbLdmSeq * sizeof(rawSeq); 118219fcbaf1SConrad Meyer 118319fcbaf1SConrad Meyer size_t const neededSpace = entropySpace + blockStateSpace + ldmSpace + 118419fcbaf1SConrad Meyer ldmSeqSpace + matchStateSize + tokenSpace + 118519fcbaf1SConrad Meyer bufferSpace; 11860c16b537SWarner Losh 1187*0f743729SConrad Meyer int const workSpaceTooSmall = zc->workSpaceSize < neededSpace; 1188*0f743729SConrad Meyer int const workSpaceTooLarge = zc->workSpaceSize > ZSTD_WORKSPACETOOLARGE_FACTOR * neededSpace; 1189*0f743729SConrad Meyer int const workSpaceWasteful = workSpaceTooLarge && (zc->workSpaceOversizedDuration > ZSTD_WORKSPACETOOLARGE_MAXDURATION); 1190*0f743729SConrad Meyer zc->workSpaceOversizedDuration = workSpaceTooLarge ? zc->workSpaceOversizedDuration+1 : 0; 1191*0f743729SConrad Meyer 1192*0f743729SConrad Meyer DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers", 1193*0f743729SConrad Meyer neededSpace>>10, matchStateSize>>10, bufferSpace>>10); 1194*0f743729SConrad Meyer DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize); 1195*0f743729SConrad Meyer 1196*0f743729SConrad Meyer if (workSpaceTooSmall || workSpaceWasteful) { 1197*0f743729SConrad Meyer DEBUGLOG(4, "Need to resize workSpaceSize from %zuKB to %zuKB", 1198*0f743729SConrad Meyer zc->workSpaceSize >> 10, 1199*0f743729SConrad Meyer neededSpace >> 10); 12000c16b537SWarner Losh /* static cctx : no resize, error out */ 12010c16b537SWarner Losh if (zc->staticSize) return ERROR(memory_allocation); 12020c16b537SWarner Losh 12030c16b537SWarner Losh zc->workSpaceSize = 0; 12040c16b537SWarner Losh ZSTD_free(zc->workSpace, zc->customMem); 12050c16b537SWarner Losh zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem); 12060c16b537SWarner Losh if (zc->workSpace == NULL) return ERROR(memory_allocation); 12070c16b537SWarner Losh zc->workSpaceSize = neededSpace; 1208*0f743729SConrad Meyer zc->workSpaceOversizedDuration = 0; 12090c16b537SWarner Losh 1210*0f743729SConrad Meyer /* Statically sized space. 1211*0f743729SConrad Meyer * entropyWorkspace never moves, 1212*0f743729SConrad Meyer * though prev/next block swap places */ 12130c16b537SWarner Losh assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */ 121419fcbaf1SConrad Meyer assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_compressedBlockState_t)); 121519fcbaf1SConrad Meyer zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)zc->workSpace; 121619fcbaf1SConrad Meyer zc->blockState.nextCBlock = zc->blockState.prevCBlock + 1; 121719fcbaf1SConrad Meyer ptr = zc->blockState.nextCBlock + 1; 121819fcbaf1SConrad Meyer zc->entropyWorkspace = (U32*)ptr; 12190c16b537SWarner Losh } } 12200c16b537SWarner Losh 12210c16b537SWarner Losh /* init params */ 12220c16b537SWarner Losh zc->appliedParams = params; 1223*0f743729SConrad Meyer zc->blockState.matchState.cParams = params.cParams; 12240c16b537SWarner Losh zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; 12250c16b537SWarner Losh zc->consumedSrcSize = 0; 122619fcbaf1SConrad Meyer zc->producedCSize = 0; 12270c16b537SWarner Losh if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) 12280c16b537SWarner Losh zc->appliedParams.fParams.contentSizeFlag = 0; 1229052d3c12SConrad Meyer DEBUGLOG(4, "pledged content size : %u ; flag : %u", 12300c16b537SWarner Losh (U32)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag); 12310c16b537SWarner Losh zc->blockSize = blockSize; 12320c16b537SWarner Losh 12330c16b537SWarner Losh XXH64_reset(&zc->xxhState, 0); 12340c16b537SWarner Losh zc->stage = ZSTDcs_init; 12350c16b537SWarner Losh zc->dictID = 0; 12360c16b537SWarner Losh 123719fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock); 12380c16b537SWarner Losh 123919fcbaf1SConrad Meyer ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32; 12400c16b537SWarner Losh 12410c16b537SWarner Losh /* ldm hash table */ 12420c16b537SWarner Losh /* initialize bucketOffsets table later for pointer alignment */ 12430c16b537SWarner Losh if (params.ldmParams.enableLdm) { 12440c16b537SWarner Losh size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog; 12450c16b537SWarner Losh memset(ptr, 0, ldmHSize * sizeof(ldmEntry_t)); 12460c16b537SWarner Losh assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ 12470c16b537SWarner Losh zc->ldmState.hashTable = (ldmEntry_t*)ptr; 12480c16b537SWarner Losh ptr = zc->ldmState.hashTable + ldmHSize; 124919fcbaf1SConrad Meyer zc->ldmSequences = (rawSeq*)ptr; 125019fcbaf1SConrad Meyer ptr = zc->ldmSequences + maxNbLdmSeq; 125119fcbaf1SConrad Meyer zc->maxNbLdmSequences = maxNbLdmSeq; 12520c16b537SWarner Losh 125319fcbaf1SConrad Meyer memset(&zc->ldmState.window, 0, sizeof(zc->ldmState.window)); 125419fcbaf1SConrad Meyer } 12550c16b537SWarner Losh assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ 125619fcbaf1SConrad Meyer 125719fcbaf1SConrad Meyer ptr = ZSTD_reset_matchState(&zc->blockState.matchState, ptr, ¶ms.cParams, crp, /* forCCtx */ 1); 12580c16b537SWarner Losh 12590c16b537SWarner Losh /* sequences storage */ 1260*0f743729SConrad Meyer zc->seqStore.maxNbSeq = maxNbSeq; 12610c16b537SWarner Losh zc->seqStore.sequencesStart = (seqDef*)ptr; 12620c16b537SWarner Losh ptr = zc->seqStore.sequencesStart + maxNbSeq; 12630c16b537SWarner Losh zc->seqStore.llCode = (BYTE*) ptr; 12640c16b537SWarner Losh zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq; 12650c16b537SWarner Losh zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq; 12660c16b537SWarner Losh zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq; 1267*0f743729SConrad Meyer /* ZSTD_wildcopy() is used to copy into the literals buffer, 1268*0f743729SConrad Meyer * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes. 1269*0f743729SConrad Meyer */ 1270*0f743729SConrad Meyer zc->seqStore.maxNbLit = blockSize; 1271*0f743729SConrad Meyer ptr = zc->seqStore.litStart + blockSize + WILDCOPY_OVERLENGTH; 12720c16b537SWarner Losh 12730c16b537SWarner Losh /* ldm bucketOffsets table */ 12740c16b537SWarner Losh if (params.ldmParams.enableLdm) { 12750c16b537SWarner Losh size_t const ldmBucketSize = 12760c16b537SWarner Losh ((size_t)1) << (params.ldmParams.hashLog - 12770c16b537SWarner Losh params.ldmParams.bucketSizeLog); 12780c16b537SWarner Losh memset(ptr, 0, ldmBucketSize); 12790c16b537SWarner Losh zc->ldmState.bucketOffsets = (BYTE*)ptr; 12800c16b537SWarner Losh ptr = zc->ldmState.bucketOffsets + ldmBucketSize; 128119fcbaf1SConrad Meyer ZSTD_window_clear(&zc->ldmState.window); 12820c16b537SWarner Losh } 128319fcbaf1SConrad Meyer ZSTD_referenceExternalSequences(zc, NULL, 0); 12840c16b537SWarner Losh 12850c16b537SWarner Losh /* buffers */ 12860c16b537SWarner Losh zc->inBuffSize = buffInSize; 12870c16b537SWarner Losh zc->inBuff = (char*)ptr; 12880c16b537SWarner Losh zc->outBuffSize = buffOutSize; 12890c16b537SWarner Losh zc->outBuff = zc->inBuff + buffInSize; 12900c16b537SWarner Losh 12910c16b537SWarner Losh return 0; 12920c16b537SWarner Losh } 12930c16b537SWarner Losh } 12940c16b537SWarner Losh 12950c16b537SWarner Losh /* ZSTD_invalidateRepCodes() : 12960c16b537SWarner Losh * ensures next compression will not use repcodes from previous block. 12970c16b537SWarner Losh * Note : only works with regular variant; 12980c16b537SWarner Losh * do not use with extDict variant ! */ 12990c16b537SWarner Losh void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) { 13000c16b537SWarner Losh int i; 130119fcbaf1SConrad Meyer for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0; 130219fcbaf1SConrad Meyer assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window)); 13030c16b537SWarner Losh } 13040c16b537SWarner Losh 1305*0f743729SConrad Meyer /* These are the approximate sizes for each strategy past which copying the 1306*0f743729SConrad Meyer * dictionary tables into the working context is faster than using them 1307*0f743729SConrad Meyer * in-place. 1308*0f743729SConrad Meyer */ 1309*0f743729SConrad Meyer static const size_t attachDictSizeCutoffs[(unsigned)ZSTD_btultra+1] = { 1310*0f743729SConrad Meyer 8 KB, /* unused */ 1311*0f743729SConrad Meyer 8 KB, /* ZSTD_fast */ 1312*0f743729SConrad Meyer 16 KB, /* ZSTD_dfast */ 1313*0f743729SConrad Meyer 32 KB, /* ZSTD_greedy */ 1314*0f743729SConrad Meyer 32 KB, /* ZSTD_lazy */ 1315*0f743729SConrad Meyer 32 KB, /* ZSTD_lazy2 */ 1316*0f743729SConrad Meyer 32 KB, /* ZSTD_btlazy2 */ 1317*0f743729SConrad Meyer 32 KB, /* ZSTD_btopt */ 1318*0f743729SConrad Meyer 8 KB /* ZSTD_btultra */ 1319*0f743729SConrad Meyer }; 1320*0f743729SConrad Meyer 1321*0f743729SConrad Meyer static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict, 1322*0f743729SConrad Meyer ZSTD_CCtx_params params, 1323*0f743729SConrad Meyer U64 pledgedSrcSize) 1324*0f743729SConrad Meyer { 1325*0f743729SConrad Meyer size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy]; 1326*0f743729SConrad Meyer return ( pledgedSrcSize <= cutoff 1327*0f743729SConrad Meyer || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN 1328*0f743729SConrad Meyer || params.attachDictPref == ZSTD_dictForceAttach ) 1329*0f743729SConrad Meyer && params.attachDictPref != ZSTD_dictForceCopy 1330*0f743729SConrad Meyer && !params.forceWindow; /* dictMatchState isn't correctly 1331*0f743729SConrad Meyer * handled in _enforceMaxDist */ 1332*0f743729SConrad Meyer } 1333*0f743729SConrad Meyer 1334*0f743729SConrad Meyer static size_t ZSTD_resetCCtx_byAttachingCDict( 1335*0f743729SConrad Meyer ZSTD_CCtx* cctx, 133619fcbaf1SConrad Meyer const ZSTD_CDict* cdict, 1337*0f743729SConrad Meyer ZSTD_CCtx_params params, 133819fcbaf1SConrad Meyer U64 pledgedSrcSize, 133919fcbaf1SConrad Meyer ZSTD_buffered_policy_e zbuff) 134019fcbaf1SConrad Meyer { 1341*0f743729SConrad Meyer { 1342*0f743729SConrad Meyer const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; 1343*0f743729SConrad Meyer unsigned const windowLog = params.cParams.windowLog; 1344*0f743729SConrad Meyer assert(windowLog != 0); 1345*0f743729SConrad Meyer /* Resize working context table params for input only, since the dict 1346*0f743729SConrad Meyer * has its own tables. */ 1347*0f743729SConrad Meyer params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0); 1348*0f743729SConrad Meyer params.cParams.windowLog = windowLog; 1349*0f743729SConrad Meyer ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 1350*0f743729SConrad Meyer ZSTDcrp_continue, zbuff); 1351*0f743729SConrad Meyer assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); 1352*0f743729SConrad Meyer } 1353*0f743729SConrad Meyer 1354*0f743729SConrad Meyer { 1355*0f743729SConrad Meyer const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc 1356*0f743729SConrad Meyer - cdict->matchState.window.base); 1357*0f743729SConrad Meyer const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit; 1358*0f743729SConrad Meyer if (cdictLen == 0) { 1359*0f743729SConrad Meyer /* don't even attach dictionaries with no contents */ 1360*0f743729SConrad Meyer DEBUGLOG(4, "skipping attaching empty dictionary"); 1361*0f743729SConrad Meyer } else { 1362*0f743729SConrad Meyer DEBUGLOG(4, "attaching dictionary into context"); 1363*0f743729SConrad Meyer cctx->blockState.matchState.dictMatchState = &cdict->matchState; 1364*0f743729SConrad Meyer 1365*0f743729SConrad Meyer /* prep working match state so dict matches never have negative indices 1366*0f743729SConrad Meyer * when they are translated to the working context's index space. */ 1367*0f743729SConrad Meyer if (cctx->blockState.matchState.window.dictLimit < cdictEnd) { 1368*0f743729SConrad Meyer cctx->blockState.matchState.window.nextSrc = 1369*0f743729SConrad Meyer cctx->blockState.matchState.window.base + cdictEnd; 1370*0f743729SConrad Meyer ZSTD_window_clear(&cctx->blockState.matchState.window); 1371*0f743729SConrad Meyer } 1372*0f743729SConrad Meyer cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit; 1373*0f743729SConrad Meyer } 1374*0f743729SConrad Meyer } 1375*0f743729SConrad Meyer 1376*0f743729SConrad Meyer cctx->dictID = cdict->dictID; 1377*0f743729SConrad Meyer 1378*0f743729SConrad Meyer /* copy block state */ 1379*0f743729SConrad Meyer memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 1380*0f743729SConrad Meyer 1381*0f743729SConrad Meyer return 0; 1382*0f743729SConrad Meyer } 1383*0f743729SConrad Meyer 1384*0f743729SConrad Meyer static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx, 1385*0f743729SConrad Meyer const ZSTD_CDict* cdict, 1386*0f743729SConrad Meyer ZSTD_CCtx_params params, 1387*0f743729SConrad Meyer U64 pledgedSrcSize, 1388*0f743729SConrad Meyer ZSTD_buffered_policy_e zbuff) 1389*0f743729SConrad Meyer { 1390*0f743729SConrad Meyer const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams; 1391*0f743729SConrad Meyer 1392*0f743729SConrad Meyer DEBUGLOG(4, "copying dictionary into context"); 1393*0f743729SConrad Meyer 1394*0f743729SConrad Meyer { unsigned const windowLog = params.cParams.windowLog; 1395*0f743729SConrad Meyer assert(windowLog != 0); 139619fcbaf1SConrad Meyer /* Copy only compression parameters related to tables. */ 1397*0f743729SConrad Meyer params.cParams = *cdict_cParams; 1398*0f743729SConrad Meyer params.cParams.windowLog = windowLog; 139919fcbaf1SConrad Meyer ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 140019fcbaf1SConrad Meyer ZSTDcrp_noMemset, zbuff); 1401*0f743729SConrad Meyer assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy); 1402*0f743729SConrad Meyer assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog); 1403*0f743729SConrad Meyer assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog); 140419fcbaf1SConrad Meyer } 140519fcbaf1SConrad Meyer 140619fcbaf1SConrad Meyer /* copy tables */ 1407*0f743729SConrad Meyer { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog); 1408*0f743729SConrad Meyer size_t const hSize = (size_t)1 << cdict_cParams->hashLog; 140919fcbaf1SConrad Meyer size_t const tableSpace = (chainSize + hSize) * sizeof(U32); 141019fcbaf1SConrad Meyer assert((U32*)cctx->blockState.matchState.chainTable == (U32*)cctx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */ 141119fcbaf1SConrad Meyer assert((U32*)cctx->blockState.matchState.hashTable3 == (U32*)cctx->blockState.matchState.chainTable + chainSize); 141219fcbaf1SConrad Meyer assert((U32*)cdict->matchState.chainTable == (U32*)cdict->matchState.hashTable + hSize); /* chainTable must follow hashTable */ 141319fcbaf1SConrad Meyer assert((U32*)cdict->matchState.hashTable3 == (U32*)cdict->matchState.chainTable + chainSize); 141419fcbaf1SConrad Meyer memcpy(cctx->blockState.matchState.hashTable, cdict->matchState.hashTable, tableSpace); /* presumes all tables follow each other */ 141519fcbaf1SConrad Meyer } 1416*0f743729SConrad Meyer 141719fcbaf1SConrad Meyer /* Zero the hashTable3, since the cdict never fills it */ 141819fcbaf1SConrad Meyer { size_t const h3Size = (size_t)1 << cctx->blockState.matchState.hashLog3; 141919fcbaf1SConrad Meyer assert(cdict->matchState.hashLog3 == 0); 142019fcbaf1SConrad Meyer memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); 142119fcbaf1SConrad Meyer } 142219fcbaf1SConrad Meyer 142319fcbaf1SConrad Meyer /* copy dictionary offsets */ 1424*0f743729SConrad Meyer { ZSTD_matchState_t const* srcMatchState = &cdict->matchState; 142519fcbaf1SConrad Meyer ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState; 142619fcbaf1SConrad Meyer dstMatchState->window = srcMatchState->window; 142719fcbaf1SConrad Meyer dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 142819fcbaf1SConrad Meyer dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3; 142919fcbaf1SConrad Meyer dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 143019fcbaf1SConrad Meyer } 1431*0f743729SConrad Meyer 143219fcbaf1SConrad Meyer cctx->dictID = cdict->dictID; 143319fcbaf1SConrad Meyer 143419fcbaf1SConrad Meyer /* copy block state */ 143519fcbaf1SConrad Meyer memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 143619fcbaf1SConrad Meyer 143719fcbaf1SConrad Meyer return 0; 143819fcbaf1SConrad Meyer } 14390c16b537SWarner Losh 1440*0f743729SConrad Meyer /* We have a choice between copying the dictionary context into the working 1441*0f743729SConrad Meyer * context, or referencing the dictionary context from the working context 1442*0f743729SConrad Meyer * in-place. We decide here which strategy to use. */ 1443*0f743729SConrad Meyer static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx, 1444*0f743729SConrad Meyer const ZSTD_CDict* cdict, 1445*0f743729SConrad Meyer ZSTD_CCtx_params params, 1446*0f743729SConrad Meyer U64 pledgedSrcSize, 1447*0f743729SConrad Meyer ZSTD_buffered_policy_e zbuff) 1448*0f743729SConrad Meyer { 1449*0f743729SConrad Meyer 1450*0f743729SConrad Meyer DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)", (U32)pledgedSrcSize); 1451*0f743729SConrad Meyer 1452*0f743729SConrad Meyer if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) { 1453*0f743729SConrad Meyer return ZSTD_resetCCtx_byAttachingCDict( 1454*0f743729SConrad Meyer cctx, cdict, params, pledgedSrcSize, zbuff); 1455*0f743729SConrad Meyer } else { 1456*0f743729SConrad Meyer return ZSTD_resetCCtx_byCopyingCDict( 1457*0f743729SConrad Meyer cctx, cdict, params, pledgedSrcSize, zbuff); 1458*0f743729SConrad Meyer } 1459*0f743729SConrad Meyer } 1460*0f743729SConrad Meyer 14610c16b537SWarner Losh /*! ZSTD_copyCCtx_internal() : 14620c16b537SWarner Losh * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 14630c16b537SWarner Losh * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 1464052d3c12SConrad Meyer * The "context", in this case, refers to the hash and chain tables, 1465052d3c12SConrad Meyer * entropy tables, and dictionary references. 1466052d3c12SConrad Meyer * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx. 14670c16b537SWarner Losh * @return : 0, or an error code */ 14680c16b537SWarner Losh static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, 14690c16b537SWarner Losh const ZSTD_CCtx* srcCCtx, 14700c16b537SWarner Losh ZSTD_frameParameters fParams, 1471052d3c12SConrad Meyer U64 pledgedSrcSize, 14720c16b537SWarner Losh ZSTD_buffered_policy_e zbuff) 14730c16b537SWarner Losh { 14740c16b537SWarner Losh DEBUGLOG(5, "ZSTD_copyCCtx_internal"); 14750c16b537SWarner Losh if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong); 14760c16b537SWarner Losh 14770c16b537SWarner Losh memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); 14780c16b537SWarner Losh { ZSTD_CCtx_params params = dstCCtx->requestedParams; 14790c16b537SWarner Losh /* Copy only compression parameters related to tables. */ 14800c16b537SWarner Losh params.cParams = srcCCtx->appliedParams.cParams; 14810c16b537SWarner Losh params.fParams = fParams; 14820c16b537SWarner Losh ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, 14830c16b537SWarner Losh ZSTDcrp_noMemset, zbuff); 148419fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog); 148519fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy); 148619fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog); 148719fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog); 148819fcbaf1SConrad Meyer assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3); 14890c16b537SWarner Losh } 14900c16b537SWarner Losh 14910c16b537SWarner Losh /* copy tables */ 14920c16b537SWarner Losh { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog); 14930c16b537SWarner Losh size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; 149419fcbaf1SConrad Meyer size_t const h3Size = (size_t)1 << srcCCtx->blockState.matchState.hashLog3; 14950c16b537SWarner Losh size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 149619fcbaf1SConrad Meyer assert((U32*)dstCCtx->blockState.matchState.chainTable == (U32*)dstCCtx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */ 149719fcbaf1SConrad Meyer assert((U32*)dstCCtx->blockState.matchState.hashTable3 == (U32*)dstCCtx->blockState.matchState.chainTable + chainSize); 149819fcbaf1SConrad Meyer memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, tableSpace); /* presumes all tables follow each other */ 14990c16b537SWarner Losh } 15000c16b537SWarner Losh 15010c16b537SWarner Losh /* copy dictionary offsets */ 150219fcbaf1SConrad Meyer { 1503*0f743729SConrad Meyer const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState; 150419fcbaf1SConrad Meyer ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState; 150519fcbaf1SConrad Meyer dstMatchState->window = srcMatchState->window; 150619fcbaf1SConrad Meyer dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 150719fcbaf1SConrad Meyer dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3; 150819fcbaf1SConrad Meyer dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 150919fcbaf1SConrad Meyer } 15100c16b537SWarner Losh dstCCtx->dictID = srcCCtx->dictID; 15110c16b537SWarner Losh 151219fcbaf1SConrad Meyer /* copy block state */ 151319fcbaf1SConrad Meyer memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); 15140c16b537SWarner Losh 15150c16b537SWarner Losh return 0; 15160c16b537SWarner Losh } 15170c16b537SWarner Losh 15180c16b537SWarner Losh /*! ZSTD_copyCCtx() : 15190c16b537SWarner Losh * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 15200c16b537SWarner Losh * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 15210c16b537SWarner Losh * pledgedSrcSize==0 means "unknown". 15220c16b537SWarner Losh * @return : 0, or an error code */ 15230c16b537SWarner Losh size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) 15240c16b537SWarner Losh { 15250c16b537SWarner Losh ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 15260c16b537SWarner Losh ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0); 15270c16b537SWarner Losh ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); 1528052d3c12SConrad Meyer if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; 1529052d3c12SConrad Meyer fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN); 15300c16b537SWarner Losh 1531052d3c12SConrad Meyer return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, 153219fcbaf1SConrad Meyer fParams, pledgedSrcSize, 1533052d3c12SConrad Meyer zbuff); 15340c16b537SWarner Losh } 15350c16b537SWarner Losh 15360c16b537SWarner Losh 153719fcbaf1SConrad Meyer #define ZSTD_ROWSIZE 16 15380c16b537SWarner Losh /*! ZSTD_reduceTable() : 153919fcbaf1SConrad Meyer * reduce table indexes by `reducerValue`, or squash to zero. 154019fcbaf1SConrad Meyer * PreserveMark preserves "unsorted mark" for btlazy2 strategy. 154119fcbaf1SConrad Meyer * It must be set to a clear 0/1 value, to remove branch during inlining. 154219fcbaf1SConrad Meyer * Presume table size is a multiple of ZSTD_ROWSIZE 154319fcbaf1SConrad Meyer * to help auto-vectorization */ 154419fcbaf1SConrad Meyer FORCE_INLINE_TEMPLATE void 154519fcbaf1SConrad Meyer ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark) 15460c16b537SWarner Losh { 154719fcbaf1SConrad Meyer int const nbRows = (int)size / ZSTD_ROWSIZE; 154819fcbaf1SConrad Meyer int cellNb = 0; 154919fcbaf1SConrad Meyer int rowNb; 155019fcbaf1SConrad Meyer assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */ 155119fcbaf1SConrad Meyer assert(size < (1U<<31)); /* can be casted to int */ 155219fcbaf1SConrad Meyer for (rowNb=0 ; rowNb < nbRows ; rowNb++) { 155319fcbaf1SConrad Meyer int column; 155419fcbaf1SConrad Meyer for (column=0; column<ZSTD_ROWSIZE; column++) { 155519fcbaf1SConrad Meyer if (preserveMark) { 155619fcbaf1SConrad Meyer U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0; 155719fcbaf1SConrad Meyer table[cellNb] += adder; 15580c16b537SWarner Losh } 155919fcbaf1SConrad Meyer if (table[cellNb] < reducerValue) table[cellNb] = 0; 156019fcbaf1SConrad Meyer else table[cellNb] -= reducerValue; 156119fcbaf1SConrad Meyer cellNb++; 156219fcbaf1SConrad Meyer } } 15630c16b537SWarner Losh } 15640c16b537SWarner Losh 156519fcbaf1SConrad Meyer static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue) 15660c16b537SWarner Losh { 156719fcbaf1SConrad Meyer ZSTD_reduceTable_internal(table, size, reducerValue, 0); 15680c16b537SWarner Losh } 156919fcbaf1SConrad Meyer 157019fcbaf1SConrad Meyer static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue) 157119fcbaf1SConrad Meyer { 157219fcbaf1SConrad Meyer ZSTD_reduceTable_internal(table, size, reducerValue, 1); 15730c16b537SWarner Losh } 15740c16b537SWarner Losh 15750c16b537SWarner Losh /*! ZSTD_reduceIndex() : 15760c16b537SWarner Losh * rescale all indexes to avoid future overflow (indexes are U32) */ 15770c16b537SWarner Losh static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) 15780c16b537SWarner Losh { 157919fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &zc->blockState.matchState; 15800c16b537SWarner Losh { U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog; 158119fcbaf1SConrad Meyer ZSTD_reduceTable(ms->hashTable, hSize, reducerValue); 15820c16b537SWarner Losh } 158319fcbaf1SConrad Meyer 158419fcbaf1SConrad Meyer if (zc->appliedParams.cParams.strategy != ZSTD_fast) { 158519fcbaf1SConrad Meyer U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog; 158619fcbaf1SConrad Meyer if (zc->appliedParams.cParams.strategy == ZSTD_btlazy2) 158719fcbaf1SConrad Meyer ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue); 158819fcbaf1SConrad Meyer else 158919fcbaf1SConrad Meyer ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue); 159019fcbaf1SConrad Meyer } 159119fcbaf1SConrad Meyer 159219fcbaf1SConrad Meyer if (ms->hashLog3) { 159319fcbaf1SConrad Meyer U32 const h3Size = (U32)1 << ms->hashLog3; 159419fcbaf1SConrad Meyer ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue); 15950c16b537SWarner Losh } 15960c16b537SWarner Losh } 15970c16b537SWarner Losh 15980c16b537SWarner Losh 15990c16b537SWarner Losh /*-******************************************************* 16000c16b537SWarner Losh * Block entropic compression 16010c16b537SWarner Losh *********************************************************/ 16020c16b537SWarner Losh 16030c16b537SWarner Losh /* See doc/zstd_compression_format.md for detailed format description */ 16040c16b537SWarner Losh 1605*0f743729SConrad Meyer static size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock) 16060c16b537SWarner Losh { 1607*0f743729SConrad Meyer U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3); 16080c16b537SWarner Losh if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall); 1609*0f743729SConrad Meyer MEM_writeLE24(dst, cBlockHeader24); 16100c16b537SWarner Losh memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize); 16110c16b537SWarner Losh return ZSTD_blockHeaderSize + srcSize; 16120c16b537SWarner Losh } 16130c16b537SWarner Losh 16140c16b537SWarner Losh static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize) 16150c16b537SWarner Losh { 16160c16b537SWarner Losh BYTE* const ostart = (BYTE* const)dst; 16170c16b537SWarner Losh U32 const flSize = 1 + (srcSize>31) + (srcSize>4095); 16180c16b537SWarner Losh 16190c16b537SWarner Losh if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall); 16200c16b537SWarner Losh 16210c16b537SWarner Losh switch(flSize) 16220c16b537SWarner Losh { 16230c16b537SWarner Losh case 1: /* 2 - 1 - 5 */ 16240c16b537SWarner Losh ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3)); 16250c16b537SWarner Losh break; 16260c16b537SWarner Losh case 2: /* 2 - 2 - 12 */ 16270c16b537SWarner Losh MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4))); 16280c16b537SWarner Losh break; 16290c16b537SWarner Losh case 3: /* 2 - 2 - 20 */ 16300c16b537SWarner Losh MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4))); 16310c16b537SWarner Losh break; 16320c16b537SWarner Losh default: /* not necessary : flSize is {1,2,3} */ 16330c16b537SWarner Losh assert(0); 16340c16b537SWarner Losh } 16350c16b537SWarner Losh 16360c16b537SWarner Losh memcpy(ostart + flSize, src, srcSize); 16370c16b537SWarner Losh return srcSize + flSize; 16380c16b537SWarner Losh } 16390c16b537SWarner Losh 16400c16b537SWarner Losh static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize) 16410c16b537SWarner Losh { 16420c16b537SWarner Losh BYTE* const ostart = (BYTE* const)dst; 16430c16b537SWarner Losh U32 const flSize = 1 + (srcSize>31) + (srcSize>4095); 16440c16b537SWarner Losh 16450c16b537SWarner Losh (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */ 16460c16b537SWarner Losh 16470c16b537SWarner Losh switch(flSize) 16480c16b537SWarner Losh { 16490c16b537SWarner Losh case 1: /* 2 - 1 - 5 */ 16500c16b537SWarner Losh ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3)); 16510c16b537SWarner Losh break; 16520c16b537SWarner Losh case 2: /* 2 - 2 - 12 */ 16530c16b537SWarner Losh MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4))); 16540c16b537SWarner Losh break; 16550c16b537SWarner Losh case 3: /* 2 - 2 - 20 */ 16560c16b537SWarner Losh MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4))); 16570c16b537SWarner Losh break; 16580c16b537SWarner Losh default: /* not necessary : flSize is {1,2,3} */ 16590c16b537SWarner Losh assert(0); 16600c16b537SWarner Losh } 16610c16b537SWarner Losh 16620c16b537SWarner Losh ostart[flSize] = *(const BYTE*)src; 16630c16b537SWarner Losh return flSize+1; 16640c16b537SWarner Losh } 16650c16b537SWarner Losh 16660c16b537SWarner Losh 1667*0f743729SConrad Meyer /* ZSTD_minGain() : 1668*0f743729SConrad Meyer * minimum compression required 1669*0f743729SConrad Meyer * to generate a compress block or a compressed literals section. 1670*0f743729SConrad Meyer * note : use same formula for both situations */ 1671*0f743729SConrad Meyer static size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat) 1672*0f743729SConrad Meyer { 1673*0f743729SConrad Meyer U32 const minlog = (strat==ZSTD_btultra) ? 7 : 6; 1674*0f743729SConrad Meyer return (srcSize >> minlog) + 2; 1675*0f743729SConrad Meyer } 16760c16b537SWarner Losh 1677*0f743729SConrad Meyer static size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf, 1678*0f743729SConrad Meyer ZSTD_hufCTables_t* nextHuf, 167919fcbaf1SConrad Meyer ZSTD_strategy strategy, int disableLiteralCompression, 16800c16b537SWarner Losh void* dst, size_t dstCapacity, 168119fcbaf1SConrad Meyer const void* src, size_t srcSize, 168219fcbaf1SConrad Meyer U32* workspace, const int bmi2) 16830c16b537SWarner Losh { 1684*0f743729SConrad Meyer size_t const minGain = ZSTD_minGain(srcSize, strategy); 16850c16b537SWarner Losh size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); 16860c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 16870c16b537SWarner Losh U32 singleStream = srcSize < 256; 16880c16b537SWarner Losh symbolEncodingType_e hType = set_compressed; 16890c16b537SWarner Losh size_t cLitSize; 16900c16b537SWarner Losh 169119fcbaf1SConrad Meyer DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i)", 169219fcbaf1SConrad Meyer disableLiteralCompression); 169319fcbaf1SConrad Meyer 169419fcbaf1SConrad Meyer /* Prepare nextEntropy assuming reusing the existing table */ 1695*0f743729SConrad Meyer memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 169619fcbaf1SConrad Meyer 169719fcbaf1SConrad Meyer if (disableLiteralCompression) 169819fcbaf1SConrad Meyer return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 16990c16b537SWarner Losh 17000c16b537SWarner Losh /* small ? don't even attempt compression (speed opt) */ 170119fcbaf1SConrad Meyer # define COMPRESS_LITERALS_SIZE_MIN 63 1702*0f743729SConrad Meyer { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; 17030c16b537SWarner Losh if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 17040c16b537SWarner Losh } 17050c16b537SWarner Losh 17060c16b537SWarner Losh if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ 1707*0f743729SConrad Meyer { HUF_repeat repeat = prevHuf->repeatMode; 17080c16b537SWarner Losh int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0; 17090c16b537SWarner Losh if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1; 17100c16b537SWarner Losh cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, 1711*0f743729SConrad Meyer workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2) 17120c16b537SWarner Losh : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, 1713*0f743729SConrad Meyer workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2); 171419fcbaf1SConrad Meyer if (repeat != HUF_repeat_none) { 171519fcbaf1SConrad Meyer /* reused the existing table */ 171619fcbaf1SConrad Meyer hType = set_repeat; 171719fcbaf1SConrad Meyer } 17180c16b537SWarner Losh } 17190c16b537SWarner Losh 17200c16b537SWarner Losh if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) { 1721*0f743729SConrad Meyer memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 17220c16b537SWarner Losh return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 17230c16b537SWarner Losh } 17240c16b537SWarner Losh if (cLitSize==1) { 1725*0f743729SConrad Meyer memcpy(nextHuf, prevHuf, sizeof(*prevHuf)); 17260c16b537SWarner Losh return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); 17270c16b537SWarner Losh } 17280c16b537SWarner Losh 172919fcbaf1SConrad Meyer if (hType == set_compressed) { 173019fcbaf1SConrad Meyer /* using a newly constructed table */ 1731*0f743729SConrad Meyer nextHuf->repeatMode = HUF_repeat_check; 173219fcbaf1SConrad Meyer } 173319fcbaf1SConrad Meyer 17340c16b537SWarner Losh /* Build header */ 17350c16b537SWarner Losh switch(lhSize) 17360c16b537SWarner Losh { 17370c16b537SWarner Losh case 3: /* 2 - 2 - 10 - 10 */ 17380c16b537SWarner Losh { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14); 17390c16b537SWarner Losh MEM_writeLE24(ostart, lhc); 17400c16b537SWarner Losh break; 17410c16b537SWarner Losh } 17420c16b537SWarner Losh case 4: /* 2 - 2 - 14 - 14 */ 17430c16b537SWarner Losh { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18); 17440c16b537SWarner Losh MEM_writeLE32(ostart, lhc); 17450c16b537SWarner Losh break; 17460c16b537SWarner Losh } 17470c16b537SWarner Losh case 5: /* 2 - 2 - 18 - 18 */ 17480c16b537SWarner Losh { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22); 17490c16b537SWarner Losh MEM_writeLE32(ostart, lhc); 17500c16b537SWarner Losh ostart[4] = (BYTE)(cLitSize >> 10); 17510c16b537SWarner Losh break; 17520c16b537SWarner Losh } 17530c16b537SWarner Losh default: /* not possible : lhSize is {3,4,5} */ 17540c16b537SWarner Losh assert(0); 17550c16b537SWarner Losh } 17560c16b537SWarner Losh return lhSize+cLitSize; 17570c16b537SWarner Losh } 17580c16b537SWarner Losh 17590c16b537SWarner Losh 17600c16b537SWarner Losh void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) 17610c16b537SWarner Losh { 17620c16b537SWarner Losh const seqDef* const sequences = seqStorePtr->sequencesStart; 17630c16b537SWarner Losh BYTE* const llCodeTable = seqStorePtr->llCode; 17640c16b537SWarner Losh BYTE* const ofCodeTable = seqStorePtr->ofCode; 17650c16b537SWarner Losh BYTE* const mlCodeTable = seqStorePtr->mlCode; 17660c16b537SWarner Losh U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 17670c16b537SWarner Losh U32 u; 1768*0f743729SConrad Meyer assert(nbSeq <= seqStorePtr->maxNbSeq); 17690c16b537SWarner Losh for (u=0; u<nbSeq; u++) { 17700c16b537SWarner Losh U32 const llv = sequences[u].litLength; 17710c16b537SWarner Losh U32 const mlv = sequences[u].matchLength; 1772052d3c12SConrad Meyer llCodeTable[u] = (BYTE)ZSTD_LLcode(llv); 17730c16b537SWarner Losh ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset); 1774052d3c12SConrad Meyer mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv); 17750c16b537SWarner Losh } 17760c16b537SWarner Losh if (seqStorePtr->longLengthID==1) 17770c16b537SWarner Losh llCodeTable[seqStorePtr->longLengthPos] = MaxLL; 17780c16b537SWarner Losh if (seqStorePtr->longLengthID==2) 17790c16b537SWarner Losh mlCodeTable[seqStorePtr->longLengthPos] = MaxML; 17800c16b537SWarner Losh } 17810c16b537SWarner Losh 1782*0f743729SConrad Meyer 1783*0f743729SConrad Meyer /** 1784*0f743729SConrad Meyer * -log2(x / 256) lookup table for x in [0, 256). 1785*0f743729SConrad Meyer * If x == 0: Return 0 1786*0f743729SConrad Meyer * Else: Return floor(-log2(x / 256) * 256) 1787*0f743729SConrad Meyer */ 1788*0f743729SConrad Meyer static unsigned const kInverseProbabiltyLog256[256] = { 1789*0f743729SConrad Meyer 0, 2048, 1792, 1642, 1536, 1453, 1386, 1329, 1280, 1236, 1197, 1162, 1790*0f743729SConrad Meyer 1130, 1100, 1073, 1047, 1024, 1001, 980, 960, 941, 923, 906, 889, 1791*0f743729SConrad Meyer 874, 859, 844, 830, 817, 804, 791, 779, 768, 756, 745, 734, 1792*0f743729SConrad Meyer 724, 714, 704, 694, 685, 676, 667, 658, 650, 642, 633, 626, 1793*0f743729SConrad Meyer 618, 610, 603, 595, 588, 581, 574, 567, 561, 554, 548, 542, 1794*0f743729SConrad Meyer 535, 529, 523, 517, 512, 506, 500, 495, 489, 484, 478, 473, 1795*0f743729SConrad Meyer 468, 463, 458, 453, 448, 443, 438, 434, 429, 424, 420, 415, 1796*0f743729SConrad Meyer 411, 407, 402, 398, 394, 390, 386, 382, 377, 373, 370, 366, 1797*0f743729SConrad Meyer 362, 358, 354, 350, 347, 343, 339, 336, 332, 329, 325, 322, 1798*0f743729SConrad Meyer 318, 315, 311, 308, 305, 302, 298, 295, 292, 289, 286, 282, 1799*0f743729SConrad Meyer 279, 276, 273, 270, 267, 264, 261, 258, 256, 253, 250, 247, 1800*0f743729SConrad Meyer 244, 241, 239, 236, 233, 230, 228, 225, 222, 220, 217, 215, 1801*0f743729SConrad Meyer 212, 209, 207, 204, 202, 199, 197, 194, 192, 190, 187, 185, 1802*0f743729SConrad Meyer 182, 180, 178, 175, 173, 171, 168, 166, 164, 162, 159, 157, 1803*0f743729SConrad Meyer 155, 153, 151, 149, 146, 144, 142, 140, 138, 136, 134, 132, 1804*0f743729SConrad Meyer 130, 128, 126, 123, 121, 119, 117, 115, 114, 112, 110, 108, 1805*0f743729SConrad Meyer 106, 104, 102, 100, 98, 96, 94, 93, 91, 89, 87, 85, 1806*0f743729SConrad Meyer 83, 82, 80, 78, 76, 74, 73, 71, 69, 67, 66, 64, 1807*0f743729SConrad Meyer 62, 61, 59, 57, 55, 54, 52, 50, 49, 47, 46, 44, 1808*0f743729SConrad Meyer 42, 41, 39, 37, 36, 34, 33, 31, 30, 28, 26, 25, 1809*0f743729SConrad Meyer 23, 22, 20, 19, 17, 16, 14, 13, 11, 10, 8, 7, 1810*0f743729SConrad Meyer 5, 4, 2, 1, 1811*0f743729SConrad Meyer }; 1812*0f743729SConrad Meyer 1813*0f743729SConrad Meyer 1814*0f743729SConrad Meyer /** 1815*0f743729SConrad Meyer * Returns the cost in bits of encoding the distribution described by count 1816*0f743729SConrad Meyer * using the entropy bound. 1817*0f743729SConrad Meyer */ 1818*0f743729SConrad Meyer static size_t ZSTD_entropyCost(unsigned const* count, unsigned const max, size_t const total) 1819*0f743729SConrad Meyer { 1820*0f743729SConrad Meyer unsigned cost = 0; 1821*0f743729SConrad Meyer unsigned s; 1822*0f743729SConrad Meyer for (s = 0; s <= max; ++s) { 1823*0f743729SConrad Meyer unsigned norm = (unsigned)((256 * count[s]) / total); 1824*0f743729SConrad Meyer if (count[s] != 0 && norm == 0) 1825*0f743729SConrad Meyer norm = 1; 1826*0f743729SConrad Meyer assert(count[s] < total); 1827*0f743729SConrad Meyer cost += count[s] * kInverseProbabiltyLog256[norm]; 1828*0f743729SConrad Meyer } 1829*0f743729SConrad Meyer return cost >> 8; 1830*0f743729SConrad Meyer } 1831*0f743729SConrad Meyer 1832*0f743729SConrad Meyer 1833*0f743729SConrad Meyer /** 1834*0f743729SConrad Meyer * Returns the cost in bits of encoding the distribution in count using the 1835*0f743729SConrad Meyer * table described by norm. The max symbol support by norm is assumed >= max. 1836*0f743729SConrad Meyer * norm must be valid for every symbol with non-zero probability in count. 1837*0f743729SConrad Meyer */ 1838*0f743729SConrad Meyer static size_t ZSTD_crossEntropyCost(short const* norm, unsigned accuracyLog, 1839*0f743729SConrad Meyer unsigned const* count, unsigned const max) 1840*0f743729SConrad Meyer { 1841*0f743729SConrad Meyer unsigned const shift = 8 - accuracyLog; 1842*0f743729SConrad Meyer size_t cost = 0; 1843*0f743729SConrad Meyer unsigned s; 1844*0f743729SConrad Meyer assert(accuracyLog <= 8); 1845*0f743729SConrad Meyer for (s = 0; s <= max; ++s) { 1846*0f743729SConrad Meyer unsigned const normAcc = norm[s] != -1 ? norm[s] : 1; 1847*0f743729SConrad Meyer unsigned const norm256 = normAcc << shift; 1848*0f743729SConrad Meyer assert(norm256 > 0); 1849*0f743729SConrad Meyer assert(norm256 < 256); 1850*0f743729SConrad Meyer cost += count[s] * kInverseProbabiltyLog256[norm256]; 1851*0f743729SConrad Meyer } 1852*0f743729SConrad Meyer return cost >> 8; 1853*0f743729SConrad Meyer } 1854*0f743729SConrad Meyer 1855*0f743729SConrad Meyer 1856*0f743729SConrad Meyer static unsigned ZSTD_getFSEMaxSymbolValue(FSE_CTable const* ctable) { 1857*0f743729SConrad Meyer void const* ptr = ctable; 1858*0f743729SConrad Meyer U16 const* u16ptr = (U16 const*)ptr; 1859*0f743729SConrad Meyer U32 const maxSymbolValue = MEM_read16(u16ptr + 1); 1860*0f743729SConrad Meyer return maxSymbolValue; 1861*0f743729SConrad Meyer } 1862*0f743729SConrad Meyer 1863*0f743729SConrad Meyer 1864*0f743729SConrad Meyer /** 1865*0f743729SConrad Meyer * Returns the cost in bits of encoding the distribution in count using ctable. 1866*0f743729SConrad Meyer * Returns an error if ctable cannot represent all the symbols in count. 1867*0f743729SConrad Meyer */ 1868*0f743729SConrad Meyer static size_t ZSTD_fseBitCost( 1869*0f743729SConrad Meyer FSE_CTable const* ctable, 1870*0f743729SConrad Meyer unsigned const* count, 1871*0f743729SConrad Meyer unsigned const max) 1872*0f743729SConrad Meyer { 1873*0f743729SConrad Meyer unsigned const kAccuracyLog = 8; 1874*0f743729SConrad Meyer size_t cost = 0; 1875*0f743729SConrad Meyer unsigned s; 1876*0f743729SConrad Meyer FSE_CState_t cstate; 1877*0f743729SConrad Meyer FSE_initCState(&cstate, ctable); 1878*0f743729SConrad Meyer if (ZSTD_getFSEMaxSymbolValue(ctable) < max) { 1879*0f743729SConrad Meyer DEBUGLOG(5, "Repeat FSE_CTable has maxSymbolValue %u < %u", 1880*0f743729SConrad Meyer ZSTD_getFSEMaxSymbolValue(ctable), max); 1881*0f743729SConrad Meyer return ERROR(GENERIC); 1882*0f743729SConrad Meyer } 1883*0f743729SConrad Meyer for (s = 0; s <= max; ++s) { 1884*0f743729SConrad Meyer unsigned const tableLog = cstate.stateLog; 1885*0f743729SConrad Meyer unsigned const badCost = (tableLog + 1) << kAccuracyLog; 1886*0f743729SConrad Meyer unsigned const bitCost = FSE_bitCost(cstate.symbolTT, tableLog, s, kAccuracyLog); 1887*0f743729SConrad Meyer if (count[s] == 0) 1888*0f743729SConrad Meyer continue; 1889*0f743729SConrad Meyer if (bitCost >= badCost) { 1890*0f743729SConrad Meyer DEBUGLOG(5, "Repeat FSE_CTable has Prob[%u] == 0", s); 1891*0f743729SConrad Meyer return ERROR(GENERIC); 1892*0f743729SConrad Meyer } 1893*0f743729SConrad Meyer cost += count[s] * bitCost; 1894*0f743729SConrad Meyer } 1895*0f743729SConrad Meyer return cost >> kAccuracyLog; 1896*0f743729SConrad Meyer } 1897*0f743729SConrad Meyer 1898*0f743729SConrad Meyer /** 1899*0f743729SConrad Meyer * Returns the cost in bytes of encoding the normalized count header. 1900*0f743729SConrad Meyer * Returns an error if any of the helper functions return an error. 1901*0f743729SConrad Meyer */ 1902*0f743729SConrad Meyer static size_t ZSTD_NCountCost(unsigned const* count, unsigned const max, 1903*0f743729SConrad Meyer size_t const nbSeq, unsigned const FSELog) 1904*0f743729SConrad Meyer { 1905*0f743729SConrad Meyer BYTE wksp[FSE_NCOUNTBOUND]; 1906*0f743729SConrad Meyer S16 norm[MaxSeq + 1]; 1907*0f743729SConrad Meyer const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); 1908*0f743729SConrad Meyer CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq, max)); 1909*0f743729SConrad Meyer return FSE_writeNCount(wksp, sizeof(wksp), norm, max, tableLog); 1910*0f743729SConrad Meyer } 1911*0f743729SConrad Meyer 1912*0f743729SConrad Meyer 19130c16b537SWarner Losh typedef enum { 19140c16b537SWarner Losh ZSTD_defaultDisallowed = 0, 19150c16b537SWarner Losh ZSTD_defaultAllowed = 1 19160c16b537SWarner Losh } ZSTD_defaultPolicy_e; 19170c16b537SWarner Losh 1918*0f743729SConrad Meyer MEM_STATIC symbolEncodingType_e 1919*0f743729SConrad Meyer ZSTD_selectEncodingType( 1920*0f743729SConrad Meyer FSE_repeat* repeatMode, unsigned const* count, unsigned const max, 1921*0f743729SConrad Meyer size_t const mostFrequent, size_t nbSeq, unsigned const FSELog, 1922*0f743729SConrad Meyer FSE_CTable const* prevCTable, 1923*0f743729SConrad Meyer short const* defaultNorm, U32 defaultNormLog, 1924*0f743729SConrad Meyer ZSTD_defaultPolicy_e const isDefaultAllowed, 1925*0f743729SConrad Meyer ZSTD_strategy const strategy) 19260c16b537SWarner Losh { 19270c16b537SWarner Losh ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0); 1928*0f743729SConrad Meyer if (mostFrequent == nbSeq) { 1929*0f743729SConrad Meyer *repeatMode = FSE_repeat_none; 1930*0f743729SConrad Meyer if (isDefaultAllowed && nbSeq <= 2) { 19310c16b537SWarner Losh /* Prefer set_basic over set_rle when there are 2 or less symbols, 19320c16b537SWarner Losh * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol. 19330c16b537SWarner Losh * If basic encoding isn't possible, always choose RLE. 19340c16b537SWarner Losh */ 1935*0f743729SConrad Meyer DEBUGLOG(5, "Selected set_basic"); 1936*0f743729SConrad Meyer return set_basic; 1937*0f743729SConrad Meyer } 1938*0f743729SConrad Meyer DEBUGLOG(5, "Selected set_rle"); 19390c16b537SWarner Losh return set_rle; 19400c16b537SWarner Losh } 1941*0f743729SConrad Meyer if (strategy < ZSTD_lazy) { 1942*0f743729SConrad Meyer if (isDefaultAllowed) { 1943*0f743729SConrad Meyer size_t const staticFse_nbSeq_max = 1000; 1944*0f743729SConrad Meyer size_t const mult = 10 - strategy; 1945*0f743729SConrad Meyer size_t const baseLog = 3; 1946*0f743729SConrad Meyer size_t const dynamicFse_nbSeq_min = (((size_t)1 << defaultNormLog) * mult) >> baseLog; /* 28-36 for offset, 56-72 for lengths */ 1947*0f743729SConrad Meyer assert(defaultNormLog >= 5 && defaultNormLog <= 6); /* xx_DEFAULTNORMLOG */ 1948*0f743729SConrad Meyer assert(mult <= 9 && mult >= 7); 1949*0f743729SConrad Meyer if ( (*repeatMode == FSE_repeat_valid) 1950*0f743729SConrad Meyer && (nbSeq < staticFse_nbSeq_max) ) { 1951052d3c12SConrad Meyer DEBUGLOG(5, "Selected set_repeat"); 19520c16b537SWarner Losh return set_repeat; 19530c16b537SWarner Losh } 1954*0f743729SConrad Meyer if ( (nbSeq < dynamicFse_nbSeq_min) 1955*0f743729SConrad Meyer || (mostFrequent < (nbSeq >> (defaultNormLog-1))) ) { 1956052d3c12SConrad Meyer DEBUGLOG(5, "Selected set_basic"); 1957052d3c12SConrad Meyer /* The format allows default tables to be repeated, but it isn't useful. 1958052d3c12SConrad Meyer * When using simple heuristics to select encoding type, we don't want 1959052d3c12SConrad Meyer * to confuse these tables with dictionaries. When running more careful 1960052d3c12SConrad Meyer * analysis, we don't need to waste time checking both repeating tables 1961052d3c12SConrad Meyer * and default tables. 1962052d3c12SConrad Meyer */ 1963052d3c12SConrad Meyer *repeatMode = FSE_repeat_none; 19640c16b537SWarner Losh return set_basic; 19650c16b537SWarner Losh } 1966*0f743729SConrad Meyer } 1967*0f743729SConrad Meyer } else { 1968*0f743729SConrad Meyer size_t const basicCost = isDefaultAllowed ? ZSTD_crossEntropyCost(defaultNorm, defaultNormLog, count, max) : ERROR(GENERIC); 1969*0f743729SConrad Meyer size_t const repeatCost = *repeatMode != FSE_repeat_none ? ZSTD_fseBitCost(prevCTable, count, max) : ERROR(GENERIC); 1970*0f743729SConrad Meyer size_t const NCountCost = ZSTD_NCountCost(count, max, nbSeq, FSELog); 1971*0f743729SConrad Meyer size_t const compressedCost = (NCountCost << 3) + ZSTD_entropyCost(count, max, nbSeq); 1972*0f743729SConrad Meyer 1973*0f743729SConrad Meyer if (isDefaultAllowed) { 1974*0f743729SConrad Meyer assert(!ZSTD_isError(basicCost)); 1975*0f743729SConrad Meyer assert(!(*repeatMode == FSE_repeat_valid && ZSTD_isError(repeatCost))); 1976*0f743729SConrad Meyer } 1977*0f743729SConrad Meyer assert(!ZSTD_isError(NCountCost)); 1978*0f743729SConrad Meyer assert(compressedCost < ERROR(maxCode)); 1979*0f743729SConrad Meyer DEBUGLOG(5, "Estimated bit costs: basic=%u\trepeat=%u\tcompressed=%u", 1980*0f743729SConrad Meyer (U32)basicCost, (U32)repeatCost, (U32)compressedCost); 1981*0f743729SConrad Meyer if (basicCost <= repeatCost && basicCost <= compressedCost) { 1982*0f743729SConrad Meyer DEBUGLOG(5, "Selected set_basic"); 1983*0f743729SConrad Meyer assert(isDefaultAllowed); 1984*0f743729SConrad Meyer *repeatMode = FSE_repeat_none; 1985*0f743729SConrad Meyer return set_basic; 1986*0f743729SConrad Meyer } 1987*0f743729SConrad Meyer if (repeatCost <= compressedCost) { 1988*0f743729SConrad Meyer DEBUGLOG(5, "Selected set_repeat"); 1989*0f743729SConrad Meyer assert(!ZSTD_isError(repeatCost)); 1990*0f743729SConrad Meyer return set_repeat; 1991*0f743729SConrad Meyer } 1992*0f743729SConrad Meyer assert(compressedCost < basicCost && compressedCost < repeatCost); 1993*0f743729SConrad Meyer } 1994052d3c12SConrad Meyer DEBUGLOG(5, "Selected set_compressed"); 19950c16b537SWarner Losh *repeatMode = FSE_repeat_check; 19960c16b537SWarner Losh return set_compressed; 19970c16b537SWarner Losh } 19980c16b537SWarner Losh 1999*0f743729SConrad Meyer MEM_STATIC size_t 2000*0f743729SConrad Meyer ZSTD_buildCTable(void* dst, size_t dstCapacity, 200119fcbaf1SConrad Meyer FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type, 20020c16b537SWarner Losh U32* count, U32 max, 2003*0f743729SConrad Meyer const BYTE* codeTable, size_t nbSeq, 2004*0f743729SConrad Meyer const S16* defaultNorm, U32 defaultNormLog, U32 defaultMax, 2005*0f743729SConrad Meyer const FSE_CTable* prevCTable, size_t prevCTableSize, 20060c16b537SWarner Losh void* workspace, size_t workspaceSize) 20070c16b537SWarner Losh { 20080c16b537SWarner Losh BYTE* op = (BYTE*)dst; 2009*0f743729SConrad Meyer const BYTE* const oend = op + dstCapacity; 20100c16b537SWarner Losh 20110c16b537SWarner Losh switch (type) { 20120c16b537SWarner Losh case set_rle: 20130c16b537SWarner Losh *op = codeTable[0]; 201419fcbaf1SConrad Meyer CHECK_F(FSE_buildCTable_rle(nextCTable, (BYTE)max)); 20150c16b537SWarner Losh return 1; 20160c16b537SWarner Losh case set_repeat: 201719fcbaf1SConrad Meyer memcpy(nextCTable, prevCTable, prevCTableSize); 20180c16b537SWarner Losh return 0; 20190c16b537SWarner Losh case set_basic: 202019fcbaf1SConrad Meyer CHECK_F(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */ 20210c16b537SWarner Losh return 0; 20220c16b537SWarner Losh case set_compressed: { 20230c16b537SWarner Losh S16 norm[MaxSeq + 1]; 20240c16b537SWarner Losh size_t nbSeq_1 = nbSeq; 20250c16b537SWarner Losh const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); 20260c16b537SWarner Losh if (count[codeTable[nbSeq-1]] > 1) { 20270c16b537SWarner Losh count[codeTable[nbSeq-1]]--; 20280c16b537SWarner Losh nbSeq_1--; 20290c16b537SWarner Losh } 20300c16b537SWarner Losh assert(nbSeq_1 > 1); 20310c16b537SWarner Losh CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max)); 20320c16b537SWarner Losh { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */ 20330c16b537SWarner Losh if (FSE_isError(NCountSize)) return NCountSize; 203419fcbaf1SConrad Meyer CHECK_F(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, workspace, workspaceSize)); 20350c16b537SWarner Losh return NCountSize; 20360c16b537SWarner Losh } 20370c16b537SWarner Losh } 20380c16b537SWarner Losh default: return assert(0), ERROR(GENERIC); 20390c16b537SWarner Losh } 20400c16b537SWarner Losh } 20410c16b537SWarner Losh 204219fcbaf1SConrad Meyer FORCE_INLINE_TEMPLATE size_t 204319fcbaf1SConrad Meyer ZSTD_encodeSequences_body( 2044052d3c12SConrad Meyer void* dst, size_t dstCapacity, 20450c16b537SWarner Losh FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 20460c16b537SWarner Losh FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 20470c16b537SWarner Losh FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 20480c16b537SWarner Losh seqDef const* sequences, size_t nbSeq, int longOffsets) 20490c16b537SWarner Losh { 20500c16b537SWarner Losh BIT_CStream_t blockStream; 20510c16b537SWarner Losh FSE_CState_t stateMatchLength; 20520c16b537SWarner Losh FSE_CState_t stateOffsetBits; 20530c16b537SWarner Losh FSE_CState_t stateLitLength; 20540c16b537SWarner Losh 20550c16b537SWarner Losh CHECK_E(BIT_initCStream(&blockStream, dst, dstCapacity), dstSize_tooSmall); /* not enough space remaining */ 20560c16b537SWarner Losh 20570c16b537SWarner Losh /* first symbols */ 20580c16b537SWarner Losh FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]); 20590c16b537SWarner Losh FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]); 20600c16b537SWarner Losh FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]); 20610c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]); 20620c16b537SWarner Losh if (MEM_32bits()) BIT_flushBits(&blockStream); 20630c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]); 20640c16b537SWarner Losh if (MEM_32bits()) BIT_flushBits(&blockStream); 20650c16b537SWarner Losh if (longOffsets) { 20660c16b537SWarner Losh U32 const ofBits = ofCodeTable[nbSeq-1]; 20670c16b537SWarner Losh int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); 20680c16b537SWarner Losh if (extraBits) { 20690c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits); 20700c16b537SWarner Losh BIT_flushBits(&blockStream); 20710c16b537SWarner Losh } 20720c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits, 20730c16b537SWarner Losh ofBits - extraBits); 20740c16b537SWarner Losh } else { 20750c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]); 20760c16b537SWarner Losh } 20770c16b537SWarner Losh BIT_flushBits(&blockStream); 20780c16b537SWarner Losh 20790c16b537SWarner Losh { size_t n; 20800c16b537SWarner Losh for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */ 20810c16b537SWarner Losh BYTE const llCode = llCodeTable[n]; 20820c16b537SWarner Losh BYTE const ofCode = ofCodeTable[n]; 20830c16b537SWarner Losh BYTE const mlCode = mlCodeTable[n]; 20840c16b537SWarner Losh U32 const llBits = LL_bits[llCode]; 2085052d3c12SConrad Meyer U32 const ofBits = ofCode; 20860c16b537SWarner Losh U32 const mlBits = ML_bits[mlCode]; 2087052d3c12SConrad Meyer DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u", 2088052d3c12SConrad Meyer sequences[n].litLength, 2089052d3c12SConrad Meyer sequences[n].matchLength + MINMATCH, 209019fcbaf1SConrad Meyer sequences[n].offset); 209119fcbaf1SConrad Meyer /* 32b*/ /* 64b*/ 20920c16b537SWarner Losh /* (7)*/ /* (7)*/ 20930c16b537SWarner Losh FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */ 20940c16b537SWarner Losh FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */ 20950c16b537SWarner Losh if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/ 20960c16b537SWarner Losh FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */ 20970c16b537SWarner Losh if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog))) 20980c16b537SWarner Losh BIT_flushBits(&blockStream); /* (7)*/ 20990c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].litLength, llBits); 21000c16b537SWarner Losh if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream); 21010c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].matchLength, mlBits); 21020c16b537SWarner Losh if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream); 21030c16b537SWarner Losh if (longOffsets) { 21040c16b537SWarner Losh int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); 21050c16b537SWarner Losh if (extraBits) { 21060c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].offset, extraBits); 21070c16b537SWarner Losh BIT_flushBits(&blockStream); /* (7)*/ 21080c16b537SWarner Losh } 21090c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].offset >> extraBits, 21100c16b537SWarner Losh ofBits - extraBits); /* 31 */ 21110c16b537SWarner Losh } else { 21120c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */ 21130c16b537SWarner Losh } 21140c16b537SWarner Losh BIT_flushBits(&blockStream); /* (7)*/ 21150c16b537SWarner Losh } } 21160c16b537SWarner Losh 211719fcbaf1SConrad Meyer DEBUGLOG(6, "ZSTD_encodeSequences: flushing ML state with %u bits", stateMatchLength.stateLog); 21180c16b537SWarner Losh FSE_flushCState(&blockStream, &stateMatchLength); 211919fcbaf1SConrad Meyer DEBUGLOG(6, "ZSTD_encodeSequences: flushing Off state with %u bits", stateOffsetBits.stateLog); 21200c16b537SWarner Losh FSE_flushCState(&blockStream, &stateOffsetBits); 212119fcbaf1SConrad Meyer DEBUGLOG(6, "ZSTD_encodeSequences: flushing LL state with %u bits", stateLitLength.stateLog); 21220c16b537SWarner Losh FSE_flushCState(&blockStream, &stateLitLength); 21230c16b537SWarner Losh 21240c16b537SWarner Losh { size_t const streamSize = BIT_closeCStream(&blockStream); 21250c16b537SWarner Losh if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */ 21260c16b537SWarner Losh return streamSize; 21270c16b537SWarner Losh } 21280c16b537SWarner Losh } 21290c16b537SWarner Losh 213019fcbaf1SConrad Meyer static size_t 213119fcbaf1SConrad Meyer ZSTD_encodeSequences_default( 213219fcbaf1SConrad Meyer void* dst, size_t dstCapacity, 213319fcbaf1SConrad Meyer FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 213419fcbaf1SConrad Meyer FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 213519fcbaf1SConrad Meyer FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 213619fcbaf1SConrad Meyer seqDef const* sequences, size_t nbSeq, int longOffsets) 21370c16b537SWarner Losh { 213819fcbaf1SConrad Meyer return ZSTD_encodeSequences_body(dst, dstCapacity, 213919fcbaf1SConrad Meyer CTable_MatchLength, mlCodeTable, 214019fcbaf1SConrad Meyer CTable_OffsetBits, ofCodeTable, 214119fcbaf1SConrad Meyer CTable_LitLength, llCodeTable, 214219fcbaf1SConrad Meyer sequences, nbSeq, longOffsets); 214319fcbaf1SConrad Meyer } 214419fcbaf1SConrad Meyer 214519fcbaf1SConrad Meyer 214619fcbaf1SConrad Meyer #if DYNAMIC_BMI2 214719fcbaf1SConrad Meyer 214819fcbaf1SConrad Meyer static TARGET_ATTRIBUTE("bmi2") size_t 214919fcbaf1SConrad Meyer ZSTD_encodeSequences_bmi2( 215019fcbaf1SConrad Meyer void* dst, size_t dstCapacity, 215119fcbaf1SConrad Meyer FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 215219fcbaf1SConrad Meyer FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 215319fcbaf1SConrad Meyer FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 215419fcbaf1SConrad Meyer seqDef const* sequences, size_t nbSeq, int longOffsets) 215519fcbaf1SConrad Meyer { 215619fcbaf1SConrad Meyer return ZSTD_encodeSequences_body(dst, dstCapacity, 215719fcbaf1SConrad Meyer CTable_MatchLength, mlCodeTable, 215819fcbaf1SConrad Meyer CTable_OffsetBits, ofCodeTable, 215919fcbaf1SConrad Meyer CTable_LitLength, llCodeTable, 216019fcbaf1SConrad Meyer sequences, nbSeq, longOffsets); 216119fcbaf1SConrad Meyer } 216219fcbaf1SConrad Meyer 216319fcbaf1SConrad Meyer #endif 216419fcbaf1SConrad Meyer 2165*0f743729SConrad Meyer static size_t ZSTD_encodeSequences( 216619fcbaf1SConrad Meyer void* dst, size_t dstCapacity, 216719fcbaf1SConrad Meyer FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 216819fcbaf1SConrad Meyer FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 216919fcbaf1SConrad Meyer FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 217019fcbaf1SConrad Meyer seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2) 217119fcbaf1SConrad Meyer { 217219fcbaf1SConrad Meyer #if DYNAMIC_BMI2 217319fcbaf1SConrad Meyer if (bmi2) { 217419fcbaf1SConrad Meyer return ZSTD_encodeSequences_bmi2(dst, dstCapacity, 217519fcbaf1SConrad Meyer CTable_MatchLength, mlCodeTable, 217619fcbaf1SConrad Meyer CTable_OffsetBits, ofCodeTable, 217719fcbaf1SConrad Meyer CTable_LitLength, llCodeTable, 217819fcbaf1SConrad Meyer sequences, nbSeq, longOffsets); 217919fcbaf1SConrad Meyer } 218019fcbaf1SConrad Meyer #endif 218119fcbaf1SConrad Meyer (void)bmi2; 218219fcbaf1SConrad Meyer return ZSTD_encodeSequences_default(dst, dstCapacity, 218319fcbaf1SConrad Meyer CTable_MatchLength, mlCodeTable, 218419fcbaf1SConrad Meyer CTable_OffsetBits, ofCodeTable, 218519fcbaf1SConrad Meyer CTable_LitLength, llCodeTable, 218619fcbaf1SConrad Meyer sequences, nbSeq, longOffsets); 218719fcbaf1SConrad Meyer } 218819fcbaf1SConrad Meyer 218919fcbaf1SConrad Meyer MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, 219019fcbaf1SConrad Meyer ZSTD_entropyCTables_t const* prevEntropy, 219119fcbaf1SConrad Meyer ZSTD_entropyCTables_t* nextEntropy, 219219fcbaf1SConrad Meyer ZSTD_CCtx_params const* cctxParams, 219319fcbaf1SConrad Meyer void* dst, size_t dstCapacity, U32* workspace, 219419fcbaf1SConrad Meyer const int bmi2) 219519fcbaf1SConrad Meyer { 219619fcbaf1SConrad Meyer const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; 2197*0f743729SConrad Meyer ZSTD_strategy const strategy = cctxParams->cParams.strategy; 21980c16b537SWarner Losh U32 count[MaxSeq+1]; 2199*0f743729SConrad Meyer FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable; 2200*0f743729SConrad Meyer FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable; 2201*0f743729SConrad Meyer FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable; 22020c16b537SWarner Losh U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ 22030c16b537SWarner Losh const seqDef* const sequences = seqStorePtr->sequencesStart; 22040c16b537SWarner Losh const BYTE* const ofCodeTable = seqStorePtr->ofCode; 22050c16b537SWarner Losh const BYTE* const llCodeTable = seqStorePtr->llCode; 22060c16b537SWarner Losh const BYTE* const mlCodeTable = seqStorePtr->mlCode; 22070c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 22080c16b537SWarner Losh BYTE* const oend = ostart + dstCapacity; 22090c16b537SWarner Losh BYTE* op = ostart; 22100c16b537SWarner Losh size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart; 22110c16b537SWarner Losh BYTE* seqHead; 2212*0f743729SConrad Meyer BYTE* lastNCount = NULL; 22130c16b537SWarner Losh 221419fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 22150c16b537SWarner Losh 22160c16b537SWarner Losh /* Compress literals */ 22170c16b537SWarner Losh { const BYTE* const literals = seqStorePtr->litStart; 22180c16b537SWarner Losh size_t const litSize = seqStorePtr->lit - literals; 2219*0f743729SConrad Meyer int const disableLiteralCompression = (cctxParams->cParams.strategy == ZSTD_fast) && (cctxParams->cParams.targetLength > 0); 22200c16b537SWarner Losh size_t const cSize = ZSTD_compressLiterals( 2221*0f743729SConrad Meyer &prevEntropy->huf, &nextEntropy->huf, 2222*0f743729SConrad Meyer cctxParams->cParams.strategy, disableLiteralCompression, 222319fcbaf1SConrad Meyer op, dstCapacity, 222419fcbaf1SConrad Meyer literals, litSize, 222519fcbaf1SConrad Meyer workspace, bmi2); 22260c16b537SWarner Losh if (ZSTD_isError(cSize)) 22270c16b537SWarner Losh return cSize; 2228052d3c12SConrad Meyer assert(cSize <= dstCapacity); 22290c16b537SWarner Losh op += cSize; 22300c16b537SWarner Losh } 22310c16b537SWarner Losh 22320c16b537SWarner Losh /* Sequences Header */ 22330c16b537SWarner Losh if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/) return ERROR(dstSize_tooSmall); 2234052d3c12SConrad Meyer if (nbSeq < 0x7F) 2235052d3c12SConrad Meyer *op++ = (BYTE)nbSeq; 2236052d3c12SConrad Meyer else if (nbSeq < LONGNBSEQ) 2237052d3c12SConrad Meyer op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; 2238052d3c12SConrad Meyer else 2239052d3c12SConrad Meyer op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; 224019fcbaf1SConrad Meyer if (nbSeq==0) { 2241*0f743729SConrad Meyer /* Copy the old tables over as if we repeated them */ 2242*0f743729SConrad Meyer memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse)); 224319fcbaf1SConrad Meyer return op - ostart; 224419fcbaf1SConrad Meyer } 22450c16b537SWarner Losh 22460c16b537SWarner Losh /* seqHead : flags for FSE encoding type */ 22470c16b537SWarner Losh seqHead = op++; 22480c16b537SWarner Losh 22490c16b537SWarner Losh /* convert length/distances into codes */ 22500c16b537SWarner Losh ZSTD_seqToCodes(seqStorePtr); 2251052d3c12SConrad Meyer /* build CTable for Literal Lengths */ 22520c16b537SWarner Losh { U32 max = MaxLL; 2253*0f743729SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace); /* can't fail */ 2254052d3c12SConrad Meyer DEBUGLOG(5, "Building LL table"); 2255*0f743729SConrad Meyer nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode; 2256*0f743729SConrad Meyer LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode, count, max, mostFrequent, nbSeq, LLFSELog, prevEntropy->fse.litlengthCTable, LL_defaultNorm, LL_defaultNormLog, ZSTD_defaultAllowed, strategy); 2257*0f743729SConrad Meyer assert(set_basic < set_compressed && set_rle < set_compressed); 2258*0f743729SConrad Meyer assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 22590c16b537SWarner Losh { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, 22600c16b537SWarner Losh count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL, 2261*0f743729SConrad Meyer prevEntropy->fse.litlengthCTable, sizeof(prevEntropy->fse.litlengthCTable), 226219fcbaf1SConrad Meyer workspace, HUF_WORKSPACE_SIZE); 22630c16b537SWarner Losh if (ZSTD_isError(countSize)) return countSize; 2264*0f743729SConrad Meyer if (LLtype == set_compressed) 2265*0f743729SConrad Meyer lastNCount = op; 22660c16b537SWarner Losh op += countSize; 22670c16b537SWarner Losh } } 2268052d3c12SConrad Meyer /* build CTable for Offsets */ 22690c16b537SWarner Losh { U32 max = MaxOff; 2270*0f743729SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace); /* can't fail */ 22710c16b537SWarner Losh /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ 2272052d3c12SConrad Meyer ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; 2273052d3c12SConrad Meyer DEBUGLOG(5, "Building OF table"); 2274*0f743729SConrad Meyer nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode; 2275*0f743729SConrad Meyer Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode, count, max, mostFrequent, nbSeq, OffFSELog, prevEntropy->fse.offcodeCTable, OF_defaultNorm, OF_defaultNormLog, defaultPolicy, strategy); 2276*0f743729SConrad Meyer assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 22770c16b537SWarner Losh { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, 22780c16b537SWarner Losh count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, 2279*0f743729SConrad Meyer prevEntropy->fse.offcodeCTable, sizeof(prevEntropy->fse.offcodeCTable), 228019fcbaf1SConrad Meyer workspace, HUF_WORKSPACE_SIZE); 22810c16b537SWarner Losh if (ZSTD_isError(countSize)) return countSize; 2282*0f743729SConrad Meyer if (Offtype == set_compressed) 2283*0f743729SConrad Meyer lastNCount = op; 22840c16b537SWarner Losh op += countSize; 22850c16b537SWarner Losh } } 2286052d3c12SConrad Meyer /* build CTable for MatchLengths */ 22870c16b537SWarner Losh { U32 max = MaxML; 2288*0f743729SConrad Meyer size_t const mostFrequent = HIST_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace); /* can't fail */ 2289052d3c12SConrad Meyer DEBUGLOG(5, "Building ML table"); 2290*0f743729SConrad Meyer nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode; 2291*0f743729SConrad Meyer MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode, count, max, mostFrequent, nbSeq, MLFSELog, prevEntropy->fse.matchlengthCTable, ML_defaultNorm, ML_defaultNormLog, ZSTD_defaultAllowed, strategy); 2292*0f743729SConrad Meyer assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */ 22930c16b537SWarner Losh { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, 22940c16b537SWarner Losh count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML, 2295*0f743729SConrad Meyer prevEntropy->fse.matchlengthCTable, sizeof(prevEntropy->fse.matchlengthCTable), 229619fcbaf1SConrad Meyer workspace, HUF_WORKSPACE_SIZE); 22970c16b537SWarner Losh if (ZSTD_isError(countSize)) return countSize; 2298*0f743729SConrad Meyer if (MLtype == set_compressed) 2299*0f743729SConrad Meyer lastNCount = op; 23000c16b537SWarner Losh op += countSize; 23010c16b537SWarner Losh } } 23020c16b537SWarner Losh 23030c16b537SWarner Losh *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); 23040c16b537SWarner Losh 2305052d3c12SConrad Meyer { size_t const bitstreamSize = ZSTD_encodeSequences( 2306052d3c12SConrad Meyer op, oend - op, 23070c16b537SWarner Losh CTable_MatchLength, mlCodeTable, 23080c16b537SWarner Losh CTable_OffsetBits, ofCodeTable, 23090c16b537SWarner Losh CTable_LitLength, llCodeTable, 2310052d3c12SConrad Meyer sequences, nbSeq, 231119fcbaf1SConrad Meyer longOffsets, bmi2); 2312052d3c12SConrad Meyer if (ZSTD_isError(bitstreamSize)) return bitstreamSize; 2313052d3c12SConrad Meyer op += bitstreamSize; 2314*0f743729SConrad Meyer /* zstd versions <= 1.3.4 mistakenly report corruption when 2315*0f743729SConrad Meyer * FSE_readNCount() recieves a buffer < 4 bytes. 2316*0f743729SConrad Meyer * Fixed by https://github.com/facebook/zstd/pull/1146. 2317*0f743729SConrad Meyer * This can happen when the last set_compressed table present is 2 2318*0f743729SConrad Meyer * bytes and the bitstream is only one byte. 2319*0f743729SConrad Meyer * In this exceedingly rare case, we will simply emit an uncompressed 2320*0f743729SConrad Meyer * block, since it isn't worth optimizing. 2321*0f743729SConrad Meyer */ 2322*0f743729SConrad Meyer if (lastNCount && (op - lastNCount) < 4) { 2323*0f743729SConrad Meyer /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */ 2324*0f743729SConrad Meyer assert(op - lastNCount == 3); 2325*0f743729SConrad Meyer DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by " 2326*0f743729SConrad Meyer "emitting an uncompressed block."); 2327*0f743729SConrad Meyer return 0; 2328*0f743729SConrad Meyer } 23290c16b537SWarner Losh } 23300c16b537SWarner Losh 23310c16b537SWarner Losh return op - ostart; 23320c16b537SWarner Losh } 23330c16b537SWarner Losh 23340c16b537SWarner Losh MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr, 2335*0f743729SConrad Meyer const ZSTD_entropyCTables_t* prevEntropy, 233619fcbaf1SConrad Meyer ZSTD_entropyCTables_t* nextEntropy, 2337*0f743729SConrad Meyer const ZSTD_CCtx_params* cctxParams, 23380c16b537SWarner Losh void* dst, size_t dstCapacity, 233919fcbaf1SConrad Meyer size_t srcSize, U32* workspace, int bmi2) 23400c16b537SWarner Losh { 234119fcbaf1SConrad Meyer size_t const cSize = ZSTD_compressSequences_internal( 234219fcbaf1SConrad Meyer seqStorePtr, prevEntropy, nextEntropy, cctxParams, dst, dstCapacity, 234319fcbaf1SConrad Meyer workspace, bmi2); 2344*0f743729SConrad Meyer if (cSize == 0) return 0; 234519fcbaf1SConrad Meyer /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block. 234619fcbaf1SConrad Meyer * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block. 23470c16b537SWarner Losh */ 234819fcbaf1SConrad Meyer if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) 234919fcbaf1SConrad Meyer return 0; /* block not compressed */ 235019fcbaf1SConrad Meyer if (ZSTD_isError(cSize)) return cSize; 235119fcbaf1SConrad Meyer 235219fcbaf1SConrad Meyer /* Check compressibility */ 2353*0f743729SConrad Meyer { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy); 235419fcbaf1SConrad Meyer if (cSize >= maxCSize) return 0; /* block not compressed */ 235519fcbaf1SConrad Meyer } 235619fcbaf1SConrad Meyer 23570c16b537SWarner Losh return cSize; 23580c16b537SWarner Losh } 23590c16b537SWarner Losh 23600c16b537SWarner Losh /* ZSTD_selectBlockCompressor() : 23610c16b537SWarner Losh * Not static, but internal use only (used by long distance matcher) 23620c16b537SWarner Losh * assumption : strat is a valid strategy */ 2363*0f743729SConrad Meyer ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode) 23640c16b537SWarner Losh { 2365*0f743729SConrad Meyer static const ZSTD_blockCompressor blockCompressor[3][(unsigned)ZSTD_btultra+1] = { 23660c16b537SWarner Losh { ZSTD_compressBlock_fast /* default for 0 */, 2367*0f743729SConrad Meyer ZSTD_compressBlock_fast, 2368*0f743729SConrad Meyer ZSTD_compressBlock_doubleFast, 2369*0f743729SConrad Meyer ZSTD_compressBlock_greedy, 2370*0f743729SConrad Meyer ZSTD_compressBlock_lazy, 2371*0f743729SConrad Meyer ZSTD_compressBlock_lazy2, 2372*0f743729SConrad Meyer ZSTD_compressBlock_btlazy2, 2373*0f743729SConrad Meyer ZSTD_compressBlock_btopt, 2374*0f743729SConrad Meyer ZSTD_compressBlock_btultra }, 23750c16b537SWarner Losh { ZSTD_compressBlock_fast_extDict /* default for 0 */, 2376*0f743729SConrad Meyer ZSTD_compressBlock_fast_extDict, 2377*0f743729SConrad Meyer ZSTD_compressBlock_doubleFast_extDict, 2378*0f743729SConrad Meyer ZSTD_compressBlock_greedy_extDict, 2379*0f743729SConrad Meyer ZSTD_compressBlock_lazy_extDict, 2380*0f743729SConrad Meyer ZSTD_compressBlock_lazy2_extDict, 2381*0f743729SConrad Meyer ZSTD_compressBlock_btlazy2_extDict, 2382*0f743729SConrad Meyer ZSTD_compressBlock_btopt_extDict, 2383*0f743729SConrad Meyer ZSTD_compressBlock_btultra_extDict }, 2384*0f743729SConrad Meyer { ZSTD_compressBlock_fast_dictMatchState /* default for 0 */, 2385*0f743729SConrad Meyer ZSTD_compressBlock_fast_dictMatchState, 2386*0f743729SConrad Meyer ZSTD_compressBlock_doubleFast_dictMatchState, 2387*0f743729SConrad Meyer ZSTD_compressBlock_greedy_dictMatchState, 2388*0f743729SConrad Meyer ZSTD_compressBlock_lazy_dictMatchState, 2389*0f743729SConrad Meyer ZSTD_compressBlock_lazy2_dictMatchState, 2390*0f743729SConrad Meyer ZSTD_compressBlock_btlazy2_dictMatchState, 2391*0f743729SConrad Meyer ZSTD_compressBlock_btopt_dictMatchState, 2392*0f743729SConrad Meyer ZSTD_compressBlock_btultra_dictMatchState } 23930c16b537SWarner Losh }; 2394*0f743729SConrad Meyer ZSTD_blockCompressor selectedCompressor; 23950c16b537SWarner Losh ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); 2396052d3c12SConrad Meyer 23970c16b537SWarner Losh assert((U32)strat >= (U32)ZSTD_fast); 23980c16b537SWarner Losh assert((U32)strat <= (U32)ZSTD_btultra); 2399*0f743729SConrad Meyer selectedCompressor = blockCompressor[(int)dictMode][(U32)strat]; 2400*0f743729SConrad Meyer assert(selectedCompressor != NULL); 2401*0f743729SConrad Meyer return selectedCompressor; 24020c16b537SWarner Losh } 24030c16b537SWarner Losh 24040c16b537SWarner Losh static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, 24050c16b537SWarner Losh const BYTE* anchor, size_t lastLLSize) 24060c16b537SWarner Losh { 24070c16b537SWarner Losh memcpy(seqStorePtr->lit, anchor, lastLLSize); 24080c16b537SWarner Losh seqStorePtr->lit += lastLLSize; 24090c16b537SWarner Losh } 24100c16b537SWarner Losh 2411*0f743729SConrad Meyer void ZSTD_resetSeqStore(seqStore_t* ssPtr) 2412052d3c12SConrad Meyer { 2413052d3c12SConrad Meyer ssPtr->lit = ssPtr->litStart; 2414052d3c12SConrad Meyer ssPtr->sequences = ssPtr->sequencesStart; 2415052d3c12SConrad Meyer ssPtr->longLengthID = 0; 2416052d3c12SConrad Meyer } 2417052d3c12SConrad Meyer 241819fcbaf1SConrad Meyer static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, 241919fcbaf1SConrad Meyer void* dst, size_t dstCapacity, 242019fcbaf1SConrad Meyer const void* src, size_t srcSize) 24210c16b537SWarner Losh { 242219fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &zc->blockState.matchState; 2423*0f743729SConrad Meyer size_t cSize; 2424*0f743729SConrad Meyer DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%zu, dictLimit=%u, nextToUpdate=%u)", 2425*0f743729SConrad Meyer dstCapacity, ms->window.dictLimit, ms->nextToUpdate); 2426*0f743729SConrad Meyer assert(srcSize <= ZSTD_BLOCKSIZE_MAX); 2427*0f743729SConrad Meyer 2428*0f743729SConrad Meyer /* Assert that we have correctly flushed the ctx params into the ms's copy */ 2429*0f743729SConrad Meyer ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams); 2430*0f743729SConrad Meyer 243119fcbaf1SConrad Meyer if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) { 243219fcbaf1SConrad Meyer ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.searchLength); 2433*0f743729SConrad Meyer cSize = 0; 2434*0f743729SConrad Meyer goto out; /* don't even attempt compression below a certain srcSize */ 243519fcbaf1SConrad Meyer } 2436052d3c12SConrad Meyer ZSTD_resetSeqStore(&(zc->seqStore)); 2437*0f743729SConrad Meyer ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy; /* required for optimal parser to read stats from dictionary */ 2438*0f743729SConrad Meyer 2439*0f743729SConrad Meyer /* a gap between an attached dict and the current window is not safe, 2440*0f743729SConrad Meyer * they must remain adjacent, and when that stops being the case, the dict 2441*0f743729SConrad Meyer * must be unset */ 2442*0f743729SConrad Meyer assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit); 2443052d3c12SConrad Meyer 2444052d3c12SConrad Meyer /* limited update after a very long match */ 244519fcbaf1SConrad Meyer { const BYTE* const base = ms->window.base; 24460c16b537SWarner Losh const BYTE* const istart = (const BYTE*)src; 24470c16b537SWarner Losh const U32 current = (U32)(istart-base); 2448*0f743729SConrad Meyer if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1)); /* ensure no overflow */ 244919fcbaf1SConrad Meyer if (current > ms->nextToUpdate + 384) 245019fcbaf1SConrad Meyer ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384)); 2451052d3c12SConrad Meyer } 245219fcbaf1SConrad Meyer 245319fcbaf1SConrad Meyer /* select and store sequences */ 2454*0f743729SConrad Meyer { ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms); 245519fcbaf1SConrad Meyer size_t lastLLSize; 245619fcbaf1SConrad Meyer { int i; 245719fcbaf1SConrad Meyer for (i = 0; i < ZSTD_REP_NUM; ++i) 245819fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i]; 2459052d3c12SConrad Meyer } 246019fcbaf1SConrad Meyer if (zc->externSeqStore.pos < zc->externSeqStore.size) { 246119fcbaf1SConrad Meyer assert(!zc->appliedParams.ldmParams.enableLdm); 246219fcbaf1SConrad Meyer /* Updates ldmSeqStore.pos */ 246319fcbaf1SConrad Meyer lastLLSize = 246419fcbaf1SConrad Meyer ZSTD_ldm_blockCompress(&zc->externSeqStore, 246519fcbaf1SConrad Meyer ms, &zc->seqStore, 246619fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep, 2467*0f743729SConrad Meyer src, srcSize); 246819fcbaf1SConrad Meyer assert(zc->externSeqStore.pos <= zc->externSeqStore.size); 246919fcbaf1SConrad Meyer } else if (zc->appliedParams.ldmParams.enableLdm) { 247019fcbaf1SConrad Meyer rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0}; 247119fcbaf1SConrad Meyer 247219fcbaf1SConrad Meyer ldmSeqStore.seq = zc->ldmSequences; 247319fcbaf1SConrad Meyer ldmSeqStore.capacity = zc->maxNbLdmSequences; 247419fcbaf1SConrad Meyer /* Updates ldmSeqStore.size */ 247519fcbaf1SConrad Meyer CHECK_F(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore, 247619fcbaf1SConrad Meyer &zc->appliedParams.ldmParams, 247719fcbaf1SConrad Meyer src, srcSize)); 247819fcbaf1SConrad Meyer /* Updates ldmSeqStore.pos */ 247919fcbaf1SConrad Meyer lastLLSize = 248019fcbaf1SConrad Meyer ZSTD_ldm_blockCompress(&ldmSeqStore, 248119fcbaf1SConrad Meyer ms, &zc->seqStore, 248219fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep, 2483*0f743729SConrad Meyer src, srcSize); 248419fcbaf1SConrad Meyer assert(ldmSeqStore.pos == ldmSeqStore.size); 248519fcbaf1SConrad Meyer } else { /* not long range mode */ 2486*0f743729SConrad Meyer ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode); 2487*0f743729SConrad Meyer lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize); 248819fcbaf1SConrad Meyer } 248919fcbaf1SConrad Meyer { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; 249019fcbaf1SConrad Meyer ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize); 249119fcbaf1SConrad Meyer } } 249219fcbaf1SConrad Meyer 249319fcbaf1SConrad Meyer /* encode sequences and literals */ 2494*0f743729SConrad Meyer cSize = ZSTD_compressSequences(&zc->seqStore, 249519fcbaf1SConrad Meyer &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, 249619fcbaf1SConrad Meyer &zc->appliedParams, 249719fcbaf1SConrad Meyer dst, dstCapacity, 249819fcbaf1SConrad Meyer srcSize, zc->entropyWorkspace, zc->bmi2); 2499*0f743729SConrad Meyer 2500*0f743729SConrad Meyer out: 2501*0f743729SConrad Meyer if (!ZSTD_isError(cSize) && cSize != 0) { 2502*0f743729SConrad Meyer /* confirm repcodes and entropy tables when emitting a compressed block */ 2503*0f743729SConrad Meyer ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock; 250419fcbaf1SConrad Meyer zc->blockState.prevCBlock = zc->blockState.nextCBlock; 250519fcbaf1SConrad Meyer zc->blockState.nextCBlock = tmp; 250619fcbaf1SConrad Meyer } 2507*0f743729SConrad Meyer /* We check that dictionaries have offset codes available for the first 2508*0f743729SConrad Meyer * block. After the first block, the offcode table might not have large 2509*0f743729SConrad Meyer * enough codes to represent the offsets in the data. 2510*0f743729SConrad Meyer */ 2511*0f743729SConrad Meyer if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid) 2512*0f743729SConrad Meyer zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check; 2513*0f743729SConrad Meyer 251419fcbaf1SConrad Meyer return cSize; 251519fcbaf1SConrad Meyer } 25160c16b537SWarner Losh 25170c16b537SWarner Losh 25180c16b537SWarner Losh /*! ZSTD_compress_frameChunk() : 25190c16b537SWarner Losh * Compress a chunk of data into one or multiple blocks. 25200c16b537SWarner Losh * All blocks will be terminated, all input will be consumed. 25210c16b537SWarner Losh * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content. 25220c16b537SWarner Losh * Frame is supposed already started (header already produced) 25230c16b537SWarner Losh * @return : compressed size, or an error code 25240c16b537SWarner Losh */ 25250c16b537SWarner Losh static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, 25260c16b537SWarner Losh void* dst, size_t dstCapacity, 25270c16b537SWarner Losh const void* src, size_t srcSize, 25280c16b537SWarner Losh U32 lastFrameChunk) 25290c16b537SWarner Losh { 25300c16b537SWarner Losh size_t blockSize = cctx->blockSize; 25310c16b537SWarner Losh size_t remaining = srcSize; 25320c16b537SWarner Losh const BYTE* ip = (const BYTE*)src; 25330c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 25340c16b537SWarner Losh BYTE* op = ostart; 25350c16b537SWarner Losh U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; 2536052d3c12SConrad Meyer assert(cctx->appliedParams.cParams.windowLog <= 31); 25370c16b537SWarner Losh 2538052d3c12SConrad Meyer DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (U32)blockSize); 25390c16b537SWarner Losh if (cctx->appliedParams.fParams.checksumFlag && srcSize) 25400c16b537SWarner Losh XXH64_update(&cctx->xxhState, src, srcSize); 25410c16b537SWarner Losh 25420c16b537SWarner Losh while (remaining) { 254319fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 25440c16b537SWarner Losh U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); 25450c16b537SWarner Losh 25460c16b537SWarner Losh if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) 25470c16b537SWarner Losh return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */ 25480c16b537SWarner Losh if (remaining < blockSize) blockSize = remaining; 25490c16b537SWarner Losh 255019fcbaf1SConrad Meyer if (ZSTD_window_needOverflowCorrection(ms->window, ip + blockSize)) { 255119fcbaf1SConrad Meyer U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy); 255219fcbaf1SConrad Meyer U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); 25530c16b537SWarner Losh ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); 25540c16b537SWarner Losh ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); 25550c16b537SWarner Losh ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); 25560c16b537SWarner Losh ZSTD_reduceIndex(cctx, correction); 255719fcbaf1SConrad Meyer if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; 255819fcbaf1SConrad Meyer else ms->nextToUpdate -= correction; 255919fcbaf1SConrad Meyer ms->loadedDictEnd = 0; 2560*0f743729SConrad Meyer ms->dictMatchState = NULL; 25610c16b537SWarner Losh } 2562*0f743729SConrad Meyer ZSTD_window_enforceMaxDist(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState); 256319fcbaf1SConrad Meyer if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; 25640c16b537SWarner Losh 2565052d3c12SConrad Meyer { size_t cSize = ZSTD_compressBlock_internal(cctx, 2566052d3c12SConrad Meyer op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, 2567052d3c12SConrad Meyer ip, blockSize); 25680c16b537SWarner Losh if (ZSTD_isError(cSize)) return cSize; 25690c16b537SWarner Losh 25700c16b537SWarner Losh if (cSize == 0) { /* block is not compressible */ 2571*0f743729SConrad Meyer cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock); 2572*0f743729SConrad Meyer if (ZSTD_isError(cSize)) return cSize; 25730c16b537SWarner Losh } else { 25740c16b537SWarner Losh U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); 25750c16b537SWarner Losh MEM_writeLE24(op, cBlockHeader24); 25760c16b537SWarner Losh cSize += ZSTD_blockHeaderSize; 25770c16b537SWarner Losh } 25780c16b537SWarner Losh 25790c16b537SWarner Losh ip += blockSize; 2580052d3c12SConrad Meyer assert(remaining >= blockSize); 2581052d3c12SConrad Meyer remaining -= blockSize; 25820c16b537SWarner Losh op += cSize; 2583052d3c12SConrad Meyer assert(dstCapacity >= cSize); 2584052d3c12SConrad Meyer dstCapacity -= cSize; 2585052d3c12SConrad Meyer DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u", 2586052d3c12SConrad Meyer (U32)cSize); 2587052d3c12SConrad Meyer } } 25880c16b537SWarner Losh 25890c16b537SWarner Losh if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending; 25900c16b537SWarner Losh return op-ostart; 25910c16b537SWarner Losh } 25920c16b537SWarner Losh 25930c16b537SWarner Losh 25940c16b537SWarner Losh static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, 25950c16b537SWarner Losh ZSTD_CCtx_params params, U64 pledgedSrcSize, U32 dictID) 25960c16b537SWarner Losh { BYTE* const op = (BYTE*)dst; 25970c16b537SWarner Losh U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */ 25980c16b537SWarner Losh U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */ 25990c16b537SWarner Losh U32 const checksumFlag = params.fParams.checksumFlag>0; 26000c16b537SWarner Losh U32 const windowSize = (U32)1 << params.cParams.windowLog; 26010c16b537SWarner Losh U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize); 26020c16b537SWarner Losh BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3); 26030c16b537SWarner Losh U32 const fcsCode = params.fParams.contentSizeFlag ? 26040c16b537SWarner Losh (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */ 26050c16b537SWarner Losh BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) ); 26060c16b537SWarner Losh size_t pos=0; 26070c16b537SWarner Losh 2608*0f743729SConrad Meyer assert(!(params.fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)); 26090c16b537SWarner Losh if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall); 26100c16b537SWarner Losh DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", 26110c16b537SWarner Losh !params.fParams.noDictIDFlag, dictID, dictIDSizeCode); 26120c16b537SWarner Losh 26130c16b537SWarner Losh if (params.format == ZSTD_f_zstd1) { 26140c16b537SWarner Losh MEM_writeLE32(dst, ZSTD_MAGICNUMBER); 26150c16b537SWarner Losh pos = 4; 26160c16b537SWarner Losh } 26170c16b537SWarner Losh op[pos++] = frameHeaderDecriptionByte; 26180c16b537SWarner Losh if (!singleSegment) op[pos++] = windowLogByte; 26190c16b537SWarner Losh switch(dictIDSizeCode) 26200c16b537SWarner Losh { 26210c16b537SWarner Losh default: assert(0); /* impossible */ 26220c16b537SWarner Losh case 0 : break; 26230c16b537SWarner Losh case 1 : op[pos] = (BYTE)(dictID); pos++; break; 26240c16b537SWarner Losh case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; 26250c16b537SWarner Losh case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break; 26260c16b537SWarner Losh } 26270c16b537SWarner Losh switch(fcsCode) 26280c16b537SWarner Losh { 26290c16b537SWarner Losh default: assert(0); /* impossible */ 26300c16b537SWarner Losh case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; 26310c16b537SWarner Losh case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; 26320c16b537SWarner Losh case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; 26330c16b537SWarner Losh case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break; 26340c16b537SWarner Losh } 26350c16b537SWarner Losh return pos; 26360c16b537SWarner Losh } 26370c16b537SWarner Losh 263819fcbaf1SConrad Meyer /* ZSTD_writeLastEmptyBlock() : 263919fcbaf1SConrad Meyer * output an empty Block with end-of-frame mark to complete a frame 264019fcbaf1SConrad Meyer * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h)) 264119fcbaf1SConrad Meyer * or an error code if `dstCapcity` is too small (<ZSTD_blockHeaderSize) 264219fcbaf1SConrad Meyer */ 264319fcbaf1SConrad Meyer size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) 264419fcbaf1SConrad Meyer { 264519fcbaf1SConrad Meyer if (dstCapacity < ZSTD_blockHeaderSize) return ERROR(dstSize_tooSmall); 264619fcbaf1SConrad Meyer { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */ 264719fcbaf1SConrad Meyer MEM_writeLE24(dst, cBlockHeader24); 264819fcbaf1SConrad Meyer return ZSTD_blockHeaderSize; 264919fcbaf1SConrad Meyer } 265019fcbaf1SConrad Meyer } 265119fcbaf1SConrad Meyer 265219fcbaf1SConrad Meyer size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) 265319fcbaf1SConrad Meyer { 265419fcbaf1SConrad Meyer if (cctx->stage != ZSTDcs_init) 265519fcbaf1SConrad Meyer return ERROR(stage_wrong); 265619fcbaf1SConrad Meyer if (cctx->appliedParams.ldmParams.enableLdm) 265719fcbaf1SConrad Meyer return ERROR(parameter_unsupported); 265819fcbaf1SConrad Meyer cctx->externSeqStore.seq = seq; 265919fcbaf1SConrad Meyer cctx->externSeqStore.size = nbSeq; 266019fcbaf1SConrad Meyer cctx->externSeqStore.capacity = nbSeq; 266119fcbaf1SConrad Meyer cctx->externSeqStore.pos = 0; 266219fcbaf1SConrad Meyer return 0; 266319fcbaf1SConrad Meyer } 266419fcbaf1SConrad Meyer 26650c16b537SWarner Losh 26660c16b537SWarner Losh static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, 26670c16b537SWarner Losh void* dst, size_t dstCapacity, 26680c16b537SWarner Losh const void* src, size_t srcSize, 26690c16b537SWarner Losh U32 frame, U32 lastFrameChunk) 26700c16b537SWarner Losh { 2671*0f743729SConrad Meyer ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 26720c16b537SWarner Losh size_t fhSize = 0; 26730c16b537SWarner Losh 267419fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u", 267519fcbaf1SConrad Meyer cctx->stage, (U32)srcSize); 26760c16b537SWarner Losh if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */ 26770c16b537SWarner Losh 26780c16b537SWarner Losh if (frame && (cctx->stage==ZSTDcs_init)) { 26790c16b537SWarner Losh fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 26800c16b537SWarner Losh cctx->pledgedSrcSizePlusOne-1, cctx->dictID); 26810c16b537SWarner Losh if (ZSTD_isError(fhSize)) return fhSize; 26820c16b537SWarner Losh dstCapacity -= fhSize; 26830c16b537SWarner Losh dst = (char*)dst + fhSize; 26840c16b537SWarner Losh cctx->stage = ZSTDcs_ongoing; 26850c16b537SWarner Losh } 26860c16b537SWarner Losh 2687052d3c12SConrad Meyer if (!srcSize) return fhSize; /* do not generate an empty block if no input */ 2688052d3c12SConrad Meyer 268919fcbaf1SConrad Meyer if (!ZSTD_window_update(&ms->window, src, srcSize)) { 269019fcbaf1SConrad Meyer ms->nextToUpdate = ms->window.dictLimit; 26910c16b537SWarner Losh } 2692*0f743729SConrad Meyer if (cctx->appliedParams.ldmParams.enableLdm) { 269319fcbaf1SConrad Meyer ZSTD_window_update(&cctx->ldmState.window, src, srcSize); 2694*0f743729SConrad Meyer } 2695*0f743729SConrad Meyer 2696*0f743729SConrad Meyer if (!frame) { 2697*0f743729SConrad Meyer /* overflow check and correction for block mode */ 2698*0f743729SConrad Meyer if (ZSTD_window_needOverflowCorrection(ms->window, (const char*)src + srcSize)) { 2699*0f743729SConrad Meyer U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy); 2700*0f743729SConrad Meyer U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, 1 << cctx->appliedParams.cParams.windowLog, src); 2701*0f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); 2702*0f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); 2703*0f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); 2704*0f743729SConrad Meyer ZSTD_reduceIndex(cctx, correction); 2705*0f743729SConrad Meyer if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; 2706*0f743729SConrad Meyer else ms->nextToUpdate -= correction; 2707*0f743729SConrad Meyer ms->loadedDictEnd = 0; 2708*0f743729SConrad Meyer ms->dictMatchState = NULL; 2709*0f743729SConrad Meyer } 2710*0f743729SConrad Meyer } 27110c16b537SWarner Losh 2712052d3c12SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (U32)cctx->blockSize); 2713052d3c12SConrad Meyer { size_t const cSize = frame ? 27140c16b537SWarner Losh ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : 27150c16b537SWarner Losh ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize); 27160c16b537SWarner Losh if (ZSTD_isError(cSize)) return cSize; 27170c16b537SWarner Losh cctx->consumedSrcSize += srcSize; 271819fcbaf1SConrad Meyer cctx->producedCSize += (cSize + fhSize); 2719*0f743729SConrad Meyer assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); 2720*0f743729SConrad Meyer if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ 2721*0f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); 272219fcbaf1SConrad Meyer if (cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne) { 272319fcbaf1SConrad Meyer DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize >= %u", 272419fcbaf1SConrad Meyer (U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize); 272519fcbaf1SConrad Meyer return ERROR(srcSize_wrong); 272619fcbaf1SConrad Meyer } 272719fcbaf1SConrad Meyer } 27280c16b537SWarner Losh return cSize + fhSize; 2729052d3c12SConrad Meyer } 27300c16b537SWarner Losh } 27310c16b537SWarner Losh 27320c16b537SWarner Losh size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, 27330c16b537SWarner Losh void* dst, size_t dstCapacity, 27340c16b537SWarner Losh const void* src, size_t srcSize) 27350c16b537SWarner Losh { 273619fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (U32)srcSize); 27370c16b537SWarner Losh return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */); 27380c16b537SWarner Losh } 27390c16b537SWarner Losh 27400c16b537SWarner Losh 27410c16b537SWarner Losh size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) 27420c16b537SWarner Losh { 274319fcbaf1SConrad Meyer ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams; 274419fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 27450c16b537SWarner Losh return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog); 27460c16b537SWarner Losh } 27470c16b537SWarner Losh 27480c16b537SWarner Losh size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) 27490c16b537SWarner Losh { 27500c16b537SWarner Losh size_t const blockSizeMax = ZSTD_getBlockSize(cctx); 27510c16b537SWarner Losh if (srcSize > blockSizeMax) return ERROR(srcSize_wrong); 2752*0f743729SConrad Meyer 27530c16b537SWarner Losh return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); 27540c16b537SWarner Losh } 27550c16b537SWarner Losh 27560c16b537SWarner Losh /*! ZSTD_loadDictionaryContent() : 27570c16b537SWarner Losh * @return : 0, or an error code 27580c16b537SWarner Losh */ 2759*0f743729SConrad Meyer static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, 2760*0f743729SConrad Meyer ZSTD_CCtx_params const* params, 2761*0f743729SConrad Meyer const void* src, size_t srcSize, 2762*0f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm) 27630c16b537SWarner Losh { 27640c16b537SWarner Losh const BYTE* const ip = (const BYTE*) src; 27650c16b537SWarner Losh const BYTE* const iend = ip + srcSize; 27660c16b537SWarner Losh 276719fcbaf1SConrad Meyer ZSTD_window_update(&ms->window, src, srcSize); 276819fcbaf1SConrad Meyer ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); 27690c16b537SWarner Losh 2770*0f743729SConrad Meyer /* Assert that we the ms params match the params we're being given */ 2771*0f743729SConrad Meyer ZSTD_assertEqualCParams(params->cParams, ms->cParams); 2772*0f743729SConrad Meyer 27730c16b537SWarner Losh if (srcSize <= HASH_READ_SIZE) return 0; 27740c16b537SWarner Losh 277519fcbaf1SConrad Meyer switch(params->cParams.strategy) 27760c16b537SWarner Losh { 27770c16b537SWarner Losh case ZSTD_fast: 2778*0f743729SConrad Meyer ZSTD_fillHashTable(ms, iend, dtlm); 27790c16b537SWarner Losh break; 27800c16b537SWarner Losh case ZSTD_dfast: 2781*0f743729SConrad Meyer ZSTD_fillDoubleHashTable(ms, iend, dtlm); 27820c16b537SWarner Losh break; 27830c16b537SWarner Losh 27840c16b537SWarner Losh case ZSTD_greedy: 27850c16b537SWarner Losh case ZSTD_lazy: 27860c16b537SWarner Losh case ZSTD_lazy2: 27870c16b537SWarner Losh if (srcSize >= HASH_READ_SIZE) 2788*0f743729SConrad Meyer ZSTD_insertAndFindFirstIndex(ms, iend-HASH_READ_SIZE); 27890c16b537SWarner Losh break; 27900c16b537SWarner Losh 279119fcbaf1SConrad Meyer case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ 27920c16b537SWarner Losh case ZSTD_btopt: 27930c16b537SWarner Losh case ZSTD_btultra: 27940c16b537SWarner Losh if (srcSize >= HASH_READ_SIZE) 2795*0f743729SConrad Meyer ZSTD_updateTree(ms, iend-HASH_READ_SIZE, iend); 27960c16b537SWarner Losh break; 27970c16b537SWarner Losh 27980c16b537SWarner Losh default: 27990c16b537SWarner Losh assert(0); /* not possible : not a valid strategy id */ 28000c16b537SWarner Losh } 28010c16b537SWarner Losh 280219fcbaf1SConrad Meyer ms->nextToUpdate = (U32)(iend - ms->window.base); 28030c16b537SWarner Losh return 0; 28040c16b537SWarner Losh } 28050c16b537SWarner Losh 28060c16b537SWarner Losh 28070c16b537SWarner Losh /* Dictionaries that assign zero probability to symbols that show up causes problems 28080c16b537SWarner Losh when FSE encoding. Refuse dictionaries that assign zero probability to symbols 28090c16b537SWarner Losh that we may encounter during compression. 28100c16b537SWarner Losh NOTE: This behavior is not standard and could be improved in the future. */ 28110c16b537SWarner Losh static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) { 28120c16b537SWarner Losh U32 s; 28130c16b537SWarner Losh if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted); 28140c16b537SWarner Losh for (s = 0; s <= maxSymbolValue; ++s) { 28150c16b537SWarner Losh if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted); 28160c16b537SWarner Losh } 28170c16b537SWarner Losh return 0; 28180c16b537SWarner Losh } 28190c16b537SWarner Losh 28200c16b537SWarner Losh 28210c16b537SWarner Losh /* Dictionary format : 28220c16b537SWarner Losh * See : 28230c16b537SWarner Losh * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format 28240c16b537SWarner Losh */ 28250c16b537SWarner Losh /*! ZSTD_loadZstdDictionary() : 282619fcbaf1SConrad Meyer * @return : dictID, or an error code 28270c16b537SWarner Losh * assumptions : magic number supposed already checked 28280c16b537SWarner Losh * dictSize supposed > 8 28290c16b537SWarner Losh */ 2830*0f743729SConrad Meyer static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, 2831*0f743729SConrad Meyer ZSTD_matchState_t* ms, 2832*0f743729SConrad Meyer ZSTD_CCtx_params const* params, 2833*0f743729SConrad Meyer const void* dict, size_t dictSize, 2834*0f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 2835*0f743729SConrad Meyer void* workspace) 28360c16b537SWarner Losh { 28370c16b537SWarner Losh const BYTE* dictPtr = (const BYTE*)dict; 28380c16b537SWarner Losh const BYTE* const dictEnd = dictPtr + dictSize; 28390c16b537SWarner Losh short offcodeNCount[MaxOff+1]; 28400c16b537SWarner Losh unsigned offcodeMaxValue = MaxOff; 284119fcbaf1SConrad Meyer size_t dictID; 28420c16b537SWarner Losh 284319fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 2844*0f743729SConrad Meyer assert(dictSize > 8); 2845*0f743729SConrad Meyer assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY); 28460c16b537SWarner Losh 28470c16b537SWarner Losh dictPtr += 4; /* skip magic number */ 284819fcbaf1SConrad Meyer dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr); 28490c16b537SWarner Losh dictPtr += 4; 28500c16b537SWarner Losh 28510c16b537SWarner Losh { unsigned maxSymbolValue = 255; 2852*0f743729SConrad Meyer size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr); 28530c16b537SWarner Losh if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted); 28540c16b537SWarner Losh if (maxSymbolValue < 255) return ERROR(dictionary_corrupted); 28550c16b537SWarner Losh dictPtr += hufHeaderSize; 28560c16b537SWarner Losh } 28570c16b537SWarner Losh 28580c16b537SWarner Losh { unsigned offcodeLog; 28590c16b537SWarner Losh size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); 28600c16b537SWarner Losh if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); 28610c16b537SWarner Losh if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted); 28620c16b537SWarner Losh /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ 2863*0f743729SConrad Meyer /* fill all offset symbols to avoid garbage at end of table */ 2864*0f743729SConrad Meyer CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.offcodeCTable, offcodeNCount, MaxOff, offcodeLog, workspace, HUF_WORKSPACE_SIZE), 28650c16b537SWarner Losh dictionary_corrupted); 28660c16b537SWarner Losh dictPtr += offcodeHeaderSize; 28670c16b537SWarner Losh } 28680c16b537SWarner Losh 28690c16b537SWarner Losh { short matchlengthNCount[MaxML+1]; 28700c16b537SWarner Losh unsigned matchlengthMaxValue = MaxML, matchlengthLog; 28710c16b537SWarner Losh size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); 28720c16b537SWarner Losh if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted); 28730c16b537SWarner Losh if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted); 28740c16b537SWarner Losh /* Every match length code must have non-zero probability */ 28750c16b537SWarner Losh CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML)); 2876*0f743729SConrad Meyer CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE), 28770c16b537SWarner Losh dictionary_corrupted); 28780c16b537SWarner Losh dictPtr += matchlengthHeaderSize; 28790c16b537SWarner Losh } 28800c16b537SWarner Losh 28810c16b537SWarner Losh { short litlengthNCount[MaxLL+1]; 28820c16b537SWarner Losh unsigned litlengthMaxValue = MaxLL, litlengthLog; 28830c16b537SWarner Losh size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); 28840c16b537SWarner Losh if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted); 28850c16b537SWarner Losh if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted); 28860c16b537SWarner Losh /* Every literal length code must have non-zero probability */ 28870c16b537SWarner Losh CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL)); 2888*0f743729SConrad Meyer CHECK_E( FSE_buildCTable_wksp(bs->entropy.fse.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE), 28890c16b537SWarner Losh dictionary_corrupted); 28900c16b537SWarner Losh dictPtr += litlengthHeaderSize; 28910c16b537SWarner Losh } 28920c16b537SWarner Losh 28930c16b537SWarner Losh if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted); 289419fcbaf1SConrad Meyer bs->rep[0] = MEM_readLE32(dictPtr+0); 289519fcbaf1SConrad Meyer bs->rep[1] = MEM_readLE32(dictPtr+4); 289619fcbaf1SConrad Meyer bs->rep[2] = MEM_readLE32(dictPtr+8); 28970c16b537SWarner Losh dictPtr += 12; 28980c16b537SWarner Losh 28990c16b537SWarner Losh { size_t const dictContentSize = (size_t)(dictEnd - dictPtr); 29000c16b537SWarner Losh U32 offcodeMax = MaxOff; 29010c16b537SWarner Losh if (dictContentSize <= ((U32)-1) - 128 KB) { 29020c16b537SWarner Losh U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ 29030c16b537SWarner Losh offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ 29040c16b537SWarner Losh } 29050c16b537SWarner Losh /* All offset values <= dictContentSize + 128 KB must be representable */ 29060c16b537SWarner Losh CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff))); 29070c16b537SWarner Losh /* All repCodes must be <= dictContentSize and != 0*/ 29080c16b537SWarner Losh { U32 u; 29090c16b537SWarner Losh for (u=0; u<3; u++) { 291019fcbaf1SConrad Meyer if (bs->rep[u] == 0) return ERROR(dictionary_corrupted); 291119fcbaf1SConrad Meyer if (bs->rep[u] > dictContentSize) return ERROR(dictionary_corrupted); 29120c16b537SWarner Losh } } 29130c16b537SWarner Losh 2914*0f743729SConrad Meyer bs->entropy.huf.repeatMode = HUF_repeat_valid; 2915*0f743729SConrad Meyer bs->entropy.fse.offcode_repeatMode = FSE_repeat_valid; 2916*0f743729SConrad Meyer bs->entropy.fse.matchlength_repeatMode = FSE_repeat_valid; 2917*0f743729SConrad Meyer bs->entropy.fse.litlength_repeatMode = FSE_repeat_valid; 2918*0f743729SConrad Meyer CHECK_F(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize, dtlm)); 291919fcbaf1SConrad Meyer return dictID; 29200c16b537SWarner Losh } 29210c16b537SWarner Losh } 29220c16b537SWarner Losh 29230c16b537SWarner Losh /** ZSTD_compress_insertDictionary() : 292419fcbaf1SConrad Meyer * @return : dictID, or an error code */ 2925*0f743729SConrad Meyer static size_t 2926*0f743729SConrad Meyer ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, 2927*0f743729SConrad Meyer ZSTD_matchState_t* ms, 2928*0f743729SConrad Meyer const ZSTD_CCtx_params* params, 29290c16b537SWarner Losh const void* dict, size_t dictSize, 293019fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 2931*0f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 293219fcbaf1SConrad Meyer void* workspace) 29330c16b537SWarner Losh { 2934052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); 29350c16b537SWarner Losh if ((dict==NULL) || (dictSize<=8)) return 0; 29360c16b537SWarner Losh 293719fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(bs); 293819fcbaf1SConrad Meyer 29390c16b537SWarner Losh /* dict restricted modes */ 294019fcbaf1SConrad Meyer if (dictContentType == ZSTD_dct_rawContent) 2941*0f743729SConrad Meyer return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm); 29420c16b537SWarner Losh 29430c16b537SWarner Losh if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { 294419fcbaf1SConrad Meyer if (dictContentType == ZSTD_dct_auto) { 2945052d3c12SConrad Meyer DEBUGLOG(4, "raw content dictionary detected"); 2946*0f743729SConrad Meyer return ZSTD_loadDictionaryContent(ms, params, dict, dictSize, dtlm); 29470c16b537SWarner Losh } 294819fcbaf1SConrad Meyer if (dictContentType == ZSTD_dct_fullDict) 29490c16b537SWarner Losh return ERROR(dictionary_wrong); 29500c16b537SWarner Losh assert(0); /* impossible */ 29510c16b537SWarner Losh } 29520c16b537SWarner Losh 29530c16b537SWarner Losh /* dict as full zstd dictionary */ 2954*0f743729SConrad Meyer return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, dtlm, workspace); 29550c16b537SWarner Losh } 29560c16b537SWarner Losh 29570c16b537SWarner Losh /*! ZSTD_compressBegin_internal() : 29580c16b537SWarner Losh * @return : 0, or an error code */ 2959*0f743729SConrad Meyer static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, 29600c16b537SWarner Losh const void* dict, size_t dictSize, 296119fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 2962*0f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 29630c16b537SWarner Losh const ZSTD_CDict* cdict, 29640c16b537SWarner Losh ZSTD_CCtx_params params, U64 pledgedSrcSize, 29650c16b537SWarner Losh ZSTD_buffered_policy_e zbuff) 29660c16b537SWarner Losh { 2967052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params.cParams.windowLog); 29680c16b537SWarner Losh /* params are supposed to be fully validated at this point */ 29690c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 29700c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 29710c16b537SWarner Losh 29720c16b537SWarner Losh if (cdict && cdict->dictContentSize>0) { 2973*0f743729SConrad Meyer return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff); 29740c16b537SWarner Losh } 29750c16b537SWarner Losh 29760c16b537SWarner Losh CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 29770c16b537SWarner Losh ZSTDcrp_continue, zbuff) ); 297819fcbaf1SConrad Meyer { 297919fcbaf1SConrad Meyer size_t const dictID = ZSTD_compress_insertDictionary( 298019fcbaf1SConrad Meyer cctx->blockState.prevCBlock, &cctx->blockState.matchState, 2981*0f743729SConrad Meyer ¶ms, dict, dictSize, dictContentType, dtlm, cctx->entropyWorkspace); 298219fcbaf1SConrad Meyer if (ZSTD_isError(dictID)) return dictID; 298319fcbaf1SConrad Meyer assert(dictID <= (size_t)(U32)-1); 298419fcbaf1SConrad Meyer cctx->dictID = (U32)dictID; 298519fcbaf1SConrad Meyer } 298619fcbaf1SConrad Meyer return 0; 29870c16b537SWarner Losh } 29880c16b537SWarner Losh 2989052d3c12SConrad Meyer size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, 29900c16b537SWarner Losh const void* dict, size_t dictSize, 299119fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 2992*0f743729SConrad Meyer ZSTD_dictTableLoadMethod_e dtlm, 2993052d3c12SConrad Meyer const ZSTD_CDict* cdict, 29940c16b537SWarner Losh ZSTD_CCtx_params params, 29950c16b537SWarner Losh unsigned long long pledgedSrcSize) 29960c16b537SWarner Losh { 2997052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params.cParams.windowLog); 29980c16b537SWarner Losh /* compression parameters verification and optimization */ 29990c16b537SWarner Losh CHECK_F( ZSTD_checkCParams(params.cParams) ); 3000052d3c12SConrad Meyer return ZSTD_compressBegin_internal(cctx, 3001*0f743729SConrad Meyer dict, dictSize, dictContentType, dtlm, 3002052d3c12SConrad Meyer cdict, 30030c16b537SWarner Losh params, pledgedSrcSize, 30040c16b537SWarner Losh ZSTDb_not_buffered); 30050c16b537SWarner Losh } 30060c16b537SWarner Losh 30070c16b537SWarner Losh /*! ZSTD_compressBegin_advanced() : 30080c16b537SWarner Losh * @return : 0, or an error code */ 30090c16b537SWarner Losh size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, 30100c16b537SWarner Losh const void* dict, size_t dictSize, 30110c16b537SWarner Losh ZSTD_parameters params, unsigned long long pledgedSrcSize) 30120c16b537SWarner Losh { 30130c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 30140c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 3015052d3c12SConrad Meyer return ZSTD_compressBegin_advanced_internal(cctx, 3016*0f743729SConrad Meyer dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, 3017052d3c12SConrad Meyer NULL /*cdict*/, 3018052d3c12SConrad Meyer cctxParams, pledgedSrcSize); 30190c16b537SWarner Losh } 30200c16b537SWarner Losh 30210c16b537SWarner Losh size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) 30220c16b537SWarner Losh { 302319fcbaf1SConrad Meyer ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); 30240c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 30250c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 302619fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (U32)dictSize); 3027*0f743729SConrad Meyer return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, 3028052d3c12SConrad Meyer cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); 30290c16b537SWarner Losh } 30300c16b537SWarner Losh 30310c16b537SWarner Losh size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) 30320c16b537SWarner Losh { 30330c16b537SWarner Losh return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); 30340c16b537SWarner Losh } 30350c16b537SWarner Losh 30360c16b537SWarner Losh 30370c16b537SWarner Losh /*! ZSTD_writeEpilogue() : 30380c16b537SWarner Losh * Ends a frame. 30390c16b537SWarner Losh * @return : nb of bytes written into dst (or an error code) */ 30400c16b537SWarner Losh static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) 30410c16b537SWarner Losh { 30420c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 30430c16b537SWarner Losh BYTE* op = ostart; 30440c16b537SWarner Losh size_t fhSize = 0; 30450c16b537SWarner Losh 304619fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_writeEpilogue"); 30470c16b537SWarner Losh if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */ 30480c16b537SWarner Losh 30490c16b537SWarner Losh /* special case : empty frame */ 30500c16b537SWarner Losh if (cctx->stage == ZSTDcs_init) { 30510c16b537SWarner Losh fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0); 30520c16b537SWarner Losh if (ZSTD_isError(fhSize)) return fhSize; 30530c16b537SWarner Losh dstCapacity -= fhSize; 30540c16b537SWarner Losh op += fhSize; 30550c16b537SWarner Losh cctx->stage = ZSTDcs_ongoing; 30560c16b537SWarner Losh } 30570c16b537SWarner Losh 30580c16b537SWarner Losh if (cctx->stage != ZSTDcs_ending) { 30590c16b537SWarner Losh /* write one last empty block, make it the "last" block */ 30600c16b537SWarner Losh U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0; 30610c16b537SWarner Losh if (dstCapacity<4) return ERROR(dstSize_tooSmall); 30620c16b537SWarner Losh MEM_writeLE32(op, cBlockHeader24); 30630c16b537SWarner Losh op += ZSTD_blockHeaderSize; 30640c16b537SWarner Losh dstCapacity -= ZSTD_blockHeaderSize; 30650c16b537SWarner Losh } 30660c16b537SWarner Losh 30670c16b537SWarner Losh if (cctx->appliedParams.fParams.checksumFlag) { 30680c16b537SWarner Losh U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); 30690c16b537SWarner Losh if (dstCapacity<4) return ERROR(dstSize_tooSmall); 307019fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", checksum); 30710c16b537SWarner Losh MEM_writeLE32(op, checksum); 30720c16b537SWarner Losh op += 4; 30730c16b537SWarner Losh } 30740c16b537SWarner Losh 30750c16b537SWarner Losh cctx->stage = ZSTDcs_created; /* return to "created but no init" status */ 30760c16b537SWarner Losh return op-ostart; 30770c16b537SWarner Losh } 30780c16b537SWarner Losh 30790c16b537SWarner Losh size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, 30800c16b537SWarner Losh void* dst, size_t dstCapacity, 30810c16b537SWarner Losh const void* src, size_t srcSize) 30820c16b537SWarner Losh { 30830c16b537SWarner Losh size_t endResult; 30840c16b537SWarner Losh size_t const cSize = ZSTD_compressContinue_internal(cctx, 30850c16b537SWarner Losh dst, dstCapacity, src, srcSize, 30860c16b537SWarner Losh 1 /* frame mode */, 1 /* last chunk */); 30870c16b537SWarner Losh if (ZSTD_isError(cSize)) return cSize; 30880c16b537SWarner Losh endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); 30890c16b537SWarner Losh if (ZSTD_isError(endResult)) return endResult; 3090*0f743729SConrad Meyer assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0)); 3091*0f743729SConrad Meyer if (cctx->pledgedSrcSizePlusOne != 0) { /* control src size */ 3092*0f743729SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1); 30930c16b537SWarner Losh DEBUGLOG(4, "end of frame : controlling src size"); 30940c16b537SWarner Losh if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) { 30950c16b537SWarner Losh DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize = %u", 30960c16b537SWarner Losh (U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize); 30970c16b537SWarner Losh return ERROR(srcSize_wrong); 30980c16b537SWarner Losh } } 30990c16b537SWarner Losh return cSize + endResult; 31000c16b537SWarner Losh } 31010c16b537SWarner Losh 31020c16b537SWarner Losh 31030c16b537SWarner Losh static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, 31040c16b537SWarner Losh void* dst, size_t dstCapacity, 31050c16b537SWarner Losh const void* src, size_t srcSize, 31060c16b537SWarner Losh const void* dict,size_t dictSize, 31070c16b537SWarner Losh ZSTD_parameters params) 31080c16b537SWarner Losh { 31090c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 31100c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 3111052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_internal"); 31120c16b537SWarner Losh return ZSTD_compress_advanced_internal(cctx, 31130c16b537SWarner Losh dst, dstCapacity, 31140c16b537SWarner Losh src, srcSize, 31150c16b537SWarner Losh dict, dictSize, 31160c16b537SWarner Losh cctxParams); 31170c16b537SWarner Losh } 31180c16b537SWarner Losh 3119*0f743729SConrad Meyer size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx, 31200c16b537SWarner Losh void* dst, size_t dstCapacity, 31210c16b537SWarner Losh const void* src, size_t srcSize, 31220c16b537SWarner Losh const void* dict,size_t dictSize, 31230c16b537SWarner Losh ZSTD_parameters params) 31240c16b537SWarner Losh { 3125052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_advanced"); 31260c16b537SWarner Losh CHECK_F(ZSTD_checkCParams(params.cParams)); 3127*0f743729SConrad Meyer return ZSTD_compress_internal(cctx, 3128*0f743729SConrad Meyer dst, dstCapacity, 3129*0f743729SConrad Meyer src, srcSize, 3130*0f743729SConrad Meyer dict, dictSize, 3131*0f743729SConrad Meyer params); 31320c16b537SWarner Losh } 31330c16b537SWarner Losh 31340c16b537SWarner Losh /* Internal */ 31350c16b537SWarner Losh size_t ZSTD_compress_advanced_internal( 31360c16b537SWarner Losh ZSTD_CCtx* cctx, 31370c16b537SWarner Losh void* dst, size_t dstCapacity, 31380c16b537SWarner Losh const void* src, size_t srcSize, 31390c16b537SWarner Losh const void* dict,size_t dictSize, 31400c16b537SWarner Losh ZSTD_CCtx_params params) 31410c16b537SWarner Losh { 3142*0f743729SConrad Meyer DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (U32)srcSize); 3143*0f743729SConrad Meyer CHECK_F( ZSTD_compressBegin_internal(cctx, 3144*0f743729SConrad Meyer dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL, 31450c16b537SWarner Losh params, srcSize, ZSTDb_not_buffered) ); 31460c16b537SWarner Losh return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 31470c16b537SWarner Losh } 31480c16b537SWarner Losh 3149*0f743729SConrad Meyer size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, 3150*0f743729SConrad Meyer void* dst, size_t dstCapacity, 3151*0f743729SConrad Meyer const void* src, size_t srcSize, 3152*0f743729SConrad Meyer const void* dict, size_t dictSize, 3153*0f743729SConrad Meyer int compressionLevel) 31540c16b537SWarner Losh { 3155*0f743729SConrad Meyer ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize + (!srcSize), dict ? dictSize : 0); 315619fcbaf1SConrad Meyer ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 315719fcbaf1SConrad Meyer assert(params.fParams.contentSizeFlag == 1); 315819fcbaf1SConrad Meyer return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, cctxParams); 31590c16b537SWarner Losh } 31600c16b537SWarner Losh 3161*0f743729SConrad Meyer size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx, 3162*0f743729SConrad Meyer void* dst, size_t dstCapacity, 3163*0f743729SConrad Meyer const void* src, size_t srcSize, 3164*0f743729SConrad Meyer int compressionLevel) 31650c16b537SWarner Losh { 316619fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (U32)srcSize); 3167*0f743729SConrad Meyer assert(cctx != NULL); 316819fcbaf1SConrad Meyer return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel); 31690c16b537SWarner Losh } 31700c16b537SWarner Losh 3171*0f743729SConrad Meyer size_t ZSTD_compress(void* dst, size_t dstCapacity, 3172*0f743729SConrad Meyer const void* src, size_t srcSize, 3173*0f743729SConrad Meyer int compressionLevel) 31740c16b537SWarner Losh { 31750c16b537SWarner Losh size_t result; 31760c16b537SWarner Losh ZSTD_CCtx ctxBody; 3177*0f743729SConrad Meyer ZSTD_initCCtx(&ctxBody, ZSTD_defaultCMem); 31780c16b537SWarner Losh result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); 3179*0f743729SConrad Meyer ZSTD_freeCCtxContent(&ctxBody); /* can't free ctxBody itself, as it's on stack; free only heap content */ 31800c16b537SWarner Losh return result; 31810c16b537SWarner Losh } 31820c16b537SWarner Losh 31830c16b537SWarner Losh 31840c16b537SWarner Losh /* ===== Dictionary API ===== */ 31850c16b537SWarner Losh 31860c16b537SWarner Losh /*! ZSTD_estimateCDictSize_advanced() : 31870c16b537SWarner Losh * Estimate amount of memory that will be needed to create a dictionary with following arguments */ 31880c16b537SWarner Losh size_t ZSTD_estimateCDictSize_advanced( 31890c16b537SWarner Losh size_t dictSize, ZSTD_compressionParameters cParams, 31900c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod) 31910c16b537SWarner Losh { 31920c16b537SWarner Losh DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict)); 319319fcbaf1SConrad Meyer return sizeof(ZSTD_CDict) + HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) 31940c16b537SWarner Losh + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); 31950c16b537SWarner Losh } 31960c16b537SWarner Losh 31970c16b537SWarner Losh size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) 31980c16b537SWarner Losh { 31990c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 32000c16b537SWarner Losh return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); 32010c16b537SWarner Losh } 32020c16b537SWarner Losh 32030c16b537SWarner Losh size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) 32040c16b537SWarner Losh { 32050c16b537SWarner Losh if (cdict==NULL) return 0; /* support sizeof on NULL */ 32060c16b537SWarner Losh DEBUGLOG(5, "sizeof(*cdict) : %u", (U32)sizeof(*cdict)); 320719fcbaf1SConrad Meyer return cdict->workspaceSize + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict); 32080c16b537SWarner Losh } 32090c16b537SWarner Losh 32100c16b537SWarner Losh static size_t ZSTD_initCDict_internal( 32110c16b537SWarner Losh ZSTD_CDict* cdict, 32120c16b537SWarner Losh const void* dictBuffer, size_t dictSize, 32130c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 321419fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 32150c16b537SWarner Losh ZSTD_compressionParameters cParams) 32160c16b537SWarner Losh { 3217*0f743729SConrad Meyer DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (U32)dictContentType); 321819fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 3219*0f743729SConrad Meyer cdict->matchState.cParams = cParams; 32200c16b537SWarner Losh if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { 32210c16b537SWarner Losh cdict->dictBuffer = NULL; 32220c16b537SWarner Losh cdict->dictContent = dictBuffer; 32230c16b537SWarner Losh } else { 322419fcbaf1SConrad Meyer void* const internalBuffer = ZSTD_malloc(dictSize, cdict->customMem); 32250c16b537SWarner Losh cdict->dictBuffer = internalBuffer; 32260c16b537SWarner Losh cdict->dictContent = internalBuffer; 32270c16b537SWarner Losh if (!internalBuffer) return ERROR(memory_allocation); 32280c16b537SWarner Losh memcpy(internalBuffer, dictBuffer, dictSize); 32290c16b537SWarner Losh } 32300c16b537SWarner Losh cdict->dictContentSize = dictSize; 32310c16b537SWarner Losh 323219fcbaf1SConrad Meyer /* Reset the state to no dictionary */ 323319fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(&cdict->cBlockState); 323419fcbaf1SConrad Meyer { void* const end = ZSTD_reset_matchState( 323519fcbaf1SConrad Meyer &cdict->matchState, 323619fcbaf1SConrad Meyer (U32*)cdict->workspace + HUF_WORKSPACE_SIZE_U32, 323719fcbaf1SConrad Meyer &cParams, ZSTDcrp_continue, /* forCCtx */ 0); 323819fcbaf1SConrad Meyer assert(end == (char*)cdict->workspace + cdict->workspaceSize); 323919fcbaf1SConrad Meyer (void)end; 324019fcbaf1SConrad Meyer } 324119fcbaf1SConrad Meyer /* (Maybe) load the dictionary 324219fcbaf1SConrad Meyer * Skips loading the dictionary if it is <= 8 bytes. 324319fcbaf1SConrad Meyer */ 324419fcbaf1SConrad Meyer { ZSTD_CCtx_params params; 324519fcbaf1SConrad Meyer memset(¶ms, 0, sizeof(params)); 324619fcbaf1SConrad Meyer params.compressionLevel = ZSTD_CLEVEL_DEFAULT; 324719fcbaf1SConrad Meyer params.fParams.contentSizeFlag = 1; 324819fcbaf1SConrad Meyer params.cParams = cParams; 324919fcbaf1SConrad Meyer { size_t const dictID = ZSTD_compress_insertDictionary( 325019fcbaf1SConrad Meyer &cdict->cBlockState, &cdict->matchState, ¶ms, 325119fcbaf1SConrad Meyer cdict->dictContent, cdict->dictContentSize, 3252*0f743729SConrad Meyer dictContentType, ZSTD_dtlm_full, cdict->workspace); 325319fcbaf1SConrad Meyer if (ZSTD_isError(dictID)) return dictID; 325419fcbaf1SConrad Meyer assert(dictID <= (size_t)(U32)-1); 325519fcbaf1SConrad Meyer cdict->dictID = (U32)dictID; 325619fcbaf1SConrad Meyer } 32570c16b537SWarner Losh } 32580c16b537SWarner Losh 32590c16b537SWarner Losh return 0; 32600c16b537SWarner Losh } 32610c16b537SWarner Losh 32620c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, 32630c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 326419fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 32650c16b537SWarner Losh ZSTD_compressionParameters cParams, ZSTD_customMem customMem) 32660c16b537SWarner Losh { 326719fcbaf1SConrad Meyer DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (U32)dictContentType); 32680c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 32690c16b537SWarner Losh 32700c16b537SWarner Losh { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); 327119fcbaf1SConrad Meyer size_t const workspaceSize = HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); 327219fcbaf1SConrad Meyer void* const workspace = ZSTD_malloc(workspaceSize, customMem); 32730c16b537SWarner Losh 327419fcbaf1SConrad Meyer if (!cdict || !workspace) { 32750c16b537SWarner Losh ZSTD_free(cdict, customMem); 327619fcbaf1SConrad Meyer ZSTD_free(workspace, customMem); 32770c16b537SWarner Losh return NULL; 32780c16b537SWarner Losh } 327919fcbaf1SConrad Meyer cdict->customMem = customMem; 328019fcbaf1SConrad Meyer cdict->workspace = workspace; 328119fcbaf1SConrad Meyer cdict->workspaceSize = workspaceSize; 32820c16b537SWarner Losh if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 32830c16b537SWarner Losh dictBuffer, dictSize, 328419fcbaf1SConrad Meyer dictLoadMethod, dictContentType, 32850c16b537SWarner Losh cParams) )) { 32860c16b537SWarner Losh ZSTD_freeCDict(cdict); 32870c16b537SWarner Losh return NULL; 32880c16b537SWarner Losh } 32890c16b537SWarner Losh 32900c16b537SWarner Losh return cdict; 32910c16b537SWarner Losh } 32920c16b537SWarner Losh } 32930c16b537SWarner Losh 32940c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) 32950c16b537SWarner Losh { 32960c16b537SWarner Losh ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 32970c16b537SWarner Losh return ZSTD_createCDict_advanced(dict, dictSize, 329819fcbaf1SConrad Meyer ZSTD_dlm_byCopy, ZSTD_dct_auto, 32990c16b537SWarner Losh cParams, ZSTD_defaultCMem); 33000c16b537SWarner Losh } 33010c16b537SWarner Losh 33020c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) 33030c16b537SWarner Losh { 33040c16b537SWarner Losh ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 33050c16b537SWarner Losh return ZSTD_createCDict_advanced(dict, dictSize, 330619fcbaf1SConrad Meyer ZSTD_dlm_byRef, ZSTD_dct_auto, 33070c16b537SWarner Losh cParams, ZSTD_defaultCMem); 33080c16b537SWarner Losh } 33090c16b537SWarner Losh 33100c16b537SWarner Losh size_t ZSTD_freeCDict(ZSTD_CDict* cdict) 33110c16b537SWarner Losh { 33120c16b537SWarner Losh if (cdict==NULL) return 0; /* support free on NULL */ 331319fcbaf1SConrad Meyer { ZSTD_customMem const cMem = cdict->customMem; 331419fcbaf1SConrad Meyer ZSTD_free(cdict->workspace, cMem); 33150c16b537SWarner Losh ZSTD_free(cdict->dictBuffer, cMem); 33160c16b537SWarner Losh ZSTD_free(cdict, cMem); 33170c16b537SWarner Losh return 0; 33180c16b537SWarner Losh } 33190c16b537SWarner Losh } 33200c16b537SWarner Losh 33210c16b537SWarner Losh /*! ZSTD_initStaticCDict_advanced() : 33220c16b537SWarner Losh * Generate a digested dictionary in provided memory area. 33230c16b537SWarner Losh * workspace: The memory area to emplace the dictionary into. 33240c16b537SWarner Losh * Provided pointer must 8-bytes aligned. 33250c16b537SWarner Losh * It must outlive dictionary usage. 33260c16b537SWarner Losh * workspaceSize: Use ZSTD_estimateCDictSize() 33270c16b537SWarner Losh * to determine how large workspace must be. 33280c16b537SWarner Losh * cParams : use ZSTD_getCParams() to transform a compression level 33290c16b537SWarner Losh * into its relevants cParams. 33300c16b537SWarner Losh * @return : pointer to ZSTD_CDict*, or NULL if error (size too small) 33310c16b537SWarner Losh * Note : there is no corresponding "free" function. 33320c16b537SWarner Losh * Since workspace was allocated externally, it must be freed externally. 33330c16b537SWarner Losh */ 333419fcbaf1SConrad Meyer const ZSTD_CDict* ZSTD_initStaticCDict( 333519fcbaf1SConrad Meyer void* workspace, size_t workspaceSize, 33360c16b537SWarner Losh const void* dict, size_t dictSize, 33370c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 333819fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 33390c16b537SWarner Losh ZSTD_compressionParameters cParams) 33400c16b537SWarner Losh { 334119fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); 33420c16b537SWarner Losh size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize) 334319fcbaf1SConrad Meyer + HUF_WORKSPACE_SIZE + matchStateSize; 33440c16b537SWarner Losh ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; 33450c16b537SWarner Losh void* ptr; 33460c16b537SWarner Losh if ((size_t)workspace & 7) return NULL; /* 8-aligned */ 3347052d3c12SConrad Meyer DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u", 33480c16b537SWarner Losh (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize)); 33490c16b537SWarner Losh if (workspaceSize < neededSize) return NULL; 33500c16b537SWarner Losh 33510c16b537SWarner Losh if (dictLoadMethod == ZSTD_dlm_byCopy) { 33520c16b537SWarner Losh memcpy(cdict+1, dict, dictSize); 33530c16b537SWarner Losh dict = cdict+1; 33540c16b537SWarner Losh ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize; 33550c16b537SWarner Losh } else { 33560c16b537SWarner Losh ptr = cdict+1; 33570c16b537SWarner Losh } 335819fcbaf1SConrad Meyer cdict->workspace = ptr; 335919fcbaf1SConrad Meyer cdict->workspaceSize = HUF_WORKSPACE_SIZE + matchStateSize; 33600c16b537SWarner Losh 33610c16b537SWarner Losh if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 33620c16b537SWarner Losh dict, dictSize, 336319fcbaf1SConrad Meyer ZSTD_dlm_byRef, dictContentType, 33640c16b537SWarner Losh cParams) )) 33650c16b537SWarner Losh return NULL; 33660c16b537SWarner Losh 33670c16b537SWarner Losh return cdict; 33680c16b537SWarner Losh } 33690c16b537SWarner Losh 337019fcbaf1SConrad Meyer ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) 337119fcbaf1SConrad Meyer { 337219fcbaf1SConrad Meyer assert(cdict != NULL); 3373*0f743729SConrad Meyer return cdict->matchState.cParams; 33740c16b537SWarner Losh } 33750c16b537SWarner Losh 33760c16b537SWarner Losh /* ZSTD_compressBegin_usingCDict_advanced() : 33770c16b537SWarner Losh * cdict must be != NULL */ 33780c16b537SWarner Losh size_t ZSTD_compressBegin_usingCDict_advanced( 33790c16b537SWarner Losh ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, 33800c16b537SWarner Losh ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) 33810c16b537SWarner Losh { 3382052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced"); 33830c16b537SWarner Losh if (cdict==NULL) return ERROR(dictionary_wrong); 33840c16b537SWarner Losh { ZSTD_CCtx_params params = cctx->requestedParams; 33850c16b537SWarner Losh params.cParams = ZSTD_getCParamsFromCDict(cdict); 338619fcbaf1SConrad Meyer /* Increase window log to fit the entire dictionary and source if the 338719fcbaf1SConrad Meyer * source size is known. Limit the increase to 19, which is the 338819fcbaf1SConrad Meyer * window log for compression level 1 with the largest source size. 338919fcbaf1SConrad Meyer */ 339019fcbaf1SConrad Meyer if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { 339119fcbaf1SConrad Meyer U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); 339219fcbaf1SConrad Meyer U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; 339319fcbaf1SConrad Meyer params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog); 339419fcbaf1SConrad Meyer } 33950c16b537SWarner Losh params.fParams = fParams; 33960c16b537SWarner Losh return ZSTD_compressBegin_internal(cctx, 3397*0f743729SConrad Meyer NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast, 33980c16b537SWarner Losh cdict, 33990c16b537SWarner Losh params, pledgedSrcSize, 34000c16b537SWarner Losh ZSTDb_not_buffered); 34010c16b537SWarner Losh } 34020c16b537SWarner Losh } 34030c16b537SWarner Losh 34040c16b537SWarner Losh /* ZSTD_compressBegin_usingCDict() : 34050c16b537SWarner Losh * pledgedSrcSize=0 means "unknown" 34060c16b537SWarner Losh * if pledgedSrcSize>0, it will enable contentSizeFlag */ 34070c16b537SWarner Losh size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 34080c16b537SWarner Losh { 34090c16b537SWarner Losh ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 3410052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); 3411*0f743729SConrad Meyer return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); 34120c16b537SWarner Losh } 34130c16b537SWarner Losh 34140c16b537SWarner Losh size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, 34150c16b537SWarner Losh void* dst, size_t dstCapacity, 34160c16b537SWarner Losh const void* src, size_t srcSize, 34170c16b537SWarner Losh const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) 34180c16b537SWarner Losh { 34190c16b537SWarner Losh CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */ 34200c16b537SWarner Losh return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 34210c16b537SWarner Losh } 34220c16b537SWarner Losh 34230c16b537SWarner Losh /*! ZSTD_compress_usingCDict() : 34240c16b537SWarner Losh * Compression using a digested Dictionary. 34250c16b537SWarner Losh * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times. 34260c16b537SWarner Losh * Note that compression parameters are decided at CDict creation time 34270c16b537SWarner Losh * while frame parameters are hardcoded */ 34280c16b537SWarner Losh size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, 34290c16b537SWarner Losh void* dst, size_t dstCapacity, 34300c16b537SWarner Losh const void* src, size_t srcSize, 34310c16b537SWarner Losh const ZSTD_CDict* cdict) 34320c16b537SWarner Losh { 34330c16b537SWarner Losh ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 34340c16b537SWarner Losh return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); 34350c16b537SWarner Losh } 34360c16b537SWarner Losh 34370c16b537SWarner Losh 34380c16b537SWarner Losh 34390c16b537SWarner Losh /* ****************************************************************** 34400c16b537SWarner Losh * Streaming 34410c16b537SWarner Losh ********************************************************************/ 34420c16b537SWarner Losh 34430c16b537SWarner Losh ZSTD_CStream* ZSTD_createCStream(void) 34440c16b537SWarner Losh { 3445052d3c12SConrad Meyer DEBUGLOG(3, "ZSTD_createCStream"); 34460c16b537SWarner Losh return ZSTD_createCStream_advanced(ZSTD_defaultCMem); 34470c16b537SWarner Losh } 34480c16b537SWarner Losh 34490c16b537SWarner Losh ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize) 34500c16b537SWarner Losh { 34510c16b537SWarner Losh return ZSTD_initStaticCCtx(workspace, workspaceSize); 34520c16b537SWarner Losh } 34530c16b537SWarner Losh 34540c16b537SWarner Losh ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem) 34550c16b537SWarner Losh { /* CStream and CCtx are now same object */ 34560c16b537SWarner Losh return ZSTD_createCCtx_advanced(customMem); 34570c16b537SWarner Losh } 34580c16b537SWarner Losh 34590c16b537SWarner Losh size_t ZSTD_freeCStream(ZSTD_CStream* zcs) 34600c16b537SWarner Losh { 34610c16b537SWarner Losh return ZSTD_freeCCtx(zcs); /* same object */ 34620c16b537SWarner Losh } 34630c16b537SWarner Losh 34640c16b537SWarner Losh 34650c16b537SWarner Losh 34660c16b537SWarner Losh /*====== Initialization ======*/ 34670c16b537SWarner Losh 34680c16b537SWarner Losh size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; } 34690c16b537SWarner Losh 34700c16b537SWarner Losh size_t ZSTD_CStreamOutSize(void) 34710c16b537SWarner Losh { 34720c16b537SWarner Losh return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; 34730c16b537SWarner Losh } 34740c16b537SWarner Losh 347519fcbaf1SConrad Meyer static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx, 347619fcbaf1SConrad Meyer const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType, 3477052d3c12SConrad Meyer const ZSTD_CDict* const cdict, 3478*0f743729SConrad Meyer ZSTD_CCtx_params params, unsigned long long const pledgedSrcSize) 34790c16b537SWarner Losh { 3480*0f743729SConrad Meyer DEBUGLOG(4, "ZSTD_resetCStream_internal"); 3481*0f743729SConrad Meyer /* Finalize the compression parameters */ 3482*0f743729SConrad Meyer params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, dictSize); 34830c16b537SWarner Losh /* params are supposed to be fully validated at this point */ 34840c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 34850c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 34860c16b537SWarner Losh 348719fcbaf1SConrad Meyer CHECK_F( ZSTD_compressBegin_internal(cctx, 3488*0f743729SConrad Meyer dict, dictSize, dictContentType, ZSTD_dtlm_fast, 34890c16b537SWarner Losh cdict, 34900c16b537SWarner Losh params, pledgedSrcSize, 34910c16b537SWarner Losh ZSTDb_buffered) ); 34920c16b537SWarner Losh 349319fcbaf1SConrad Meyer cctx->inToCompress = 0; 349419fcbaf1SConrad Meyer cctx->inBuffPos = 0; 349519fcbaf1SConrad Meyer cctx->inBuffTarget = cctx->blockSize 349619fcbaf1SConrad 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 */ 349719fcbaf1SConrad Meyer cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; 349819fcbaf1SConrad Meyer cctx->streamStage = zcss_load; 349919fcbaf1SConrad Meyer cctx->frameEnded = 0; 35000c16b537SWarner Losh return 0; /* ready to go */ 35010c16b537SWarner Losh } 35020c16b537SWarner Losh 3503052d3c12SConrad Meyer /* ZSTD_resetCStream(): 3504052d3c12SConrad Meyer * pledgedSrcSize == 0 means "unknown" */ 35050c16b537SWarner Losh size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) 35060c16b537SWarner Losh { 35070c16b537SWarner Losh ZSTD_CCtx_params params = zcs->requestedParams; 3508052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (U32)pledgedSrcSize); 3509052d3c12SConrad Meyer if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; 3510052d3c12SConrad Meyer params.fParams.contentSizeFlag = 1; 351119fcbaf1SConrad Meyer return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize); 35120c16b537SWarner Losh } 35130c16b537SWarner Losh 35140c16b537SWarner Losh /*! ZSTD_initCStream_internal() : 3515052d3c12SConrad Meyer * Note : for lib/compress only. Used by zstdmt_compress.c. 35160c16b537SWarner Losh * Assumption 1 : params are valid 35170c16b537SWarner Losh * Assumption 2 : either dict, or cdict, is defined, not both */ 35180c16b537SWarner Losh size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, 35190c16b537SWarner Losh const void* dict, size_t dictSize, const ZSTD_CDict* cdict, 35200c16b537SWarner Losh ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) 35210c16b537SWarner Losh { 35220c16b537SWarner Losh DEBUGLOG(4, "ZSTD_initCStream_internal"); 3523*0f743729SConrad Meyer params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, dictSize); 35240c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 35250c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 35260c16b537SWarner Losh 35270c16b537SWarner Losh if (dict && dictSize >= 8) { 3528052d3c12SConrad Meyer DEBUGLOG(4, "loading dictionary of size %u", (U32)dictSize); 35290c16b537SWarner Losh if (zcs->staticSize) { /* static CCtx : never uses malloc */ 35300c16b537SWarner Losh /* incompatible with internal cdict creation */ 35310c16b537SWarner Losh return ERROR(memory_allocation); 35320c16b537SWarner Losh } 35330c16b537SWarner Losh ZSTD_freeCDict(zcs->cdictLocal); 35340c16b537SWarner Losh zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 353519fcbaf1SConrad Meyer ZSTD_dlm_byCopy, ZSTD_dct_auto, 35360c16b537SWarner Losh params.cParams, zcs->customMem); 35370c16b537SWarner Losh zcs->cdict = zcs->cdictLocal; 35380c16b537SWarner Losh if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); 35390c16b537SWarner Losh } else { 35400c16b537SWarner Losh if (cdict) { 3541052d3c12SConrad Meyer params.cParams = ZSTD_getCParamsFromCDict(cdict); /* cParams are enforced from cdict; it includes windowLog */ 35420c16b537SWarner Losh } 35430c16b537SWarner Losh ZSTD_freeCDict(zcs->cdictLocal); 35440c16b537SWarner Losh zcs->cdictLocal = NULL; 35450c16b537SWarner Losh zcs->cdict = cdict; 35460c16b537SWarner Losh } 35470c16b537SWarner Losh 354819fcbaf1SConrad Meyer return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize); 35490c16b537SWarner Losh } 35500c16b537SWarner Losh 35510c16b537SWarner Losh /* ZSTD_initCStream_usingCDict_advanced() : 35520c16b537SWarner Losh * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ 35530c16b537SWarner Losh size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, 35540c16b537SWarner Losh const ZSTD_CDict* cdict, 35550c16b537SWarner Losh ZSTD_frameParameters fParams, 35560c16b537SWarner Losh unsigned long long pledgedSrcSize) 3557052d3c12SConrad Meyer { 3558052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced"); 3559052d3c12SConrad Meyer if (!cdict) return ERROR(dictionary_wrong); /* cannot handle NULL cdict (does not know what to do) */ 35600c16b537SWarner Losh { ZSTD_CCtx_params params = zcs->requestedParams; 35610c16b537SWarner Losh params.cParams = ZSTD_getCParamsFromCDict(cdict); 35620c16b537SWarner Losh params.fParams = fParams; 35630c16b537SWarner Losh return ZSTD_initCStream_internal(zcs, 35640c16b537SWarner Losh NULL, 0, cdict, 35650c16b537SWarner Losh params, pledgedSrcSize); 35660c16b537SWarner Losh } 35670c16b537SWarner Losh } 35680c16b537SWarner Losh 35690c16b537SWarner Losh /* note : cdict must outlive compression session */ 35700c16b537SWarner Losh size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict) 35710c16b537SWarner Losh { 3572052d3c12SConrad Meyer ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksum */, 0 /* hideDictID */ }; 3573052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingCDict"); 3574052d3c12SConrad Meyer return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); /* note : will check that cdict != NULL */ 35750c16b537SWarner Losh } 35760c16b537SWarner Losh 357719fcbaf1SConrad Meyer 3578052d3c12SConrad Meyer /* ZSTD_initCStream_advanced() : 357919fcbaf1SConrad Meyer * pledgedSrcSize must be exact. 3580052d3c12SConrad Meyer * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. 3581052d3c12SConrad Meyer * dict is loaded with default parameters ZSTD_dm_auto and ZSTD_dlm_byCopy. */ 35820c16b537SWarner Losh size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, 35830c16b537SWarner Losh const void* dict, size_t dictSize, 35840c16b537SWarner Losh ZSTD_parameters params, unsigned long long pledgedSrcSize) 35850c16b537SWarner Losh { 3586052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_advanced: pledgedSrcSize=%u, flag=%u", 3587052d3c12SConrad Meyer (U32)pledgedSrcSize, params.fParams.contentSizeFlag); 35880c16b537SWarner Losh CHECK_F( ZSTD_checkCParams(params.cParams) ); 3589052d3c12SConrad Meyer if ((pledgedSrcSize==0) && (params.fParams.contentSizeFlag==0)) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* for compatibility with older programs relying on this behavior. Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. This line will be removed in the future. */ 3590*0f743729SConrad Meyer zcs->requestedParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); 3591*0f743729SConrad Meyer return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL /*cdict*/, zcs->requestedParams, pledgedSrcSize); 359219fcbaf1SConrad Meyer } 35930c16b537SWarner Losh 35940c16b537SWarner Losh size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) 35950c16b537SWarner Losh { 3596*0f743729SConrad Meyer ZSTD_CCtxParams_init(&zcs->requestedParams, compressionLevel); 3597*0f743729SConrad Meyer return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, zcs->requestedParams, ZSTD_CONTENTSIZE_UNKNOWN); 35980c16b537SWarner Losh } 35990c16b537SWarner Losh 3600052d3c12SConrad Meyer size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss) 36010c16b537SWarner Losh { 3602052d3c12SConrad Meyer U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; /* temporary : 0 interpreted as "unknown" during transition period. Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. `0` will be interpreted as "empty" in the future */ 3603*0f743729SConrad Meyer ZSTD_CCtxParams_init(&zcs->requestedParams, compressionLevel); 3604*0f743729SConrad Meyer return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, zcs->requestedParams, pledgedSrcSize); 36050c16b537SWarner Losh } 36060c16b537SWarner Losh 36070c16b537SWarner Losh size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) 36080c16b537SWarner Losh { 3609052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream"); 3610052d3c12SConrad Meyer return ZSTD_initCStream_srcSize(zcs, compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN); 36110c16b537SWarner Losh } 36120c16b537SWarner Losh 36130c16b537SWarner Losh /*====== Compression ======*/ 36140c16b537SWarner Losh 36150c16b537SWarner Losh MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, 36160c16b537SWarner Losh const void* src, size_t srcSize) 36170c16b537SWarner Losh { 36180c16b537SWarner Losh size_t const length = MIN(dstCapacity, srcSize); 36190c16b537SWarner Losh if (length) memcpy(dst, src, length); 36200c16b537SWarner Losh return length; 36210c16b537SWarner Losh } 36220c16b537SWarner Losh 36230c16b537SWarner Losh /** ZSTD_compressStream_generic(): 36240c16b537SWarner Losh * internal function for all *compressStream*() variants and *compress_generic() 362519fcbaf1SConrad Meyer * non-static, because can be called from zstdmt_compress.c 36260c16b537SWarner Losh * @return : hint size for next input */ 36270c16b537SWarner Losh size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, 36280c16b537SWarner Losh ZSTD_outBuffer* output, 36290c16b537SWarner Losh ZSTD_inBuffer* input, 36300c16b537SWarner Losh ZSTD_EndDirective const flushMode) 36310c16b537SWarner Losh { 36320c16b537SWarner Losh const char* const istart = (const char*)input->src; 36330c16b537SWarner Losh const char* const iend = istart + input->size; 36340c16b537SWarner Losh const char* ip = istart + input->pos; 36350c16b537SWarner Losh char* const ostart = (char*)output->dst; 36360c16b537SWarner Losh char* const oend = ostart + output->size; 36370c16b537SWarner Losh char* op = ostart + output->pos; 36380c16b537SWarner Losh U32 someMoreWork = 1; 36390c16b537SWarner Losh 36400c16b537SWarner Losh /* check expectations */ 36410c16b537SWarner Losh DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (U32)flushMode); 36420c16b537SWarner Losh assert(zcs->inBuff != NULL); 36430c16b537SWarner Losh assert(zcs->inBuffSize > 0); 36440c16b537SWarner Losh assert(zcs->outBuff != NULL); 36450c16b537SWarner Losh assert(zcs->outBuffSize > 0); 36460c16b537SWarner Losh assert(output->pos <= output->size); 36470c16b537SWarner Losh assert(input->pos <= input->size); 36480c16b537SWarner Losh 36490c16b537SWarner Losh while (someMoreWork) { 36500c16b537SWarner Losh switch(zcs->streamStage) 36510c16b537SWarner Losh { 36520c16b537SWarner Losh case zcss_init: 36530c16b537SWarner Losh /* call ZSTD_initCStream() first ! */ 36540c16b537SWarner Losh return ERROR(init_missing); 36550c16b537SWarner Losh 36560c16b537SWarner Losh case zcss_load: 36570c16b537SWarner Losh if ( (flushMode == ZSTD_e_end) 36580c16b537SWarner Losh && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */ 36590c16b537SWarner Losh && (zcs->inBuffPos == 0) ) { 36600c16b537SWarner Losh /* shortcut to compression pass directly into output buffer */ 36610c16b537SWarner Losh size_t const cSize = ZSTD_compressEnd(zcs, 36620c16b537SWarner Losh op, oend-op, ip, iend-ip); 36630c16b537SWarner Losh DEBUGLOG(4, "ZSTD_compressEnd : %u", (U32)cSize); 36640c16b537SWarner Losh if (ZSTD_isError(cSize)) return cSize; 36650c16b537SWarner Losh ip = iend; 36660c16b537SWarner Losh op += cSize; 36670c16b537SWarner Losh zcs->frameEnded = 1; 3668*0f743729SConrad Meyer ZSTD_CCtx_reset(zcs); 36690c16b537SWarner Losh someMoreWork = 0; break; 36700c16b537SWarner Losh } 36710c16b537SWarner Losh /* complete loading into inBuffer */ 36720c16b537SWarner Losh { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; 36730c16b537SWarner Losh size_t const loaded = ZSTD_limitCopy( 36740c16b537SWarner Losh zcs->inBuff + zcs->inBuffPos, toLoad, 36750c16b537SWarner Losh ip, iend-ip); 36760c16b537SWarner Losh zcs->inBuffPos += loaded; 36770c16b537SWarner Losh ip += loaded; 36780c16b537SWarner Losh if ( (flushMode == ZSTD_e_continue) 36790c16b537SWarner Losh && (zcs->inBuffPos < zcs->inBuffTarget) ) { 36800c16b537SWarner Losh /* not enough input to fill full block : stop here */ 36810c16b537SWarner Losh someMoreWork = 0; break; 36820c16b537SWarner Losh } 36830c16b537SWarner Losh if ( (flushMode == ZSTD_e_flush) 36840c16b537SWarner Losh && (zcs->inBuffPos == zcs->inToCompress) ) { 36850c16b537SWarner Losh /* empty */ 36860c16b537SWarner Losh someMoreWork = 0; break; 36870c16b537SWarner Losh } 36880c16b537SWarner Losh } 36890c16b537SWarner Losh /* compress current block (note : this stage cannot be stopped in the middle) */ 36900c16b537SWarner Losh DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode); 36910c16b537SWarner Losh { void* cDst; 36920c16b537SWarner Losh size_t cSize; 36930c16b537SWarner Losh size_t const iSize = zcs->inBuffPos - zcs->inToCompress; 36940c16b537SWarner Losh size_t oSize = oend-op; 36950c16b537SWarner Losh unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); 36960c16b537SWarner Losh if (oSize >= ZSTD_compressBound(iSize)) 36970c16b537SWarner Losh cDst = op; /* compress into output buffer, to skip flush stage */ 36980c16b537SWarner Losh else 36990c16b537SWarner Losh cDst = zcs->outBuff, oSize = zcs->outBuffSize; 37000c16b537SWarner Losh cSize = lastBlock ? 37010c16b537SWarner Losh ZSTD_compressEnd(zcs, cDst, oSize, 37020c16b537SWarner Losh zcs->inBuff + zcs->inToCompress, iSize) : 37030c16b537SWarner Losh ZSTD_compressContinue(zcs, cDst, oSize, 37040c16b537SWarner Losh zcs->inBuff + zcs->inToCompress, iSize); 37050c16b537SWarner Losh if (ZSTD_isError(cSize)) return cSize; 37060c16b537SWarner Losh zcs->frameEnded = lastBlock; 37070c16b537SWarner Losh /* prepare next block */ 37080c16b537SWarner Losh zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; 37090c16b537SWarner Losh if (zcs->inBuffTarget > zcs->inBuffSize) 37100c16b537SWarner Losh zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; 37110c16b537SWarner Losh DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", 37120c16b537SWarner Losh (U32)zcs->inBuffTarget, (U32)zcs->inBuffSize); 37130c16b537SWarner Losh if (!lastBlock) 37140c16b537SWarner Losh assert(zcs->inBuffTarget <= zcs->inBuffSize); 37150c16b537SWarner Losh zcs->inToCompress = zcs->inBuffPos; 37160c16b537SWarner Losh if (cDst == op) { /* no need to flush */ 37170c16b537SWarner Losh op += cSize; 37180c16b537SWarner Losh if (zcs->frameEnded) { 37190c16b537SWarner Losh DEBUGLOG(5, "Frame completed directly in outBuffer"); 37200c16b537SWarner Losh someMoreWork = 0; 3721*0f743729SConrad Meyer ZSTD_CCtx_reset(zcs); 37220c16b537SWarner Losh } 37230c16b537SWarner Losh break; 37240c16b537SWarner Losh } 37250c16b537SWarner Losh zcs->outBuffContentSize = cSize; 37260c16b537SWarner Losh zcs->outBuffFlushedSize = 0; 37270c16b537SWarner Losh zcs->streamStage = zcss_flush; /* pass-through to flush stage */ 37280c16b537SWarner Losh } 37290c16b537SWarner Losh /* fall-through */ 37300c16b537SWarner Losh case zcss_flush: 37310c16b537SWarner Losh DEBUGLOG(5, "flush stage"); 37320c16b537SWarner Losh { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; 37330c16b537SWarner Losh size_t const flushed = ZSTD_limitCopy(op, oend-op, 37340c16b537SWarner Losh zcs->outBuff + zcs->outBuffFlushedSize, toFlush); 37350c16b537SWarner Losh DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u", 37360c16b537SWarner Losh (U32)toFlush, (U32)(oend-op), (U32)flushed); 37370c16b537SWarner Losh op += flushed; 37380c16b537SWarner Losh zcs->outBuffFlushedSize += flushed; 37390c16b537SWarner Losh if (toFlush!=flushed) { 37400c16b537SWarner Losh /* flush not fully completed, presumably because dst is too small */ 37410c16b537SWarner Losh assert(op==oend); 37420c16b537SWarner Losh someMoreWork = 0; 37430c16b537SWarner Losh break; 37440c16b537SWarner Losh } 37450c16b537SWarner Losh zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; 37460c16b537SWarner Losh if (zcs->frameEnded) { 37470c16b537SWarner Losh DEBUGLOG(5, "Frame completed on flush"); 37480c16b537SWarner Losh someMoreWork = 0; 3749*0f743729SConrad Meyer ZSTD_CCtx_reset(zcs); 37500c16b537SWarner Losh break; 37510c16b537SWarner Losh } 37520c16b537SWarner Losh zcs->streamStage = zcss_load; 37530c16b537SWarner Losh break; 37540c16b537SWarner Losh } 37550c16b537SWarner Losh 37560c16b537SWarner Losh default: /* impossible */ 37570c16b537SWarner Losh assert(0); 37580c16b537SWarner Losh } 37590c16b537SWarner Losh } 37600c16b537SWarner Losh 37610c16b537SWarner Losh input->pos = ip - istart; 37620c16b537SWarner Losh output->pos = op - ostart; 37630c16b537SWarner Losh if (zcs->frameEnded) return 0; 37640c16b537SWarner Losh { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos; 37650c16b537SWarner Losh if (hintInSize==0) hintInSize = zcs->blockSize; 37660c16b537SWarner Losh return hintInSize; 37670c16b537SWarner Losh } 37680c16b537SWarner Losh } 37690c16b537SWarner Losh 37700c16b537SWarner Losh size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) 37710c16b537SWarner Losh { 37720c16b537SWarner Losh /* check conditions */ 37730c16b537SWarner Losh if (output->pos > output->size) return ERROR(GENERIC); 37740c16b537SWarner Losh if (input->pos > input->size) return ERROR(GENERIC); 37750c16b537SWarner Losh 37760c16b537SWarner Losh return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue); 37770c16b537SWarner Losh } 37780c16b537SWarner Losh 37790c16b537SWarner Losh 37800c16b537SWarner Losh size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, 37810c16b537SWarner Losh ZSTD_outBuffer* output, 37820c16b537SWarner Losh ZSTD_inBuffer* input, 37830c16b537SWarner Losh ZSTD_EndDirective endOp) 37840c16b537SWarner Losh { 3785052d3c12SConrad Meyer DEBUGLOG(5, "ZSTD_compress_generic, endOp=%u ", (U32)endOp); 37860c16b537SWarner Losh /* check conditions */ 37870c16b537SWarner Losh if (output->pos > output->size) return ERROR(GENERIC); 37880c16b537SWarner Losh if (input->pos > input->size) return ERROR(GENERIC); 37890c16b537SWarner Losh assert(cctx!=NULL); 37900c16b537SWarner Losh 37910c16b537SWarner Losh /* transparent initialization stage */ 37920c16b537SWarner Losh if (cctx->streamStage == zcss_init) { 37930c16b537SWarner Losh ZSTD_CCtx_params params = cctx->requestedParams; 3794052d3c12SConrad Meyer ZSTD_prefixDict const prefixDict = cctx->prefixDict; 37950c16b537SWarner Losh memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ 37960c16b537SWarner Losh assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ 37970c16b537SWarner Losh DEBUGLOG(4, "ZSTD_compress_generic : transparent init stage"); 3798052d3c12SConrad Meyer if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */ 3799052d3c12SConrad Meyer params.cParams = ZSTD_getCParamsFromCCtxParams( 380019fcbaf1SConrad Meyer &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); 38010c16b537SWarner Losh 3802*0f743729SConrad Meyer 38030c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 380419fcbaf1SConrad Meyer if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { 380519fcbaf1SConrad Meyer params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ 380619fcbaf1SConrad Meyer } 380719fcbaf1SConrad Meyer if (params.nbWorkers > 0) { 380819fcbaf1SConrad Meyer /* mt context creation */ 3809*0f743729SConrad Meyer if (cctx->mtctx == NULL) { 381019fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_compress_generic: creating new mtctx for nbWorkers=%u", 381119fcbaf1SConrad Meyer params.nbWorkers); 381219fcbaf1SConrad Meyer cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbWorkers, cctx->customMem); 38130c16b537SWarner Losh if (cctx->mtctx == NULL) return ERROR(memory_allocation); 38140c16b537SWarner Losh } 381519fcbaf1SConrad Meyer /* mt compression */ 381619fcbaf1SConrad Meyer DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); 38170c16b537SWarner Losh CHECK_F( ZSTDMT_initCStream_internal( 38180c16b537SWarner Losh cctx->mtctx, 381919fcbaf1SConrad Meyer prefixDict.dict, prefixDict.dictSize, ZSTD_dct_rawContent, 38200c16b537SWarner Losh cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); 38210c16b537SWarner Losh cctx->streamStage = zcss_load; 382219fcbaf1SConrad Meyer cctx->appliedParams.nbWorkers = params.nbWorkers; 38230c16b537SWarner Losh } else 38240c16b537SWarner Losh #endif 382519fcbaf1SConrad Meyer { CHECK_F( ZSTD_resetCStream_internal(cctx, 382619fcbaf1SConrad Meyer prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, 382719fcbaf1SConrad Meyer cctx->cdict, 382819fcbaf1SConrad Meyer params, cctx->pledgedSrcSizePlusOne-1) ); 3829052d3c12SConrad Meyer assert(cctx->streamStage == zcss_load); 383019fcbaf1SConrad Meyer assert(cctx->appliedParams.nbWorkers == 0); 38310c16b537SWarner Losh } } 38320c16b537SWarner Losh 38330c16b537SWarner Losh /* compression stage */ 38340c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 383519fcbaf1SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 383619fcbaf1SConrad Meyer if (cctx->cParamsChanged) { 383719fcbaf1SConrad Meyer ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams); 383819fcbaf1SConrad Meyer cctx->cParamsChanged = 0; 383919fcbaf1SConrad Meyer } 384019fcbaf1SConrad Meyer { size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); 38410c16b537SWarner Losh if ( ZSTD_isError(flushMin) 38420c16b537SWarner Losh || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ 3843*0f743729SConrad Meyer ZSTD_CCtx_reset(cctx); 38440c16b537SWarner Losh } 3845*0f743729SConrad Meyer DEBUGLOG(5, "completed ZSTD_compress_generic delegating to ZSTDMT_compressStream_generic"); 38460c16b537SWarner Losh return flushMin; 384719fcbaf1SConrad Meyer } } 38480c16b537SWarner Losh #endif 38490c16b537SWarner Losh CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) ); 38500c16b537SWarner Losh DEBUGLOG(5, "completed ZSTD_compress_generic"); 38510c16b537SWarner Losh return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ 38520c16b537SWarner Losh } 38530c16b537SWarner Losh 38540c16b537SWarner Losh size_t ZSTD_compress_generic_simpleArgs ( 38550c16b537SWarner Losh ZSTD_CCtx* cctx, 38560c16b537SWarner Losh void* dst, size_t dstCapacity, size_t* dstPos, 38570c16b537SWarner Losh const void* src, size_t srcSize, size_t* srcPos, 38580c16b537SWarner Losh ZSTD_EndDirective endOp) 38590c16b537SWarner Losh { 38600c16b537SWarner Losh ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; 38610c16b537SWarner Losh ZSTD_inBuffer input = { src, srcSize, *srcPos }; 38620c16b537SWarner Losh /* ZSTD_compress_generic() will check validity of dstPos and srcPos */ 38630c16b537SWarner Losh size_t const cErr = ZSTD_compress_generic(cctx, &output, &input, endOp); 38640c16b537SWarner Losh *dstPos = output.pos; 38650c16b537SWarner Losh *srcPos = input.pos; 38660c16b537SWarner Losh return cErr; 38670c16b537SWarner Losh } 38680c16b537SWarner Losh 38690c16b537SWarner Losh 38700c16b537SWarner Losh /*====== Finalize ======*/ 38710c16b537SWarner Losh 38720c16b537SWarner Losh /*! ZSTD_flushStream() : 38730c16b537SWarner Losh * @return : amount of data remaining to flush */ 38740c16b537SWarner Losh size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 38750c16b537SWarner Losh { 38760c16b537SWarner Losh ZSTD_inBuffer input = { NULL, 0, 0 }; 38770c16b537SWarner Losh if (output->pos > output->size) return ERROR(GENERIC); 38780c16b537SWarner Losh CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_flush) ); 38790c16b537SWarner Losh return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */ 38800c16b537SWarner Losh } 38810c16b537SWarner Losh 38820c16b537SWarner Losh 38830c16b537SWarner Losh size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 38840c16b537SWarner Losh { 38850c16b537SWarner Losh ZSTD_inBuffer input = { NULL, 0, 0 }; 38860c16b537SWarner Losh if (output->pos > output->size) return ERROR(GENERIC); 38870c16b537SWarner Losh CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_end) ); 38880c16b537SWarner Losh { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; 38890c16b537SWarner Losh size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4; 38900c16b537SWarner Losh size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize + lastBlockSize + checksumSize; 3891052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (U32)toFlush); 38920c16b537SWarner Losh return toFlush; 38930c16b537SWarner Losh } 38940c16b537SWarner Losh } 38950c16b537SWarner Losh 38960c16b537SWarner Losh 38970c16b537SWarner Losh /*-===== Pre-defined compression levels =====-*/ 38980c16b537SWarner Losh 38990c16b537SWarner Losh #define ZSTD_MAX_CLEVEL 22 39000c16b537SWarner Losh int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } 3901*0f743729SConrad Meyer int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; } 39020c16b537SWarner Losh 39030c16b537SWarner Losh static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { 39040c16b537SWarner Losh { /* "default" - guarantees a monotonically increasing memory budget */ 39050c16b537SWarner Losh /* W, C, H, S, L, TL, strat */ 390619fcbaf1SConrad Meyer { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ 3907*0f743729SConrad Meyer { 19, 13, 14, 1, 7, 0, ZSTD_fast }, /* level 1 */ 3908*0f743729SConrad Meyer { 19, 15, 16, 1, 6, 0, ZSTD_fast }, /* level 2 */ 3909*0f743729SConrad Meyer { 20, 16, 17, 1, 5, 1, ZSTD_dfast }, /* level 3 */ 3910*0f743729SConrad Meyer { 20, 18, 18, 1, 5, 1, ZSTD_dfast }, /* level 4 */ 3911*0f743729SConrad Meyer { 20, 18, 18, 2, 5, 2, ZSTD_greedy }, /* level 5 */ 3912*0f743729SConrad Meyer { 21, 18, 19, 2, 5, 4, ZSTD_lazy }, /* level 6 */ 3913*0f743729SConrad Meyer { 21, 18, 19, 3, 5, 8, ZSTD_lazy2 }, /* level 7 */ 3914*0f743729SConrad Meyer { 21, 19, 19, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ 3915*0f743729SConrad Meyer { 21, 19, 20, 4, 5, 16, ZSTD_lazy2 }, /* level 9 */ 3916*0f743729SConrad Meyer { 21, 20, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ 3917*0f743729SConrad Meyer { 21, 21, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ 39180c16b537SWarner Losh { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ 391919fcbaf1SConrad Meyer { 22, 21, 22, 4, 5, 32, ZSTD_btlazy2 }, /* level 13 */ 392019fcbaf1SConrad Meyer { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ 392119fcbaf1SConrad Meyer { 22, 22, 22, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ 3922052d3c12SConrad Meyer { 22, 21, 22, 4, 5, 48, ZSTD_btopt }, /* level 16 */ 3923*0f743729SConrad Meyer { 23, 22, 22, 4, 4, 64, ZSTD_btopt }, /* level 17 */ 3924*0f743729SConrad Meyer { 23, 23, 22, 6, 3,256, ZSTD_btopt }, /* level 18 */ 3925*0f743729SConrad Meyer { 23, 24, 22, 7, 3,256, ZSTD_btultra }, /* level 19 */ 3926*0f743729SConrad Meyer { 25, 25, 23, 7, 3,256, ZSTD_btultra }, /* level 20 */ 3927*0f743729SConrad Meyer { 26, 26, 24, 7, 3,512, ZSTD_btultra }, /* level 21 */ 3928*0f743729SConrad Meyer { 27, 27, 25, 9, 3,999, ZSTD_btultra }, /* level 22 */ 39290c16b537SWarner Losh }, 39300c16b537SWarner Losh { /* for srcSize <= 256 KB */ 39310c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 393219fcbaf1SConrad Meyer { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 3933*0f743729SConrad Meyer { 18, 13, 14, 1, 6, 0, ZSTD_fast }, /* level 1 */ 3934*0f743729SConrad Meyer { 18, 14, 14, 1, 5, 1, ZSTD_dfast }, /* level 2 */ 3935*0f743729SConrad Meyer { 18, 16, 16, 1, 4, 1, ZSTD_dfast }, /* level 3 */ 3936*0f743729SConrad Meyer { 18, 16, 17, 2, 5, 2, ZSTD_greedy }, /* level 4.*/ 3937*0f743729SConrad Meyer { 18, 18, 18, 3, 5, 2, ZSTD_greedy }, /* level 5.*/ 3938*0f743729SConrad Meyer { 18, 18, 19, 3, 5, 4, ZSTD_lazy }, /* level 6.*/ 3939*0f743729SConrad Meyer { 18, 18, 19, 4, 4, 4, ZSTD_lazy }, /* level 7 */ 3940*0f743729SConrad Meyer { 18, 18, 19, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 3941*0f743729SConrad Meyer { 18, 18, 19, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 3942*0f743729SConrad Meyer { 18, 18, 19, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 3943*0f743729SConrad Meyer { 18, 18, 19, 5, 4, 16, ZSTD_btlazy2 }, /* level 11.*/ 3944*0f743729SConrad Meyer { 18, 19, 19, 6, 4, 16, ZSTD_btlazy2 }, /* level 12.*/ 3945*0f743729SConrad Meyer { 18, 19, 19, 8, 4, 16, ZSTD_btlazy2 }, /* level 13 */ 3946*0f743729SConrad Meyer { 18, 18, 19, 4, 4, 24, ZSTD_btopt }, /* level 14.*/ 3947*0f743729SConrad Meyer { 18, 18, 19, 4, 3, 24, ZSTD_btopt }, /* level 15.*/ 3948*0f743729SConrad Meyer { 18, 19, 19, 6, 3, 64, ZSTD_btopt }, /* level 16.*/ 3949*0f743729SConrad Meyer { 18, 19, 19, 8, 3,128, ZSTD_btopt }, /* level 17.*/ 3950*0f743729SConrad Meyer { 18, 19, 19, 10, 3,256, ZSTD_btopt }, /* level 18.*/ 3951*0f743729SConrad Meyer { 18, 19, 19, 10, 3,256, ZSTD_btultra }, /* level 19.*/ 3952*0f743729SConrad Meyer { 18, 19, 19, 11, 3,512, ZSTD_btultra }, /* level 20.*/ 3953*0f743729SConrad Meyer { 18, 19, 19, 12, 3,512, ZSTD_btultra }, /* level 21.*/ 3954*0f743729SConrad Meyer { 18, 19, 19, 13, 3,999, ZSTD_btultra }, /* level 22.*/ 39550c16b537SWarner Losh }, 39560c16b537SWarner Losh { /* for srcSize <= 128 KB */ 39570c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 3958*0f743729SConrad Meyer { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 3959*0f743729SConrad Meyer { 17, 12, 13, 1, 6, 0, ZSTD_fast }, /* level 1 */ 3960*0f743729SConrad Meyer { 17, 13, 15, 1, 5, 0, ZSTD_fast }, /* level 2 */ 3961*0f743729SConrad Meyer { 17, 15, 16, 2, 5, 1, ZSTD_dfast }, /* level 3 */ 3962*0f743729SConrad Meyer { 17, 17, 17, 2, 4, 1, ZSTD_dfast }, /* level 4 */ 3963*0f743729SConrad Meyer { 17, 16, 17, 3, 4, 2, ZSTD_greedy }, /* level 5 */ 3964*0f743729SConrad Meyer { 17, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */ 3965*0f743729SConrad Meyer { 17, 17, 17, 3, 4, 8, ZSTD_lazy2 }, /* level 7 */ 39660c16b537SWarner Losh { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 39670c16b537SWarner Losh { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 39680c16b537SWarner Losh { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 39690c16b537SWarner Losh { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */ 3970*0f743729SConrad Meyer { 17, 18, 17, 6, 4, 16, ZSTD_btlazy2 }, /* level 12 */ 3971*0f743729SConrad Meyer { 17, 18, 17, 8, 4, 16, ZSTD_btlazy2 }, /* level 13.*/ 3972*0f743729SConrad Meyer { 17, 18, 17, 4, 4, 32, ZSTD_btopt }, /* level 14.*/ 3973*0f743729SConrad Meyer { 17, 18, 17, 6, 3, 64, ZSTD_btopt }, /* level 15.*/ 3974*0f743729SConrad Meyer { 17, 18, 17, 7, 3,128, ZSTD_btopt }, /* level 16.*/ 3975*0f743729SConrad Meyer { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 17.*/ 3976*0f743729SConrad Meyer { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 18.*/ 3977*0f743729SConrad Meyer { 17, 18, 17, 8, 3,256, ZSTD_btultra }, /* level 19.*/ 39780c16b537SWarner Losh { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/ 39790c16b537SWarner Losh { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/ 39800c16b537SWarner Losh { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/ 39810c16b537SWarner Losh }, 39820c16b537SWarner Losh { /* for srcSize <= 16 KB */ 39830c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 398419fcbaf1SConrad Meyer { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 3985*0f743729SConrad Meyer { 14, 14, 15, 1, 5, 0, ZSTD_fast }, /* level 1 */ 3986*0f743729SConrad Meyer { 14, 14, 15, 1, 4, 0, ZSTD_fast }, /* level 2 */ 3987*0f743729SConrad Meyer { 14, 14, 14, 2, 4, 1, ZSTD_dfast }, /* level 3.*/ 3988*0f743729SConrad Meyer { 14, 14, 14, 4, 4, 2, ZSTD_greedy }, /* level 4.*/ 3989*0f743729SConrad Meyer { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 5.*/ 3990*0f743729SConrad Meyer { 14, 14, 14, 4, 4, 8, ZSTD_lazy2 }, /* level 6 */ 3991*0f743729SConrad Meyer { 14, 14, 14, 6, 4, 8, ZSTD_lazy2 }, /* level 7 */ 3992*0f743729SConrad Meyer { 14, 14, 14, 8, 4, 8, ZSTD_lazy2 }, /* level 8.*/ 3993*0f743729SConrad Meyer { 14, 15, 14, 5, 4, 8, ZSTD_btlazy2 }, /* level 9.*/ 3994*0f743729SConrad Meyer { 14, 15, 14, 9, 4, 8, ZSTD_btlazy2 }, /* level 10.*/ 3995*0f743729SConrad Meyer { 14, 15, 14, 3, 4, 12, ZSTD_btopt }, /* level 11.*/ 39960c16b537SWarner Losh { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/ 39970c16b537SWarner Losh { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/ 39980c16b537SWarner Losh { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/ 39990c16b537SWarner Losh { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/ 40000c16b537SWarner Losh { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/ 40010c16b537SWarner Losh { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/ 4002*0f743729SConrad Meyer { 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 18.*/ 4003*0f743729SConrad Meyer { 14, 15, 15, 6, 3,256, ZSTD_btultra }, /* level 19.*/ 40040c16b537SWarner Losh { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/ 40050c16b537SWarner Losh { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/ 4006*0f743729SConrad Meyer { 14, 15, 15, 10, 3,512, ZSTD_btultra }, /* level 22.*/ 40070c16b537SWarner Losh }, 40080c16b537SWarner Losh }; 40090c16b537SWarner Losh 40100c16b537SWarner Losh /*! ZSTD_getCParams() : 401119fcbaf1SConrad Meyer * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. 40120c16b537SWarner Losh * Size values are optional, provide 0 if not known or unused */ 40130c16b537SWarner Losh ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) 40140c16b537SWarner Losh { 40150c16b537SWarner Losh size_t const addedSize = srcSizeHint ? 0 : 500; 40160c16b537SWarner Losh U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1; 40170c16b537SWarner Losh U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */ 401819fcbaf1SConrad Meyer int row = compressionLevel; 401919fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_getCParams (cLevel=%i)", compressionLevel); 402019fcbaf1SConrad Meyer if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ 402119fcbaf1SConrad Meyer if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ 402219fcbaf1SConrad Meyer if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; 402319fcbaf1SConrad Meyer { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row]; 402419fcbaf1SConrad Meyer if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */ 40250c16b537SWarner Losh return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); } 40260c16b537SWarner Losh 40270c16b537SWarner Losh } 40280c16b537SWarner Losh 40290c16b537SWarner Losh /*! ZSTD_getParams() : 40300c16b537SWarner Losh * same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`). 40310c16b537SWarner Losh * All fields of `ZSTD_frameParameters` are set to default (0) */ 40320c16b537SWarner Losh ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { 40330c16b537SWarner Losh ZSTD_parameters params; 40340c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize); 403519fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel); 40360c16b537SWarner Losh memset(¶ms, 0, sizeof(params)); 40370c16b537SWarner Losh params.cParams = cParams; 4038052d3c12SConrad Meyer params.fParams.contentSizeFlag = 1; 40390c16b537SWarner Losh return params; 40400c16b537SWarner Losh } 4041