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 /*-************************************* 130c16b537SWarner Losh * Tuning parameters 140c16b537SWarner Losh ***************************************/ 150c16b537SWarner Losh #ifndef ZSTD_CLEVEL_DEFAULT 160c16b537SWarner Losh # define ZSTD_CLEVEL_DEFAULT 3 170c16b537SWarner Losh #endif 180c16b537SWarner Losh 190c16b537SWarner Losh 200c16b537SWarner Losh /*-************************************* 210c16b537SWarner Losh * Dependencies 220c16b537SWarner Losh ***************************************/ 230c16b537SWarner Losh #include <string.h> /* memset */ 24*19fcbaf1SConrad Meyer #include "cpu.h" 250c16b537SWarner Losh #include "mem.h" 260c16b537SWarner Losh #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */ 270c16b537SWarner Losh #include "fse.h" 280c16b537SWarner Losh #define HUF_STATIC_LINKING_ONLY 290c16b537SWarner Losh #include "huf.h" 30052d3c12SConrad Meyer #include "zstd_compress_internal.h" 310c16b537SWarner Losh #include "zstd_fast.h" 320c16b537SWarner Losh #include "zstd_double_fast.h" 330c16b537SWarner Losh #include "zstd_lazy.h" 340c16b537SWarner Losh #include "zstd_opt.h" 350c16b537SWarner Losh #include "zstd_ldm.h" 360c16b537SWarner Losh 370c16b537SWarner Losh 380c16b537SWarner Losh /*-************************************* 390c16b537SWarner Losh * Helper functions 400c16b537SWarner Losh ***************************************/ 410c16b537SWarner Losh size_t ZSTD_compressBound(size_t srcSize) { 420c16b537SWarner Losh return ZSTD_COMPRESSBOUND(srcSize); 430c16b537SWarner Losh } 440c16b537SWarner Losh 450c16b537SWarner Losh 460c16b537SWarner Losh /*-************************************* 470c16b537SWarner Losh * Context memory management 480c16b537SWarner Losh ***************************************/ 490c16b537SWarner Losh struct ZSTD_CDict_s { 500c16b537SWarner Losh void* dictBuffer; 510c16b537SWarner Losh const void* dictContent; 520c16b537SWarner Losh size_t dictContentSize; 53*19fcbaf1SConrad Meyer void* workspace; 54*19fcbaf1SConrad Meyer size_t workspaceSize; 55*19fcbaf1SConrad Meyer ZSTD_matchState_t matchState; 56*19fcbaf1SConrad Meyer ZSTD_compressedBlockState_t cBlockState; 57*19fcbaf1SConrad Meyer ZSTD_compressionParameters cParams; 58*19fcbaf1SConrad Meyer ZSTD_customMem customMem; 59*19fcbaf1SConrad Meyer U32 dictID; 600c16b537SWarner Losh }; /* typedef'd to ZSTD_CDict within "zstd.h" */ 610c16b537SWarner Losh 620c16b537SWarner Losh ZSTD_CCtx* ZSTD_createCCtx(void) 630c16b537SWarner Losh { 640c16b537SWarner Losh return ZSTD_createCCtx_advanced(ZSTD_defaultCMem); 650c16b537SWarner Losh } 660c16b537SWarner Losh 670c16b537SWarner Losh ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) 680c16b537SWarner Losh { 69*19fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(zcss_init==0); 70*19fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1)); 710c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 72*19fcbaf1SConrad Meyer { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_calloc(sizeof(ZSTD_CCtx), customMem); 730c16b537SWarner Losh if (!cctx) return NULL; 740c16b537SWarner Losh cctx->customMem = customMem; 750c16b537SWarner Losh cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; 76052d3c12SConrad Meyer cctx->requestedParams.fParams.contentSizeFlag = 1; 77*19fcbaf1SConrad Meyer cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); 780c16b537SWarner Losh return cctx; 790c16b537SWarner Losh } 80*19fcbaf1SConrad 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 92*19fcbaf1SConrad Meyer /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ 93*19fcbaf1SConrad 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 */ 95*19fcbaf1SConrad Meyer cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)cctx->workSpace; 96*19fcbaf1SConrad Meyer cctx->blockState.nextCBlock = cctx->blockState.prevCBlock + 1; 97*19fcbaf1SConrad Meyer { 98*19fcbaf1SConrad Meyer void* const ptr = cctx->blockState.nextCBlock + 1; 99*19fcbaf1SConrad Meyer cctx->entropyWorkspace = (U32*)ptr; 100*19fcbaf1SConrad Meyer } 101*19fcbaf1SConrad Meyer cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid()); 1020c16b537SWarner Losh return cctx; 1030c16b537SWarner Losh } 1040c16b537SWarner Losh 1050c16b537SWarner Losh size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) 1060c16b537SWarner Losh { 1070c16b537SWarner Losh if (cctx==NULL) return 0; /* support free on NULL */ 1080c16b537SWarner Losh if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */ 109*19fcbaf1SConrad Meyer ZSTD_free(cctx->workSpace, cctx->customMem); cctx->workSpace = NULL; 110*19fcbaf1SConrad Meyer ZSTD_freeCDict(cctx->cdictLocal); cctx->cdictLocal = NULL; 1110c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 112*19fcbaf1SConrad Meyer ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL; 1130c16b537SWarner Losh #endif 1140c16b537SWarner Losh ZSTD_free(cctx, cctx->customMem); 1150c16b537SWarner Losh return 0; /* reserved as a potential error code in the future */ 1160c16b537SWarner Losh } 1170c16b537SWarner Losh 1180c16b537SWarner Losh 1190c16b537SWarner Losh static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx) 1200c16b537SWarner Losh { 1210c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 1220c16b537SWarner Losh return ZSTDMT_sizeof_CCtx(cctx->mtctx); 1230c16b537SWarner Losh #else 1240c16b537SWarner Losh (void) cctx; 1250c16b537SWarner Losh return 0; 1260c16b537SWarner Losh #endif 1270c16b537SWarner Losh } 1280c16b537SWarner Losh 1290c16b537SWarner Losh 1300c16b537SWarner Losh size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) 1310c16b537SWarner Losh { 1320c16b537SWarner Losh if (cctx==NULL) return 0; /* support sizeof on NULL */ 1330c16b537SWarner Losh return sizeof(*cctx) + cctx->workSpaceSize 1340c16b537SWarner Losh + ZSTD_sizeof_CDict(cctx->cdictLocal) 1350c16b537SWarner Losh + ZSTD_sizeof_mtctx(cctx); 1360c16b537SWarner Losh } 1370c16b537SWarner Losh 1380c16b537SWarner Losh size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs) 1390c16b537SWarner Losh { 1400c16b537SWarner Losh return ZSTD_sizeof_CCtx(zcs); /* same object */ 1410c16b537SWarner Losh } 1420c16b537SWarner Losh 1430c16b537SWarner Losh /* private API call, for dictBuilder only */ 1440c16b537SWarner Losh const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); } 1450c16b537SWarner Losh 146*19fcbaf1SConrad Meyer ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams( 147*19fcbaf1SConrad Meyer const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize) 1480c16b537SWarner Losh { 149*19fcbaf1SConrad Meyer ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize); 150*19fcbaf1SConrad Meyer if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG; 151*19fcbaf1SConrad Meyer if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog; 152*19fcbaf1SConrad Meyer if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog; 153*19fcbaf1SConrad Meyer if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog; 154*19fcbaf1SConrad Meyer if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog; 155*19fcbaf1SConrad Meyer if (CCtxParams->cParams.searchLength) cParams.searchLength = CCtxParams->cParams.searchLength; 156*19fcbaf1SConrad Meyer if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength; 157*19fcbaf1SConrad Meyer if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy; 158*19fcbaf1SConrad Meyer return cParams; 1590c16b537SWarner Losh } 1600c16b537SWarner Losh 1610c16b537SWarner Losh static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams( 1620c16b537SWarner Losh ZSTD_compressionParameters cParams) 1630c16b537SWarner Losh { 1640c16b537SWarner Losh ZSTD_CCtx_params cctxParams; 1650c16b537SWarner Losh memset(&cctxParams, 0, sizeof(cctxParams)); 1660c16b537SWarner Losh cctxParams.cParams = cParams; 167*19fcbaf1SConrad Meyer cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 168*19fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 169*19fcbaf1SConrad Meyer cctxParams.fParams.contentSizeFlag = 1; 1700c16b537SWarner Losh return cctxParams; 1710c16b537SWarner Losh } 1720c16b537SWarner Losh 1730c16b537SWarner Losh static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced( 1740c16b537SWarner Losh ZSTD_customMem customMem) 1750c16b537SWarner Losh { 1760c16b537SWarner Losh ZSTD_CCtx_params* params; 1770c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 1780c16b537SWarner Losh params = (ZSTD_CCtx_params*)ZSTD_calloc( 1790c16b537SWarner Losh sizeof(ZSTD_CCtx_params), customMem); 1800c16b537SWarner Losh if (!params) { return NULL; } 1810c16b537SWarner Losh params->customMem = customMem; 1820c16b537SWarner Losh params->compressionLevel = ZSTD_CLEVEL_DEFAULT; 183*19fcbaf1SConrad Meyer params->fParams.contentSizeFlag = 1; 1840c16b537SWarner Losh return params; 1850c16b537SWarner Losh } 1860c16b537SWarner Losh 1870c16b537SWarner Losh ZSTD_CCtx_params* ZSTD_createCCtxParams(void) 1880c16b537SWarner Losh { 1890c16b537SWarner Losh return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem); 1900c16b537SWarner Losh } 1910c16b537SWarner Losh 1920c16b537SWarner Losh size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params) 1930c16b537SWarner Losh { 1940c16b537SWarner Losh if (params == NULL) { return 0; } 1950c16b537SWarner Losh ZSTD_free(params, params->customMem); 1960c16b537SWarner Losh return 0; 1970c16b537SWarner Losh } 1980c16b537SWarner Losh 199*19fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params) 2000c16b537SWarner Losh { 201*19fcbaf1SConrad Meyer return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT); 2020c16b537SWarner Losh } 2030c16b537SWarner Losh 204*19fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) { 2050c16b537SWarner Losh if (!cctxParams) { return ERROR(GENERIC); } 2060c16b537SWarner Losh memset(cctxParams, 0, sizeof(*cctxParams)); 2070c16b537SWarner Losh cctxParams->compressionLevel = compressionLevel; 208*19fcbaf1SConrad Meyer cctxParams->fParams.contentSizeFlag = 1; 2090c16b537SWarner Losh return 0; 2100c16b537SWarner Losh } 2110c16b537SWarner Losh 212*19fcbaf1SConrad Meyer size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params) 2130c16b537SWarner Losh { 2140c16b537SWarner Losh if (!cctxParams) { return ERROR(GENERIC); } 2150c16b537SWarner Losh CHECK_F( ZSTD_checkCParams(params.cParams) ); 2160c16b537SWarner Losh memset(cctxParams, 0, sizeof(*cctxParams)); 2170c16b537SWarner Losh cctxParams->cParams = params.cParams; 2180c16b537SWarner Losh cctxParams->fParams = params.fParams; 219*19fcbaf1SConrad Meyer cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 220*19fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(params.cParams)); 2210c16b537SWarner Losh return 0; 2220c16b537SWarner Losh } 2230c16b537SWarner Losh 224*19fcbaf1SConrad Meyer /* ZSTD_assignParamsToCCtxParams() : 225*19fcbaf1SConrad Meyer * params is presumed valid at this stage */ 2260c16b537SWarner Losh static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams( 2270c16b537SWarner Losh ZSTD_CCtx_params cctxParams, ZSTD_parameters params) 2280c16b537SWarner Losh { 2290c16b537SWarner Losh ZSTD_CCtx_params ret = cctxParams; 2300c16b537SWarner Losh ret.cParams = params.cParams; 2310c16b537SWarner Losh ret.fParams = params.fParams; 232*19fcbaf1SConrad Meyer ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */ 233*19fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(params.cParams)); 2340c16b537SWarner Losh return ret; 2350c16b537SWarner Losh } 2360c16b537SWarner Losh 2370c16b537SWarner Losh #define CLAMPCHECK(val,min,max) { \ 2380c16b537SWarner Losh if (((val)<(min)) | ((val)>(max))) { \ 2390c16b537SWarner Losh return ERROR(parameter_outOfBound); \ 2400c16b537SWarner Losh } } 2410c16b537SWarner Losh 242*19fcbaf1SConrad Meyer 243*19fcbaf1SConrad Meyer static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param) 244*19fcbaf1SConrad Meyer { 245*19fcbaf1SConrad Meyer switch(param) 246*19fcbaf1SConrad Meyer { 247*19fcbaf1SConrad Meyer case ZSTD_p_compressionLevel: 248*19fcbaf1SConrad Meyer case ZSTD_p_hashLog: 249*19fcbaf1SConrad Meyer case ZSTD_p_chainLog: 250*19fcbaf1SConrad Meyer case ZSTD_p_searchLog: 251*19fcbaf1SConrad Meyer case ZSTD_p_minMatch: 252*19fcbaf1SConrad Meyer case ZSTD_p_targetLength: 253*19fcbaf1SConrad Meyer case ZSTD_p_compressionStrategy: 254*19fcbaf1SConrad Meyer case ZSTD_p_compressLiterals: 255*19fcbaf1SConrad Meyer return 1; 256*19fcbaf1SConrad Meyer 257*19fcbaf1SConrad Meyer case ZSTD_p_format: 258*19fcbaf1SConrad Meyer case ZSTD_p_windowLog: 259*19fcbaf1SConrad Meyer case ZSTD_p_contentSizeFlag: 260*19fcbaf1SConrad Meyer case ZSTD_p_checksumFlag: 261*19fcbaf1SConrad Meyer case ZSTD_p_dictIDFlag: 262*19fcbaf1SConrad Meyer case ZSTD_p_forceMaxWindow : 263*19fcbaf1SConrad Meyer case ZSTD_p_nbWorkers: 264*19fcbaf1SConrad Meyer case ZSTD_p_jobSize: 265*19fcbaf1SConrad Meyer case ZSTD_p_overlapSizeLog: 266*19fcbaf1SConrad Meyer case ZSTD_p_enableLongDistanceMatching: 267*19fcbaf1SConrad Meyer case ZSTD_p_ldmHashLog: 268*19fcbaf1SConrad Meyer case ZSTD_p_ldmMinMatch: 269*19fcbaf1SConrad Meyer case ZSTD_p_ldmBucketSizeLog: 270*19fcbaf1SConrad Meyer case ZSTD_p_ldmHashEveryLog: 271*19fcbaf1SConrad Meyer default: 272*19fcbaf1SConrad Meyer return 0; 273*19fcbaf1SConrad Meyer } 274*19fcbaf1SConrad Meyer } 275*19fcbaf1SConrad Meyer 2760c16b537SWarner Losh size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value) 2770c16b537SWarner Losh { 278052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setParameter (%u, %u)", (U32)param, value); 279*19fcbaf1SConrad Meyer if (cctx->streamStage != zcss_init) { 280*19fcbaf1SConrad Meyer if (ZSTD_isUpdateAuthorized(param)) { 281*19fcbaf1SConrad Meyer cctx->cParamsChanged = 1; 282*19fcbaf1SConrad Meyer } else { 283*19fcbaf1SConrad Meyer return ERROR(stage_wrong); 284*19fcbaf1SConrad Meyer } } 2850c16b537SWarner Losh 2860c16b537SWarner Losh switch(param) 2870c16b537SWarner Losh { 2880c16b537SWarner Losh case ZSTD_p_format : 2890c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 2900c16b537SWarner Losh 2910c16b537SWarner Losh case ZSTD_p_compressionLevel: 2920c16b537SWarner Losh if (cctx->cdict) return ERROR(stage_wrong); 2930c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 2940c16b537SWarner Losh 2950c16b537SWarner Losh case ZSTD_p_windowLog: 2960c16b537SWarner Losh case ZSTD_p_hashLog: 2970c16b537SWarner Losh case ZSTD_p_chainLog: 2980c16b537SWarner Losh case ZSTD_p_searchLog: 2990c16b537SWarner Losh case ZSTD_p_minMatch: 3000c16b537SWarner Losh case ZSTD_p_targetLength: 3010c16b537SWarner Losh case ZSTD_p_compressionStrategy: 3020c16b537SWarner Losh if (cctx->cdict) return ERROR(stage_wrong); 3030c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 3040c16b537SWarner Losh 305*19fcbaf1SConrad Meyer case ZSTD_p_compressLiterals: 3060c16b537SWarner Losh case ZSTD_p_contentSizeFlag: 3070c16b537SWarner Losh case ZSTD_p_checksumFlag: 3080c16b537SWarner Losh case ZSTD_p_dictIDFlag: 3090c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 3100c16b537SWarner Losh 3110c16b537SWarner Losh case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize, 312052d3c12SConrad Meyer * even when referencing into Dictionary content. 3130c16b537SWarner Losh * default : 0 when using a CDict, 1 when using a Prefix */ 3140c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 3150c16b537SWarner Losh 316*19fcbaf1SConrad Meyer case ZSTD_p_nbWorkers: 317*19fcbaf1SConrad Meyer if ((value>0) && cctx->staticSize) { 3180c16b537SWarner Losh return ERROR(parameter_unsupported); /* MT not compatible with static alloc */ 3190c16b537SWarner Losh } 3200c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 3210c16b537SWarner Losh 3220c16b537SWarner Losh case ZSTD_p_jobSize: 3230c16b537SWarner Losh case ZSTD_p_overlapSizeLog: 3240c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 3250c16b537SWarner Losh 3260c16b537SWarner Losh case ZSTD_p_enableLongDistanceMatching: 3270c16b537SWarner Losh case ZSTD_p_ldmHashLog: 3280c16b537SWarner Losh case ZSTD_p_ldmMinMatch: 3290c16b537SWarner Losh case ZSTD_p_ldmBucketSizeLog: 3300c16b537SWarner Losh case ZSTD_p_ldmHashEveryLog: 3310c16b537SWarner Losh if (cctx->cdict) return ERROR(stage_wrong); 3320c16b537SWarner Losh return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value); 3330c16b537SWarner Losh 3340c16b537SWarner Losh default: return ERROR(parameter_unsupported); 3350c16b537SWarner Losh } 3360c16b537SWarner Losh } 3370c16b537SWarner Losh 3380c16b537SWarner Losh size_t ZSTD_CCtxParam_setParameter( 339052d3c12SConrad Meyer ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, unsigned value) 3400c16b537SWarner Losh { 341052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtxParam_setParameter (%u, %u)", (U32)param, value); 3420c16b537SWarner Losh switch(param) 3430c16b537SWarner Losh { 3440c16b537SWarner Losh case ZSTD_p_format : 3450c16b537SWarner Losh if (value > (unsigned)ZSTD_f_zstd1_magicless) 3460c16b537SWarner Losh return ERROR(parameter_unsupported); 347052d3c12SConrad Meyer CCtxParams->format = (ZSTD_format_e)value; 348052d3c12SConrad Meyer return (size_t)CCtxParams->format; 3490c16b537SWarner Losh 350*19fcbaf1SConrad Meyer case ZSTD_p_compressionLevel : { 351*19fcbaf1SConrad Meyer int cLevel = (int)value; /* cast expected to restore negative sign */ 352*19fcbaf1SConrad Meyer if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel(); 353*19fcbaf1SConrad Meyer if (cLevel) { /* 0 : does not change current level */ 354*19fcbaf1SConrad Meyer CCtxParams->disableLiteralCompression = (cLevel<0); /* negative levels disable huffman */ 355*19fcbaf1SConrad Meyer CCtxParams->compressionLevel = cLevel; 356*19fcbaf1SConrad Meyer } 357*19fcbaf1SConrad Meyer if (CCtxParams->compressionLevel >= 0) return CCtxParams->compressionLevel; 358*19fcbaf1SConrad Meyer return 0; /* return type (size_t) cannot represent negative values */ 359*19fcbaf1SConrad Meyer } 3600c16b537SWarner Losh 3610c16b537SWarner Losh case ZSTD_p_windowLog : 362*19fcbaf1SConrad Meyer if (value>0) /* 0 => use default */ 3630c16b537SWarner Losh CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); 364052d3c12SConrad Meyer CCtxParams->cParams.windowLog = value; 365052d3c12SConrad Meyer return CCtxParams->cParams.windowLog; 3660c16b537SWarner Losh 3670c16b537SWarner Losh case ZSTD_p_hashLog : 368*19fcbaf1SConrad Meyer if (value>0) /* 0 => use default */ 3690c16b537SWarner Losh CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); 370052d3c12SConrad Meyer CCtxParams->cParams.hashLog = value; 371052d3c12SConrad Meyer return CCtxParams->cParams.hashLog; 3720c16b537SWarner Losh 3730c16b537SWarner Losh case ZSTD_p_chainLog : 374*19fcbaf1SConrad Meyer if (value>0) /* 0 => use default */ 3750c16b537SWarner Losh CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); 376052d3c12SConrad Meyer CCtxParams->cParams.chainLog = value; 377052d3c12SConrad Meyer return CCtxParams->cParams.chainLog; 3780c16b537SWarner Losh 3790c16b537SWarner Losh case ZSTD_p_searchLog : 380*19fcbaf1SConrad Meyer if (value>0) /* 0 => use default */ 3810c16b537SWarner Losh CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); 382052d3c12SConrad Meyer CCtxParams->cParams.searchLog = value; 383052d3c12SConrad Meyer return value; 3840c16b537SWarner Losh 3850c16b537SWarner Losh case ZSTD_p_minMatch : 386*19fcbaf1SConrad Meyer if (value>0) /* 0 => use default */ 3870c16b537SWarner Losh CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); 388052d3c12SConrad Meyer CCtxParams->cParams.searchLength = value; 389052d3c12SConrad Meyer return CCtxParams->cParams.searchLength; 3900c16b537SWarner Losh 3910c16b537SWarner Losh case ZSTD_p_targetLength : 392*19fcbaf1SConrad Meyer /* all values are valid. 0 => use default */ 393052d3c12SConrad Meyer CCtxParams->cParams.targetLength = value; 394052d3c12SConrad Meyer return CCtxParams->cParams.targetLength; 3950c16b537SWarner Losh 3960c16b537SWarner Losh case ZSTD_p_compressionStrategy : 397*19fcbaf1SConrad Meyer if (value>0) /* 0 => use default */ 3980c16b537SWarner Losh CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra); 399052d3c12SConrad Meyer CCtxParams->cParams.strategy = (ZSTD_strategy)value; 400052d3c12SConrad Meyer return (size_t)CCtxParams->cParams.strategy; 4010c16b537SWarner Losh 402*19fcbaf1SConrad Meyer case ZSTD_p_compressLiterals: 403*19fcbaf1SConrad Meyer CCtxParams->disableLiteralCompression = !value; 404*19fcbaf1SConrad Meyer return !CCtxParams->disableLiteralCompression; 405*19fcbaf1SConrad Meyer 4060c16b537SWarner Losh case ZSTD_p_contentSizeFlag : 4070c16b537SWarner Losh /* Content size written in frame header _when known_ (default:1) */ 408052d3c12SConrad Meyer DEBUGLOG(4, "set content size flag = %u", (value>0)); 409052d3c12SConrad Meyer CCtxParams->fParams.contentSizeFlag = value > 0; 410052d3c12SConrad Meyer return CCtxParams->fParams.contentSizeFlag; 4110c16b537SWarner Losh 4120c16b537SWarner Losh case ZSTD_p_checksumFlag : 4130c16b537SWarner Losh /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */ 414052d3c12SConrad Meyer CCtxParams->fParams.checksumFlag = value > 0; 415052d3c12SConrad Meyer return CCtxParams->fParams.checksumFlag; 4160c16b537SWarner Losh 4170c16b537SWarner Losh case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */ 418052d3c12SConrad Meyer DEBUGLOG(4, "set dictIDFlag = %u", (value>0)); 419*19fcbaf1SConrad Meyer CCtxParams->fParams.noDictIDFlag = !value; 420052d3c12SConrad Meyer return !CCtxParams->fParams.noDictIDFlag; 4210c16b537SWarner Losh 4220c16b537SWarner Losh case ZSTD_p_forceMaxWindow : 423052d3c12SConrad Meyer CCtxParams->forceWindow = (value > 0); 424052d3c12SConrad Meyer return CCtxParams->forceWindow; 4250c16b537SWarner Losh 426*19fcbaf1SConrad Meyer case ZSTD_p_nbWorkers : 4270c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 428*19fcbaf1SConrad Meyer if (value>0) return ERROR(parameter_unsupported); 429*19fcbaf1SConrad Meyer return 0; 4300c16b537SWarner Losh #else 431*19fcbaf1SConrad Meyer return ZSTDMT_CCtxParam_setNbWorkers(CCtxParams, value); 4320c16b537SWarner Losh #endif 4330c16b537SWarner Losh 4340c16b537SWarner Losh case ZSTD_p_jobSize : 4350c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 4360c16b537SWarner Losh return ERROR(parameter_unsupported); 4370c16b537SWarner Losh #else 438052d3c12SConrad Meyer return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_jobSize, value); 4390c16b537SWarner Losh #endif 4400c16b537SWarner Losh 4410c16b537SWarner Losh case ZSTD_p_overlapSizeLog : 4420c16b537SWarner Losh #ifndef ZSTD_MULTITHREAD 4430c16b537SWarner Losh return ERROR(parameter_unsupported); 4440c16b537SWarner Losh #else 445052d3c12SConrad Meyer return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_overlapSectionLog, value); 4460c16b537SWarner Losh #endif 4470c16b537SWarner Losh 4480c16b537SWarner Losh case ZSTD_p_enableLongDistanceMatching : 449*19fcbaf1SConrad Meyer CCtxParams->ldmParams.enableLdm = (value>0); 450*19fcbaf1SConrad Meyer return CCtxParams->ldmParams.enableLdm; 4510c16b537SWarner Losh 4520c16b537SWarner Losh case ZSTD_p_ldmHashLog : 453*19fcbaf1SConrad Meyer if (value>0) /* 0 ==> auto */ 4540c16b537SWarner Losh CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); 455052d3c12SConrad Meyer CCtxParams->ldmParams.hashLog = value; 456052d3c12SConrad Meyer return CCtxParams->ldmParams.hashLog; 4570c16b537SWarner Losh 4580c16b537SWarner Losh case ZSTD_p_ldmMinMatch : 459*19fcbaf1SConrad Meyer if (value>0) /* 0 ==> default */ 4600c16b537SWarner Losh CLAMPCHECK(value, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX); 461052d3c12SConrad Meyer CCtxParams->ldmParams.minMatchLength = value; 462052d3c12SConrad Meyer return CCtxParams->ldmParams.minMatchLength; 4630c16b537SWarner Losh 4640c16b537SWarner Losh case ZSTD_p_ldmBucketSizeLog : 465*19fcbaf1SConrad Meyer if (value > ZSTD_LDM_BUCKETSIZELOG_MAX) 4660c16b537SWarner Losh return ERROR(parameter_outOfBound); 467052d3c12SConrad Meyer CCtxParams->ldmParams.bucketSizeLog = value; 468*19fcbaf1SConrad Meyer return CCtxParams->ldmParams.bucketSizeLog; 4690c16b537SWarner Losh 4700c16b537SWarner Losh case ZSTD_p_ldmHashEveryLog : 471*19fcbaf1SConrad Meyer if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN) 4720c16b537SWarner Losh return ERROR(parameter_outOfBound); 473052d3c12SConrad Meyer CCtxParams->ldmParams.hashEveryLog = value; 474*19fcbaf1SConrad Meyer return CCtxParams->ldmParams.hashEveryLog; 4750c16b537SWarner Losh 4760c16b537SWarner Losh default: return ERROR(parameter_unsupported); 4770c16b537SWarner Losh } 4780c16b537SWarner Losh } 4790c16b537SWarner Losh 480052d3c12SConrad Meyer /** ZSTD_CCtx_setParametersUsingCCtxParams() : 481052d3c12SConrad Meyer * just applies `params` into `cctx` 482052d3c12SConrad Meyer * no action is performed, parameters are merely stored. 483*19fcbaf1SConrad Meyer * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx. 484*19fcbaf1SConrad Meyer * This is possible even if a compression is ongoing. 485*19fcbaf1SConrad Meyer * In which case, new parameters will be applied on the fly, starting with next compression job. 4860c16b537SWarner Losh */ 4870c16b537SWarner Losh size_t ZSTD_CCtx_setParametersUsingCCtxParams( 4880c16b537SWarner Losh ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params) 4890c16b537SWarner Losh { 4900c16b537SWarner Losh if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); 4910c16b537SWarner Losh if (cctx->cdict) return ERROR(stage_wrong); 4920c16b537SWarner Losh 493052d3c12SConrad Meyer cctx->requestedParams = *params; 4940c16b537SWarner Losh return 0; 4950c16b537SWarner Losh } 4960c16b537SWarner Losh 4970c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize) 4980c16b537SWarner Losh { 499052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize); 5000c16b537SWarner Losh if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); 5010c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; 5020c16b537SWarner Losh return 0; 5030c16b537SWarner Losh } 5040c16b537SWarner Losh 5050c16b537SWarner Losh size_t ZSTD_CCtx_loadDictionary_advanced( 5060c16b537SWarner Losh ZSTD_CCtx* cctx, const void* dict, size_t dictSize, 507*19fcbaf1SConrad Meyer ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType) 5080c16b537SWarner Losh { 5090c16b537SWarner Losh if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); 5100c16b537SWarner Losh if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */ 511052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize); 5120c16b537SWarner Losh ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */ 5130c16b537SWarner Losh if (dict==NULL || dictSize==0) { /* no dictionary mode */ 5140c16b537SWarner Losh cctx->cdictLocal = NULL; 5150c16b537SWarner Losh cctx->cdict = NULL; 5160c16b537SWarner Losh } else { 5170c16b537SWarner Losh ZSTD_compressionParameters const cParams = 518*19fcbaf1SConrad Meyer ZSTD_getCParamsFromCCtxParams(&cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, dictSize); 5190c16b537SWarner Losh cctx->cdictLocal = ZSTD_createCDict_advanced( 5200c16b537SWarner Losh dict, dictSize, 521*19fcbaf1SConrad Meyer dictLoadMethod, dictContentType, 5220c16b537SWarner Losh cParams, cctx->customMem); 5230c16b537SWarner Losh cctx->cdict = cctx->cdictLocal; 5240c16b537SWarner Losh if (cctx->cdictLocal == NULL) 5250c16b537SWarner Losh return ERROR(memory_allocation); 5260c16b537SWarner Losh } 5270c16b537SWarner Losh return 0; 5280c16b537SWarner Losh } 5290c16b537SWarner Losh 5300c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference( 5310c16b537SWarner Losh ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 5320c16b537SWarner Losh { 5330c16b537SWarner Losh return ZSTD_CCtx_loadDictionary_advanced( 534*19fcbaf1SConrad Meyer cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto); 5350c16b537SWarner Losh } 5360c16b537SWarner Losh 5370c16b537SWarner Losh ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize) 5380c16b537SWarner Losh { 5390c16b537SWarner Losh return ZSTD_CCtx_loadDictionary_advanced( 540*19fcbaf1SConrad Meyer cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto); 5410c16b537SWarner Losh } 5420c16b537SWarner Losh 5430c16b537SWarner Losh 5440c16b537SWarner Losh size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 5450c16b537SWarner Losh { 5460c16b537SWarner Losh if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); 5470c16b537SWarner Losh cctx->cdict = cdict; 5480c16b537SWarner Losh memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* exclusive */ 5490c16b537SWarner Losh return 0; 5500c16b537SWarner Losh } 5510c16b537SWarner Losh 5520c16b537SWarner Losh size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize) 5530c16b537SWarner Losh { 554*19fcbaf1SConrad Meyer return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent); 5550c16b537SWarner Losh } 5560c16b537SWarner Losh 5570c16b537SWarner Losh size_t ZSTD_CCtx_refPrefix_advanced( 558*19fcbaf1SConrad Meyer ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType) 5590c16b537SWarner Losh { 5600c16b537SWarner Losh if (cctx->streamStage != zcss_init) return ERROR(stage_wrong); 5610c16b537SWarner Losh cctx->cdict = NULL; /* prefix discards any prior cdict */ 5620c16b537SWarner Losh cctx->prefixDict.dict = prefix; 5630c16b537SWarner Losh cctx->prefixDict.dictSize = prefixSize; 564*19fcbaf1SConrad Meyer cctx->prefixDict.dictContentType = dictContentType; 5650c16b537SWarner Losh return 0; 5660c16b537SWarner Losh } 5670c16b537SWarner Losh 5680c16b537SWarner Losh static void ZSTD_startNewCompression(ZSTD_CCtx* cctx) 5690c16b537SWarner Losh { 5700c16b537SWarner Losh cctx->streamStage = zcss_init; 5710c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = 0; 5720c16b537SWarner Losh } 5730c16b537SWarner Losh 5740c16b537SWarner Losh /*! ZSTD_CCtx_reset() : 5750c16b537SWarner Losh * Also dumps dictionary */ 5760c16b537SWarner Losh void ZSTD_CCtx_reset(ZSTD_CCtx* cctx) 5770c16b537SWarner Losh { 5780c16b537SWarner Losh ZSTD_startNewCompression(cctx); 5790c16b537SWarner Losh cctx->cdict = NULL; 5800c16b537SWarner Losh } 5810c16b537SWarner Losh 5820c16b537SWarner Losh /** ZSTD_checkCParams() : 5830c16b537SWarner Losh control CParam values remain within authorized range. 5840c16b537SWarner Losh @return : 0, or an error code if one value is beyond authorized range */ 5850c16b537SWarner Losh size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) 5860c16b537SWarner Losh { 5870c16b537SWarner Losh CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); 5880c16b537SWarner Losh CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); 5890c16b537SWarner Losh CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); 5900c16b537SWarner Losh CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); 5910c16b537SWarner Losh CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); 592*19fcbaf1SConrad Meyer if ((U32)(cParams.targetLength) < ZSTD_TARGETLENGTH_MIN) 593*19fcbaf1SConrad Meyer return ERROR(parameter_unsupported); 5940c16b537SWarner Losh if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) 5950c16b537SWarner Losh return ERROR(parameter_unsupported); 5960c16b537SWarner Losh return 0; 5970c16b537SWarner Losh } 5980c16b537SWarner Losh 5990c16b537SWarner Losh /** ZSTD_clampCParams() : 6000c16b537SWarner Losh * make CParam values within valid range. 6010c16b537SWarner Losh * @return : valid CParams */ 6020c16b537SWarner Losh static ZSTD_compressionParameters ZSTD_clampCParams(ZSTD_compressionParameters cParams) 6030c16b537SWarner Losh { 6040c16b537SWarner Losh # define CLAMP(val,min,max) { \ 6050c16b537SWarner Losh if (val<min) val=min; \ 6060c16b537SWarner Losh else if (val>max) val=max; \ 6070c16b537SWarner Losh } 6080c16b537SWarner Losh CLAMP(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); 6090c16b537SWarner Losh CLAMP(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); 6100c16b537SWarner Losh CLAMP(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); 6110c16b537SWarner Losh CLAMP(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); 6120c16b537SWarner Losh CLAMP(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX); 613*19fcbaf1SConrad Meyer if ((U32)(cParams.targetLength) < ZSTD_TARGETLENGTH_MIN) cParams.targetLength = ZSTD_TARGETLENGTH_MIN; 6140c16b537SWarner Losh if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) cParams.strategy = ZSTD_btultra; 6150c16b537SWarner Losh return cParams; 6160c16b537SWarner Losh } 6170c16b537SWarner Losh 6180c16b537SWarner Losh /** ZSTD_cycleLog() : 6190c16b537SWarner Losh * condition for correct operation : hashLog > 1 */ 6200c16b537SWarner Losh static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) 6210c16b537SWarner Losh { 6220c16b537SWarner Losh U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2); 6230c16b537SWarner Losh return hashLog - btScale; 6240c16b537SWarner Losh } 6250c16b537SWarner Losh 6260c16b537SWarner Losh /** ZSTD_adjustCParams_internal() : 6270c16b537SWarner Losh optimize `cPar` for a given input (`srcSize` and `dictSize`). 6280c16b537SWarner Losh mostly downsizing to reduce memory consumption and initialization latency. 6290c16b537SWarner Losh Both `srcSize` and `dictSize` are optional (use 0 if unknown). 6300c16b537SWarner Losh Note : cPar is considered validated at this stage. Use ZSTD_checkCParams() to ensure that condition. */ 6310c16b537SWarner Losh ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize) 6320c16b537SWarner Losh { 6330c16b537SWarner Losh static const U64 minSrcSize = 513; /* (1<<9) + 1 */ 6340c16b537SWarner Losh static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1); 6350c16b537SWarner Losh assert(ZSTD_checkCParams(cPar)==0); 6360c16b537SWarner Losh 6370c16b537SWarner Losh if (dictSize && (srcSize+1<2) /* srcSize unknown */ ) 6380c16b537SWarner Losh srcSize = minSrcSize; /* presumed small when there is a dictionary */ 6390c16b537SWarner Losh else if (srcSize == 0) 6400c16b537SWarner Losh srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */ 6410c16b537SWarner Losh 6420c16b537SWarner Losh /* resize windowLog if input is small enough, to use less memory */ 6430c16b537SWarner Losh if ( (srcSize < maxWindowResize) 6440c16b537SWarner Losh && (dictSize < maxWindowResize) ) { 6450c16b537SWarner Losh U32 const tSize = (U32)(srcSize + dictSize); 6460c16b537SWarner Losh static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN; 6470c16b537SWarner Losh U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN : 6480c16b537SWarner Losh ZSTD_highbit32(tSize-1) + 1; 6490c16b537SWarner Losh if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; 6500c16b537SWarner Losh } 6510c16b537SWarner Losh if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog; 6520c16b537SWarner Losh { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); 6530c16b537SWarner Losh if (cycleLog > cPar.windowLog) 6540c16b537SWarner Losh cPar.chainLog -= (cycleLog - cPar.windowLog); 6550c16b537SWarner Losh } 6560c16b537SWarner Losh 6570c16b537SWarner Losh if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) 6580c16b537SWarner Losh cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ 6590c16b537SWarner Losh 6600c16b537SWarner Losh return cPar; 6610c16b537SWarner Losh } 6620c16b537SWarner Losh 6630c16b537SWarner Losh ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize) 6640c16b537SWarner Losh { 6650c16b537SWarner Losh cPar = ZSTD_clampCParams(cPar); 6660c16b537SWarner Losh return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize); 6670c16b537SWarner Losh } 6680c16b537SWarner Losh 669*19fcbaf1SConrad Meyer static size_t ZSTD_sizeof_matchState(ZSTD_compressionParameters const* cParams, const U32 forCCtx) 670*19fcbaf1SConrad Meyer { 671*19fcbaf1SConrad Meyer size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); 672*19fcbaf1SConrad Meyer size_t const hSize = ((size_t)1) << cParams->hashLog; 673*19fcbaf1SConrad Meyer U32 const hashLog3 = (forCCtx && cParams->searchLength==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 674*19fcbaf1SConrad Meyer size_t const h3Size = ((size_t)1) << hashLog3; 675*19fcbaf1SConrad Meyer size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 676*19fcbaf1SConrad Meyer size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32) 677*19fcbaf1SConrad Meyer + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t)); 678*19fcbaf1SConrad Meyer size_t const optSpace = (forCCtx && ((cParams->strategy == ZSTD_btopt) || 679*19fcbaf1SConrad Meyer (cParams->strategy == ZSTD_btultra))) 680*19fcbaf1SConrad Meyer ? optPotentialSpace 681*19fcbaf1SConrad Meyer : 0; 682*19fcbaf1SConrad Meyer DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u", 683*19fcbaf1SConrad Meyer (U32)chainSize, (U32)hSize, (U32)h3Size); 684*19fcbaf1SConrad Meyer return tableSpace + optSpace; 685*19fcbaf1SConrad Meyer } 686*19fcbaf1SConrad Meyer 6870c16b537SWarner Losh size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params) 6880c16b537SWarner Losh { 6890c16b537SWarner Losh /* Estimate CCtx size is supported for single-threaded compression only. */ 690*19fcbaf1SConrad Meyer if (params->nbWorkers > 0) { return ERROR(GENERIC); } 6910c16b537SWarner Losh { ZSTD_compressionParameters const cParams = 692*19fcbaf1SConrad Meyer ZSTD_getCParamsFromCCtxParams(params, 0, 0); 6930c16b537SWarner Losh size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog); 6940c16b537SWarner Losh U32 const divider = (cParams.searchLength==3) ? 3 : 4; 6950c16b537SWarner Losh size_t const maxNbSeq = blockSize / divider; 6960c16b537SWarner Losh size_t const tokenSpace = blockSize + 11*maxNbSeq; 697*19fcbaf1SConrad Meyer size_t const entropySpace = HUF_WORKSPACE_SIZE; 698*19fcbaf1SConrad Meyer size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t); 699*19fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1); 7000c16b537SWarner Losh 701*19fcbaf1SConrad Meyer size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams); 702*19fcbaf1SConrad Meyer size_t const ldmSeqSpace = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq); 7030c16b537SWarner Losh 704*19fcbaf1SConrad Meyer size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace + 705*19fcbaf1SConrad Meyer matchStateSize + ldmSpace + ldmSeqSpace; 7060c16b537SWarner Losh 7070c16b537SWarner Losh DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx)); 7080c16b537SWarner Losh DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace); 7090c16b537SWarner Losh return sizeof(ZSTD_CCtx) + neededSpace; 7100c16b537SWarner Losh } 7110c16b537SWarner Losh } 7120c16b537SWarner Losh 7130c16b537SWarner Losh size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams) 7140c16b537SWarner Losh { 7150c16b537SWarner Losh ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); 7160c16b537SWarner Losh return ZSTD_estimateCCtxSize_usingCCtxParams(¶ms); 7170c16b537SWarner Losh } 7180c16b537SWarner Losh 719*19fcbaf1SConrad Meyer static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel) 7200c16b537SWarner Losh { 7210c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); 7220c16b537SWarner Losh return ZSTD_estimateCCtxSize_usingCParams(cParams); 7230c16b537SWarner Losh } 7240c16b537SWarner Losh 725*19fcbaf1SConrad Meyer size_t ZSTD_estimateCCtxSize(int compressionLevel) 726*19fcbaf1SConrad Meyer { 727*19fcbaf1SConrad Meyer int level; 728*19fcbaf1SConrad Meyer size_t memBudget = 0; 729*19fcbaf1SConrad Meyer for (level=1; level<=compressionLevel; level++) { 730*19fcbaf1SConrad Meyer size_t const newMB = ZSTD_estimateCCtxSize_internal(level); 731*19fcbaf1SConrad Meyer if (newMB > memBudget) memBudget = newMB; 732*19fcbaf1SConrad Meyer } 733*19fcbaf1SConrad Meyer return memBudget; 734*19fcbaf1SConrad Meyer } 735*19fcbaf1SConrad Meyer 7360c16b537SWarner Losh size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params) 7370c16b537SWarner Losh { 738*19fcbaf1SConrad Meyer if (params->nbWorkers > 0) { return ERROR(GENERIC); } 7390c16b537SWarner Losh { size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params); 7400c16b537SWarner Losh size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog); 7410c16b537SWarner Losh size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize; 7420c16b537SWarner Losh size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1; 7430c16b537SWarner Losh size_t const streamingSize = inBuffSize + outBuffSize; 7440c16b537SWarner Losh 7450c16b537SWarner Losh return CCtxSize + streamingSize; 7460c16b537SWarner Losh } 7470c16b537SWarner Losh } 7480c16b537SWarner Losh 7490c16b537SWarner Losh size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams) 7500c16b537SWarner Losh { 7510c16b537SWarner Losh ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams); 7520c16b537SWarner Losh return ZSTD_estimateCStreamSize_usingCCtxParams(¶ms); 7530c16b537SWarner Losh } 7540c16b537SWarner Losh 755*19fcbaf1SConrad Meyer static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) { 7560c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0); 7570c16b537SWarner Losh return ZSTD_estimateCStreamSize_usingCParams(cParams); 7580c16b537SWarner Losh } 7590c16b537SWarner Losh 760*19fcbaf1SConrad Meyer size_t ZSTD_estimateCStreamSize(int compressionLevel) { 761*19fcbaf1SConrad Meyer int level; 762*19fcbaf1SConrad Meyer size_t memBudget = 0; 763*19fcbaf1SConrad Meyer for (level=1; level<=compressionLevel; level++) { 764*19fcbaf1SConrad Meyer size_t const newMB = ZSTD_estimateCStreamSize_internal(level); 765*19fcbaf1SConrad Meyer if (newMB > memBudget) memBudget = newMB; 766*19fcbaf1SConrad Meyer } 767*19fcbaf1SConrad Meyer return memBudget; 768*19fcbaf1SConrad Meyer } 769*19fcbaf1SConrad Meyer 770*19fcbaf1SConrad Meyer /* ZSTD_getFrameProgression(): 771*19fcbaf1SConrad Meyer * tells how much data has been consumed (input) and produced (output) for current frame. 772*19fcbaf1SConrad Meyer * able to count progression inside worker threads (non-blocking mode). 773*19fcbaf1SConrad Meyer */ 774*19fcbaf1SConrad Meyer ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx) 775*19fcbaf1SConrad Meyer { 776*19fcbaf1SConrad Meyer #ifdef ZSTD_MULTITHREAD 777*19fcbaf1SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 778*19fcbaf1SConrad Meyer return ZSTDMT_getFrameProgression(cctx->mtctx); 779*19fcbaf1SConrad Meyer } 780*19fcbaf1SConrad Meyer #endif 781*19fcbaf1SConrad Meyer { ZSTD_frameProgression fp; 782*19fcbaf1SConrad Meyer size_t const buffered = (cctx->inBuff == NULL) ? 0 : 783*19fcbaf1SConrad Meyer cctx->inBuffPos - cctx->inToCompress; 784*19fcbaf1SConrad Meyer if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress); 785*19fcbaf1SConrad Meyer assert(buffered <= ZSTD_BLOCKSIZE_MAX); 786*19fcbaf1SConrad Meyer fp.ingested = cctx->consumedSrcSize + buffered; 787*19fcbaf1SConrad Meyer fp.consumed = cctx->consumedSrcSize; 788*19fcbaf1SConrad Meyer fp.produced = cctx->producedCSize; 789*19fcbaf1SConrad Meyer return fp; 790*19fcbaf1SConrad Meyer } } 791*19fcbaf1SConrad Meyer 792*19fcbaf1SConrad Meyer 7930c16b537SWarner Losh static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1, 7940c16b537SWarner Losh ZSTD_compressionParameters cParams2) 7950c16b537SWarner Losh { 796052d3c12SConrad Meyer return (cParams1.hashLog == cParams2.hashLog) 7970c16b537SWarner Losh & (cParams1.chainLog == cParams2.chainLog) 7980c16b537SWarner Losh & (cParams1.strategy == cParams2.strategy) /* opt parser space */ 7990c16b537SWarner Losh & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */ 8000c16b537SWarner Losh } 8010c16b537SWarner Losh 8020c16b537SWarner Losh /** The parameters are equivalent if ldm is not enabled in both sets or 8030c16b537SWarner Losh * all the parameters are equivalent. */ 8040c16b537SWarner Losh static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1, 8050c16b537SWarner Losh ldmParams_t ldmParams2) 8060c16b537SWarner Losh { 8070c16b537SWarner Losh return (!ldmParams1.enableLdm && !ldmParams2.enableLdm) || 8080c16b537SWarner Losh (ldmParams1.enableLdm == ldmParams2.enableLdm && 8090c16b537SWarner Losh ldmParams1.hashLog == ldmParams2.hashLog && 8100c16b537SWarner Losh ldmParams1.bucketSizeLog == ldmParams2.bucketSizeLog && 8110c16b537SWarner Losh ldmParams1.minMatchLength == ldmParams2.minMatchLength && 8120c16b537SWarner Losh ldmParams1.hashEveryLog == ldmParams2.hashEveryLog); 8130c16b537SWarner Losh } 8140c16b537SWarner Losh 815052d3c12SConrad Meyer typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e; 816052d3c12SConrad Meyer 817052d3c12SConrad Meyer /* ZSTD_sufficientBuff() : 818052d3c12SConrad Meyer * check internal buffers exist for streaming if buffPol == ZSTDb_buffered . 819052d3c12SConrad Meyer * Note : they are assumed to be correctly sized if ZSTD_equivalentCParams()==1 */ 820052d3c12SConrad Meyer static U32 ZSTD_sufficientBuff(size_t bufferSize1, size_t blockSize1, 821052d3c12SConrad Meyer ZSTD_buffered_policy_e buffPol2, 822052d3c12SConrad Meyer ZSTD_compressionParameters cParams2, 823052d3c12SConrad Meyer U64 pledgedSrcSize) 824052d3c12SConrad Meyer { 825052d3c12SConrad Meyer size_t const windowSize2 = MAX(1, (size_t)MIN(((U64)1 << cParams2.windowLog), pledgedSrcSize)); 826052d3c12SConrad Meyer size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2); 827052d3c12SConrad Meyer size_t const neededBufferSize2 = (buffPol2==ZSTDb_buffered) ? windowSize2 + blockSize2 : 0; 828*19fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff: is windowSize2=%u <= wlog1=%u", 829052d3c12SConrad Meyer (U32)windowSize2, cParams2.windowLog); 830*19fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_sufficientBuff: is blockSize2=%u <= blockSize1=%u", 831052d3c12SConrad Meyer (U32)blockSize2, (U32)blockSize1); 832052d3c12SConrad Meyer return (blockSize2 <= blockSize1) /* seqStore space depends on blockSize */ 833052d3c12SConrad Meyer & (neededBufferSize2 <= bufferSize1); 834052d3c12SConrad Meyer } 835052d3c12SConrad Meyer 8360c16b537SWarner Losh /** Equivalence for resetCCtx purposes */ 8370c16b537SWarner Losh static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1, 838052d3c12SConrad Meyer ZSTD_CCtx_params params2, 839052d3c12SConrad Meyer size_t buffSize1, size_t blockSize1, 840052d3c12SConrad Meyer ZSTD_buffered_policy_e buffPol2, 841052d3c12SConrad Meyer U64 pledgedSrcSize) 8420c16b537SWarner Losh { 843052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentParams: pledgedSrcSize=%u", (U32)pledgedSrcSize); 8440c16b537SWarner Losh return ZSTD_equivalentCParams(params1.cParams, params2.cParams) && 845052d3c12SConrad Meyer ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams) && 846052d3c12SConrad Meyer ZSTD_sufficientBuff(buffSize1, blockSize1, buffPol2, params2.cParams, pledgedSrcSize); 8470c16b537SWarner Losh } 8480c16b537SWarner Losh 849*19fcbaf1SConrad Meyer static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs) 850*19fcbaf1SConrad Meyer { 851*19fcbaf1SConrad Meyer int i; 852*19fcbaf1SConrad Meyer for (i = 0; i < ZSTD_REP_NUM; ++i) 853*19fcbaf1SConrad Meyer bs->rep[i] = repStartValue[i]; 854*19fcbaf1SConrad Meyer bs->entropy.hufCTable_repeatMode = HUF_repeat_none; 855*19fcbaf1SConrad Meyer bs->entropy.offcode_repeatMode = FSE_repeat_none; 856*19fcbaf1SConrad Meyer bs->entropy.matchlength_repeatMode = FSE_repeat_none; 857*19fcbaf1SConrad Meyer bs->entropy.litlength_repeatMode = FSE_repeat_none; 858*19fcbaf1SConrad Meyer } 859*19fcbaf1SConrad Meyer 860*19fcbaf1SConrad Meyer /*! ZSTD_invalidateMatchState() 861*19fcbaf1SConrad Meyer * Invalidate all the matches in the match finder tables. 862*19fcbaf1SConrad Meyer * Requires nextSrc and base to be set (can be NULL). 863*19fcbaf1SConrad Meyer */ 864*19fcbaf1SConrad Meyer static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms) 865*19fcbaf1SConrad Meyer { 866*19fcbaf1SConrad Meyer ZSTD_window_clear(&ms->window); 867*19fcbaf1SConrad Meyer 868*19fcbaf1SConrad Meyer ms->nextToUpdate = ms->window.dictLimit + 1; 869*19fcbaf1SConrad Meyer ms->loadedDictEnd = 0; 870*19fcbaf1SConrad Meyer ms->opt.litLengthSum = 0; /* force reset of btopt stats */ 871*19fcbaf1SConrad Meyer } 872*19fcbaf1SConrad Meyer 8730c16b537SWarner Losh /*! ZSTD_continueCCtx() : 8740c16b537SWarner Losh * reuse CCtx without reset (note : requires no dictionary) */ 8750c16b537SWarner Losh static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize) 8760c16b537SWarner Losh { 877052d3c12SConrad Meyer size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); 878052d3c12SConrad Meyer size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); 879*19fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_continueCCtx: re-use context in place"); 880052d3c12SConrad Meyer 881052d3c12SConrad Meyer cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */ 8820c16b537SWarner Losh cctx->appliedParams = params; 8830c16b537SWarner Losh cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1; 8840c16b537SWarner Losh cctx->consumedSrcSize = 0; 885*19fcbaf1SConrad Meyer cctx->producedCSize = 0; 8860c16b537SWarner Losh if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) 8870c16b537SWarner Losh cctx->appliedParams.fParams.contentSizeFlag = 0; 8880c16b537SWarner Losh DEBUGLOG(4, "pledged content size : %u ; flag : %u", 8890c16b537SWarner Losh (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag); 8900c16b537SWarner Losh cctx->stage = ZSTDcs_init; 8910c16b537SWarner Losh cctx->dictID = 0; 892*19fcbaf1SConrad Meyer if (params.ldmParams.enableLdm) 893*19fcbaf1SConrad Meyer ZSTD_window_clear(&cctx->ldmState.window); 894*19fcbaf1SConrad Meyer ZSTD_referenceExternalSequences(cctx, NULL, 0); 895*19fcbaf1SConrad Meyer ZSTD_invalidateMatchState(&cctx->blockState.matchState); 896*19fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(cctx->blockState.prevCBlock); 8970c16b537SWarner Losh XXH64_reset(&cctx->xxhState, 0); 8980c16b537SWarner Losh return 0; 8990c16b537SWarner Losh } 9000c16b537SWarner Losh 9010c16b537SWarner Losh typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e; 9020c16b537SWarner Losh 903*19fcbaf1SConrad Meyer static void* ZSTD_reset_matchState(ZSTD_matchState_t* ms, void* ptr, ZSTD_compressionParameters const* cParams, ZSTD_compResetPolicy_e const crp, U32 const forCCtx) 904*19fcbaf1SConrad Meyer { 905*19fcbaf1SConrad Meyer size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog); 906*19fcbaf1SConrad Meyer size_t const hSize = ((size_t)1) << cParams->hashLog; 907*19fcbaf1SConrad Meyer U32 const hashLog3 = (forCCtx && cParams->searchLength==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0; 908*19fcbaf1SConrad Meyer size_t const h3Size = ((size_t)1) << hashLog3; 909*19fcbaf1SConrad Meyer size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 910*19fcbaf1SConrad Meyer 911*19fcbaf1SConrad Meyer assert(((size_t)ptr & 3) == 0); 912*19fcbaf1SConrad Meyer 913*19fcbaf1SConrad Meyer ms->hashLog3 = hashLog3; 914*19fcbaf1SConrad Meyer memset(&ms->window, 0, sizeof(ms->window)); 915*19fcbaf1SConrad Meyer ZSTD_invalidateMatchState(ms); 916*19fcbaf1SConrad Meyer 917*19fcbaf1SConrad Meyer /* opt parser space */ 918*19fcbaf1SConrad Meyer if (forCCtx && ((cParams->strategy == ZSTD_btopt) | (cParams->strategy == ZSTD_btultra))) { 919*19fcbaf1SConrad Meyer DEBUGLOG(4, "reserving optimal parser space"); 920*19fcbaf1SConrad Meyer ms->opt.litFreq = (U32*)ptr; 921*19fcbaf1SConrad Meyer ms->opt.litLengthFreq = ms->opt.litFreq + (1<<Litbits); 922*19fcbaf1SConrad Meyer ms->opt.matchLengthFreq = ms->opt.litLengthFreq + (MaxLL+1); 923*19fcbaf1SConrad Meyer ms->opt.offCodeFreq = ms->opt.matchLengthFreq + (MaxML+1); 924*19fcbaf1SConrad Meyer ptr = ms->opt.offCodeFreq + (MaxOff+1); 925*19fcbaf1SConrad Meyer ms->opt.matchTable = (ZSTD_match_t*)ptr; 926*19fcbaf1SConrad Meyer ptr = ms->opt.matchTable + ZSTD_OPT_NUM+1; 927*19fcbaf1SConrad Meyer ms->opt.priceTable = (ZSTD_optimal_t*)ptr; 928*19fcbaf1SConrad Meyer ptr = ms->opt.priceTable + ZSTD_OPT_NUM+1; 929*19fcbaf1SConrad Meyer } 930*19fcbaf1SConrad Meyer 931*19fcbaf1SConrad Meyer /* table Space */ 932*19fcbaf1SConrad Meyer DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset); 933*19fcbaf1SConrad Meyer assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ 934*19fcbaf1SConrad Meyer if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */ 935*19fcbaf1SConrad Meyer ms->hashTable = (U32*)(ptr); 936*19fcbaf1SConrad Meyer ms->chainTable = ms->hashTable + hSize; 937*19fcbaf1SConrad Meyer ms->hashTable3 = ms->chainTable + chainSize; 938*19fcbaf1SConrad Meyer ptr = ms->hashTable3 + h3Size; 939*19fcbaf1SConrad Meyer 940*19fcbaf1SConrad Meyer assert(((size_t)ptr & 3) == 0); 941*19fcbaf1SConrad Meyer return ptr; 942*19fcbaf1SConrad Meyer } 943*19fcbaf1SConrad Meyer 9440c16b537SWarner Losh /*! ZSTD_resetCCtx_internal() : 9450c16b537SWarner Losh note : `params` are assumed fully validated at this stage */ 9460c16b537SWarner Losh static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc, 9470c16b537SWarner Losh ZSTD_CCtx_params params, U64 pledgedSrcSize, 9480c16b537SWarner Losh ZSTD_compResetPolicy_e const crp, 9490c16b537SWarner Losh ZSTD_buffered_policy_e const zbuff) 9500c16b537SWarner Losh { 951052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u", 952052d3c12SConrad Meyer (U32)pledgedSrcSize, params.cParams.windowLog); 9530c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 9540c16b537SWarner Losh 9550c16b537SWarner Losh if (crp == ZSTDcrp_continue) { 956052d3c12SConrad Meyer if (ZSTD_equivalentParams(zc->appliedParams, params, 957052d3c12SConrad Meyer zc->inBuffSize, zc->blockSize, 958052d3c12SConrad Meyer zbuff, pledgedSrcSize)) { 959052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%u)", 960052d3c12SConrad Meyer zc->appliedParams.cParams.windowLog, (U32)zc->blockSize); 9610c16b537SWarner Losh return ZSTD_continueCCtx(zc, params, pledgedSrcSize); 9620c16b537SWarner Losh } } 963052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx"); 9640c16b537SWarner Losh 9650c16b537SWarner Losh if (params.ldmParams.enableLdm) { 9660c16b537SWarner Losh /* Adjust long distance matching parameters */ 967*19fcbaf1SConrad Meyer params.ldmParams.windowLog = params.cParams.windowLog; 968*19fcbaf1SConrad Meyer ZSTD_ldm_adjustParameters(¶ms.ldmParams, ¶ms.cParams); 9690c16b537SWarner Losh assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog); 9700c16b537SWarner Losh assert(params.ldmParams.hashEveryLog < 32); 9710c16b537SWarner Losh zc->ldmState.hashPower = 9720c16b537SWarner Losh ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength); 9730c16b537SWarner Losh } 9740c16b537SWarner Losh 975052d3c12SConrad Meyer { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize)); 976052d3c12SConrad Meyer size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize); 9770c16b537SWarner Losh U32 const divider = (params.cParams.searchLength==3) ? 3 : 4; 9780c16b537SWarner Losh size_t const maxNbSeq = blockSize / divider; 9790c16b537SWarner Losh size_t const tokenSpace = blockSize + 11*maxNbSeq; 9800c16b537SWarner Losh size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0; 981052d3c12SConrad Meyer size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0; 982*19fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(¶ms.cParams, /* forCCtx */ 1); 983*19fcbaf1SConrad Meyer size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize); 9840c16b537SWarner Losh void* ptr; 9850c16b537SWarner Losh 9860c16b537SWarner Losh /* Check if workSpace is large enough, alloc a new one if needed */ 987*19fcbaf1SConrad Meyer { size_t const entropySpace = HUF_WORKSPACE_SIZE; 988*19fcbaf1SConrad Meyer size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t); 9890c16b537SWarner Losh size_t const bufferSpace = buffInSize + buffOutSize; 990*19fcbaf1SConrad Meyer size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams); 991*19fcbaf1SConrad Meyer size_t const ldmSeqSpace = maxNbLdmSeq * sizeof(rawSeq); 992*19fcbaf1SConrad Meyer 993*19fcbaf1SConrad Meyer size_t const neededSpace = entropySpace + blockStateSpace + ldmSpace + 994*19fcbaf1SConrad Meyer ldmSeqSpace + matchStateSize + tokenSpace + 995*19fcbaf1SConrad Meyer bufferSpace; 996*19fcbaf1SConrad Meyer DEBUGLOG(4, "Need %uKB workspace, including %uKB for match state, and %uKB for buffers", 997*19fcbaf1SConrad Meyer (U32)(neededSpace>>10), (U32)(matchStateSize>>10), (U32)(bufferSpace>>10)); 998*19fcbaf1SConrad Meyer DEBUGLOG(4, "windowSize: %u - blockSize: %u", (U32)windowSize, (U32)blockSize); 9990c16b537SWarner Losh 10000c16b537SWarner Losh if (zc->workSpaceSize < neededSpace) { /* too small : resize */ 1001052d3c12SConrad Meyer DEBUGLOG(4, "Need to update workSpaceSize from %uK to %uK", 1002052d3c12SConrad Meyer (unsigned)(zc->workSpaceSize>>10), 1003052d3c12SConrad Meyer (unsigned)(neededSpace>>10)); 10040c16b537SWarner Losh /* static cctx : no resize, error out */ 10050c16b537SWarner Losh if (zc->staticSize) return ERROR(memory_allocation); 10060c16b537SWarner Losh 10070c16b537SWarner Losh zc->workSpaceSize = 0; 10080c16b537SWarner Losh ZSTD_free(zc->workSpace, zc->customMem); 10090c16b537SWarner Losh zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem); 10100c16b537SWarner Losh if (zc->workSpace == NULL) return ERROR(memory_allocation); 10110c16b537SWarner Losh zc->workSpaceSize = neededSpace; 10120c16b537SWarner Losh ptr = zc->workSpace; 10130c16b537SWarner Losh 1014*19fcbaf1SConrad Meyer /* Statically sized space. entropyWorkspace never moves (but prev/next block swap places) */ 10150c16b537SWarner Losh assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */ 1016*19fcbaf1SConrad Meyer assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_compressedBlockState_t)); 1017*19fcbaf1SConrad Meyer zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)zc->workSpace; 1018*19fcbaf1SConrad Meyer zc->blockState.nextCBlock = zc->blockState.prevCBlock + 1; 1019*19fcbaf1SConrad Meyer ptr = zc->blockState.nextCBlock + 1; 1020*19fcbaf1SConrad Meyer zc->entropyWorkspace = (U32*)ptr; 10210c16b537SWarner Losh } } 10220c16b537SWarner Losh 10230c16b537SWarner Losh /* init params */ 10240c16b537SWarner Losh zc->appliedParams = params; 10250c16b537SWarner Losh zc->pledgedSrcSizePlusOne = pledgedSrcSize+1; 10260c16b537SWarner Losh zc->consumedSrcSize = 0; 1027*19fcbaf1SConrad Meyer zc->producedCSize = 0; 10280c16b537SWarner Losh if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN) 10290c16b537SWarner Losh zc->appliedParams.fParams.contentSizeFlag = 0; 1030052d3c12SConrad Meyer DEBUGLOG(4, "pledged content size : %u ; flag : %u", 10310c16b537SWarner Losh (U32)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag); 10320c16b537SWarner Losh zc->blockSize = blockSize; 10330c16b537SWarner Losh 10340c16b537SWarner Losh XXH64_reset(&zc->xxhState, 0); 10350c16b537SWarner Losh zc->stage = ZSTDcs_init; 10360c16b537SWarner Losh zc->dictID = 0; 10370c16b537SWarner Losh 1038*19fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock); 10390c16b537SWarner Losh 1040*19fcbaf1SConrad Meyer ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32; 10410c16b537SWarner Losh 10420c16b537SWarner Losh /* ldm hash table */ 10430c16b537SWarner Losh /* initialize bucketOffsets table later for pointer alignment */ 10440c16b537SWarner Losh if (params.ldmParams.enableLdm) { 10450c16b537SWarner Losh size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog; 10460c16b537SWarner Losh memset(ptr, 0, ldmHSize * sizeof(ldmEntry_t)); 10470c16b537SWarner Losh assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ 10480c16b537SWarner Losh zc->ldmState.hashTable = (ldmEntry_t*)ptr; 10490c16b537SWarner Losh ptr = zc->ldmState.hashTable + ldmHSize; 1050*19fcbaf1SConrad Meyer zc->ldmSequences = (rawSeq*)ptr; 1051*19fcbaf1SConrad Meyer ptr = zc->ldmSequences + maxNbLdmSeq; 1052*19fcbaf1SConrad Meyer zc->maxNbLdmSequences = maxNbLdmSeq; 10530c16b537SWarner Losh 1054*19fcbaf1SConrad Meyer memset(&zc->ldmState.window, 0, sizeof(zc->ldmState.window)); 1055*19fcbaf1SConrad Meyer } 10560c16b537SWarner Losh assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */ 1057*19fcbaf1SConrad Meyer 1058*19fcbaf1SConrad Meyer ptr = ZSTD_reset_matchState(&zc->blockState.matchState, ptr, ¶ms.cParams, crp, /* forCCtx */ 1); 10590c16b537SWarner Losh 10600c16b537SWarner Losh /* sequences storage */ 10610c16b537SWarner Losh zc->seqStore.sequencesStart = (seqDef*)ptr; 10620c16b537SWarner Losh ptr = zc->seqStore.sequencesStart + maxNbSeq; 10630c16b537SWarner Losh zc->seqStore.llCode = (BYTE*) ptr; 10640c16b537SWarner Losh zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq; 10650c16b537SWarner Losh zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq; 10660c16b537SWarner Losh zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq; 10670c16b537SWarner Losh ptr = zc->seqStore.litStart + blockSize; 10680c16b537SWarner Losh 10690c16b537SWarner Losh /* ldm bucketOffsets table */ 10700c16b537SWarner Losh if (params.ldmParams.enableLdm) { 10710c16b537SWarner Losh size_t const ldmBucketSize = 10720c16b537SWarner Losh ((size_t)1) << (params.ldmParams.hashLog - 10730c16b537SWarner Losh params.ldmParams.bucketSizeLog); 10740c16b537SWarner Losh memset(ptr, 0, ldmBucketSize); 10750c16b537SWarner Losh zc->ldmState.bucketOffsets = (BYTE*)ptr; 10760c16b537SWarner Losh ptr = zc->ldmState.bucketOffsets + ldmBucketSize; 1077*19fcbaf1SConrad Meyer ZSTD_window_clear(&zc->ldmState.window); 10780c16b537SWarner Losh } 1079*19fcbaf1SConrad Meyer ZSTD_referenceExternalSequences(zc, NULL, 0); 10800c16b537SWarner Losh 10810c16b537SWarner Losh /* buffers */ 10820c16b537SWarner Losh zc->inBuffSize = buffInSize; 10830c16b537SWarner Losh zc->inBuff = (char*)ptr; 10840c16b537SWarner Losh zc->outBuffSize = buffOutSize; 10850c16b537SWarner Losh zc->outBuff = zc->inBuff + buffInSize; 10860c16b537SWarner Losh 10870c16b537SWarner Losh return 0; 10880c16b537SWarner Losh } 10890c16b537SWarner Losh } 10900c16b537SWarner Losh 10910c16b537SWarner Losh /* ZSTD_invalidateRepCodes() : 10920c16b537SWarner Losh * ensures next compression will not use repcodes from previous block. 10930c16b537SWarner Losh * Note : only works with regular variant; 10940c16b537SWarner Losh * do not use with extDict variant ! */ 10950c16b537SWarner Losh void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) { 10960c16b537SWarner Losh int i; 1097*19fcbaf1SConrad Meyer for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0; 1098*19fcbaf1SConrad Meyer assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window)); 10990c16b537SWarner Losh } 11000c16b537SWarner Losh 1101*19fcbaf1SConrad Meyer static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx, 1102*19fcbaf1SConrad Meyer const ZSTD_CDict* cdict, 1103*19fcbaf1SConrad Meyer unsigned windowLog, 1104*19fcbaf1SConrad Meyer ZSTD_frameParameters fParams, 1105*19fcbaf1SConrad Meyer U64 pledgedSrcSize, 1106*19fcbaf1SConrad Meyer ZSTD_buffered_policy_e zbuff) 1107*19fcbaf1SConrad Meyer { 1108*19fcbaf1SConrad Meyer { ZSTD_CCtx_params params = cctx->requestedParams; 1109*19fcbaf1SConrad Meyer /* Copy only compression parameters related to tables. */ 1110*19fcbaf1SConrad Meyer params.cParams = cdict->cParams; 1111*19fcbaf1SConrad Meyer if (windowLog) params.cParams.windowLog = windowLog; 1112*19fcbaf1SConrad Meyer params.fParams = fParams; 1113*19fcbaf1SConrad Meyer ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 1114*19fcbaf1SConrad Meyer ZSTDcrp_noMemset, zbuff); 1115*19fcbaf1SConrad Meyer assert(cctx->appliedParams.cParams.strategy == cdict->cParams.strategy); 1116*19fcbaf1SConrad Meyer assert(cctx->appliedParams.cParams.hashLog == cdict->cParams.hashLog); 1117*19fcbaf1SConrad Meyer assert(cctx->appliedParams.cParams.chainLog == cdict->cParams.chainLog); 1118*19fcbaf1SConrad Meyer } 1119*19fcbaf1SConrad Meyer 1120*19fcbaf1SConrad Meyer /* copy tables */ 1121*19fcbaf1SConrad Meyer { size_t const chainSize = (cdict->cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict->cParams.chainLog); 1122*19fcbaf1SConrad Meyer size_t const hSize = (size_t)1 << cdict->cParams.hashLog; 1123*19fcbaf1SConrad Meyer size_t const tableSpace = (chainSize + hSize) * sizeof(U32); 1124*19fcbaf1SConrad Meyer assert((U32*)cctx->blockState.matchState.chainTable == (U32*)cctx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */ 1125*19fcbaf1SConrad Meyer assert((U32*)cctx->blockState.matchState.hashTable3 == (U32*)cctx->blockState.matchState.chainTable + chainSize); 1126*19fcbaf1SConrad Meyer assert((U32*)cdict->matchState.chainTable == (U32*)cdict->matchState.hashTable + hSize); /* chainTable must follow hashTable */ 1127*19fcbaf1SConrad Meyer assert((U32*)cdict->matchState.hashTable3 == (U32*)cdict->matchState.chainTable + chainSize); 1128*19fcbaf1SConrad Meyer memcpy(cctx->blockState.matchState.hashTable, cdict->matchState.hashTable, tableSpace); /* presumes all tables follow each other */ 1129*19fcbaf1SConrad Meyer } 1130*19fcbaf1SConrad Meyer /* Zero the hashTable3, since the cdict never fills it */ 1131*19fcbaf1SConrad Meyer { size_t const h3Size = (size_t)1 << cctx->blockState.matchState.hashLog3; 1132*19fcbaf1SConrad Meyer assert(cdict->matchState.hashLog3 == 0); 1133*19fcbaf1SConrad Meyer memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32)); 1134*19fcbaf1SConrad Meyer } 1135*19fcbaf1SConrad Meyer 1136*19fcbaf1SConrad Meyer /* copy dictionary offsets */ 1137*19fcbaf1SConrad Meyer { 1138*19fcbaf1SConrad Meyer ZSTD_matchState_t const* srcMatchState = &cdict->matchState; 1139*19fcbaf1SConrad Meyer ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState; 1140*19fcbaf1SConrad Meyer dstMatchState->window = srcMatchState->window; 1141*19fcbaf1SConrad Meyer dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 1142*19fcbaf1SConrad Meyer dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3; 1143*19fcbaf1SConrad Meyer dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 1144*19fcbaf1SConrad Meyer } 1145*19fcbaf1SConrad Meyer cctx->dictID = cdict->dictID; 1146*19fcbaf1SConrad Meyer 1147*19fcbaf1SConrad Meyer /* copy block state */ 1148*19fcbaf1SConrad Meyer memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState)); 1149*19fcbaf1SConrad Meyer 1150*19fcbaf1SConrad Meyer return 0; 1151*19fcbaf1SConrad Meyer } 11520c16b537SWarner Losh 11530c16b537SWarner Losh /*! ZSTD_copyCCtx_internal() : 11540c16b537SWarner Losh * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 11550c16b537SWarner Losh * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 1156052d3c12SConrad Meyer * The "context", in this case, refers to the hash and chain tables, 1157052d3c12SConrad Meyer * entropy tables, and dictionary references. 1158052d3c12SConrad Meyer * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx. 11590c16b537SWarner Losh * @return : 0, or an error code */ 11600c16b537SWarner Losh static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, 11610c16b537SWarner Losh const ZSTD_CCtx* srcCCtx, 11620c16b537SWarner Losh ZSTD_frameParameters fParams, 1163052d3c12SConrad Meyer U64 pledgedSrcSize, 11640c16b537SWarner Losh ZSTD_buffered_policy_e zbuff) 11650c16b537SWarner Losh { 11660c16b537SWarner Losh DEBUGLOG(5, "ZSTD_copyCCtx_internal"); 11670c16b537SWarner Losh if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong); 11680c16b537SWarner Losh 11690c16b537SWarner Losh memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); 11700c16b537SWarner Losh { ZSTD_CCtx_params params = dstCCtx->requestedParams; 11710c16b537SWarner Losh /* Copy only compression parameters related to tables. */ 11720c16b537SWarner Losh params.cParams = srcCCtx->appliedParams.cParams; 11730c16b537SWarner Losh params.fParams = fParams; 11740c16b537SWarner Losh ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, 11750c16b537SWarner Losh ZSTDcrp_noMemset, zbuff); 1176*19fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog); 1177*19fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy); 1178*19fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog); 1179*19fcbaf1SConrad Meyer assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog); 1180*19fcbaf1SConrad Meyer assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3); 11810c16b537SWarner Losh } 11820c16b537SWarner Losh 11830c16b537SWarner Losh /* copy tables */ 11840c16b537SWarner Losh { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog); 11850c16b537SWarner Losh size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog; 1186*19fcbaf1SConrad Meyer size_t const h3Size = (size_t)1 << srcCCtx->blockState.matchState.hashLog3; 11870c16b537SWarner Losh size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 1188*19fcbaf1SConrad Meyer assert((U32*)dstCCtx->blockState.matchState.chainTable == (U32*)dstCCtx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */ 1189*19fcbaf1SConrad Meyer assert((U32*)dstCCtx->blockState.matchState.hashTable3 == (U32*)dstCCtx->blockState.matchState.chainTable + chainSize); 1190*19fcbaf1SConrad Meyer memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, tableSpace); /* presumes all tables follow each other */ 11910c16b537SWarner Losh } 11920c16b537SWarner Losh 11930c16b537SWarner Losh /* copy dictionary offsets */ 1194*19fcbaf1SConrad Meyer { 1195*19fcbaf1SConrad Meyer ZSTD_matchState_t const* srcMatchState = &srcCCtx->blockState.matchState; 1196*19fcbaf1SConrad Meyer ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState; 1197*19fcbaf1SConrad Meyer dstMatchState->window = srcMatchState->window; 1198*19fcbaf1SConrad Meyer dstMatchState->nextToUpdate = srcMatchState->nextToUpdate; 1199*19fcbaf1SConrad Meyer dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3; 1200*19fcbaf1SConrad Meyer dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd; 1201*19fcbaf1SConrad Meyer } 12020c16b537SWarner Losh dstCCtx->dictID = srcCCtx->dictID; 12030c16b537SWarner Losh 1204*19fcbaf1SConrad Meyer /* copy block state */ 1205*19fcbaf1SConrad Meyer memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock)); 12060c16b537SWarner Losh 12070c16b537SWarner Losh return 0; 12080c16b537SWarner Losh } 12090c16b537SWarner Losh 12100c16b537SWarner Losh /*! ZSTD_copyCCtx() : 12110c16b537SWarner Losh * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 12120c16b537SWarner Losh * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 12130c16b537SWarner Losh * pledgedSrcSize==0 means "unknown". 12140c16b537SWarner Losh * @return : 0, or an error code */ 12150c16b537SWarner Losh size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) 12160c16b537SWarner Losh { 12170c16b537SWarner Losh ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 12180c16b537SWarner Losh ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0); 12190c16b537SWarner Losh ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1); 1220052d3c12SConrad Meyer if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; 1221052d3c12SConrad Meyer fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN); 12220c16b537SWarner Losh 1223052d3c12SConrad Meyer return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, 1224*19fcbaf1SConrad Meyer fParams, pledgedSrcSize, 1225052d3c12SConrad Meyer zbuff); 12260c16b537SWarner Losh } 12270c16b537SWarner Losh 12280c16b537SWarner Losh 1229*19fcbaf1SConrad Meyer #define ZSTD_ROWSIZE 16 12300c16b537SWarner Losh /*! ZSTD_reduceTable() : 1231*19fcbaf1SConrad Meyer * reduce table indexes by `reducerValue`, or squash to zero. 1232*19fcbaf1SConrad Meyer * PreserveMark preserves "unsorted mark" for btlazy2 strategy. 1233*19fcbaf1SConrad Meyer * It must be set to a clear 0/1 value, to remove branch during inlining. 1234*19fcbaf1SConrad Meyer * Presume table size is a multiple of ZSTD_ROWSIZE 1235*19fcbaf1SConrad Meyer * to help auto-vectorization */ 1236*19fcbaf1SConrad Meyer FORCE_INLINE_TEMPLATE void 1237*19fcbaf1SConrad Meyer ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark) 12380c16b537SWarner Losh { 1239*19fcbaf1SConrad Meyer int const nbRows = (int)size / ZSTD_ROWSIZE; 1240*19fcbaf1SConrad Meyer int cellNb = 0; 1241*19fcbaf1SConrad Meyer int rowNb; 1242*19fcbaf1SConrad Meyer assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */ 1243*19fcbaf1SConrad Meyer assert(size < (1U<<31)); /* can be casted to int */ 1244*19fcbaf1SConrad Meyer for (rowNb=0 ; rowNb < nbRows ; rowNb++) { 1245*19fcbaf1SConrad Meyer int column; 1246*19fcbaf1SConrad Meyer for (column=0; column<ZSTD_ROWSIZE; column++) { 1247*19fcbaf1SConrad Meyer if (preserveMark) { 1248*19fcbaf1SConrad Meyer U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0; 1249*19fcbaf1SConrad Meyer table[cellNb] += adder; 12500c16b537SWarner Losh } 1251*19fcbaf1SConrad Meyer if (table[cellNb] < reducerValue) table[cellNb] = 0; 1252*19fcbaf1SConrad Meyer else table[cellNb] -= reducerValue; 1253*19fcbaf1SConrad Meyer cellNb++; 1254*19fcbaf1SConrad Meyer } } 12550c16b537SWarner Losh } 12560c16b537SWarner Losh 1257*19fcbaf1SConrad Meyer static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue) 12580c16b537SWarner Losh { 1259*19fcbaf1SConrad Meyer ZSTD_reduceTable_internal(table, size, reducerValue, 0); 12600c16b537SWarner Losh } 1261*19fcbaf1SConrad Meyer 1262*19fcbaf1SConrad Meyer static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue) 1263*19fcbaf1SConrad Meyer { 1264*19fcbaf1SConrad Meyer ZSTD_reduceTable_internal(table, size, reducerValue, 1); 12650c16b537SWarner Losh } 12660c16b537SWarner Losh 12670c16b537SWarner Losh /*! ZSTD_reduceIndex() : 12680c16b537SWarner Losh * rescale all indexes to avoid future overflow (indexes are U32) */ 12690c16b537SWarner Losh static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) 12700c16b537SWarner Losh { 1271*19fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &zc->blockState.matchState; 12720c16b537SWarner Losh { U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog; 1273*19fcbaf1SConrad Meyer ZSTD_reduceTable(ms->hashTable, hSize, reducerValue); 12740c16b537SWarner Losh } 1275*19fcbaf1SConrad Meyer 1276*19fcbaf1SConrad Meyer if (zc->appliedParams.cParams.strategy != ZSTD_fast) { 1277*19fcbaf1SConrad Meyer U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog; 1278*19fcbaf1SConrad Meyer if (zc->appliedParams.cParams.strategy == ZSTD_btlazy2) 1279*19fcbaf1SConrad Meyer ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue); 1280*19fcbaf1SConrad Meyer else 1281*19fcbaf1SConrad Meyer ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue); 1282*19fcbaf1SConrad Meyer } 1283*19fcbaf1SConrad Meyer 1284*19fcbaf1SConrad Meyer if (ms->hashLog3) { 1285*19fcbaf1SConrad Meyer U32 const h3Size = (U32)1 << ms->hashLog3; 1286*19fcbaf1SConrad Meyer ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue); 12870c16b537SWarner Losh } 12880c16b537SWarner Losh } 12890c16b537SWarner Losh 12900c16b537SWarner Losh 12910c16b537SWarner Losh /*-******************************************************* 12920c16b537SWarner Losh * Block entropic compression 12930c16b537SWarner Losh *********************************************************/ 12940c16b537SWarner Losh 12950c16b537SWarner Losh /* See doc/zstd_compression_format.md for detailed format description */ 12960c16b537SWarner Losh 12970c16b537SWarner Losh size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize) 12980c16b537SWarner Losh { 12990c16b537SWarner Losh if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall); 13000c16b537SWarner Losh memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize); 13010c16b537SWarner Losh MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw); 13020c16b537SWarner Losh return ZSTD_blockHeaderSize+srcSize; 13030c16b537SWarner Losh } 13040c16b537SWarner Losh 13050c16b537SWarner Losh 13060c16b537SWarner Losh static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize) 13070c16b537SWarner Losh { 13080c16b537SWarner Losh BYTE* const ostart = (BYTE* const)dst; 13090c16b537SWarner Losh U32 const flSize = 1 + (srcSize>31) + (srcSize>4095); 13100c16b537SWarner Losh 13110c16b537SWarner Losh if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall); 13120c16b537SWarner Losh 13130c16b537SWarner Losh switch(flSize) 13140c16b537SWarner Losh { 13150c16b537SWarner Losh case 1: /* 2 - 1 - 5 */ 13160c16b537SWarner Losh ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3)); 13170c16b537SWarner Losh break; 13180c16b537SWarner Losh case 2: /* 2 - 2 - 12 */ 13190c16b537SWarner Losh MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4))); 13200c16b537SWarner Losh break; 13210c16b537SWarner Losh case 3: /* 2 - 2 - 20 */ 13220c16b537SWarner Losh MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4))); 13230c16b537SWarner Losh break; 13240c16b537SWarner Losh default: /* not necessary : flSize is {1,2,3} */ 13250c16b537SWarner Losh assert(0); 13260c16b537SWarner Losh } 13270c16b537SWarner Losh 13280c16b537SWarner Losh memcpy(ostart + flSize, src, srcSize); 13290c16b537SWarner Losh return srcSize + flSize; 13300c16b537SWarner Losh } 13310c16b537SWarner Losh 13320c16b537SWarner Losh static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize) 13330c16b537SWarner Losh { 13340c16b537SWarner Losh BYTE* const ostart = (BYTE* const)dst; 13350c16b537SWarner Losh U32 const flSize = 1 + (srcSize>31) + (srcSize>4095); 13360c16b537SWarner Losh 13370c16b537SWarner Losh (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */ 13380c16b537SWarner Losh 13390c16b537SWarner Losh switch(flSize) 13400c16b537SWarner Losh { 13410c16b537SWarner Losh case 1: /* 2 - 1 - 5 */ 13420c16b537SWarner Losh ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3)); 13430c16b537SWarner Losh break; 13440c16b537SWarner Losh case 2: /* 2 - 2 - 12 */ 13450c16b537SWarner Losh MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4))); 13460c16b537SWarner Losh break; 13470c16b537SWarner Losh case 3: /* 2 - 2 - 20 */ 13480c16b537SWarner Losh MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4))); 13490c16b537SWarner Losh break; 13500c16b537SWarner Losh default: /* not necessary : flSize is {1,2,3} */ 13510c16b537SWarner Losh assert(0); 13520c16b537SWarner Losh } 13530c16b537SWarner Losh 13540c16b537SWarner Losh ostart[flSize] = *(const BYTE*)src; 13550c16b537SWarner Losh return flSize+1; 13560c16b537SWarner Losh } 13570c16b537SWarner Losh 13580c16b537SWarner Losh 13590c16b537SWarner Losh static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; } 13600c16b537SWarner Losh 1361*19fcbaf1SConrad Meyer static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t const* prevEntropy, 1362*19fcbaf1SConrad Meyer ZSTD_entropyCTables_t* nextEntropy, 1363*19fcbaf1SConrad Meyer ZSTD_strategy strategy, int disableLiteralCompression, 13640c16b537SWarner Losh void* dst, size_t dstCapacity, 1365*19fcbaf1SConrad Meyer const void* src, size_t srcSize, 1366*19fcbaf1SConrad Meyer U32* workspace, const int bmi2) 13670c16b537SWarner Losh { 13680c16b537SWarner Losh size_t const minGain = ZSTD_minGain(srcSize); 13690c16b537SWarner Losh size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); 13700c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 13710c16b537SWarner Losh U32 singleStream = srcSize < 256; 13720c16b537SWarner Losh symbolEncodingType_e hType = set_compressed; 13730c16b537SWarner Losh size_t cLitSize; 13740c16b537SWarner Losh 1375*19fcbaf1SConrad Meyer DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i)", 1376*19fcbaf1SConrad Meyer disableLiteralCompression); 1377*19fcbaf1SConrad Meyer 1378*19fcbaf1SConrad Meyer /* Prepare nextEntropy assuming reusing the existing table */ 1379*19fcbaf1SConrad Meyer nextEntropy->hufCTable_repeatMode = prevEntropy->hufCTable_repeatMode; 1380*19fcbaf1SConrad Meyer memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, 1381*19fcbaf1SConrad Meyer sizeof(prevEntropy->hufCTable)); 1382*19fcbaf1SConrad Meyer 1383*19fcbaf1SConrad Meyer if (disableLiteralCompression) 1384*19fcbaf1SConrad Meyer return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 13850c16b537SWarner Losh 13860c16b537SWarner Losh /* small ? don't even attempt compression (speed opt) */ 1387*19fcbaf1SConrad Meyer # define COMPRESS_LITERALS_SIZE_MIN 63 1388*19fcbaf1SConrad Meyer { size_t const minLitSize = (prevEntropy->hufCTable_repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN; 13890c16b537SWarner Losh if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 13900c16b537SWarner Losh } 13910c16b537SWarner Losh 13920c16b537SWarner Losh if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ 1393*19fcbaf1SConrad Meyer { HUF_repeat repeat = prevEntropy->hufCTable_repeatMode; 13940c16b537SWarner Losh int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0; 13950c16b537SWarner Losh if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1; 13960c16b537SWarner Losh cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, 1397*19fcbaf1SConrad Meyer workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextEntropy->hufCTable, &repeat, preferRepeat, bmi2) 13980c16b537SWarner Losh : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, 1399*19fcbaf1SConrad Meyer workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextEntropy->hufCTable, &repeat, preferRepeat, bmi2); 1400*19fcbaf1SConrad Meyer if (repeat != HUF_repeat_none) { 1401*19fcbaf1SConrad Meyer /* reused the existing table */ 1402*19fcbaf1SConrad Meyer hType = set_repeat; 1403*19fcbaf1SConrad Meyer } 14040c16b537SWarner Losh } 14050c16b537SWarner Losh 14060c16b537SWarner Losh if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) { 1407*19fcbaf1SConrad Meyer memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, sizeof(prevEntropy->hufCTable)); 14080c16b537SWarner Losh return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 14090c16b537SWarner Losh } 14100c16b537SWarner Losh if (cLitSize==1) { 1411*19fcbaf1SConrad Meyer memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, sizeof(prevEntropy->hufCTable)); 14120c16b537SWarner Losh return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); 14130c16b537SWarner Losh } 14140c16b537SWarner Losh 1415*19fcbaf1SConrad Meyer if (hType == set_compressed) { 1416*19fcbaf1SConrad Meyer /* using a newly constructed table */ 1417*19fcbaf1SConrad Meyer nextEntropy->hufCTable_repeatMode = HUF_repeat_check; 1418*19fcbaf1SConrad Meyer } 1419*19fcbaf1SConrad Meyer 14200c16b537SWarner Losh /* Build header */ 14210c16b537SWarner Losh switch(lhSize) 14220c16b537SWarner Losh { 14230c16b537SWarner Losh case 3: /* 2 - 2 - 10 - 10 */ 14240c16b537SWarner Losh { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14); 14250c16b537SWarner Losh MEM_writeLE24(ostart, lhc); 14260c16b537SWarner Losh break; 14270c16b537SWarner Losh } 14280c16b537SWarner Losh case 4: /* 2 - 2 - 14 - 14 */ 14290c16b537SWarner Losh { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18); 14300c16b537SWarner Losh MEM_writeLE32(ostart, lhc); 14310c16b537SWarner Losh break; 14320c16b537SWarner Losh } 14330c16b537SWarner Losh case 5: /* 2 - 2 - 18 - 18 */ 14340c16b537SWarner Losh { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22); 14350c16b537SWarner Losh MEM_writeLE32(ostart, lhc); 14360c16b537SWarner Losh ostart[4] = (BYTE)(cLitSize >> 10); 14370c16b537SWarner Losh break; 14380c16b537SWarner Losh } 14390c16b537SWarner Losh default: /* not possible : lhSize is {3,4,5} */ 14400c16b537SWarner Losh assert(0); 14410c16b537SWarner Losh } 14420c16b537SWarner Losh return lhSize+cLitSize; 14430c16b537SWarner Losh } 14440c16b537SWarner Losh 14450c16b537SWarner Losh 14460c16b537SWarner Losh void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) 14470c16b537SWarner Losh { 14480c16b537SWarner Losh const seqDef* const sequences = seqStorePtr->sequencesStart; 14490c16b537SWarner Losh BYTE* const llCodeTable = seqStorePtr->llCode; 14500c16b537SWarner Losh BYTE* const ofCodeTable = seqStorePtr->ofCode; 14510c16b537SWarner Losh BYTE* const mlCodeTable = seqStorePtr->mlCode; 14520c16b537SWarner Losh U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 14530c16b537SWarner Losh U32 u; 14540c16b537SWarner Losh for (u=0; u<nbSeq; u++) { 14550c16b537SWarner Losh U32 const llv = sequences[u].litLength; 14560c16b537SWarner Losh U32 const mlv = sequences[u].matchLength; 1457052d3c12SConrad Meyer llCodeTable[u] = (BYTE)ZSTD_LLcode(llv); 14580c16b537SWarner Losh ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset); 1459052d3c12SConrad Meyer mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv); 14600c16b537SWarner Losh } 14610c16b537SWarner Losh if (seqStorePtr->longLengthID==1) 14620c16b537SWarner Losh llCodeTable[seqStorePtr->longLengthPos] = MaxLL; 14630c16b537SWarner Losh if (seqStorePtr->longLengthID==2) 14640c16b537SWarner Losh mlCodeTable[seqStorePtr->longLengthPos] = MaxML; 14650c16b537SWarner Losh } 14660c16b537SWarner Losh 14670c16b537SWarner Losh typedef enum { 14680c16b537SWarner Losh ZSTD_defaultDisallowed = 0, 14690c16b537SWarner Losh ZSTD_defaultAllowed = 1 14700c16b537SWarner Losh } ZSTD_defaultPolicy_e; 14710c16b537SWarner Losh 1472052d3c12SConrad Meyer MEM_STATIC 1473052d3c12SConrad Meyer symbolEncodingType_e ZSTD_selectEncodingType( 14740c16b537SWarner Losh FSE_repeat* repeatMode, size_t const mostFrequent, size_t nbSeq, 14750c16b537SWarner Losh U32 defaultNormLog, ZSTD_defaultPolicy_e const isDefaultAllowed) 14760c16b537SWarner Losh { 14770c16b537SWarner Losh #define MIN_SEQ_FOR_DYNAMIC_FSE 64 14780c16b537SWarner Losh #define MAX_SEQ_FOR_STATIC_FSE 1000 14790c16b537SWarner Losh ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0); 14800c16b537SWarner Losh if ((mostFrequent == nbSeq) && (!isDefaultAllowed || nbSeq > 2)) { 1481052d3c12SConrad Meyer DEBUGLOG(5, "Selected set_rle"); 14820c16b537SWarner Losh /* Prefer set_basic over set_rle when there are 2 or less symbols, 14830c16b537SWarner Losh * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol. 14840c16b537SWarner Losh * If basic encoding isn't possible, always choose RLE. 14850c16b537SWarner Losh */ 14860c16b537SWarner Losh *repeatMode = FSE_repeat_check; 14870c16b537SWarner Losh return set_rle; 14880c16b537SWarner Losh } 1489052d3c12SConrad Meyer if ( isDefaultAllowed 1490052d3c12SConrad Meyer && (*repeatMode == FSE_repeat_valid) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { 1491052d3c12SConrad Meyer DEBUGLOG(5, "Selected set_repeat"); 14920c16b537SWarner Losh return set_repeat; 14930c16b537SWarner Losh } 1494052d3c12SConrad Meyer if ( isDefaultAllowed 1495052d3c12SConrad Meyer && ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (defaultNormLog-1)))) ) { 1496052d3c12SConrad Meyer DEBUGLOG(5, "Selected set_basic"); 1497052d3c12SConrad Meyer /* The format allows default tables to be repeated, but it isn't useful. 1498052d3c12SConrad Meyer * When using simple heuristics to select encoding type, we don't want 1499052d3c12SConrad Meyer * to confuse these tables with dictionaries. When running more careful 1500052d3c12SConrad Meyer * analysis, we don't need to waste time checking both repeating tables 1501052d3c12SConrad Meyer * and default tables. 1502052d3c12SConrad Meyer */ 1503052d3c12SConrad Meyer *repeatMode = FSE_repeat_none; 15040c16b537SWarner Losh return set_basic; 15050c16b537SWarner Losh } 1506052d3c12SConrad Meyer DEBUGLOG(5, "Selected set_compressed"); 15070c16b537SWarner Losh *repeatMode = FSE_repeat_check; 15080c16b537SWarner Losh return set_compressed; 15090c16b537SWarner Losh } 15100c16b537SWarner Losh 1511052d3c12SConrad Meyer MEM_STATIC 1512052d3c12SConrad Meyer size_t ZSTD_buildCTable(void* dst, size_t dstCapacity, 1513*19fcbaf1SConrad Meyer FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type, 15140c16b537SWarner Losh U32* count, U32 max, 15150c16b537SWarner Losh BYTE const* codeTable, size_t nbSeq, 15160c16b537SWarner Losh S16 const* defaultNorm, U32 defaultNormLog, U32 defaultMax, 1517*19fcbaf1SConrad Meyer FSE_CTable const* prevCTable, size_t prevCTableSize, 15180c16b537SWarner Losh void* workspace, size_t workspaceSize) 15190c16b537SWarner Losh { 15200c16b537SWarner Losh BYTE* op = (BYTE*)dst; 15210c16b537SWarner Losh BYTE const* const oend = op + dstCapacity; 15220c16b537SWarner Losh 15230c16b537SWarner Losh switch (type) { 15240c16b537SWarner Losh case set_rle: 15250c16b537SWarner Losh *op = codeTable[0]; 1526*19fcbaf1SConrad Meyer CHECK_F(FSE_buildCTable_rle(nextCTable, (BYTE)max)); 15270c16b537SWarner Losh return 1; 15280c16b537SWarner Losh case set_repeat: 1529*19fcbaf1SConrad Meyer memcpy(nextCTable, prevCTable, prevCTableSize); 15300c16b537SWarner Losh return 0; 15310c16b537SWarner Losh case set_basic: 1532*19fcbaf1SConrad Meyer CHECK_F(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */ 15330c16b537SWarner Losh return 0; 15340c16b537SWarner Losh case set_compressed: { 15350c16b537SWarner Losh S16 norm[MaxSeq + 1]; 15360c16b537SWarner Losh size_t nbSeq_1 = nbSeq; 15370c16b537SWarner Losh const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max); 15380c16b537SWarner Losh if (count[codeTable[nbSeq-1]] > 1) { 15390c16b537SWarner Losh count[codeTable[nbSeq-1]]--; 15400c16b537SWarner Losh nbSeq_1--; 15410c16b537SWarner Losh } 15420c16b537SWarner Losh assert(nbSeq_1 > 1); 15430c16b537SWarner Losh CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max)); 15440c16b537SWarner Losh { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */ 15450c16b537SWarner Losh if (FSE_isError(NCountSize)) return NCountSize; 1546*19fcbaf1SConrad Meyer CHECK_F(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, workspace, workspaceSize)); 15470c16b537SWarner Losh return NCountSize; 15480c16b537SWarner Losh } 15490c16b537SWarner Losh } 15500c16b537SWarner Losh default: return assert(0), ERROR(GENERIC); 15510c16b537SWarner Losh } 15520c16b537SWarner Losh } 15530c16b537SWarner Losh 1554*19fcbaf1SConrad Meyer FORCE_INLINE_TEMPLATE size_t 1555*19fcbaf1SConrad Meyer ZSTD_encodeSequences_body( 1556052d3c12SConrad Meyer void* dst, size_t dstCapacity, 15570c16b537SWarner Losh FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 15580c16b537SWarner Losh FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 15590c16b537SWarner Losh FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 15600c16b537SWarner Losh seqDef const* sequences, size_t nbSeq, int longOffsets) 15610c16b537SWarner Losh { 15620c16b537SWarner Losh BIT_CStream_t blockStream; 15630c16b537SWarner Losh FSE_CState_t stateMatchLength; 15640c16b537SWarner Losh FSE_CState_t stateOffsetBits; 15650c16b537SWarner Losh FSE_CState_t stateLitLength; 15660c16b537SWarner Losh 15670c16b537SWarner Losh CHECK_E(BIT_initCStream(&blockStream, dst, dstCapacity), dstSize_tooSmall); /* not enough space remaining */ 15680c16b537SWarner Losh 15690c16b537SWarner Losh /* first symbols */ 15700c16b537SWarner Losh FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]); 15710c16b537SWarner Losh FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]); 15720c16b537SWarner Losh FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]); 15730c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]); 15740c16b537SWarner Losh if (MEM_32bits()) BIT_flushBits(&blockStream); 15750c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]); 15760c16b537SWarner Losh if (MEM_32bits()) BIT_flushBits(&blockStream); 15770c16b537SWarner Losh if (longOffsets) { 15780c16b537SWarner Losh U32 const ofBits = ofCodeTable[nbSeq-1]; 15790c16b537SWarner Losh int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); 15800c16b537SWarner Losh if (extraBits) { 15810c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits); 15820c16b537SWarner Losh BIT_flushBits(&blockStream); 15830c16b537SWarner Losh } 15840c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits, 15850c16b537SWarner Losh ofBits - extraBits); 15860c16b537SWarner Losh } else { 15870c16b537SWarner Losh BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]); 15880c16b537SWarner Losh } 15890c16b537SWarner Losh BIT_flushBits(&blockStream); 15900c16b537SWarner Losh 15910c16b537SWarner Losh { size_t n; 15920c16b537SWarner Losh for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */ 15930c16b537SWarner Losh BYTE const llCode = llCodeTable[n]; 15940c16b537SWarner Losh BYTE const ofCode = ofCodeTable[n]; 15950c16b537SWarner Losh BYTE const mlCode = mlCodeTable[n]; 15960c16b537SWarner Losh U32 const llBits = LL_bits[llCode]; 1597052d3c12SConrad Meyer U32 const ofBits = ofCode; 15980c16b537SWarner Losh U32 const mlBits = ML_bits[mlCode]; 1599052d3c12SConrad Meyer DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u", 1600052d3c12SConrad Meyer sequences[n].litLength, 1601052d3c12SConrad Meyer sequences[n].matchLength + MINMATCH, 1602*19fcbaf1SConrad Meyer sequences[n].offset); 1603*19fcbaf1SConrad Meyer /* 32b*/ /* 64b*/ 16040c16b537SWarner Losh /* (7)*/ /* (7)*/ 16050c16b537SWarner Losh FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */ 16060c16b537SWarner Losh FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */ 16070c16b537SWarner Losh if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/ 16080c16b537SWarner Losh FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */ 16090c16b537SWarner Losh if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog))) 16100c16b537SWarner Losh BIT_flushBits(&blockStream); /* (7)*/ 16110c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].litLength, llBits); 16120c16b537SWarner Losh if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream); 16130c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].matchLength, mlBits); 16140c16b537SWarner Losh if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream); 16150c16b537SWarner Losh if (longOffsets) { 16160c16b537SWarner Losh int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1); 16170c16b537SWarner Losh if (extraBits) { 16180c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].offset, extraBits); 16190c16b537SWarner Losh BIT_flushBits(&blockStream); /* (7)*/ 16200c16b537SWarner Losh } 16210c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].offset >> extraBits, 16220c16b537SWarner Losh ofBits - extraBits); /* 31 */ 16230c16b537SWarner Losh } else { 16240c16b537SWarner Losh BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */ 16250c16b537SWarner Losh } 16260c16b537SWarner Losh BIT_flushBits(&blockStream); /* (7)*/ 16270c16b537SWarner Losh } } 16280c16b537SWarner Losh 1629*19fcbaf1SConrad Meyer DEBUGLOG(6, "ZSTD_encodeSequences: flushing ML state with %u bits", stateMatchLength.stateLog); 16300c16b537SWarner Losh FSE_flushCState(&blockStream, &stateMatchLength); 1631*19fcbaf1SConrad Meyer DEBUGLOG(6, "ZSTD_encodeSequences: flushing Off state with %u bits", stateOffsetBits.stateLog); 16320c16b537SWarner Losh FSE_flushCState(&blockStream, &stateOffsetBits); 1633*19fcbaf1SConrad Meyer DEBUGLOG(6, "ZSTD_encodeSequences: flushing LL state with %u bits", stateLitLength.stateLog); 16340c16b537SWarner Losh FSE_flushCState(&blockStream, &stateLitLength); 16350c16b537SWarner Losh 16360c16b537SWarner Losh { size_t const streamSize = BIT_closeCStream(&blockStream); 16370c16b537SWarner Losh if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */ 16380c16b537SWarner Losh return streamSize; 16390c16b537SWarner Losh } 16400c16b537SWarner Losh } 16410c16b537SWarner Losh 1642*19fcbaf1SConrad Meyer static size_t 1643*19fcbaf1SConrad Meyer ZSTD_encodeSequences_default( 1644*19fcbaf1SConrad Meyer void* dst, size_t dstCapacity, 1645*19fcbaf1SConrad Meyer FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 1646*19fcbaf1SConrad Meyer FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 1647*19fcbaf1SConrad Meyer FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 1648*19fcbaf1SConrad Meyer seqDef const* sequences, size_t nbSeq, int longOffsets) 16490c16b537SWarner Losh { 1650*19fcbaf1SConrad Meyer return ZSTD_encodeSequences_body(dst, dstCapacity, 1651*19fcbaf1SConrad Meyer CTable_MatchLength, mlCodeTable, 1652*19fcbaf1SConrad Meyer CTable_OffsetBits, ofCodeTable, 1653*19fcbaf1SConrad Meyer CTable_LitLength, llCodeTable, 1654*19fcbaf1SConrad Meyer sequences, nbSeq, longOffsets); 1655*19fcbaf1SConrad Meyer } 1656*19fcbaf1SConrad Meyer 1657*19fcbaf1SConrad Meyer 1658*19fcbaf1SConrad Meyer #if DYNAMIC_BMI2 1659*19fcbaf1SConrad Meyer 1660*19fcbaf1SConrad Meyer static TARGET_ATTRIBUTE("bmi2") size_t 1661*19fcbaf1SConrad Meyer ZSTD_encodeSequences_bmi2( 1662*19fcbaf1SConrad Meyer void* dst, size_t dstCapacity, 1663*19fcbaf1SConrad Meyer FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 1664*19fcbaf1SConrad Meyer FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 1665*19fcbaf1SConrad Meyer FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 1666*19fcbaf1SConrad Meyer seqDef const* sequences, size_t nbSeq, int longOffsets) 1667*19fcbaf1SConrad Meyer { 1668*19fcbaf1SConrad Meyer return ZSTD_encodeSequences_body(dst, dstCapacity, 1669*19fcbaf1SConrad Meyer CTable_MatchLength, mlCodeTable, 1670*19fcbaf1SConrad Meyer CTable_OffsetBits, ofCodeTable, 1671*19fcbaf1SConrad Meyer CTable_LitLength, llCodeTable, 1672*19fcbaf1SConrad Meyer sequences, nbSeq, longOffsets); 1673*19fcbaf1SConrad Meyer } 1674*19fcbaf1SConrad Meyer 1675*19fcbaf1SConrad Meyer #endif 1676*19fcbaf1SConrad Meyer 1677*19fcbaf1SConrad Meyer size_t ZSTD_encodeSequences( 1678*19fcbaf1SConrad Meyer void* dst, size_t dstCapacity, 1679*19fcbaf1SConrad Meyer FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable, 1680*19fcbaf1SConrad Meyer FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable, 1681*19fcbaf1SConrad Meyer FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable, 1682*19fcbaf1SConrad Meyer seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2) 1683*19fcbaf1SConrad Meyer { 1684*19fcbaf1SConrad Meyer #if DYNAMIC_BMI2 1685*19fcbaf1SConrad Meyer if (bmi2) { 1686*19fcbaf1SConrad Meyer return ZSTD_encodeSequences_bmi2(dst, dstCapacity, 1687*19fcbaf1SConrad Meyer CTable_MatchLength, mlCodeTable, 1688*19fcbaf1SConrad Meyer CTable_OffsetBits, ofCodeTable, 1689*19fcbaf1SConrad Meyer CTable_LitLength, llCodeTable, 1690*19fcbaf1SConrad Meyer sequences, nbSeq, longOffsets); 1691*19fcbaf1SConrad Meyer } 1692*19fcbaf1SConrad Meyer #endif 1693*19fcbaf1SConrad Meyer (void)bmi2; 1694*19fcbaf1SConrad Meyer return ZSTD_encodeSequences_default(dst, dstCapacity, 1695*19fcbaf1SConrad Meyer CTable_MatchLength, mlCodeTable, 1696*19fcbaf1SConrad Meyer CTable_OffsetBits, ofCodeTable, 1697*19fcbaf1SConrad Meyer CTable_LitLength, llCodeTable, 1698*19fcbaf1SConrad Meyer sequences, nbSeq, longOffsets); 1699*19fcbaf1SConrad Meyer } 1700*19fcbaf1SConrad Meyer 1701*19fcbaf1SConrad Meyer MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr, 1702*19fcbaf1SConrad Meyer ZSTD_entropyCTables_t const* prevEntropy, 1703*19fcbaf1SConrad Meyer ZSTD_entropyCTables_t* nextEntropy, 1704*19fcbaf1SConrad Meyer ZSTD_CCtx_params const* cctxParams, 1705*19fcbaf1SConrad Meyer void* dst, size_t dstCapacity, U32* workspace, 1706*19fcbaf1SConrad Meyer const int bmi2) 1707*19fcbaf1SConrad Meyer { 1708*19fcbaf1SConrad Meyer const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN; 17090c16b537SWarner Losh U32 count[MaxSeq+1]; 1710*19fcbaf1SConrad Meyer FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable; 1711*19fcbaf1SConrad Meyer FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable; 1712*19fcbaf1SConrad Meyer FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable; 17130c16b537SWarner Losh U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ 17140c16b537SWarner Losh const seqDef* const sequences = seqStorePtr->sequencesStart; 17150c16b537SWarner Losh const BYTE* const ofCodeTable = seqStorePtr->ofCode; 17160c16b537SWarner Losh const BYTE* const llCodeTable = seqStorePtr->llCode; 17170c16b537SWarner Losh const BYTE* const mlCodeTable = seqStorePtr->mlCode; 17180c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 17190c16b537SWarner Losh BYTE* const oend = ostart + dstCapacity; 17200c16b537SWarner Losh BYTE* op = ostart; 17210c16b537SWarner Losh size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart; 17220c16b537SWarner Losh BYTE* seqHead; 17230c16b537SWarner Losh 1724*19fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 17250c16b537SWarner Losh 17260c16b537SWarner Losh /* Compress literals */ 17270c16b537SWarner Losh { const BYTE* const literals = seqStorePtr->litStart; 17280c16b537SWarner Losh size_t const litSize = seqStorePtr->lit - literals; 17290c16b537SWarner Losh size_t const cSize = ZSTD_compressLiterals( 1730*19fcbaf1SConrad Meyer prevEntropy, nextEntropy, 1731*19fcbaf1SConrad Meyer cctxParams->cParams.strategy, cctxParams->disableLiteralCompression, 1732*19fcbaf1SConrad Meyer op, dstCapacity, 1733*19fcbaf1SConrad Meyer literals, litSize, 1734*19fcbaf1SConrad Meyer workspace, bmi2); 17350c16b537SWarner Losh if (ZSTD_isError(cSize)) 17360c16b537SWarner Losh return cSize; 1737052d3c12SConrad Meyer assert(cSize <= dstCapacity); 17380c16b537SWarner Losh op += cSize; 17390c16b537SWarner Losh } 17400c16b537SWarner Losh 17410c16b537SWarner Losh /* Sequences Header */ 17420c16b537SWarner Losh if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/) return ERROR(dstSize_tooSmall); 1743052d3c12SConrad Meyer if (nbSeq < 0x7F) 1744052d3c12SConrad Meyer *op++ = (BYTE)nbSeq; 1745052d3c12SConrad Meyer else if (nbSeq < LONGNBSEQ) 1746052d3c12SConrad Meyer op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; 1747052d3c12SConrad Meyer else 1748052d3c12SConrad Meyer op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; 1749*19fcbaf1SConrad Meyer if (nbSeq==0) { 1750*19fcbaf1SConrad Meyer memcpy(nextEntropy->litlengthCTable, prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable)); 1751*19fcbaf1SConrad Meyer nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode; 1752*19fcbaf1SConrad Meyer memcpy(nextEntropy->offcodeCTable, prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable)); 1753*19fcbaf1SConrad Meyer nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode; 1754*19fcbaf1SConrad Meyer memcpy(nextEntropy->matchlengthCTable, prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable)); 1755*19fcbaf1SConrad Meyer nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode; 1756*19fcbaf1SConrad Meyer return op - ostart; 1757*19fcbaf1SConrad Meyer } 17580c16b537SWarner Losh 17590c16b537SWarner Losh /* seqHead : flags for FSE encoding type */ 17600c16b537SWarner Losh seqHead = op++; 17610c16b537SWarner Losh 17620c16b537SWarner Losh /* convert length/distances into codes */ 17630c16b537SWarner Losh ZSTD_seqToCodes(seqStorePtr); 1764052d3c12SConrad Meyer /* build CTable for Literal Lengths */ 17650c16b537SWarner Losh { U32 max = MaxLL; 1766*19fcbaf1SConrad Meyer size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace); 1767052d3c12SConrad Meyer DEBUGLOG(5, "Building LL table"); 1768*19fcbaf1SConrad Meyer nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode; 1769*19fcbaf1SConrad Meyer LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed); 17700c16b537SWarner Losh { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype, 17710c16b537SWarner Losh count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL, 1772*19fcbaf1SConrad Meyer prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable), 1773*19fcbaf1SConrad Meyer workspace, HUF_WORKSPACE_SIZE); 17740c16b537SWarner Losh if (ZSTD_isError(countSize)) return countSize; 17750c16b537SWarner Losh op += countSize; 17760c16b537SWarner Losh } } 1777052d3c12SConrad Meyer /* build CTable for Offsets */ 17780c16b537SWarner Losh { U32 max = MaxOff; 1779*19fcbaf1SConrad Meyer size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace); 17800c16b537SWarner Losh /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */ 1781052d3c12SConrad Meyer ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed; 1782052d3c12SConrad Meyer DEBUGLOG(5, "Building OF table"); 1783*19fcbaf1SConrad Meyer nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode; 1784*19fcbaf1SConrad Meyer Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy); 17850c16b537SWarner Losh { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype, 17860c16b537SWarner Losh count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff, 1787*19fcbaf1SConrad Meyer prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable), 1788*19fcbaf1SConrad Meyer workspace, HUF_WORKSPACE_SIZE); 17890c16b537SWarner Losh if (ZSTD_isError(countSize)) return countSize; 17900c16b537SWarner Losh op += countSize; 17910c16b537SWarner Losh } } 1792052d3c12SConrad Meyer /* build CTable for MatchLengths */ 17930c16b537SWarner Losh { U32 max = MaxML; 1794*19fcbaf1SConrad Meyer size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace); 1795052d3c12SConrad Meyer DEBUGLOG(5, "Building ML table"); 1796*19fcbaf1SConrad Meyer nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode; 1797*19fcbaf1SConrad Meyer MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed); 17980c16b537SWarner Losh { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype, 17990c16b537SWarner Losh count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML, 1800*19fcbaf1SConrad Meyer prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable), 1801*19fcbaf1SConrad Meyer workspace, HUF_WORKSPACE_SIZE); 18020c16b537SWarner Losh if (ZSTD_isError(countSize)) return countSize; 18030c16b537SWarner Losh op += countSize; 18040c16b537SWarner Losh } } 18050c16b537SWarner Losh 18060c16b537SWarner Losh *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); 18070c16b537SWarner Losh 1808052d3c12SConrad Meyer { size_t const bitstreamSize = ZSTD_encodeSequences( 1809052d3c12SConrad Meyer op, oend - op, 18100c16b537SWarner Losh CTable_MatchLength, mlCodeTable, 18110c16b537SWarner Losh CTable_OffsetBits, ofCodeTable, 18120c16b537SWarner Losh CTable_LitLength, llCodeTable, 1813052d3c12SConrad Meyer sequences, nbSeq, 1814*19fcbaf1SConrad Meyer longOffsets, bmi2); 1815052d3c12SConrad Meyer if (ZSTD_isError(bitstreamSize)) return bitstreamSize; 1816052d3c12SConrad Meyer op += bitstreamSize; 18170c16b537SWarner Losh } 18180c16b537SWarner Losh 18190c16b537SWarner Losh return op - ostart; 18200c16b537SWarner Losh } 18210c16b537SWarner Losh 18220c16b537SWarner Losh MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr, 1823*19fcbaf1SConrad Meyer ZSTD_entropyCTables_t const* prevEntropy, 1824*19fcbaf1SConrad Meyer ZSTD_entropyCTables_t* nextEntropy, 1825*19fcbaf1SConrad Meyer ZSTD_CCtx_params const* cctxParams, 18260c16b537SWarner Losh void* dst, size_t dstCapacity, 1827*19fcbaf1SConrad Meyer size_t srcSize, U32* workspace, int bmi2) 18280c16b537SWarner Losh { 1829*19fcbaf1SConrad Meyer size_t const cSize = ZSTD_compressSequences_internal( 1830*19fcbaf1SConrad Meyer seqStorePtr, prevEntropy, nextEntropy, cctxParams, dst, dstCapacity, 1831*19fcbaf1SConrad Meyer workspace, bmi2); 1832*19fcbaf1SConrad Meyer /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block. 1833*19fcbaf1SConrad Meyer * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block. 18340c16b537SWarner Losh */ 1835*19fcbaf1SConrad Meyer if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity)) 1836*19fcbaf1SConrad Meyer return 0; /* block not compressed */ 1837*19fcbaf1SConrad Meyer if (ZSTD_isError(cSize)) return cSize; 1838*19fcbaf1SConrad Meyer 1839*19fcbaf1SConrad Meyer /* Check compressibility */ 1840*19fcbaf1SConrad Meyer { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize); /* note : fixed formula, maybe should depend on compression level, or strategy */ 1841*19fcbaf1SConrad Meyer if (cSize >= maxCSize) return 0; /* block not compressed */ 1842*19fcbaf1SConrad Meyer } 1843*19fcbaf1SConrad Meyer 1844052d3c12SConrad Meyer /* We check that dictionaries have offset codes available for the first 1845052d3c12SConrad Meyer * block. After the first block, the offcode table might not have large 1846052d3c12SConrad Meyer * enough codes to represent the offsets in the data. 1847052d3c12SConrad Meyer */ 1848*19fcbaf1SConrad Meyer if (nextEntropy->offcode_repeatMode == FSE_repeat_valid) 1849*19fcbaf1SConrad Meyer nextEntropy->offcode_repeatMode = FSE_repeat_check; 1850052d3c12SConrad Meyer 18510c16b537SWarner Losh return cSize; 18520c16b537SWarner Losh } 18530c16b537SWarner Losh 18540c16b537SWarner Losh /* ZSTD_selectBlockCompressor() : 18550c16b537SWarner Losh * Not static, but internal use only (used by long distance matcher) 18560c16b537SWarner Losh * assumption : strat is a valid strategy */ 18570c16b537SWarner Losh ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict) 18580c16b537SWarner Losh { 18590c16b537SWarner Losh static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = { 18600c16b537SWarner Losh { ZSTD_compressBlock_fast /* default for 0 */, 18610c16b537SWarner Losh ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, 18620c16b537SWarner Losh ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, 18630c16b537SWarner Losh ZSTD_compressBlock_btopt, ZSTD_compressBlock_btultra }, 18640c16b537SWarner Losh { ZSTD_compressBlock_fast_extDict /* default for 0 */, 18650c16b537SWarner Losh ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict, 18660c16b537SWarner Losh ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, 18670c16b537SWarner Losh ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict } 18680c16b537SWarner Losh }; 18690c16b537SWarner Losh ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1); 1870052d3c12SConrad Meyer 18710c16b537SWarner Losh assert((U32)strat >= (U32)ZSTD_fast); 18720c16b537SWarner Losh assert((U32)strat <= (U32)ZSTD_btultra); 18730c16b537SWarner Losh return blockCompressor[extDict!=0][(U32)strat]; 18740c16b537SWarner Losh } 18750c16b537SWarner Losh 18760c16b537SWarner Losh static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr, 18770c16b537SWarner Losh const BYTE* anchor, size_t lastLLSize) 18780c16b537SWarner Losh { 18790c16b537SWarner Losh memcpy(seqStorePtr->lit, anchor, lastLLSize); 18800c16b537SWarner Losh seqStorePtr->lit += lastLLSize; 18810c16b537SWarner Losh } 18820c16b537SWarner Losh 1883052d3c12SConrad Meyer static void ZSTD_resetSeqStore(seqStore_t* ssPtr) 1884052d3c12SConrad Meyer { 1885052d3c12SConrad Meyer ssPtr->lit = ssPtr->litStart; 1886052d3c12SConrad Meyer ssPtr->sequences = ssPtr->sequencesStart; 1887052d3c12SConrad Meyer ssPtr->longLengthID = 0; 1888052d3c12SConrad Meyer } 1889052d3c12SConrad Meyer 1890*19fcbaf1SConrad Meyer static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, 1891*19fcbaf1SConrad Meyer void* dst, size_t dstCapacity, 1892*19fcbaf1SConrad Meyer const void* src, size_t srcSize) 18930c16b537SWarner Losh { 1894*19fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &zc->blockState.matchState; 1895*19fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)", 1896*19fcbaf1SConrad Meyer (U32)dstCapacity, ms->window.dictLimit, ms->nextToUpdate); 1897*19fcbaf1SConrad Meyer if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) { 1898*19fcbaf1SConrad Meyer ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.searchLength); 1899052d3c12SConrad Meyer return 0; /* don't even attempt compression below a certain srcSize */ 1900*19fcbaf1SConrad Meyer } 1901052d3c12SConrad Meyer ZSTD_resetSeqStore(&(zc->seqStore)); 1902052d3c12SConrad Meyer 1903052d3c12SConrad Meyer /* limited update after a very long match */ 1904*19fcbaf1SConrad Meyer { const BYTE* const base = ms->window.base; 19050c16b537SWarner Losh const BYTE* const istart = (const BYTE*)src; 19060c16b537SWarner Losh const U32 current = (U32)(istart-base); 1907*19fcbaf1SConrad Meyer if (current > ms->nextToUpdate + 384) 1908*19fcbaf1SConrad Meyer ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384)); 1909052d3c12SConrad Meyer } 1910*19fcbaf1SConrad Meyer 1911*19fcbaf1SConrad Meyer /* select and store sequences */ 1912*19fcbaf1SConrad Meyer { U32 const extDict = ZSTD_window_hasExtDict(ms->window); 1913*19fcbaf1SConrad Meyer size_t lastLLSize; 1914*19fcbaf1SConrad Meyer { int i; 1915*19fcbaf1SConrad Meyer for (i = 0; i < ZSTD_REP_NUM; ++i) 1916*19fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i]; 1917052d3c12SConrad Meyer } 1918*19fcbaf1SConrad Meyer if (zc->externSeqStore.pos < zc->externSeqStore.size) { 1919*19fcbaf1SConrad Meyer assert(!zc->appliedParams.ldmParams.enableLdm); 1920*19fcbaf1SConrad Meyer /* Updates ldmSeqStore.pos */ 1921*19fcbaf1SConrad Meyer lastLLSize = 1922*19fcbaf1SConrad Meyer ZSTD_ldm_blockCompress(&zc->externSeqStore, 1923*19fcbaf1SConrad Meyer ms, &zc->seqStore, 1924*19fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep, 1925*19fcbaf1SConrad Meyer &zc->appliedParams.cParams, 1926*19fcbaf1SConrad Meyer src, srcSize, extDict); 1927*19fcbaf1SConrad Meyer assert(zc->externSeqStore.pos <= zc->externSeqStore.size); 1928*19fcbaf1SConrad Meyer } else if (zc->appliedParams.ldmParams.enableLdm) { 1929*19fcbaf1SConrad Meyer rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0}; 1930*19fcbaf1SConrad Meyer 1931*19fcbaf1SConrad Meyer ldmSeqStore.seq = zc->ldmSequences; 1932*19fcbaf1SConrad Meyer ldmSeqStore.capacity = zc->maxNbLdmSequences; 1933*19fcbaf1SConrad Meyer /* Updates ldmSeqStore.size */ 1934*19fcbaf1SConrad Meyer CHECK_F(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore, 1935*19fcbaf1SConrad Meyer &zc->appliedParams.ldmParams, 1936*19fcbaf1SConrad Meyer src, srcSize)); 1937*19fcbaf1SConrad Meyer /* Updates ldmSeqStore.pos */ 1938*19fcbaf1SConrad Meyer lastLLSize = 1939*19fcbaf1SConrad Meyer ZSTD_ldm_blockCompress(&ldmSeqStore, 1940*19fcbaf1SConrad Meyer ms, &zc->seqStore, 1941*19fcbaf1SConrad Meyer zc->blockState.nextCBlock->rep, 1942*19fcbaf1SConrad Meyer &zc->appliedParams.cParams, 1943*19fcbaf1SConrad Meyer src, srcSize, extDict); 1944*19fcbaf1SConrad Meyer assert(ldmSeqStore.pos == ldmSeqStore.size); 1945*19fcbaf1SConrad Meyer } else { /* not long range mode */ 1946*19fcbaf1SConrad Meyer ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict); 1947*19fcbaf1SConrad Meyer lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, &zc->appliedParams.cParams, src, srcSize); 1948*19fcbaf1SConrad Meyer } 1949*19fcbaf1SConrad Meyer { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize; 1950*19fcbaf1SConrad Meyer ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize); 1951*19fcbaf1SConrad Meyer } } 1952*19fcbaf1SConrad Meyer 1953*19fcbaf1SConrad Meyer /* encode sequences and literals */ 1954*19fcbaf1SConrad Meyer { size_t const cSize = ZSTD_compressSequences(&zc->seqStore, 1955*19fcbaf1SConrad Meyer &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy, 1956*19fcbaf1SConrad Meyer &zc->appliedParams, 1957*19fcbaf1SConrad Meyer dst, dstCapacity, 1958*19fcbaf1SConrad Meyer srcSize, zc->entropyWorkspace, zc->bmi2); 1959*19fcbaf1SConrad Meyer if (ZSTD_isError(cSize) || cSize == 0) return cSize; 1960*19fcbaf1SConrad Meyer /* confirm repcodes and entropy tables */ 1961*19fcbaf1SConrad Meyer { ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock; 1962*19fcbaf1SConrad Meyer zc->blockState.prevCBlock = zc->blockState.nextCBlock; 1963*19fcbaf1SConrad Meyer zc->blockState.nextCBlock = tmp; 1964*19fcbaf1SConrad Meyer } 1965*19fcbaf1SConrad Meyer return cSize; 1966*19fcbaf1SConrad Meyer } 19670c16b537SWarner Losh } 19680c16b537SWarner Losh 19690c16b537SWarner Losh 19700c16b537SWarner Losh /*! ZSTD_compress_frameChunk() : 19710c16b537SWarner Losh * Compress a chunk of data into one or multiple blocks. 19720c16b537SWarner Losh * All blocks will be terminated, all input will be consumed. 19730c16b537SWarner Losh * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content. 19740c16b537SWarner Losh * Frame is supposed already started (header already produced) 19750c16b537SWarner Losh * @return : compressed size, or an error code 19760c16b537SWarner Losh */ 19770c16b537SWarner Losh static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx, 19780c16b537SWarner Losh void* dst, size_t dstCapacity, 19790c16b537SWarner Losh const void* src, size_t srcSize, 19800c16b537SWarner Losh U32 lastFrameChunk) 19810c16b537SWarner Losh { 19820c16b537SWarner Losh size_t blockSize = cctx->blockSize; 19830c16b537SWarner Losh size_t remaining = srcSize; 19840c16b537SWarner Losh const BYTE* ip = (const BYTE*)src; 19850c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 19860c16b537SWarner Losh BYTE* op = ostart; 19870c16b537SWarner Losh U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog; 1988052d3c12SConrad Meyer assert(cctx->appliedParams.cParams.windowLog <= 31); 19890c16b537SWarner Losh 1990052d3c12SConrad Meyer DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (U32)blockSize); 19910c16b537SWarner Losh if (cctx->appliedParams.fParams.checksumFlag && srcSize) 19920c16b537SWarner Losh XXH64_update(&cctx->xxhState, src, srcSize); 19930c16b537SWarner Losh 19940c16b537SWarner Losh while (remaining) { 1995*19fcbaf1SConrad Meyer ZSTD_matchState_t* const ms = &cctx->blockState.matchState; 19960c16b537SWarner Losh U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); 19970c16b537SWarner Losh 19980c16b537SWarner Losh if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) 19990c16b537SWarner Losh return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */ 20000c16b537SWarner Losh if (remaining < blockSize) blockSize = remaining; 20010c16b537SWarner Losh 2002*19fcbaf1SConrad Meyer if (ZSTD_window_needOverflowCorrection(ms->window, ip + blockSize)) { 2003*19fcbaf1SConrad Meyer U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy); 2004*19fcbaf1SConrad Meyer U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip); 20050c16b537SWarner Losh ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30); 20060c16b537SWarner Losh ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30); 20070c16b537SWarner Losh ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31); 2008*19fcbaf1SConrad Meyer 20090c16b537SWarner Losh ZSTD_reduceIndex(cctx, correction); 2010*19fcbaf1SConrad Meyer if (ms->nextToUpdate < correction) ms->nextToUpdate = 0; 2011*19fcbaf1SConrad Meyer else ms->nextToUpdate -= correction; 2012*19fcbaf1SConrad Meyer ms->loadedDictEnd = 0; 20130c16b537SWarner Losh } 2014*19fcbaf1SConrad Meyer ZSTD_window_enforceMaxDist(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd); 2015*19fcbaf1SConrad Meyer if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit; 20160c16b537SWarner Losh 2017052d3c12SConrad Meyer { size_t cSize = ZSTD_compressBlock_internal(cctx, 2018052d3c12SConrad Meyer op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, 2019052d3c12SConrad Meyer ip, blockSize); 20200c16b537SWarner Losh if (ZSTD_isError(cSize)) return cSize; 20210c16b537SWarner Losh 20220c16b537SWarner Losh if (cSize == 0) { /* block is not compressible */ 20230c16b537SWarner Losh U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3); 20240c16b537SWarner Losh if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall); 2025052d3c12SConrad Meyer MEM_writeLE32(op, cBlockHeader24); /* 4th byte will be overwritten */ 20260c16b537SWarner Losh memcpy(op + ZSTD_blockHeaderSize, ip, blockSize); 20270c16b537SWarner Losh cSize = ZSTD_blockHeaderSize + blockSize; 20280c16b537SWarner Losh } else { 20290c16b537SWarner Losh U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); 20300c16b537SWarner Losh MEM_writeLE24(op, cBlockHeader24); 20310c16b537SWarner Losh cSize += ZSTD_blockHeaderSize; 20320c16b537SWarner Losh } 20330c16b537SWarner Losh 20340c16b537SWarner Losh ip += blockSize; 2035052d3c12SConrad Meyer assert(remaining >= blockSize); 2036052d3c12SConrad Meyer remaining -= blockSize; 20370c16b537SWarner Losh op += cSize; 2038052d3c12SConrad Meyer assert(dstCapacity >= cSize); 2039052d3c12SConrad Meyer dstCapacity -= cSize; 2040052d3c12SConrad Meyer DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u", 2041052d3c12SConrad Meyer (U32)cSize); 2042052d3c12SConrad Meyer } } 20430c16b537SWarner Losh 20440c16b537SWarner Losh if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending; 20450c16b537SWarner Losh return op-ostart; 20460c16b537SWarner Losh } 20470c16b537SWarner Losh 20480c16b537SWarner Losh 20490c16b537SWarner Losh static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, 20500c16b537SWarner Losh ZSTD_CCtx_params params, U64 pledgedSrcSize, U32 dictID) 20510c16b537SWarner Losh { BYTE* const op = (BYTE*)dst; 20520c16b537SWarner Losh U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */ 20530c16b537SWarner Losh U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */ 20540c16b537SWarner Losh U32 const checksumFlag = params.fParams.checksumFlag>0; 20550c16b537SWarner Losh U32 const windowSize = (U32)1 << params.cParams.windowLog; 20560c16b537SWarner Losh U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize); 20570c16b537SWarner Losh BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3); 20580c16b537SWarner Losh U32 const fcsCode = params.fParams.contentSizeFlag ? 20590c16b537SWarner Losh (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */ 20600c16b537SWarner Losh BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) ); 20610c16b537SWarner Losh size_t pos=0; 20620c16b537SWarner Losh 20630c16b537SWarner Losh if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall); 20640c16b537SWarner Losh DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u", 20650c16b537SWarner Losh !params.fParams.noDictIDFlag, dictID, dictIDSizeCode); 20660c16b537SWarner Losh 20670c16b537SWarner Losh if (params.format == ZSTD_f_zstd1) { 20680c16b537SWarner Losh MEM_writeLE32(dst, ZSTD_MAGICNUMBER); 20690c16b537SWarner Losh pos = 4; 20700c16b537SWarner Losh } 20710c16b537SWarner Losh op[pos++] = frameHeaderDecriptionByte; 20720c16b537SWarner Losh if (!singleSegment) op[pos++] = windowLogByte; 20730c16b537SWarner Losh switch(dictIDSizeCode) 20740c16b537SWarner Losh { 20750c16b537SWarner Losh default: assert(0); /* impossible */ 20760c16b537SWarner Losh case 0 : break; 20770c16b537SWarner Losh case 1 : op[pos] = (BYTE)(dictID); pos++; break; 20780c16b537SWarner Losh case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; 20790c16b537SWarner Losh case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break; 20800c16b537SWarner Losh } 20810c16b537SWarner Losh switch(fcsCode) 20820c16b537SWarner Losh { 20830c16b537SWarner Losh default: assert(0); /* impossible */ 20840c16b537SWarner Losh case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; 20850c16b537SWarner Losh case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; 20860c16b537SWarner Losh case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; 20870c16b537SWarner Losh case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break; 20880c16b537SWarner Losh } 20890c16b537SWarner Losh return pos; 20900c16b537SWarner Losh } 20910c16b537SWarner Losh 2092*19fcbaf1SConrad Meyer /* ZSTD_writeLastEmptyBlock() : 2093*19fcbaf1SConrad Meyer * output an empty Block with end-of-frame mark to complete a frame 2094*19fcbaf1SConrad Meyer * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h)) 2095*19fcbaf1SConrad Meyer * or an error code if `dstCapcity` is too small (<ZSTD_blockHeaderSize) 2096*19fcbaf1SConrad Meyer */ 2097*19fcbaf1SConrad Meyer size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity) 2098*19fcbaf1SConrad Meyer { 2099*19fcbaf1SConrad Meyer if (dstCapacity < ZSTD_blockHeaderSize) return ERROR(dstSize_tooSmall); 2100*19fcbaf1SConrad Meyer { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */ 2101*19fcbaf1SConrad Meyer MEM_writeLE24(dst, cBlockHeader24); 2102*19fcbaf1SConrad Meyer return ZSTD_blockHeaderSize; 2103*19fcbaf1SConrad Meyer } 2104*19fcbaf1SConrad Meyer } 2105*19fcbaf1SConrad Meyer 2106*19fcbaf1SConrad Meyer size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq) 2107*19fcbaf1SConrad Meyer { 2108*19fcbaf1SConrad Meyer if (cctx->stage != ZSTDcs_init) 2109*19fcbaf1SConrad Meyer return ERROR(stage_wrong); 2110*19fcbaf1SConrad Meyer if (cctx->appliedParams.ldmParams.enableLdm) 2111*19fcbaf1SConrad Meyer return ERROR(parameter_unsupported); 2112*19fcbaf1SConrad Meyer cctx->externSeqStore.seq = seq; 2113*19fcbaf1SConrad Meyer cctx->externSeqStore.size = nbSeq; 2114*19fcbaf1SConrad Meyer cctx->externSeqStore.capacity = nbSeq; 2115*19fcbaf1SConrad Meyer cctx->externSeqStore.pos = 0; 2116*19fcbaf1SConrad Meyer return 0; 2117*19fcbaf1SConrad Meyer } 2118*19fcbaf1SConrad Meyer 21190c16b537SWarner Losh 21200c16b537SWarner Losh static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, 21210c16b537SWarner Losh void* dst, size_t dstCapacity, 21220c16b537SWarner Losh const void* src, size_t srcSize, 21230c16b537SWarner Losh U32 frame, U32 lastFrameChunk) 21240c16b537SWarner Losh { 2125*19fcbaf1SConrad Meyer ZSTD_matchState_t* ms = &cctx->blockState.matchState; 21260c16b537SWarner Losh size_t fhSize = 0; 21270c16b537SWarner Losh 2128*19fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u", 2129*19fcbaf1SConrad Meyer cctx->stage, (U32)srcSize); 21300c16b537SWarner Losh if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */ 21310c16b537SWarner Losh 21320c16b537SWarner Losh if (frame && (cctx->stage==ZSTDcs_init)) { 21330c16b537SWarner Losh fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 21340c16b537SWarner Losh cctx->pledgedSrcSizePlusOne-1, cctx->dictID); 21350c16b537SWarner Losh if (ZSTD_isError(fhSize)) return fhSize; 21360c16b537SWarner Losh dstCapacity -= fhSize; 21370c16b537SWarner Losh dst = (char*)dst + fhSize; 21380c16b537SWarner Losh cctx->stage = ZSTDcs_ongoing; 21390c16b537SWarner Losh } 21400c16b537SWarner Losh 2141052d3c12SConrad Meyer if (!srcSize) return fhSize; /* do not generate an empty block if no input */ 2142052d3c12SConrad Meyer 2143*19fcbaf1SConrad Meyer if (!ZSTD_window_update(&ms->window, src, srcSize)) { 2144*19fcbaf1SConrad Meyer ms->nextToUpdate = ms->window.dictLimit; 21450c16b537SWarner Losh } 2146*19fcbaf1SConrad Meyer if (cctx->appliedParams.ldmParams.enableLdm) 2147*19fcbaf1SConrad Meyer ZSTD_window_update(&cctx->ldmState.window, src, srcSize); 21480c16b537SWarner Losh 2149052d3c12SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (U32)cctx->blockSize); 2150052d3c12SConrad Meyer { size_t const cSize = frame ? 21510c16b537SWarner Losh ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) : 21520c16b537SWarner Losh ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize); 21530c16b537SWarner Losh if (ZSTD_isError(cSize)) return cSize; 21540c16b537SWarner Losh cctx->consumedSrcSize += srcSize; 2155*19fcbaf1SConrad Meyer cctx->producedCSize += (cSize + fhSize); 2156*19fcbaf1SConrad Meyer if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */ 2157*19fcbaf1SConrad Meyer if (cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne) { 2158*19fcbaf1SConrad Meyer DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize >= %u", 2159*19fcbaf1SConrad Meyer (U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize); 2160*19fcbaf1SConrad Meyer return ERROR(srcSize_wrong); 2161*19fcbaf1SConrad Meyer } 2162*19fcbaf1SConrad Meyer } 21630c16b537SWarner Losh return cSize + fhSize; 2164052d3c12SConrad Meyer } 21650c16b537SWarner Losh } 21660c16b537SWarner Losh 21670c16b537SWarner Losh size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, 21680c16b537SWarner Losh void* dst, size_t dstCapacity, 21690c16b537SWarner Losh const void* src, size_t srcSize) 21700c16b537SWarner Losh { 2171*19fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (U32)srcSize); 21720c16b537SWarner Losh return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */); 21730c16b537SWarner Losh } 21740c16b537SWarner Losh 21750c16b537SWarner Losh 21760c16b537SWarner Losh size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx) 21770c16b537SWarner Losh { 2178*19fcbaf1SConrad Meyer ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams; 2179*19fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 21800c16b537SWarner Losh return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog); 21810c16b537SWarner Losh } 21820c16b537SWarner Losh 21830c16b537SWarner Losh size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) 21840c16b537SWarner Losh { 21850c16b537SWarner Losh size_t const blockSizeMax = ZSTD_getBlockSize(cctx); 21860c16b537SWarner Losh if (srcSize > blockSizeMax) return ERROR(srcSize_wrong); 21870c16b537SWarner Losh return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */); 21880c16b537SWarner Losh } 21890c16b537SWarner Losh 21900c16b537SWarner Losh /*! ZSTD_loadDictionaryContent() : 21910c16b537SWarner Losh * @return : 0, or an error code 21920c16b537SWarner Losh */ 2193*19fcbaf1SConrad Meyer static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const void* src, size_t srcSize) 21940c16b537SWarner Losh { 21950c16b537SWarner Losh const BYTE* const ip = (const BYTE*) src; 21960c16b537SWarner Losh const BYTE* const iend = ip + srcSize; 2197*19fcbaf1SConrad Meyer ZSTD_compressionParameters const* cParams = ¶ms->cParams; 21980c16b537SWarner Losh 2199*19fcbaf1SConrad Meyer ZSTD_window_update(&ms->window, src, srcSize); 2200*19fcbaf1SConrad Meyer ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base); 22010c16b537SWarner Losh 22020c16b537SWarner Losh if (srcSize <= HASH_READ_SIZE) return 0; 22030c16b537SWarner Losh 2204*19fcbaf1SConrad Meyer switch(params->cParams.strategy) 22050c16b537SWarner Losh { 22060c16b537SWarner Losh case ZSTD_fast: 2207*19fcbaf1SConrad Meyer ZSTD_fillHashTable(ms, cParams, iend); 22080c16b537SWarner Losh break; 22090c16b537SWarner Losh case ZSTD_dfast: 2210*19fcbaf1SConrad Meyer ZSTD_fillDoubleHashTable(ms, cParams, iend); 22110c16b537SWarner Losh break; 22120c16b537SWarner Losh 22130c16b537SWarner Losh case ZSTD_greedy: 22140c16b537SWarner Losh case ZSTD_lazy: 22150c16b537SWarner Losh case ZSTD_lazy2: 22160c16b537SWarner Losh if (srcSize >= HASH_READ_SIZE) 2217*19fcbaf1SConrad Meyer ZSTD_insertAndFindFirstIndex(ms, cParams, iend-HASH_READ_SIZE); 22180c16b537SWarner Losh break; 22190c16b537SWarner Losh 2220*19fcbaf1SConrad Meyer case ZSTD_btlazy2: /* we want the dictionary table fully sorted */ 22210c16b537SWarner Losh case ZSTD_btopt: 22220c16b537SWarner Losh case ZSTD_btultra: 22230c16b537SWarner Losh if (srcSize >= HASH_READ_SIZE) 2224*19fcbaf1SConrad Meyer ZSTD_updateTree(ms, cParams, iend-HASH_READ_SIZE, iend); 22250c16b537SWarner Losh break; 22260c16b537SWarner Losh 22270c16b537SWarner Losh default: 22280c16b537SWarner Losh assert(0); /* not possible : not a valid strategy id */ 22290c16b537SWarner Losh } 22300c16b537SWarner Losh 2231*19fcbaf1SConrad Meyer ms->nextToUpdate = (U32)(iend - ms->window.base); 22320c16b537SWarner Losh return 0; 22330c16b537SWarner Losh } 22340c16b537SWarner Losh 22350c16b537SWarner Losh 22360c16b537SWarner Losh /* Dictionaries that assign zero probability to symbols that show up causes problems 22370c16b537SWarner Losh when FSE encoding. Refuse dictionaries that assign zero probability to symbols 22380c16b537SWarner Losh that we may encounter during compression. 22390c16b537SWarner Losh NOTE: This behavior is not standard and could be improved in the future. */ 22400c16b537SWarner Losh static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) { 22410c16b537SWarner Losh U32 s; 22420c16b537SWarner Losh if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted); 22430c16b537SWarner Losh for (s = 0; s <= maxSymbolValue; ++s) { 22440c16b537SWarner Losh if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted); 22450c16b537SWarner Losh } 22460c16b537SWarner Losh return 0; 22470c16b537SWarner Losh } 22480c16b537SWarner Losh 22490c16b537SWarner Losh 22500c16b537SWarner Losh /* Dictionary format : 22510c16b537SWarner Losh * See : 22520c16b537SWarner Losh * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format 22530c16b537SWarner Losh */ 22540c16b537SWarner Losh /*! ZSTD_loadZstdDictionary() : 2255*19fcbaf1SConrad Meyer * @return : dictID, or an error code 22560c16b537SWarner Losh * assumptions : magic number supposed already checked 22570c16b537SWarner Losh * dictSize supposed > 8 22580c16b537SWarner Losh */ 2259*19fcbaf1SConrad Meyer static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const void* dict, size_t dictSize, void* workspace) 22600c16b537SWarner Losh { 22610c16b537SWarner Losh const BYTE* dictPtr = (const BYTE*)dict; 22620c16b537SWarner Losh const BYTE* const dictEnd = dictPtr + dictSize; 22630c16b537SWarner Losh short offcodeNCount[MaxOff+1]; 22640c16b537SWarner Losh unsigned offcodeMaxValue = MaxOff; 2265*19fcbaf1SConrad Meyer size_t dictID; 22660c16b537SWarner Losh 2267*19fcbaf1SConrad Meyer ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog))); 22680c16b537SWarner Losh 22690c16b537SWarner Losh dictPtr += 4; /* skip magic number */ 2270*19fcbaf1SConrad Meyer dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr); 22710c16b537SWarner Losh dictPtr += 4; 22720c16b537SWarner Losh 22730c16b537SWarner Losh { unsigned maxSymbolValue = 255; 2274*19fcbaf1SConrad Meyer size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.hufCTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr); 22750c16b537SWarner Losh if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted); 22760c16b537SWarner Losh if (maxSymbolValue < 255) return ERROR(dictionary_corrupted); 22770c16b537SWarner Losh dictPtr += hufHeaderSize; 22780c16b537SWarner Losh } 22790c16b537SWarner Losh 22800c16b537SWarner Losh { unsigned offcodeLog; 22810c16b537SWarner Losh size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); 22820c16b537SWarner Losh if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); 22830c16b537SWarner Losh if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted); 22840c16b537SWarner Losh /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ 2285*19fcbaf1SConrad Meyer CHECK_E( FSE_buildCTable_wksp(bs->entropy.offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, workspace, HUF_WORKSPACE_SIZE), 22860c16b537SWarner Losh dictionary_corrupted); 22870c16b537SWarner Losh dictPtr += offcodeHeaderSize; 22880c16b537SWarner Losh } 22890c16b537SWarner Losh 22900c16b537SWarner Losh { short matchlengthNCount[MaxML+1]; 22910c16b537SWarner Losh unsigned matchlengthMaxValue = MaxML, matchlengthLog; 22920c16b537SWarner Losh size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); 22930c16b537SWarner Losh if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted); 22940c16b537SWarner Losh if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted); 22950c16b537SWarner Losh /* Every match length code must have non-zero probability */ 22960c16b537SWarner Losh CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML)); 2297*19fcbaf1SConrad Meyer CHECK_E( FSE_buildCTable_wksp(bs->entropy.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE), 22980c16b537SWarner Losh dictionary_corrupted); 22990c16b537SWarner Losh dictPtr += matchlengthHeaderSize; 23000c16b537SWarner Losh } 23010c16b537SWarner Losh 23020c16b537SWarner Losh { short litlengthNCount[MaxLL+1]; 23030c16b537SWarner Losh unsigned litlengthMaxValue = MaxLL, litlengthLog; 23040c16b537SWarner Losh size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); 23050c16b537SWarner Losh if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted); 23060c16b537SWarner Losh if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted); 23070c16b537SWarner Losh /* Every literal length code must have non-zero probability */ 23080c16b537SWarner Losh CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL)); 2309*19fcbaf1SConrad Meyer CHECK_E( FSE_buildCTable_wksp(bs->entropy.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE), 23100c16b537SWarner Losh dictionary_corrupted); 23110c16b537SWarner Losh dictPtr += litlengthHeaderSize; 23120c16b537SWarner Losh } 23130c16b537SWarner Losh 23140c16b537SWarner Losh if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted); 2315*19fcbaf1SConrad Meyer bs->rep[0] = MEM_readLE32(dictPtr+0); 2316*19fcbaf1SConrad Meyer bs->rep[1] = MEM_readLE32(dictPtr+4); 2317*19fcbaf1SConrad Meyer bs->rep[2] = MEM_readLE32(dictPtr+8); 23180c16b537SWarner Losh dictPtr += 12; 23190c16b537SWarner Losh 23200c16b537SWarner Losh { size_t const dictContentSize = (size_t)(dictEnd - dictPtr); 23210c16b537SWarner Losh U32 offcodeMax = MaxOff; 23220c16b537SWarner Losh if (dictContentSize <= ((U32)-1) - 128 KB) { 23230c16b537SWarner Losh U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */ 23240c16b537SWarner Losh offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */ 23250c16b537SWarner Losh } 23260c16b537SWarner Losh /* All offset values <= dictContentSize + 128 KB must be representable */ 23270c16b537SWarner Losh CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff))); 23280c16b537SWarner Losh /* All repCodes must be <= dictContentSize and != 0*/ 23290c16b537SWarner Losh { U32 u; 23300c16b537SWarner Losh for (u=0; u<3; u++) { 2331*19fcbaf1SConrad Meyer if (bs->rep[u] == 0) return ERROR(dictionary_corrupted); 2332*19fcbaf1SConrad Meyer if (bs->rep[u] > dictContentSize) return ERROR(dictionary_corrupted); 23330c16b537SWarner Losh } } 23340c16b537SWarner Losh 2335*19fcbaf1SConrad Meyer bs->entropy.hufCTable_repeatMode = HUF_repeat_valid; 2336*19fcbaf1SConrad Meyer bs->entropy.offcode_repeatMode = FSE_repeat_valid; 2337*19fcbaf1SConrad Meyer bs->entropy.matchlength_repeatMode = FSE_repeat_valid; 2338*19fcbaf1SConrad Meyer bs->entropy.litlength_repeatMode = FSE_repeat_valid; 2339*19fcbaf1SConrad Meyer CHECK_F(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize)); 2340*19fcbaf1SConrad Meyer return dictID; 23410c16b537SWarner Losh } 23420c16b537SWarner Losh } 23430c16b537SWarner Losh 23440c16b537SWarner Losh /** ZSTD_compress_insertDictionary() : 2345*19fcbaf1SConrad Meyer * @return : dictID, or an error code */ 2346*19fcbaf1SConrad Meyer static size_t ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matchState_t* ms, 2347*19fcbaf1SConrad Meyer ZSTD_CCtx_params const* params, 23480c16b537SWarner Losh const void* dict, size_t dictSize, 2349*19fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 2350*19fcbaf1SConrad Meyer void* workspace) 23510c16b537SWarner Losh { 2352052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize); 23530c16b537SWarner Losh if ((dict==NULL) || (dictSize<=8)) return 0; 23540c16b537SWarner Losh 2355*19fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(bs); 2356*19fcbaf1SConrad Meyer 23570c16b537SWarner Losh /* dict restricted modes */ 2358*19fcbaf1SConrad Meyer if (dictContentType == ZSTD_dct_rawContent) 2359*19fcbaf1SConrad Meyer return ZSTD_loadDictionaryContent(ms, params, dict, dictSize); 23600c16b537SWarner Losh 23610c16b537SWarner Losh if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) { 2362*19fcbaf1SConrad Meyer if (dictContentType == ZSTD_dct_auto) { 2363052d3c12SConrad Meyer DEBUGLOG(4, "raw content dictionary detected"); 2364*19fcbaf1SConrad Meyer return ZSTD_loadDictionaryContent(ms, params, dict, dictSize); 23650c16b537SWarner Losh } 2366*19fcbaf1SConrad Meyer if (dictContentType == ZSTD_dct_fullDict) 23670c16b537SWarner Losh return ERROR(dictionary_wrong); 23680c16b537SWarner Losh assert(0); /* impossible */ 23690c16b537SWarner Losh } 23700c16b537SWarner Losh 23710c16b537SWarner Losh /* dict as full zstd dictionary */ 2372*19fcbaf1SConrad Meyer return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, workspace); 23730c16b537SWarner Losh } 23740c16b537SWarner Losh 23750c16b537SWarner Losh /*! ZSTD_compressBegin_internal() : 23760c16b537SWarner Losh * @return : 0, or an error code */ 2377052d3c12SConrad Meyer size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, 23780c16b537SWarner Losh const void* dict, size_t dictSize, 2379*19fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 23800c16b537SWarner Losh const ZSTD_CDict* cdict, 23810c16b537SWarner Losh ZSTD_CCtx_params params, U64 pledgedSrcSize, 23820c16b537SWarner Losh ZSTD_buffered_policy_e zbuff) 23830c16b537SWarner Losh { 2384052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params.cParams.windowLog); 23850c16b537SWarner Losh /* params are supposed to be fully validated at this point */ 23860c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 23870c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 23880c16b537SWarner Losh 23890c16b537SWarner Losh if (cdict && cdict->dictContentSize>0) { 2390052d3c12SConrad Meyer cctx->requestedParams = params; 2391*19fcbaf1SConrad Meyer return ZSTD_resetCCtx_usingCDict(cctx, cdict, params.cParams.windowLog, 2392*19fcbaf1SConrad Meyer params.fParams, pledgedSrcSize, zbuff); 23930c16b537SWarner Losh } 23940c16b537SWarner Losh 23950c16b537SWarner Losh CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, 23960c16b537SWarner Losh ZSTDcrp_continue, zbuff) ); 2397*19fcbaf1SConrad Meyer { 2398*19fcbaf1SConrad Meyer size_t const dictID = ZSTD_compress_insertDictionary( 2399*19fcbaf1SConrad Meyer cctx->blockState.prevCBlock, &cctx->blockState.matchState, 2400*19fcbaf1SConrad Meyer ¶ms, dict, dictSize, dictContentType, cctx->entropyWorkspace); 2401*19fcbaf1SConrad Meyer if (ZSTD_isError(dictID)) return dictID; 2402*19fcbaf1SConrad Meyer assert(dictID <= (size_t)(U32)-1); 2403*19fcbaf1SConrad Meyer cctx->dictID = (U32)dictID; 2404*19fcbaf1SConrad Meyer } 2405*19fcbaf1SConrad Meyer return 0; 24060c16b537SWarner Losh } 24070c16b537SWarner Losh 2408052d3c12SConrad Meyer size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx, 24090c16b537SWarner Losh const void* dict, size_t dictSize, 2410*19fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 2411052d3c12SConrad Meyer const ZSTD_CDict* cdict, 24120c16b537SWarner Losh ZSTD_CCtx_params params, 24130c16b537SWarner Losh unsigned long long pledgedSrcSize) 24140c16b537SWarner Losh { 2415052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params.cParams.windowLog); 24160c16b537SWarner Losh /* compression parameters verification and optimization */ 24170c16b537SWarner Losh CHECK_F( ZSTD_checkCParams(params.cParams) ); 2418052d3c12SConrad Meyer return ZSTD_compressBegin_internal(cctx, 2419*19fcbaf1SConrad Meyer dict, dictSize, dictContentType, 2420052d3c12SConrad Meyer cdict, 24210c16b537SWarner Losh params, pledgedSrcSize, 24220c16b537SWarner Losh ZSTDb_not_buffered); 24230c16b537SWarner Losh } 24240c16b537SWarner Losh 24250c16b537SWarner Losh /*! ZSTD_compressBegin_advanced() : 24260c16b537SWarner Losh * @return : 0, or an error code */ 24270c16b537SWarner Losh size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, 24280c16b537SWarner Losh const void* dict, size_t dictSize, 24290c16b537SWarner Losh ZSTD_parameters params, unsigned long long pledgedSrcSize) 24300c16b537SWarner Losh { 24310c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 24320c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 2433052d3c12SConrad Meyer return ZSTD_compressBegin_advanced_internal(cctx, 2434*19fcbaf1SConrad Meyer dict, dictSize, ZSTD_dct_auto, 2435052d3c12SConrad Meyer NULL /*cdict*/, 2436052d3c12SConrad Meyer cctxParams, pledgedSrcSize); 24370c16b537SWarner Losh } 24380c16b537SWarner Losh 24390c16b537SWarner Losh size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) 24400c16b537SWarner Losh { 2441*19fcbaf1SConrad Meyer ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize); 24420c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 24430c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 2444*19fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (U32)dictSize); 2445*19fcbaf1SConrad Meyer return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, NULL, 2446052d3c12SConrad Meyer cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered); 24470c16b537SWarner Losh } 24480c16b537SWarner Losh 24490c16b537SWarner Losh size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) 24500c16b537SWarner Losh { 24510c16b537SWarner Losh return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); 24520c16b537SWarner Losh } 24530c16b537SWarner Losh 24540c16b537SWarner Losh 24550c16b537SWarner Losh /*! ZSTD_writeEpilogue() : 24560c16b537SWarner Losh * Ends a frame. 24570c16b537SWarner Losh * @return : nb of bytes written into dst (or an error code) */ 24580c16b537SWarner Losh static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity) 24590c16b537SWarner Losh { 24600c16b537SWarner Losh BYTE* const ostart = (BYTE*)dst; 24610c16b537SWarner Losh BYTE* op = ostart; 24620c16b537SWarner Losh size_t fhSize = 0; 24630c16b537SWarner Losh 2464*19fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_writeEpilogue"); 24650c16b537SWarner Losh if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */ 24660c16b537SWarner Losh 24670c16b537SWarner Losh /* special case : empty frame */ 24680c16b537SWarner Losh if (cctx->stage == ZSTDcs_init) { 24690c16b537SWarner Losh fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0); 24700c16b537SWarner Losh if (ZSTD_isError(fhSize)) return fhSize; 24710c16b537SWarner Losh dstCapacity -= fhSize; 24720c16b537SWarner Losh op += fhSize; 24730c16b537SWarner Losh cctx->stage = ZSTDcs_ongoing; 24740c16b537SWarner Losh } 24750c16b537SWarner Losh 24760c16b537SWarner Losh if (cctx->stage != ZSTDcs_ending) { 24770c16b537SWarner Losh /* write one last empty block, make it the "last" block */ 24780c16b537SWarner Losh U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0; 24790c16b537SWarner Losh if (dstCapacity<4) return ERROR(dstSize_tooSmall); 24800c16b537SWarner Losh MEM_writeLE32(op, cBlockHeader24); 24810c16b537SWarner Losh op += ZSTD_blockHeaderSize; 24820c16b537SWarner Losh dstCapacity -= ZSTD_blockHeaderSize; 24830c16b537SWarner Losh } 24840c16b537SWarner Losh 24850c16b537SWarner Losh if (cctx->appliedParams.fParams.checksumFlag) { 24860c16b537SWarner Losh U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); 24870c16b537SWarner Losh if (dstCapacity<4) return ERROR(dstSize_tooSmall); 2488*19fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", checksum); 24890c16b537SWarner Losh MEM_writeLE32(op, checksum); 24900c16b537SWarner Losh op += 4; 24910c16b537SWarner Losh } 24920c16b537SWarner Losh 24930c16b537SWarner Losh cctx->stage = ZSTDcs_created; /* return to "created but no init" status */ 24940c16b537SWarner Losh return op-ostart; 24950c16b537SWarner Losh } 24960c16b537SWarner Losh 24970c16b537SWarner Losh size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, 24980c16b537SWarner Losh void* dst, size_t dstCapacity, 24990c16b537SWarner Losh const void* src, size_t srcSize) 25000c16b537SWarner Losh { 25010c16b537SWarner Losh size_t endResult; 25020c16b537SWarner Losh size_t const cSize = ZSTD_compressContinue_internal(cctx, 25030c16b537SWarner Losh dst, dstCapacity, src, srcSize, 25040c16b537SWarner Losh 1 /* frame mode */, 1 /* last chunk */); 25050c16b537SWarner Losh if (ZSTD_isError(cSize)) return cSize; 25060c16b537SWarner Losh endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); 25070c16b537SWarner Losh if (ZSTD_isError(endResult)) return endResult; 25080c16b537SWarner Losh if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */ 25090c16b537SWarner Losh DEBUGLOG(4, "end of frame : controlling src size"); 25100c16b537SWarner Losh if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) { 25110c16b537SWarner Losh DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize = %u", 25120c16b537SWarner Losh (U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize); 25130c16b537SWarner Losh return ERROR(srcSize_wrong); 25140c16b537SWarner Losh } } 25150c16b537SWarner Losh return cSize + endResult; 25160c16b537SWarner Losh } 25170c16b537SWarner Losh 25180c16b537SWarner Losh 25190c16b537SWarner Losh static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, 25200c16b537SWarner Losh void* dst, size_t dstCapacity, 25210c16b537SWarner Losh const void* src, size_t srcSize, 25220c16b537SWarner Losh const void* dict,size_t dictSize, 25230c16b537SWarner Losh ZSTD_parameters params) 25240c16b537SWarner Losh { 25250c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 25260c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 2527052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_internal"); 25280c16b537SWarner Losh return ZSTD_compress_advanced_internal(cctx, 25290c16b537SWarner Losh dst, dstCapacity, 25300c16b537SWarner Losh src, srcSize, 25310c16b537SWarner Losh dict, dictSize, 25320c16b537SWarner Losh cctxParams); 25330c16b537SWarner Losh } 25340c16b537SWarner Losh 25350c16b537SWarner Losh size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, 25360c16b537SWarner Losh void* dst, size_t dstCapacity, 25370c16b537SWarner Losh const void* src, size_t srcSize, 25380c16b537SWarner Losh const void* dict,size_t dictSize, 25390c16b537SWarner Losh ZSTD_parameters params) 25400c16b537SWarner Losh { 2541052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compress_advanced"); 25420c16b537SWarner Losh CHECK_F(ZSTD_checkCParams(params.cParams)); 25430c16b537SWarner Losh return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params); 25440c16b537SWarner Losh } 25450c16b537SWarner Losh 25460c16b537SWarner Losh /* Internal */ 25470c16b537SWarner Losh size_t ZSTD_compress_advanced_internal( 25480c16b537SWarner Losh ZSTD_CCtx* cctx, 25490c16b537SWarner Losh void* dst, size_t dstCapacity, 25500c16b537SWarner Losh const void* src, size_t srcSize, 25510c16b537SWarner Losh const void* dict,size_t dictSize, 25520c16b537SWarner Losh ZSTD_CCtx_params params) 25530c16b537SWarner Losh { 2554*19fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", 2555*19fcbaf1SConrad Meyer (U32)srcSize); 2556*19fcbaf1SConrad Meyer CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, NULL, 25570c16b537SWarner Losh params, srcSize, ZSTDb_not_buffered) ); 25580c16b537SWarner Losh return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 25590c16b537SWarner Losh } 25600c16b537SWarner Losh 2561*19fcbaf1SConrad Meyer size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, 25620c16b537SWarner Losh const void* dict, size_t dictSize, int compressionLevel) 25630c16b537SWarner Losh { 2564*19fcbaf1SConrad Meyer ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize ? srcSize : 1, dict ? dictSize : 0); 2565*19fcbaf1SConrad Meyer ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params); 2566*19fcbaf1SConrad Meyer assert(params.fParams.contentSizeFlag == 1); 2567*19fcbaf1SConrad Meyer ZSTD_CCtxParam_setParameter(&cctxParams, ZSTD_p_compressLiterals, compressionLevel>=0); 2568*19fcbaf1SConrad Meyer return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, cctxParams); 25690c16b537SWarner Losh } 25700c16b537SWarner Losh 2571*19fcbaf1SConrad Meyer size_t ZSTD_compressCCtx (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel) 25720c16b537SWarner Losh { 2573*19fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (U32)srcSize); 2574*19fcbaf1SConrad Meyer return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel); 25750c16b537SWarner Losh } 25760c16b537SWarner Losh 25770c16b537SWarner Losh size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel) 25780c16b537SWarner Losh { 25790c16b537SWarner Losh size_t result; 25800c16b537SWarner Losh ZSTD_CCtx ctxBody; 25810c16b537SWarner Losh memset(&ctxBody, 0, sizeof(ctxBody)); 25820c16b537SWarner Losh ctxBody.customMem = ZSTD_defaultCMem; 25830c16b537SWarner Losh result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); 25840c16b537SWarner Losh ZSTD_free(ctxBody.workSpace, ZSTD_defaultCMem); /* can't free ctxBody itself, as it's on stack; free only heap content */ 25850c16b537SWarner Losh return result; 25860c16b537SWarner Losh } 25870c16b537SWarner Losh 25880c16b537SWarner Losh 25890c16b537SWarner Losh /* ===== Dictionary API ===== */ 25900c16b537SWarner Losh 25910c16b537SWarner Losh /*! ZSTD_estimateCDictSize_advanced() : 25920c16b537SWarner Losh * Estimate amount of memory that will be needed to create a dictionary with following arguments */ 25930c16b537SWarner Losh size_t ZSTD_estimateCDictSize_advanced( 25940c16b537SWarner Losh size_t dictSize, ZSTD_compressionParameters cParams, 25950c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod) 25960c16b537SWarner Losh { 25970c16b537SWarner Losh DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict)); 2598*19fcbaf1SConrad Meyer return sizeof(ZSTD_CDict) + HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) 25990c16b537SWarner Losh + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize); 26000c16b537SWarner Losh } 26010c16b537SWarner Losh 26020c16b537SWarner Losh size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel) 26030c16b537SWarner Losh { 26040c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 26050c16b537SWarner Losh return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy); 26060c16b537SWarner Losh } 26070c16b537SWarner Losh 26080c16b537SWarner Losh size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) 26090c16b537SWarner Losh { 26100c16b537SWarner Losh if (cdict==NULL) return 0; /* support sizeof on NULL */ 26110c16b537SWarner Losh DEBUGLOG(5, "sizeof(*cdict) : %u", (U32)sizeof(*cdict)); 2612*19fcbaf1SConrad Meyer return cdict->workspaceSize + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict); 26130c16b537SWarner Losh } 26140c16b537SWarner Losh 26150c16b537SWarner Losh static size_t ZSTD_initCDict_internal( 26160c16b537SWarner Losh ZSTD_CDict* cdict, 26170c16b537SWarner Losh const void* dictBuffer, size_t dictSize, 26180c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 2619*19fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 26200c16b537SWarner Losh ZSTD_compressionParameters cParams) 26210c16b537SWarner Losh { 2622*19fcbaf1SConrad Meyer DEBUGLOG(3, "ZSTD_initCDict_internal, dictContentType %u", (U32)dictContentType); 2623*19fcbaf1SConrad Meyer assert(!ZSTD_checkCParams(cParams)); 2624*19fcbaf1SConrad Meyer cdict->cParams = cParams; 26250c16b537SWarner Losh if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) { 26260c16b537SWarner Losh cdict->dictBuffer = NULL; 26270c16b537SWarner Losh cdict->dictContent = dictBuffer; 26280c16b537SWarner Losh } else { 2629*19fcbaf1SConrad Meyer void* const internalBuffer = ZSTD_malloc(dictSize, cdict->customMem); 26300c16b537SWarner Losh cdict->dictBuffer = internalBuffer; 26310c16b537SWarner Losh cdict->dictContent = internalBuffer; 26320c16b537SWarner Losh if (!internalBuffer) return ERROR(memory_allocation); 26330c16b537SWarner Losh memcpy(internalBuffer, dictBuffer, dictSize); 26340c16b537SWarner Losh } 26350c16b537SWarner Losh cdict->dictContentSize = dictSize; 26360c16b537SWarner Losh 2637*19fcbaf1SConrad Meyer /* Reset the state to no dictionary */ 2638*19fcbaf1SConrad Meyer ZSTD_reset_compressedBlockState(&cdict->cBlockState); 2639*19fcbaf1SConrad Meyer { void* const end = ZSTD_reset_matchState( 2640*19fcbaf1SConrad Meyer &cdict->matchState, 2641*19fcbaf1SConrad Meyer (U32*)cdict->workspace + HUF_WORKSPACE_SIZE_U32, 2642*19fcbaf1SConrad Meyer &cParams, ZSTDcrp_continue, /* forCCtx */ 0); 2643*19fcbaf1SConrad Meyer assert(end == (char*)cdict->workspace + cdict->workspaceSize); 2644*19fcbaf1SConrad Meyer (void)end; 2645*19fcbaf1SConrad Meyer } 2646*19fcbaf1SConrad Meyer /* (Maybe) load the dictionary 2647*19fcbaf1SConrad Meyer * Skips loading the dictionary if it is <= 8 bytes. 2648*19fcbaf1SConrad Meyer */ 2649*19fcbaf1SConrad Meyer { ZSTD_CCtx_params params; 2650*19fcbaf1SConrad Meyer memset(¶ms, 0, sizeof(params)); 2651*19fcbaf1SConrad Meyer params.compressionLevel = ZSTD_CLEVEL_DEFAULT; 2652*19fcbaf1SConrad Meyer params.fParams.contentSizeFlag = 1; 2653*19fcbaf1SConrad Meyer params.cParams = cParams; 2654*19fcbaf1SConrad Meyer { size_t const dictID = ZSTD_compress_insertDictionary( 2655*19fcbaf1SConrad Meyer &cdict->cBlockState, &cdict->matchState, ¶ms, 2656*19fcbaf1SConrad Meyer cdict->dictContent, cdict->dictContentSize, 2657*19fcbaf1SConrad Meyer dictContentType, cdict->workspace); 2658*19fcbaf1SConrad Meyer if (ZSTD_isError(dictID)) return dictID; 2659*19fcbaf1SConrad Meyer assert(dictID <= (size_t)(U32)-1); 2660*19fcbaf1SConrad Meyer cdict->dictID = (U32)dictID; 2661*19fcbaf1SConrad Meyer } 26620c16b537SWarner Losh } 26630c16b537SWarner Losh 26640c16b537SWarner Losh return 0; 26650c16b537SWarner Losh } 26660c16b537SWarner Losh 26670c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, 26680c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 2669*19fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 26700c16b537SWarner Losh ZSTD_compressionParameters cParams, ZSTD_customMem customMem) 26710c16b537SWarner Losh { 2672*19fcbaf1SConrad Meyer DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (U32)dictContentType); 26730c16b537SWarner Losh if (!customMem.customAlloc ^ !customMem.customFree) return NULL; 26740c16b537SWarner Losh 26750c16b537SWarner Losh { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem); 2676*19fcbaf1SConrad Meyer size_t const workspaceSize = HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); 2677*19fcbaf1SConrad Meyer void* const workspace = ZSTD_malloc(workspaceSize, customMem); 26780c16b537SWarner Losh 2679*19fcbaf1SConrad Meyer if (!cdict || !workspace) { 26800c16b537SWarner Losh ZSTD_free(cdict, customMem); 2681*19fcbaf1SConrad Meyer ZSTD_free(workspace, customMem); 26820c16b537SWarner Losh return NULL; 26830c16b537SWarner Losh } 2684*19fcbaf1SConrad Meyer cdict->customMem = customMem; 2685*19fcbaf1SConrad Meyer cdict->workspace = workspace; 2686*19fcbaf1SConrad Meyer cdict->workspaceSize = workspaceSize; 26870c16b537SWarner Losh if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 26880c16b537SWarner Losh dictBuffer, dictSize, 2689*19fcbaf1SConrad Meyer dictLoadMethod, dictContentType, 26900c16b537SWarner Losh cParams) )) { 26910c16b537SWarner Losh ZSTD_freeCDict(cdict); 26920c16b537SWarner Losh return NULL; 26930c16b537SWarner Losh } 26940c16b537SWarner Losh 26950c16b537SWarner Losh return cdict; 26960c16b537SWarner Losh } 26970c16b537SWarner Losh } 26980c16b537SWarner Losh 26990c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) 27000c16b537SWarner Losh { 27010c16b537SWarner Losh ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 27020c16b537SWarner Losh return ZSTD_createCDict_advanced(dict, dictSize, 2703*19fcbaf1SConrad Meyer ZSTD_dlm_byCopy, ZSTD_dct_auto, 27040c16b537SWarner Losh cParams, ZSTD_defaultCMem); 27050c16b537SWarner Losh } 27060c16b537SWarner Losh 27070c16b537SWarner Losh ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) 27080c16b537SWarner Losh { 27090c16b537SWarner Losh ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize); 27100c16b537SWarner Losh return ZSTD_createCDict_advanced(dict, dictSize, 2711*19fcbaf1SConrad Meyer ZSTD_dlm_byRef, ZSTD_dct_auto, 27120c16b537SWarner Losh cParams, ZSTD_defaultCMem); 27130c16b537SWarner Losh } 27140c16b537SWarner Losh 27150c16b537SWarner Losh size_t ZSTD_freeCDict(ZSTD_CDict* cdict) 27160c16b537SWarner Losh { 27170c16b537SWarner Losh if (cdict==NULL) return 0; /* support free on NULL */ 2718*19fcbaf1SConrad Meyer { ZSTD_customMem const cMem = cdict->customMem; 2719*19fcbaf1SConrad Meyer ZSTD_free(cdict->workspace, cMem); 27200c16b537SWarner Losh ZSTD_free(cdict->dictBuffer, cMem); 27210c16b537SWarner Losh ZSTD_free(cdict, cMem); 27220c16b537SWarner Losh return 0; 27230c16b537SWarner Losh } 27240c16b537SWarner Losh } 27250c16b537SWarner Losh 27260c16b537SWarner Losh /*! ZSTD_initStaticCDict_advanced() : 27270c16b537SWarner Losh * Generate a digested dictionary in provided memory area. 27280c16b537SWarner Losh * workspace: The memory area to emplace the dictionary into. 27290c16b537SWarner Losh * Provided pointer must 8-bytes aligned. 27300c16b537SWarner Losh * It must outlive dictionary usage. 27310c16b537SWarner Losh * workspaceSize: Use ZSTD_estimateCDictSize() 27320c16b537SWarner Losh * to determine how large workspace must be. 27330c16b537SWarner Losh * cParams : use ZSTD_getCParams() to transform a compression level 27340c16b537SWarner Losh * into its relevants cParams. 27350c16b537SWarner Losh * @return : pointer to ZSTD_CDict*, or NULL if error (size too small) 27360c16b537SWarner Losh * Note : there is no corresponding "free" function. 27370c16b537SWarner Losh * Since workspace was allocated externally, it must be freed externally. 27380c16b537SWarner Losh */ 2739*19fcbaf1SConrad Meyer const ZSTD_CDict* ZSTD_initStaticCDict( 2740*19fcbaf1SConrad Meyer void* workspace, size_t workspaceSize, 27410c16b537SWarner Losh const void* dict, size_t dictSize, 27420c16b537SWarner Losh ZSTD_dictLoadMethod_e dictLoadMethod, 2743*19fcbaf1SConrad Meyer ZSTD_dictContentType_e dictContentType, 27440c16b537SWarner Losh ZSTD_compressionParameters cParams) 27450c16b537SWarner Losh { 2746*19fcbaf1SConrad Meyer size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0); 27470c16b537SWarner Losh size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize) 2748*19fcbaf1SConrad Meyer + HUF_WORKSPACE_SIZE + matchStateSize; 27490c16b537SWarner Losh ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace; 27500c16b537SWarner Losh void* ptr; 27510c16b537SWarner Losh if ((size_t)workspace & 7) return NULL; /* 8-aligned */ 2752052d3c12SConrad Meyer DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u", 27530c16b537SWarner Losh (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize)); 27540c16b537SWarner Losh if (workspaceSize < neededSize) return NULL; 27550c16b537SWarner Losh 27560c16b537SWarner Losh if (dictLoadMethod == ZSTD_dlm_byCopy) { 27570c16b537SWarner Losh memcpy(cdict+1, dict, dictSize); 27580c16b537SWarner Losh dict = cdict+1; 27590c16b537SWarner Losh ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize; 27600c16b537SWarner Losh } else { 27610c16b537SWarner Losh ptr = cdict+1; 27620c16b537SWarner Losh } 2763*19fcbaf1SConrad Meyer cdict->workspace = ptr; 2764*19fcbaf1SConrad Meyer cdict->workspaceSize = HUF_WORKSPACE_SIZE + matchStateSize; 27650c16b537SWarner Losh 27660c16b537SWarner Losh if (ZSTD_isError( ZSTD_initCDict_internal(cdict, 27670c16b537SWarner Losh dict, dictSize, 2768*19fcbaf1SConrad Meyer ZSTD_dlm_byRef, dictContentType, 27690c16b537SWarner Losh cParams) )) 27700c16b537SWarner Losh return NULL; 27710c16b537SWarner Losh 27720c16b537SWarner Losh return cdict; 27730c16b537SWarner Losh } 27740c16b537SWarner Losh 2775*19fcbaf1SConrad Meyer ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict) 2776*19fcbaf1SConrad Meyer { 2777*19fcbaf1SConrad Meyer assert(cdict != NULL); 2778*19fcbaf1SConrad Meyer return cdict->cParams; 27790c16b537SWarner Losh } 27800c16b537SWarner Losh 27810c16b537SWarner Losh /* ZSTD_compressBegin_usingCDict_advanced() : 27820c16b537SWarner Losh * cdict must be != NULL */ 27830c16b537SWarner Losh size_t ZSTD_compressBegin_usingCDict_advanced( 27840c16b537SWarner Losh ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict, 27850c16b537SWarner Losh ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize) 27860c16b537SWarner Losh { 2787052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced"); 27880c16b537SWarner Losh if (cdict==NULL) return ERROR(dictionary_wrong); 27890c16b537SWarner Losh { ZSTD_CCtx_params params = cctx->requestedParams; 27900c16b537SWarner Losh params.cParams = ZSTD_getCParamsFromCDict(cdict); 2791*19fcbaf1SConrad Meyer /* Increase window log to fit the entire dictionary and source if the 2792*19fcbaf1SConrad Meyer * source size is known. Limit the increase to 19, which is the 2793*19fcbaf1SConrad Meyer * window log for compression level 1 with the largest source size. 2794*19fcbaf1SConrad Meyer */ 2795*19fcbaf1SConrad Meyer if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) { 2796*19fcbaf1SConrad Meyer U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19); 2797*19fcbaf1SConrad Meyer U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1; 2798*19fcbaf1SConrad Meyer params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog); 2799*19fcbaf1SConrad Meyer } 28000c16b537SWarner Losh params.fParams = fParams; 28010c16b537SWarner Losh return ZSTD_compressBegin_internal(cctx, 2802*19fcbaf1SConrad Meyer NULL, 0, ZSTD_dct_auto, 28030c16b537SWarner Losh cdict, 28040c16b537SWarner Losh params, pledgedSrcSize, 28050c16b537SWarner Losh ZSTDb_not_buffered); 28060c16b537SWarner Losh } 28070c16b537SWarner Losh } 28080c16b537SWarner Losh 28090c16b537SWarner Losh /* ZSTD_compressBegin_usingCDict() : 28100c16b537SWarner Losh * pledgedSrcSize=0 means "unknown" 28110c16b537SWarner Losh * if pledgedSrcSize>0, it will enable contentSizeFlag */ 28120c16b537SWarner Losh size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict) 28130c16b537SWarner Losh { 28140c16b537SWarner Losh ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 2815052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag); 28160c16b537SWarner Losh return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0); 28170c16b537SWarner Losh } 28180c16b537SWarner Losh 28190c16b537SWarner Losh size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx, 28200c16b537SWarner Losh void* dst, size_t dstCapacity, 28210c16b537SWarner Losh const void* src, size_t srcSize, 28220c16b537SWarner Losh const ZSTD_CDict* cdict, ZSTD_frameParameters fParams) 28230c16b537SWarner Losh { 28240c16b537SWarner Losh CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */ 28250c16b537SWarner Losh return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 28260c16b537SWarner Losh } 28270c16b537SWarner Losh 28280c16b537SWarner Losh /*! ZSTD_compress_usingCDict() : 28290c16b537SWarner Losh * Compression using a digested Dictionary. 28300c16b537SWarner Losh * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times. 28310c16b537SWarner Losh * Note that compression parameters are decided at CDict creation time 28320c16b537SWarner Losh * while frame parameters are hardcoded */ 28330c16b537SWarner Losh size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, 28340c16b537SWarner Losh void* dst, size_t dstCapacity, 28350c16b537SWarner Losh const void* src, size_t srcSize, 28360c16b537SWarner Losh const ZSTD_CDict* cdict) 28370c16b537SWarner Losh { 28380c16b537SWarner Losh ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ }; 28390c16b537SWarner Losh return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams); 28400c16b537SWarner Losh } 28410c16b537SWarner Losh 28420c16b537SWarner Losh 28430c16b537SWarner Losh 28440c16b537SWarner Losh /* ****************************************************************** 28450c16b537SWarner Losh * Streaming 28460c16b537SWarner Losh ********************************************************************/ 28470c16b537SWarner Losh 28480c16b537SWarner Losh ZSTD_CStream* ZSTD_createCStream(void) 28490c16b537SWarner Losh { 2850052d3c12SConrad Meyer DEBUGLOG(3, "ZSTD_createCStream"); 28510c16b537SWarner Losh return ZSTD_createCStream_advanced(ZSTD_defaultCMem); 28520c16b537SWarner Losh } 28530c16b537SWarner Losh 28540c16b537SWarner Losh ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize) 28550c16b537SWarner Losh { 28560c16b537SWarner Losh return ZSTD_initStaticCCtx(workspace, workspaceSize); 28570c16b537SWarner Losh } 28580c16b537SWarner Losh 28590c16b537SWarner Losh ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem) 28600c16b537SWarner Losh { /* CStream and CCtx are now same object */ 28610c16b537SWarner Losh return ZSTD_createCCtx_advanced(customMem); 28620c16b537SWarner Losh } 28630c16b537SWarner Losh 28640c16b537SWarner Losh size_t ZSTD_freeCStream(ZSTD_CStream* zcs) 28650c16b537SWarner Losh { 28660c16b537SWarner Losh return ZSTD_freeCCtx(zcs); /* same object */ 28670c16b537SWarner Losh } 28680c16b537SWarner Losh 28690c16b537SWarner Losh 28700c16b537SWarner Losh 28710c16b537SWarner Losh /*====== Initialization ======*/ 28720c16b537SWarner Losh 28730c16b537SWarner Losh size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; } 28740c16b537SWarner Losh 28750c16b537SWarner Losh size_t ZSTD_CStreamOutSize(void) 28760c16b537SWarner Losh { 28770c16b537SWarner Losh return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; 28780c16b537SWarner Losh } 28790c16b537SWarner Losh 2880*19fcbaf1SConrad Meyer static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx, 2881*19fcbaf1SConrad Meyer const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType, 2882052d3c12SConrad Meyer const ZSTD_CDict* const cdict, 2883052d3c12SConrad Meyer ZSTD_CCtx_params const params, unsigned long long const pledgedSrcSize) 28840c16b537SWarner Losh { 2885*19fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_resetCStream_internal (disableLiteralCompression=%i)", 2886*19fcbaf1SConrad Meyer params.disableLiteralCompression); 28870c16b537SWarner Losh /* params are supposed to be fully validated at this point */ 28880c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 28890c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 28900c16b537SWarner Losh 2891*19fcbaf1SConrad Meyer CHECK_F( ZSTD_compressBegin_internal(cctx, 2892*19fcbaf1SConrad Meyer dict, dictSize, dictContentType, 28930c16b537SWarner Losh cdict, 28940c16b537SWarner Losh params, pledgedSrcSize, 28950c16b537SWarner Losh ZSTDb_buffered) ); 28960c16b537SWarner Losh 2897*19fcbaf1SConrad Meyer cctx->inToCompress = 0; 2898*19fcbaf1SConrad Meyer cctx->inBuffPos = 0; 2899*19fcbaf1SConrad Meyer cctx->inBuffTarget = cctx->blockSize 2900*19fcbaf1SConrad 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 */ 2901*19fcbaf1SConrad Meyer cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0; 2902*19fcbaf1SConrad Meyer cctx->streamStage = zcss_load; 2903*19fcbaf1SConrad Meyer cctx->frameEnded = 0; 29040c16b537SWarner Losh return 0; /* ready to go */ 29050c16b537SWarner Losh } 29060c16b537SWarner Losh 2907052d3c12SConrad Meyer /* ZSTD_resetCStream(): 2908052d3c12SConrad Meyer * pledgedSrcSize == 0 means "unknown" */ 29090c16b537SWarner Losh size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) 29100c16b537SWarner Losh { 29110c16b537SWarner Losh ZSTD_CCtx_params params = zcs->requestedParams; 2912052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (U32)pledgedSrcSize); 2913052d3c12SConrad Meyer if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; 2914052d3c12SConrad Meyer params.fParams.contentSizeFlag = 1; 2915*19fcbaf1SConrad Meyer params.cParams = ZSTD_getCParamsFromCCtxParams(¶ms, pledgedSrcSize, 0); 2916*19fcbaf1SConrad Meyer return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize); 29170c16b537SWarner Losh } 29180c16b537SWarner Losh 29190c16b537SWarner Losh /*! ZSTD_initCStream_internal() : 2920052d3c12SConrad Meyer * Note : for lib/compress only. Used by zstdmt_compress.c. 29210c16b537SWarner Losh * Assumption 1 : params are valid 29220c16b537SWarner Losh * Assumption 2 : either dict, or cdict, is defined, not both */ 29230c16b537SWarner Losh size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs, 29240c16b537SWarner Losh const void* dict, size_t dictSize, const ZSTD_CDict* cdict, 29250c16b537SWarner Losh ZSTD_CCtx_params params, unsigned long long pledgedSrcSize) 29260c16b537SWarner Losh { 29270c16b537SWarner Losh DEBUGLOG(4, "ZSTD_initCStream_internal"); 29280c16b537SWarner Losh assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams))); 29290c16b537SWarner Losh assert(!((dict) && (cdict))); /* either dict or cdict, not both */ 29300c16b537SWarner Losh 29310c16b537SWarner Losh if (dict && dictSize >= 8) { 2932052d3c12SConrad Meyer DEBUGLOG(4, "loading dictionary of size %u", (U32)dictSize); 29330c16b537SWarner Losh if (zcs->staticSize) { /* static CCtx : never uses malloc */ 29340c16b537SWarner Losh /* incompatible with internal cdict creation */ 29350c16b537SWarner Losh return ERROR(memory_allocation); 29360c16b537SWarner Losh } 29370c16b537SWarner Losh ZSTD_freeCDict(zcs->cdictLocal); 29380c16b537SWarner Losh zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 2939*19fcbaf1SConrad Meyer ZSTD_dlm_byCopy, ZSTD_dct_auto, 29400c16b537SWarner Losh params.cParams, zcs->customMem); 29410c16b537SWarner Losh zcs->cdict = zcs->cdictLocal; 29420c16b537SWarner Losh if (zcs->cdictLocal == NULL) return ERROR(memory_allocation); 29430c16b537SWarner Losh } else { 29440c16b537SWarner Losh if (cdict) { 2945052d3c12SConrad Meyer params.cParams = ZSTD_getCParamsFromCDict(cdict); /* cParams are enforced from cdict; it includes windowLog */ 29460c16b537SWarner Losh } 29470c16b537SWarner Losh ZSTD_freeCDict(zcs->cdictLocal); 29480c16b537SWarner Losh zcs->cdictLocal = NULL; 29490c16b537SWarner Losh zcs->cdict = cdict; 29500c16b537SWarner Losh } 29510c16b537SWarner Losh 2952*19fcbaf1SConrad Meyer return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize); 29530c16b537SWarner Losh } 29540c16b537SWarner Losh 29550c16b537SWarner Losh /* ZSTD_initCStream_usingCDict_advanced() : 29560c16b537SWarner Losh * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */ 29570c16b537SWarner Losh size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, 29580c16b537SWarner Losh const ZSTD_CDict* cdict, 29590c16b537SWarner Losh ZSTD_frameParameters fParams, 29600c16b537SWarner Losh unsigned long long pledgedSrcSize) 2961052d3c12SConrad Meyer { 2962052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced"); 2963052d3c12SConrad Meyer if (!cdict) return ERROR(dictionary_wrong); /* cannot handle NULL cdict (does not know what to do) */ 29640c16b537SWarner Losh { ZSTD_CCtx_params params = zcs->requestedParams; 29650c16b537SWarner Losh params.cParams = ZSTD_getCParamsFromCDict(cdict); 29660c16b537SWarner Losh params.fParams = fParams; 29670c16b537SWarner Losh return ZSTD_initCStream_internal(zcs, 29680c16b537SWarner Losh NULL, 0, cdict, 29690c16b537SWarner Losh params, pledgedSrcSize); 29700c16b537SWarner Losh } 29710c16b537SWarner Losh } 29720c16b537SWarner Losh 29730c16b537SWarner Losh /* note : cdict must outlive compression session */ 29740c16b537SWarner Losh size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict) 29750c16b537SWarner Losh { 2976052d3c12SConrad Meyer ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksum */, 0 /* hideDictID */ }; 2977052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_usingCDict"); 2978052d3c12SConrad Meyer return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); /* note : will check that cdict != NULL */ 29790c16b537SWarner Losh } 29800c16b537SWarner Losh 2981*19fcbaf1SConrad Meyer 2982052d3c12SConrad Meyer /* ZSTD_initCStream_advanced() : 2983*19fcbaf1SConrad Meyer * pledgedSrcSize must be exact. 2984052d3c12SConrad Meyer * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN. 2985052d3c12SConrad Meyer * dict is loaded with default parameters ZSTD_dm_auto and ZSTD_dlm_byCopy. */ 29860c16b537SWarner Losh size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, 29870c16b537SWarner Losh const void* dict, size_t dictSize, 29880c16b537SWarner Losh ZSTD_parameters params, unsigned long long pledgedSrcSize) 29890c16b537SWarner Losh { 2990052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream_advanced: pledgedSrcSize=%u, flag=%u", 2991052d3c12SConrad Meyer (U32)pledgedSrcSize, params.fParams.contentSizeFlag); 29920c16b537SWarner Losh CHECK_F( ZSTD_checkCParams(params.cParams) ); 2993052d3c12SConrad 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. */ 2994*19fcbaf1SConrad Meyer { ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); 2995052d3c12SConrad Meyer return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL /*cdict*/, cctxParams, pledgedSrcSize); 29960c16b537SWarner Losh } 2997*19fcbaf1SConrad Meyer } 29980c16b537SWarner Losh 29990c16b537SWarner Losh size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) 30000c16b537SWarner Losh { 30010c16b537SWarner Losh ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); 30020c16b537SWarner Losh ZSTD_CCtx_params const cctxParams = 30030c16b537SWarner Losh ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); 3004052d3c12SConrad Meyer return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN); 30050c16b537SWarner Losh } 30060c16b537SWarner Losh 3007052d3c12SConrad Meyer size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss) 30080c16b537SWarner Losh { 3009052d3c12SConrad 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 */ 30100c16b537SWarner Losh ZSTD_parameters const params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0); 3011052d3c12SConrad Meyer ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params); 30120c16b537SWarner Losh return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, cctxParams, pledgedSrcSize); 30130c16b537SWarner Losh } 30140c16b537SWarner Losh 30150c16b537SWarner Losh size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) 30160c16b537SWarner Losh { 3017052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_initCStream"); 3018052d3c12SConrad Meyer return ZSTD_initCStream_srcSize(zcs, compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN); 30190c16b537SWarner Losh } 30200c16b537SWarner Losh 30210c16b537SWarner Losh /*====== Compression ======*/ 30220c16b537SWarner Losh 30230c16b537SWarner Losh MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, 30240c16b537SWarner Losh const void* src, size_t srcSize) 30250c16b537SWarner Losh { 30260c16b537SWarner Losh size_t const length = MIN(dstCapacity, srcSize); 30270c16b537SWarner Losh if (length) memcpy(dst, src, length); 30280c16b537SWarner Losh return length; 30290c16b537SWarner Losh } 30300c16b537SWarner Losh 30310c16b537SWarner Losh /** ZSTD_compressStream_generic(): 30320c16b537SWarner Losh * internal function for all *compressStream*() variants and *compress_generic() 3033*19fcbaf1SConrad Meyer * non-static, because can be called from zstdmt_compress.c 30340c16b537SWarner Losh * @return : hint size for next input */ 30350c16b537SWarner Losh size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, 30360c16b537SWarner Losh ZSTD_outBuffer* output, 30370c16b537SWarner Losh ZSTD_inBuffer* input, 30380c16b537SWarner Losh ZSTD_EndDirective const flushMode) 30390c16b537SWarner Losh { 30400c16b537SWarner Losh const char* const istart = (const char*)input->src; 30410c16b537SWarner Losh const char* const iend = istart + input->size; 30420c16b537SWarner Losh const char* ip = istart + input->pos; 30430c16b537SWarner Losh char* const ostart = (char*)output->dst; 30440c16b537SWarner Losh char* const oend = ostart + output->size; 30450c16b537SWarner Losh char* op = ostart + output->pos; 30460c16b537SWarner Losh U32 someMoreWork = 1; 30470c16b537SWarner Losh 30480c16b537SWarner Losh /* check expectations */ 30490c16b537SWarner Losh DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (U32)flushMode); 30500c16b537SWarner Losh assert(zcs->inBuff != NULL); 30510c16b537SWarner Losh assert(zcs->inBuffSize > 0); 30520c16b537SWarner Losh assert(zcs->outBuff != NULL); 30530c16b537SWarner Losh assert(zcs->outBuffSize > 0); 30540c16b537SWarner Losh assert(output->pos <= output->size); 30550c16b537SWarner Losh assert(input->pos <= input->size); 30560c16b537SWarner Losh 30570c16b537SWarner Losh while (someMoreWork) { 30580c16b537SWarner Losh switch(zcs->streamStage) 30590c16b537SWarner Losh { 30600c16b537SWarner Losh case zcss_init: 30610c16b537SWarner Losh /* call ZSTD_initCStream() first ! */ 30620c16b537SWarner Losh return ERROR(init_missing); 30630c16b537SWarner Losh 30640c16b537SWarner Losh case zcss_load: 30650c16b537SWarner Losh if ( (flushMode == ZSTD_e_end) 30660c16b537SWarner Losh && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */ 30670c16b537SWarner Losh && (zcs->inBuffPos == 0) ) { 30680c16b537SWarner Losh /* shortcut to compression pass directly into output buffer */ 30690c16b537SWarner Losh size_t const cSize = ZSTD_compressEnd(zcs, 30700c16b537SWarner Losh op, oend-op, ip, iend-ip); 30710c16b537SWarner Losh DEBUGLOG(4, "ZSTD_compressEnd : %u", (U32)cSize); 30720c16b537SWarner Losh if (ZSTD_isError(cSize)) return cSize; 30730c16b537SWarner Losh ip = iend; 30740c16b537SWarner Losh op += cSize; 30750c16b537SWarner Losh zcs->frameEnded = 1; 30760c16b537SWarner Losh ZSTD_startNewCompression(zcs); 30770c16b537SWarner Losh someMoreWork = 0; break; 30780c16b537SWarner Losh } 30790c16b537SWarner Losh /* complete loading into inBuffer */ 30800c16b537SWarner Losh { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; 30810c16b537SWarner Losh size_t const loaded = ZSTD_limitCopy( 30820c16b537SWarner Losh zcs->inBuff + zcs->inBuffPos, toLoad, 30830c16b537SWarner Losh ip, iend-ip); 30840c16b537SWarner Losh zcs->inBuffPos += loaded; 30850c16b537SWarner Losh ip += loaded; 30860c16b537SWarner Losh if ( (flushMode == ZSTD_e_continue) 30870c16b537SWarner Losh && (zcs->inBuffPos < zcs->inBuffTarget) ) { 30880c16b537SWarner Losh /* not enough input to fill full block : stop here */ 30890c16b537SWarner Losh someMoreWork = 0; break; 30900c16b537SWarner Losh } 30910c16b537SWarner Losh if ( (flushMode == ZSTD_e_flush) 30920c16b537SWarner Losh && (zcs->inBuffPos == zcs->inToCompress) ) { 30930c16b537SWarner Losh /* empty */ 30940c16b537SWarner Losh someMoreWork = 0; break; 30950c16b537SWarner Losh } 30960c16b537SWarner Losh } 30970c16b537SWarner Losh /* compress current block (note : this stage cannot be stopped in the middle) */ 30980c16b537SWarner Losh DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode); 30990c16b537SWarner Losh { void* cDst; 31000c16b537SWarner Losh size_t cSize; 31010c16b537SWarner Losh size_t const iSize = zcs->inBuffPos - zcs->inToCompress; 31020c16b537SWarner Losh size_t oSize = oend-op; 31030c16b537SWarner Losh unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend); 31040c16b537SWarner Losh if (oSize >= ZSTD_compressBound(iSize)) 31050c16b537SWarner Losh cDst = op; /* compress into output buffer, to skip flush stage */ 31060c16b537SWarner Losh else 31070c16b537SWarner Losh cDst = zcs->outBuff, oSize = zcs->outBuffSize; 31080c16b537SWarner Losh cSize = lastBlock ? 31090c16b537SWarner Losh ZSTD_compressEnd(zcs, cDst, oSize, 31100c16b537SWarner Losh zcs->inBuff + zcs->inToCompress, iSize) : 31110c16b537SWarner Losh ZSTD_compressContinue(zcs, cDst, oSize, 31120c16b537SWarner Losh zcs->inBuff + zcs->inToCompress, iSize); 31130c16b537SWarner Losh if (ZSTD_isError(cSize)) return cSize; 31140c16b537SWarner Losh zcs->frameEnded = lastBlock; 31150c16b537SWarner Losh /* prepare next block */ 31160c16b537SWarner Losh zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; 31170c16b537SWarner Losh if (zcs->inBuffTarget > zcs->inBuffSize) 31180c16b537SWarner Losh zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; 31190c16b537SWarner Losh DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u", 31200c16b537SWarner Losh (U32)zcs->inBuffTarget, (U32)zcs->inBuffSize); 31210c16b537SWarner Losh if (!lastBlock) 31220c16b537SWarner Losh assert(zcs->inBuffTarget <= zcs->inBuffSize); 31230c16b537SWarner Losh zcs->inToCompress = zcs->inBuffPos; 31240c16b537SWarner Losh if (cDst == op) { /* no need to flush */ 31250c16b537SWarner Losh op += cSize; 31260c16b537SWarner Losh if (zcs->frameEnded) { 31270c16b537SWarner Losh DEBUGLOG(5, "Frame completed directly in outBuffer"); 31280c16b537SWarner Losh someMoreWork = 0; 31290c16b537SWarner Losh ZSTD_startNewCompression(zcs); 31300c16b537SWarner Losh } 31310c16b537SWarner Losh break; 31320c16b537SWarner Losh } 31330c16b537SWarner Losh zcs->outBuffContentSize = cSize; 31340c16b537SWarner Losh zcs->outBuffFlushedSize = 0; 31350c16b537SWarner Losh zcs->streamStage = zcss_flush; /* pass-through to flush stage */ 31360c16b537SWarner Losh } 31370c16b537SWarner Losh /* fall-through */ 31380c16b537SWarner Losh case zcss_flush: 31390c16b537SWarner Losh DEBUGLOG(5, "flush stage"); 31400c16b537SWarner Losh { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; 31410c16b537SWarner Losh size_t const flushed = ZSTD_limitCopy(op, oend-op, 31420c16b537SWarner Losh zcs->outBuff + zcs->outBuffFlushedSize, toFlush); 31430c16b537SWarner Losh DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u", 31440c16b537SWarner Losh (U32)toFlush, (U32)(oend-op), (U32)flushed); 31450c16b537SWarner Losh op += flushed; 31460c16b537SWarner Losh zcs->outBuffFlushedSize += flushed; 31470c16b537SWarner Losh if (toFlush!=flushed) { 31480c16b537SWarner Losh /* flush not fully completed, presumably because dst is too small */ 31490c16b537SWarner Losh assert(op==oend); 31500c16b537SWarner Losh someMoreWork = 0; 31510c16b537SWarner Losh break; 31520c16b537SWarner Losh } 31530c16b537SWarner Losh zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; 31540c16b537SWarner Losh if (zcs->frameEnded) { 31550c16b537SWarner Losh DEBUGLOG(5, "Frame completed on flush"); 31560c16b537SWarner Losh someMoreWork = 0; 31570c16b537SWarner Losh ZSTD_startNewCompression(zcs); 31580c16b537SWarner Losh break; 31590c16b537SWarner Losh } 31600c16b537SWarner Losh zcs->streamStage = zcss_load; 31610c16b537SWarner Losh break; 31620c16b537SWarner Losh } 31630c16b537SWarner Losh 31640c16b537SWarner Losh default: /* impossible */ 31650c16b537SWarner Losh assert(0); 31660c16b537SWarner Losh } 31670c16b537SWarner Losh } 31680c16b537SWarner Losh 31690c16b537SWarner Losh input->pos = ip - istart; 31700c16b537SWarner Losh output->pos = op - ostart; 31710c16b537SWarner Losh if (zcs->frameEnded) return 0; 31720c16b537SWarner Losh { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos; 31730c16b537SWarner Losh if (hintInSize==0) hintInSize = zcs->blockSize; 31740c16b537SWarner Losh return hintInSize; 31750c16b537SWarner Losh } 31760c16b537SWarner Losh } 31770c16b537SWarner Losh 31780c16b537SWarner Losh size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) 31790c16b537SWarner Losh { 31800c16b537SWarner Losh /* check conditions */ 31810c16b537SWarner Losh if (output->pos > output->size) return ERROR(GENERIC); 31820c16b537SWarner Losh if (input->pos > input->size) return ERROR(GENERIC); 31830c16b537SWarner Losh 31840c16b537SWarner Losh return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue); 31850c16b537SWarner Losh } 31860c16b537SWarner Losh 31870c16b537SWarner Losh 31880c16b537SWarner Losh size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, 31890c16b537SWarner Losh ZSTD_outBuffer* output, 31900c16b537SWarner Losh ZSTD_inBuffer* input, 31910c16b537SWarner Losh ZSTD_EndDirective endOp) 31920c16b537SWarner Losh { 3193052d3c12SConrad Meyer DEBUGLOG(5, "ZSTD_compress_generic, endOp=%u ", (U32)endOp); 31940c16b537SWarner Losh /* check conditions */ 31950c16b537SWarner Losh if (output->pos > output->size) return ERROR(GENERIC); 31960c16b537SWarner Losh if (input->pos > input->size) return ERROR(GENERIC); 31970c16b537SWarner Losh assert(cctx!=NULL); 31980c16b537SWarner Losh 31990c16b537SWarner Losh /* transparent initialization stage */ 32000c16b537SWarner Losh if (cctx->streamStage == zcss_init) { 32010c16b537SWarner Losh ZSTD_CCtx_params params = cctx->requestedParams; 3202052d3c12SConrad Meyer ZSTD_prefixDict const prefixDict = cctx->prefixDict; 32030c16b537SWarner Losh memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */ 32040c16b537SWarner Losh assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */ 32050c16b537SWarner Losh DEBUGLOG(4, "ZSTD_compress_generic : transparent init stage"); 3206052d3c12SConrad Meyer if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */ 3207052d3c12SConrad Meyer params.cParams = ZSTD_getCParamsFromCCtxParams( 3208*19fcbaf1SConrad Meyer &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/); 32090c16b537SWarner Losh 32100c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 3211*19fcbaf1SConrad Meyer if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) { 3212*19fcbaf1SConrad Meyer params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */ 3213*19fcbaf1SConrad Meyer } 3214*19fcbaf1SConrad Meyer if (params.nbWorkers > 0) { 3215*19fcbaf1SConrad Meyer /* mt context creation */ 3216*19fcbaf1SConrad Meyer if (cctx->mtctx == NULL || (params.nbWorkers != ZSTDMT_getNbWorkers(cctx->mtctx))) { 3217*19fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_compress_generic: creating new mtctx for nbWorkers=%u", 3218*19fcbaf1SConrad Meyer params.nbWorkers); 3219*19fcbaf1SConrad Meyer if (cctx->mtctx != NULL) 3220*19fcbaf1SConrad Meyer DEBUGLOG(4, "ZSTD_compress_generic: previous nbWorkers was %u", 3221*19fcbaf1SConrad Meyer ZSTDMT_getNbWorkers(cctx->mtctx)); 32220c16b537SWarner Losh ZSTDMT_freeCCtx(cctx->mtctx); 3223*19fcbaf1SConrad Meyer cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbWorkers, cctx->customMem); 32240c16b537SWarner Losh if (cctx->mtctx == NULL) return ERROR(memory_allocation); 32250c16b537SWarner Losh } 3226*19fcbaf1SConrad Meyer /* mt compression */ 3227*19fcbaf1SConrad Meyer DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers); 32280c16b537SWarner Losh CHECK_F( ZSTDMT_initCStream_internal( 32290c16b537SWarner Losh cctx->mtctx, 3230*19fcbaf1SConrad Meyer prefixDict.dict, prefixDict.dictSize, ZSTD_dct_rawContent, 32310c16b537SWarner Losh cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) ); 32320c16b537SWarner Losh cctx->streamStage = zcss_load; 3233*19fcbaf1SConrad Meyer cctx->appliedParams.nbWorkers = params.nbWorkers; 32340c16b537SWarner Losh } else 32350c16b537SWarner Losh #endif 3236*19fcbaf1SConrad Meyer { CHECK_F( ZSTD_resetCStream_internal(cctx, 3237*19fcbaf1SConrad Meyer prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, 3238*19fcbaf1SConrad Meyer cctx->cdict, 3239*19fcbaf1SConrad Meyer params, cctx->pledgedSrcSizePlusOne-1) ); 3240052d3c12SConrad Meyer assert(cctx->streamStage == zcss_load); 3241*19fcbaf1SConrad Meyer assert(cctx->appliedParams.nbWorkers == 0); 32420c16b537SWarner Losh } } 32430c16b537SWarner Losh 32440c16b537SWarner Losh /* compression stage */ 32450c16b537SWarner Losh #ifdef ZSTD_MULTITHREAD 3246*19fcbaf1SConrad Meyer if (cctx->appliedParams.nbWorkers > 0) { 3247*19fcbaf1SConrad Meyer if (cctx->cParamsChanged) { 3248*19fcbaf1SConrad Meyer ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams); 3249*19fcbaf1SConrad Meyer cctx->cParamsChanged = 0; 3250*19fcbaf1SConrad Meyer } 3251*19fcbaf1SConrad Meyer { size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp); 32520c16b537SWarner Losh if ( ZSTD_isError(flushMin) 32530c16b537SWarner Losh || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */ 32540c16b537SWarner Losh ZSTD_startNewCompression(cctx); 32550c16b537SWarner Losh } 32560c16b537SWarner Losh return flushMin; 3257*19fcbaf1SConrad Meyer } } 32580c16b537SWarner Losh #endif 32590c16b537SWarner Losh CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) ); 32600c16b537SWarner Losh DEBUGLOG(5, "completed ZSTD_compress_generic"); 32610c16b537SWarner Losh return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */ 32620c16b537SWarner Losh } 32630c16b537SWarner Losh 32640c16b537SWarner Losh size_t ZSTD_compress_generic_simpleArgs ( 32650c16b537SWarner Losh ZSTD_CCtx* cctx, 32660c16b537SWarner Losh void* dst, size_t dstCapacity, size_t* dstPos, 32670c16b537SWarner Losh const void* src, size_t srcSize, size_t* srcPos, 32680c16b537SWarner Losh ZSTD_EndDirective endOp) 32690c16b537SWarner Losh { 32700c16b537SWarner Losh ZSTD_outBuffer output = { dst, dstCapacity, *dstPos }; 32710c16b537SWarner Losh ZSTD_inBuffer input = { src, srcSize, *srcPos }; 32720c16b537SWarner Losh /* ZSTD_compress_generic() will check validity of dstPos and srcPos */ 32730c16b537SWarner Losh size_t const cErr = ZSTD_compress_generic(cctx, &output, &input, endOp); 32740c16b537SWarner Losh *dstPos = output.pos; 32750c16b537SWarner Losh *srcPos = input.pos; 32760c16b537SWarner Losh return cErr; 32770c16b537SWarner Losh } 32780c16b537SWarner Losh 32790c16b537SWarner Losh 32800c16b537SWarner Losh /*====== Finalize ======*/ 32810c16b537SWarner Losh 32820c16b537SWarner Losh /*! ZSTD_flushStream() : 32830c16b537SWarner Losh * @return : amount of data remaining to flush */ 32840c16b537SWarner Losh size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 32850c16b537SWarner Losh { 32860c16b537SWarner Losh ZSTD_inBuffer input = { NULL, 0, 0 }; 32870c16b537SWarner Losh if (output->pos > output->size) return ERROR(GENERIC); 32880c16b537SWarner Losh CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_flush) ); 32890c16b537SWarner Losh return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */ 32900c16b537SWarner Losh } 32910c16b537SWarner Losh 32920c16b537SWarner Losh 32930c16b537SWarner Losh size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 32940c16b537SWarner Losh { 32950c16b537SWarner Losh ZSTD_inBuffer input = { NULL, 0, 0 }; 32960c16b537SWarner Losh if (output->pos > output->size) return ERROR(GENERIC); 32970c16b537SWarner Losh CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_end) ); 32980c16b537SWarner Losh { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE; 32990c16b537SWarner Losh size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4; 33000c16b537SWarner Losh size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize + lastBlockSize + checksumSize; 3301052d3c12SConrad Meyer DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (U32)toFlush); 33020c16b537SWarner Losh return toFlush; 33030c16b537SWarner Losh } 33040c16b537SWarner Losh } 33050c16b537SWarner Losh 33060c16b537SWarner Losh 33070c16b537SWarner Losh /*-===== Pre-defined compression levels =====-*/ 33080c16b537SWarner Losh 33090c16b537SWarner Losh #define ZSTD_MAX_CLEVEL 22 33100c16b537SWarner Losh int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } 33110c16b537SWarner Losh 33120c16b537SWarner Losh static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { 33130c16b537SWarner Losh { /* "default" - guarantees a monotonically increasing memory budget */ 33140c16b537SWarner Losh /* W, C, H, S, L, TL, strat */ 3315*19fcbaf1SConrad Meyer { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */ 3316*19fcbaf1SConrad Meyer { 19, 13, 14, 1, 7, 1, ZSTD_fast }, /* level 1 */ 3317*19fcbaf1SConrad Meyer { 19, 15, 16, 1, 6, 1, ZSTD_fast }, /* level 2 */ 3318*19fcbaf1SConrad Meyer { 20, 16, 17, 1, 5, 8, ZSTD_dfast }, /* level 3 */ 3319*19fcbaf1SConrad Meyer { 20, 17, 18, 1, 5, 8, ZSTD_dfast }, /* level 4 */ 33200c16b537SWarner Losh { 20, 17, 18, 2, 5, 16, ZSTD_greedy }, /* level 5 */ 33210c16b537SWarner Losh { 21, 17, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */ 33220c16b537SWarner Losh { 21, 18, 19, 3, 5, 16, ZSTD_lazy }, /* level 7 */ 33230c16b537SWarner Losh { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ 33240c16b537SWarner Losh { 21, 19, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */ 33250c16b537SWarner Losh { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ 33260c16b537SWarner Losh { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ 33270c16b537SWarner Losh { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ 3328*19fcbaf1SConrad Meyer { 22, 21, 22, 4, 5, 32, ZSTD_btlazy2 }, /* level 13 */ 3329*19fcbaf1SConrad Meyer { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */ 3330*19fcbaf1SConrad Meyer { 22, 22, 22, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */ 3331052d3c12SConrad Meyer { 22, 21, 22, 4, 5, 48, ZSTD_btopt }, /* level 16 */ 3332052d3c12SConrad Meyer { 23, 22, 22, 4, 4, 48, ZSTD_btopt }, /* level 17 */ 3333052d3c12SConrad Meyer { 23, 22, 22, 5, 3, 64, ZSTD_btopt }, /* level 18 */ 3334052d3c12SConrad Meyer { 23, 23, 22, 7, 3,128, ZSTD_btopt }, /* level 19 */ 3335052d3c12SConrad Meyer { 25, 25, 23, 7, 3,128, ZSTD_btultra }, /* level 20 */ 33360c16b537SWarner Losh { 26, 26, 24, 7, 3,256, ZSTD_btultra }, /* level 21 */ 33370c16b537SWarner Losh { 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */ 33380c16b537SWarner Losh }, 33390c16b537SWarner Losh { /* for srcSize <= 256 KB */ 33400c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 3341*19fcbaf1SConrad Meyer { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 3342*19fcbaf1SConrad Meyer { 18, 13, 14, 1, 6, 1, ZSTD_fast }, /* level 1 */ 33430c16b537SWarner Losh { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */ 33440c16b537SWarner Losh { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */ 33450c16b537SWarner Losh { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/ 33460c16b537SWarner Losh { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/ 33470c16b537SWarner Losh { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/ 33480c16b537SWarner Losh { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */ 33490c16b537SWarner Losh { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 33500c16b537SWarner Losh { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 33510c16b537SWarner Losh { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 33520c16b537SWarner Losh { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/ 3353*19fcbaf1SConrad Meyer { 18, 18, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 12.*/ 3354*19fcbaf1SConrad Meyer { 18, 19, 17, 7, 4, 8, ZSTD_btlazy2 }, /* level 13 */ 33550c16b537SWarner Losh { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/ 33560c16b537SWarner Losh { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/ 33570c16b537SWarner Losh { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/ 33580c16b537SWarner Losh { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/ 33590c16b537SWarner Losh { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/ 33600c16b537SWarner Losh { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/ 33610c16b537SWarner Losh { 18, 19, 18, 11, 3,512, ZSTD_btultra }, /* level 20.*/ 33620c16b537SWarner Losh { 18, 19, 18, 12, 3,512, ZSTD_btultra }, /* level 21.*/ 33630c16b537SWarner Losh { 18, 19, 18, 13, 3,512, ZSTD_btultra }, /* level 22.*/ 33640c16b537SWarner Losh }, 33650c16b537SWarner Losh { /* for srcSize <= 128 KB */ 33660c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 3367*19fcbaf1SConrad Meyer { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* level 0 - not used */ 3368*19fcbaf1SConrad Meyer { 17, 12, 13, 1, 6, 1, ZSTD_fast }, /* level 1 */ 3369*19fcbaf1SConrad Meyer { 17, 13, 16, 1, 5, 1, ZSTD_fast }, /* level 2 */ 33700c16b537SWarner Losh { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */ 33710c16b537SWarner Losh { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */ 33720c16b537SWarner Losh { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */ 33730c16b537SWarner Losh { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */ 33740c16b537SWarner Losh { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */ 33750c16b537SWarner Losh { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 33760c16b537SWarner Losh { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 33770c16b537SWarner Losh { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 33780c16b537SWarner Losh { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */ 33790c16b537SWarner Losh { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */ 33800c16b537SWarner Losh { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/ 33810c16b537SWarner Losh { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/ 33820c16b537SWarner Losh { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/ 33830c16b537SWarner Losh { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/ 33840c16b537SWarner Losh { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/ 33850c16b537SWarner Losh { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/ 33860c16b537SWarner Losh { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/ 33870c16b537SWarner Losh { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/ 33880c16b537SWarner Losh { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/ 33890c16b537SWarner Losh { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/ 33900c16b537SWarner Losh }, 33910c16b537SWarner Losh { /* for srcSize <= 16 KB */ 33920c16b537SWarner Losh /* W, C, H, S, L, T, strat */ 3393*19fcbaf1SConrad Meyer { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */ 3394*19fcbaf1SConrad Meyer { 14, 14, 14, 1, 6, 1, ZSTD_fast }, /* level 1 */ 3395*19fcbaf1SConrad Meyer { 14, 14, 14, 1, 4, 1, ZSTD_fast }, /* level 2 */ 33960c16b537SWarner Losh { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/ 33970c16b537SWarner Losh { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/ 33980c16b537SWarner Losh { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/ 33990c16b537SWarner Losh { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */ 34000c16b537SWarner Losh { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */ 34010c16b537SWarner Losh { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/ 34020c16b537SWarner Losh { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/ 34030c16b537SWarner Losh { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/ 34040c16b537SWarner Losh { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/ 34050c16b537SWarner Losh { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/ 34060c16b537SWarner Losh { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/ 34070c16b537SWarner Losh { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/ 34080c16b537SWarner Losh { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/ 34090c16b537SWarner Losh { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/ 34100c16b537SWarner Losh { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/ 34110c16b537SWarner Losh { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/ 34120c16b537SWarner Losh { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/ 34130c16b537SWarner Losh { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/ 34140c16b537SWarner Losh { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/ 34150c16b537SWarner Losh { 14, 15, 15, 10, 3,256, ZSTD_btultra }, /* level 22.*/ 34160c16b537SWarner Losh }, 34170c16b537SWarner Losh }; 34180c16b537SWarner Losh 34190c16b537SWarner Losh /*! ZSTD_getCParams() : 3420*19fcbaf1SConrad Meyer * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize. 34210c16b537SWarner Losh * Size values are optional, provide 0 if not known or unused */ 34220c16b537SWarner Losh ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) 34230c16b537SWarner Losh { 34240c16b537SWarner Losh size_t const addedSize = srcSizeHint ? 0 : 500; 34250c16b537SWarner Losh U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1; 34260c16b537SWarner Losh U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */ 3427*19fcbaf1SConrad Meyer int row = compressionLevel; 3428*19fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_getCParams (cLevel=%i)", compressionLevel); 3429*19fcbaf1SConrad Meyer if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */ 3430*19fcbaf1SConrad Meyer if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */ 3431*19fcbaf1SConrad Meyer if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL; 3432*19fcbaf1SConrad Meyer { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row]; 3433*19fcbaf1SConrad Meyer if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */ 34340c16b537SWarner Losh return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); } 34350c16b537SWarner Losh 34360c16b537SWarner Losh } 34370c16b537SWarner Losh 34380c16b537SWarner Losh /*! ZSTD_getParams() : 34390c16b537SWarner Losh * same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`). 34400c16b537SWarner Losh * All fields of `ZSTD_frameParameters` are set to default (0) */ 34410c16b537SWarner Losh ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) { 34420c16b537SWarner Losh ZSTD_parameters params; 34430c16b537SWarner Losh ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize); 3444*19fcbaf1SConrad Meyer DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel); 34450c16b537SWarner Losh memset(¶ms, 0, sizeof(params)); 34460c16b537SWarner Losh params.cParams = cParams; 3447052d3c12SConrad Meyer params.fParams.contentSizeFlag = 1; 34480c16b537SWarner Losh return params; 34490c16b537SWarner Losh } 3450