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