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