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