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