1 /*
2  * Copyright (c) Yann Collet, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under both the BSD-style license (found in the
6  * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7  * in the COPYING file in the root directory of this source tree).
8  * You may select, at your option, one of the above-listed licenses.
9  */
10 
11 /*-*************************************
12 *  Dependencies
13 ***************************************/
14 #include "../common/zstd_deps.h"  /* INT_MAX, ZSTD_memset, ZSTD_memcpy */
15 #include "../common/cpu.h"
16 #include "../common/mem.h"
17 #include "hist.h"           /* HIST_countFast_wksp */
18 #define FSE_STATIC_LINKING_ONLY   /* FSE_encodeSymbol */
19 #include "../common/fse.h"
20 #define HUF_STATIC_LINKING_ONLY
21 #include "../common/huf.h"
22 #include "zstd_compress_internal.h"
23 #include "zstd_compress_sequences.h"
24 #include "zstd_compress_literals.h"
25 #include "zstd_fast.h"
26 #include "zstd_double_fast.h"
27 #include "zstd_lazy.h"
28 #include "zstd_opt.h"
29 #include "zstd_ldm.h"
30 #include "zstd_compress_superblock.h"
31 
32 /* ***************************************************************
33 *  Tuning parameters
34 *****************************************************************/
35 /*!
36  * COMPRESS_HEAPMODE :
37  * Select how default decompression function ZSTD_compress() allocates its context,
38  * on stack (0, default), or into heap (1).
39  * Note that functions with explicit context such as ZSTD_compressCCtx() are unaffected.
40  */
41 
42 
43 /*-*************************************
44 *  Helper functions
45 ***************************************/
46 /* ZSTD_compressBound()
47  * Note that the result from this function is only compatible with the "normal"
48  * full-block strategy.
49  * When there are a lot of small blocks due to frequent flush in streaming mode
50  * the overhead of headers can make the compressed data to be larger than the
51  * return value of ZSTD_compressBound().
52  */
ZSTD_compressBound(size_t srcSize)53 size_t ZSTD_compressBound(size_t srcSize) {
54     return ZSTD_COMPRESSBOUND(srcSize);
55 }
56 
57 
58 /*-*************************************
59 *  Context memory management
60 ***************************************/
61 struct ZSTD_CDict_s {
62     const void* dictContent;
63     size_t dictContentSize;
64     ZSTD_dictContentType_e dictContentType; /* The dictContentType the CDict was created with */
65     U32* entropyWorkspace; /* entropy workspace of HUF_WORKSPACE_SIZE bytes */
66     ZSTD_cwksp workspace;
67     ZSTD_matchState_t matchState;
68     ZSTD_compressedBlockState_t cBlockState;
69     ZSTD_customMem customMem;
70     U32 dictID;
71     int compressionLevel; /* 0 indicates that advanced API was used to select CDict params */
72 };  /* typedef'd to ZSTD_CDict within "zstd.h" */
73 
ZSTD_createCCtx(void)74 ZSTD_CCtx* ZSTD_createCCtx(void)
75 {
76     return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
77 }
78 
ZSTD_initCCtx(ZSTD_CCtx * cctx,ZSTD_customMem memManager)79 static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager)
80 {
81     assert(cctx != NULL);
82     ZSTD_memset(cctx, 0, sizeof(*cctx));
83     cctx->customMem = memManager;
84     cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
85     {   size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters);
86         assert(!ZSTD_isError(err));
87         (void)err;
88     }
89 }
90 
ZSTD_createCCtx_advanced(ZSTD_customMem customMem)91 ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
92 {
93     ZSTD_STATIC_ASSERT(zcss_init==0);
94     ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
95     if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
96     {   ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_customMalloc(sizeof(ZSTD_CCtx), customMem);
97         if (!cctx) return NULL;
98         ZSTD_initCCtx(cctx, customMem);
99         return cctx;
100     }
101 }
102 
ZSTD_initStaticCCtx(void * workspace,size_t workspaceSize)103 ZSTD_CCtx* ZSTD_initStaticCCtx(void* workspace, size_t workspaceSize)
104 {
105     ZSTD_cwksp ws;
106     ZSTD_CCtx* cctx;
107     if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL;  /* minimum size */
108     if ((size_t)workspace & 7) return NULL;  /* must be 8-aligned */
109     ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc);
110 
111     cctx = (ZSTD_CCtx*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CCtx));
112     if (cctx == NULL) return NULL;
113 
114     ZSTD_memset(cctx, 0, sizeof(ZSTD_CCtx));
115     ZSTD_cwksp_move(&cctx->workspace, &ws);
116     cctx->staticSize = workspaceSize;
117 
118     /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
119     if (!ZSTD_cwksp_check_available(&cctx->workspace, ENTROPY_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t))) return NULL;
120     cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
121     cctx->blockState.nextCBlock = (ZSTD_compressedBlockState_t*)ZSTD_cwksp_reserve_object(&cctx->workspace, sizeof(ZSTD_compressedBlockState_t));
122     cctx->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cctx->workspace, ENTROPY_WORKSPACE_SIZE);
123     cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
124     return cctx;
125 }
126 
127 /*
128  * Clears and frees all of the dictionaries in the CCtx.
129  */
ZSTD_clearAllDicts(ZSTD_CCtx * cctx)130 static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx)
131 {
132     ZSTD_customFree(cctx->localDict.dictBuffer, cctx->customMem);
133     ZSTD_freeCDict(cctx->localDict.cdict);
134     ZSTD_memset(&cctx->localDict, 0, sizeof(cctx->localDict));
135     ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));
136     cctx->cdict = NULL;
137 }
138 
ZSTD_sizeof_localDict(ZSTD_localDict dict)139 static size_t ZSTD_sizeof_localDict(ZSTD_localDict dict)
140 {
141     size_t const bufferSize = dict.dictBuffer != NULL ? dict.dictSize : 0;
142     size_t const cdictSize = ZSTD_sizeof_CDict(dict.cdict);
143     return bufferSize + cdictSize;
144 }
145 
ZSTD_freeCCtxContent(ZSTD_CCtx * cctx)146 static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx)
147 {
148     assert(cctx != NULL);
149     assert(cctx->staticSize == 0);
150     ZSTD_clearAllDicts(cctx);
151     ZSTD_cwksp_free(&cctx->workspace, cctx->customMem);
152 }
153 
ZSTD_freeCCtx(ZSTD_CCtx * cctx)154 size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
155 {
156     if (cctx==NULL) return 0;   /* support free on NULL */
157     RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
158                     "not compatible with static CCtx");
159     {
160         int cctxInWorkspace = ZSTD_cwksp_owns_buffer(&cctx->workspace, cctx);
161         ZSTD_freeCCtxContent(cctx);
162         if (!cctxInWorkspace) {
163             ZSTD_customFree(cctx, cctx->customMem);
164         }
165     }
166     return 0;
167 }
168 
169 
ZSTD_sizeof_mtctx(const ZSTD_CCtx * cctx)170 static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx)
171 {
172     (void)cctx;
173     return 0;
174 }
175 
176 
ZSTD_sizeof_CCtx(const ZSTD_CCtx * cctx)177 size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
178 {
179     if (cctx==NULL) return 0;   /* support sizeof on NULL */
180     /* cctx may be in the workspace */
181     return (cctx->workspace.workspace == cctx ? 0 : sizeof(*cctx))
182            + ZSTD_cwksp_sizeof(&cctx->workspace)
183            + ZSTD_sizeof_localDict(cctx->localDict)
184            + ZSTD_sizeof_mtctx(cctx);
185 }
186 
ZSTD_sizeof_CStream(const ZSTD_CStream * zcs)187 size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
188 {
189     return ZSTD_sizeof_CCtx(zcs);  /* same object */
190 }
191 
192 /* private API call, for dictBuilder only */
ZSTD_getSeqStore(const ZSTD_CCtx * ctx)193 const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
194 
195 /* Returns 1 if compression parameters are such that we should
196  * enable long distance matching (wlog >= 27, strategy >= btopt).
197  * Returns 0 otherwise.
198  */
ZSTD_CParams_shouldEnableLdm(const ZSTD_compressionParameters * const cParams)199 static U32 ZSTD_CParams_shouldEnableLdm(const ZSTD_compressionParameters* const cParams) {
200     return cParams->strategy >= ZSTD_btopt && cParams->windowLog >= 27;
201 }
202 
ZSTD_makeCCtxParamsFromCParams(ZSTD_compressionParameters cParams)203 static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
204         ZSTD_compressionParameters cParams)
205 {
206     ZSTD_CCtx_params cctxParams;
207     /* should not matter, as all cParams are presumed properly defined */
208     ZSTD_CCtxParams_init(&cctxParams, ZSTD_CLEVEL_DEFAULT);
209     cctxParams.cParams = cParams;
210 
211     if (ZSTD_CParams_shouldEnableLdm(&cParams)) {
212         DEBUGLOG(4, "ZSTD_makeCCtxParamsFromCParams(): Including LDM into cctx params");
213         cctxParams.ldmParams.enableLdm = 1;
214         /* LDM is enabled by default for optimal parser and window size >= 128MB */
215         ZSTD_ldm_adjustParameters(&cctxParams.ldmParams, &cParams);
216         assert(cctxParams.ldmParams.hashLog >= cctxParams.ldmParams.bucketSizeLog);
217         assert(cctxParams.ldmParams.hashRateLog < 32);
218     }
219 
220     assert(!ZSTD_checkCParams(cParams));
221     return cctxParams;
222 }
223 
ZSTD_createCCtxParams_advanced(ZSTD_customMem customMem)224 static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
225         ZSTD_customMem customMem)
226 {
227     ZSTD_CCtx_params* params;
228     if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
229     params = (ZSTD_CCtx_params*)ZSTD_customCalloc(
230             sizeof(ZSTD_CCtx_params), customMem);
231     if (!params) { return NULL; }
232     ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
233     params->customMem = customMem;
234     return params;
235 }
236 
ZSTD_createCCtxParams(void)237 ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
238 {
239     return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem);
240 }
241 
ZSTD_freeCCtxParams(ZSTD_CCtx_params * params)242 size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
243 {
244     if (params == NULL) { return 0; }
245     ZSTD_customFree(params, params->customMem);
246     return 0;
247 }
248 
ZSTD_CCtxParams_reset(ZSTD_CCtx_params * params)249 size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params)
250 {
251     return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
252 }
253 
ZSTD_CCtxParams_init(ZSTD_CCtx_params * cctxParams,int compressionLevel)254 size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
255     RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
256     ZSTD_memset(cctxParams, 0, sizeof(*cctxParams));
257     cctxParams->compressionLevel = compressionLevel;
258     cctxParams->fParams.contentSizeFlag = 1;
259     return 0;
260 }
261 
262 #define ZSTD_NO_CLEVEL 0
263 
264 /*
265  * Initializes the cctxParams from params and compressionLevel.
266  * @param compressionLevel If params are derived from a compression level then that compression level, otherwise ZSTD_NO_CLEVEL.
267  */
ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params * cctxParams,ZSTD_parameters const * params,int compressionLevel)268 static void ZSTD_CCtxParams_init_internal(ZSTD_CCtx_params* cctxParams, ZSTD_parameters const* params, int compressionLevel)
269 {
270     assert(!ZSTD_checkCParams(params->cParams));
271     ZSTD_memset(cctxParams, 0, sizeof(*cctxParams));
272     cctxParams->cParams = params->cParams;
273     cctxParams->fParams = params->fParams;
274     /* Should not matter, as all cParams are presumed properly defined.
275      * But, set it for tracing anyway.
276      */
277     cctxParams->compressionLevel = compressionLevel;
278 }
279 
ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params * cctxParams,ZSTD_parameters params)280 size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
281 {
282     RETURN_ERROR_IF(!cctxParams, GENERIC, "NULL pointer!");
283     FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
284     ZSTD_CCtxParams_init_internal(cctxParams, &params, ZSTD_NO_CLEVEL);
285     return 0;
286 }
287 
288 /*
289  * Sets cctxParams' cParams and fParams from params, but otherwise leaves them alone.
290  * @param param Validated zstd parameters.
291  */
ZSTD_CCtxParams_setZstdParams(ZSTD_CCtx_params * cctxParams,const ZSTD_parameters * params)292 static void ZSTD_CCtxParams_setZstdParams(
293         ZSTD_CCtx_params* cctxParams, const ZSTD_parameters* params)
294 {
295     assert(!ZSTD_checkCParams(params->cParams));
296     cctxParams->cParams = params->cParams;
297     cctxParams->fParams = params->fParams;
298     /* Should not matter, as all cParams are presumed properly defined.
299      * But, set it for tracing anyway.
300      */
301     cctxParams->compressionLevel = ZSTD_NO_CLEVEL;
302 }
303 
ZSTD_cParam_getBounds(ZSTD_cParameter param)304 ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
305 {
306     ZSTD_bounds bounds = { 0, 0, 0 };
307 
308     switch(param)
309     {
310     case ZSTD_c_compressionLevel:
311         bounds.lowerBound = ZSTD_minCLevel();
312         bounds.upperBound = ZSTD_maxCLevel();
313         return bounds;
314 
315     case ZSTD_c_windowLog:
316         bounds.lowerBound = ZSTD_WINDOWLOG_MIN;
317         bounds.upperBound = ZSTD_WINDOWLOG_MAX;
318         return bounds;
319 
320     case ZSTD_c_hashLog:
321         bounds.lowerBound = ZSTD_HASHLOG_MIN;
322         bounds.upperBound = ZSTD_HASHLOG_MAX;
323         return bounds;
324 
325     case ZSTD_c_chainLog:
326         bounds.lowerBound = ZSTD_CHAINLOG_MIN;
327         bounds.upperBound = ZSTD_CHAINLOG_MAX;
328         return bounds;
329 
330     case ZSTD_c_searchLog:
331         bounds.lowerBound = ZSTD_SEARCHLOG_MIN;
332         bounds.upperBound = ZSTD_SEARCHLOG_MAX;
333         return bounds;
334 
335     case ZSTD_c_minMatch:
336         bounds.lowerBound = ZSTD_MINMATCH_MIN;
337         bounds.upperBound = ZSTD_MINMATCH_MAX;
338         return bounds;
339 
340     case ZSTD_c_targetLength:
341         bounds.lowerBound = ZSTD_TARGETLENGTH_MIN;
342         bounds.upperBound = ZSTD_TARGETLENGTH_MAX;
343         return bounds;
344 
345     case ZSTD_c_strategy:
346         bounds.lowerBound = ZSTD_STRATEGY_MIN;
347         bounds.upperBound = ZSTD_STRATEGY_MAX;
348         return bounds;
349 
350     case ZSTD_c_contentSizeFlag:
351         bounds.lowerBound = 0;
352         bounds.upperBound = 1;
353         return bounds;
354 
355     case ZSTD_c_checksumFlag:
356         bounds.lowerBound = 0;
357         bounds.upperBound = 1;
358         return bounds;
359 
360     case ZSTD_c_dictIDFlag:
361         bounds.lowerBound = 0;
362         bounds.upperBound = 1;
363         return bounds;
364 
365     case ZSTD_c_nbWorkers:
366         bounds.lowerBound = 0;
367         bounds.upperBound = 0;
368         return bounds;
369 
370     case ZSTD_c_jobSize:
371         bounds.lowerBound = 0;
372         bounds.upperBound = 0;
373         return bounds;
374 
375     case ZSTD_c_overlapLog:
376         bounds.lowerBound = 0;
377         bounds.upperBound = 0;
378         return bounds;
379 
380     case ZSTD_c_enableDedicatedDictSearch:
381         bounds.lowerBound = 0;
382         bounds.upperBound = 1;
383         return bounds;
384 
385     case ZSTD_c_enableLongDistanceMatching:
386         bounds.lowerBound = 0;
387         bounds.upperBound = 1;
388         return bounds;
389 
390     case ZSTD_c_ldmHashLog:
391         bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN;
392         bounds.upperBound = ZSTD_LDM_HASHLOG_MAX;
393         return bounds;
394 
395     case ZSTD_c_ldmMinMatch:
396         bounds.lowerBound = ZSTD_LDM_MINMATCH_MIN;
397         bounds.upperBound = ZSTD_LDM_MINMATCH_MAX;
398         return bounds;
399 
400     case ZSTD_c_ldmBucketSizeLog:
401         bounds.lowerBound = ZSTD_LDM_BUCKETSIZELOG_MIN;
402         bounds.upperBound = ZSTD_LDM_BUCKETSIZELOG_MAX;
403         return bounds;
404 
405     case ZSTD_c_ldmHashRateLog:
406         bounds.lowerBound = ZSTD_LDM_HASHRATELOG_MIN;
407         bounds.upperBound = ZSTD_LDM_HASHRATELOG_MAX;
408         return bounds;
409 
410     /* experimental parameters */
411     case ZSTD_c_rsyncable:
412         bounds.lowerBound = 0;
413         bounds.upperBound = 1;
414         return bounds;
415 
416     case ZSTD_c_forceMaxWindow :
417         bounds.lowerBound = 0;
418         bounds.upperBound = 1;
419         return bounds;
420 
421     case ZSTD_c_format:
422         ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
423         bounds.lowerBound = ZSTD_f_zstd1;
424         bounds.upperBound = ZSTD_f_zstd1_magicless;   /* note : how to ensure at compile time that this is the highest value enum ? */
425         return bounds;
426 
427     case ZSTD_c_forceAttachDict:
428         ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceLoad);
429         bounds.lowerBound = ZSTD_dictDefaultAttach;
430         bounds.upperBound = ZSTD_dictForceLoad;       /* note : how to ensure at compile time that this is the highest value enum ? */
431         return bounds;
432 
433     case ZSTD_c_literalCompressionMode:
434         ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed);
435         bounds.lowerBound = ZSTD_lcm_auto;
436         bounds.upperBound = ZSTD_lcm_uncompressed;
437         return bounds;
438 
439     case ZSTD_c_targetCBlockSize:
440         bounds.lowerBound = ZSTD_TARGETCBLOCKSIZE_MIN;
441         bounds.upperBound = ZSTD_TARGETCBLOCKSIZE_MAX;
442         return bounds;
443 
444     case ZSTD_c_srcSizeHint:
445         bounds.lowerBound = ZSTD_SRCSIZEHINT_MIN;
446         bounds.upperBound = ZSTD_SRCSIZEHINT_MAX;
447         return bounds;
448 
449     case ZSTD_c_stableInBuffer:
450     case ZSTD_c_stableOutBuffer:
451         bounds.lowerBound = (int)ZSTD_bm_buffered;
452         bounds.upperBound = (int)ZSTD_bm_stable;
453         return bounds;
454 
455     case ZSTD_c_blockDelimiters:
456         bounds.lowerBound = (int)ZSTD_sf_noBlockDelimiters;
457         bounds.upperBound = (int)ZSTD_sf_explicitBlockDelimiters;
458         return bounds;
459 
460     case ZSTD_c_validateSequences:
461         bounds.lowerBound = 0;
462         bounds.upperBound = 1;
463         return bounds;
464 
465     default:
466         bounds.error = ERROR(parameter_unsupported);
467         return bounds;
468     }
469 }
470 
471 /* ZSTD_cParam_clampBounds:
472  * Clamps the value into the bounded range.
473  */
ZSTD_cParam_clampBounds(ZSTD_cParameter cParam,int * value)474 static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value)
475 {
476     ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);
477     if (ZSTD_isError(bounds.error)) return bounds.error;
478     if (*value < bounds.lowerBound) *value = bounds.lowerBound;
479     if (*value > bounds.upperBound) *value = bounds.upperBound;
480     return 0;
481 }
482 
483 #define BOUNDCHECK(cParam, val) { \
484     RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \
485                     parameter_outOfBound, "Param out of bounds"); \
486 }
487 
488 
ZSTD_isUpdateAuthorized(ZSTD_cParameter param)489 static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
490 {
491     switch(param)
492     {
493     case ZSTD_c_compressionLevel:
494     case ZSTD_c_hashLog:
495     case ZSTD_c_chainLog:
496     case ZSTD_c_searchLog:
497     case ZSTD_c_minMatch:
498     case ZSTD_c_targetLength:
499     case ZSTD_c_strategy:
500         return 1;
501 
502     case ZSTD_c_format:
503     case ZSTD_c_windowLog:
504     case ZSTD_c_contentSizeFlag:
505     case ZSTD_c_checksumFlag:
506     case ZSTD_c_dictIDFlag:
507     case ZSTD_c_forceMaxWindow :
508     case ZSTD_c_nbWorkers:
509     case ZSTD_c_jobSize:
510     case ZSTD_c_overlapLog:
511     case ZSTD_c_rsyncable:
512     case ZSTD_c_enableDedicatedDictSearch:
513     case ZSTD_c_enableLongDistanceMatching:
514     case ZSTD_c_ldmHashLog:
515     case ZSTD_c_ldmMinMatch:
516     case ZSTD_c_ldmBucketSizeLog:
517     case ZSTD_c_ldmHashRateLog:
518     case ZSTD_c_forceAttachDict:
519     case ZSTD_c_literalCompressionMode:
520     case ZSTD_c_targetCBlockSize:
521     case ZSTD_c_srcSizeHint:
522     case ZSTD_c_stableInBuffer:
523     case ZSTD_c_stableOutBuffer:
524     case ZSTD_c_blockDelimiters:
525     case ZSTD_c_validateSequences:
526     default:
527         return 0;
528     }
529 }
530 
ZSTD_CCtx_setParameter(ZSTD_CCtx * cctx,ZSTD_cParameter param,int value)531 size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
532 {
533     DEBUGLOG(4, "ZSTD_CCtx_setParameter (%i, %i)", (int)param, value);
534     if (cctx->streamStage != zcss_init) {
535         if (ZSTD_isUpdateAuthorized(param)) {
536             cctx->cParamsChanged = 1;
537         } else {
538             RETURN_ERROR(stage_wrong, "can only set params in ctx init stage");
539     }   }
540 
541     switch(param)
542     {
543     case ZSTD_c_nbWorkers:
544         RETURN_ERROR_IF((value!=0) && cctx->staticSize, parameter_unsupported,
545                         "MT not compatible with static alloc");
546         break;
547 
548     case ZSTD_c_compressionLevel:
549     case ZSTD_c_windowLog:
550     case ZSTD_c_hashLog:
551     case ZSTD_c_chainLog:
552     case ZSTD_c_searchLog:
553     case ZSTD_c_minMatch:
554     case ZSTD_c_targetLength:
555     case ZSTD_c_strategy:
556     case ZSTD_c_ldmHashRateLog:
557     case ZSTD_c_format:
558     case ZSTD_c_contentSizeFlag:
559     case ZSTD_c_checksumFlag:
560     case ZSTD_c_dictIDFlag:
561     case ZSTD_c_forceMaxWindow:
562     case ZSTD_c_forceAttachDict:
563     case ZSTD_c_literalCompressionMode:
564     case ZSTD_c_jobSize:
565     case ZSTD_c_overlapLog:
566     case ZSTD_c_rsyncable:
567     case ZSTD_c_enableDedicatedDictSearch:
568     case ZSTD_c_enableLongDistanceMatching:
569     case ZSTD_c_ldmHashLog:
570     case ZSTD_c_ldmMinMatch:
571     case ZSTD_c_ldmBucketSizeLog:
572     case ZSTD_c_targetCBlockSize:
573     case ZSTD_c_srcSizeHint:
574     case ZSTD_c_stableInBuffer:
575     case ZSTD_c_stableOutBuffer:
576     case ZSTD_c_blockDelimiters:
577     case ZSTD_c_validateSequences:
578         break;
579 
580     default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
581     }
582     return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value);
583 }
584 
ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params * CCtxParams,ZSTD_cParameter param,int value)585 size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
586                                     ZSTD_cParameter param, int value)
587 {
588     DEBUGLOG(4, "ZSTD_CCtxParams_setParameter (%i, %i)", (int)param, value);
589     switch(param)
590     {
591     case ZSTD_c_format :
592         BOUNDCHECK(ZSTD_c_format, value);
593         CCtxParams->format = (ZSTD_format_e)value;
594         return (size_t)CCtxParams->format;
595 
596     case ZSTD_c_compressionLevel : {
597         FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value), "");
598         if (value == 0)
599             CCtxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default */
600         else
601             CCtxParams->compressionLevel = value;
602         if (CCtxParams->compressionLevel >= 0) return (size_t)CCtxParams->compressionLevel;
603         return 0;  /* return type (size_t) cannot represent negative values */
604     }
605 
606     case ZSTD_c_windowLog :
607         if (value!=0)   /* 0 => use default */
608             BOUNDCHECK(ZSTD_c_windowLog, value);
609         CCtxParams->cParams.windowLog = (U32)value;
610         return CCtxParams->cParams.windowLog;
611 
612     case ZSTD_c_hashLog :
613         if (value!=0)   /* 0 => use default */
614             BOUNDCHECK(ZSTD_c_hashLog, value);
615         CCtxParams->cParams.hashLog = (U32)value;
616         return CCtxParams->cParams.hashLog;
617 
618     case ZSTD_c_chainLog :
619         if (value!=0)   /* 0 => use default */
620             BOUNDCHECK(ZSTD_c_chainLog, value);
621         CCtxParams->cParams.chainLog = (U32)value;
622         return CCtxParams->cParams.chainLog;
623 
624     case ZSTD_c_searchLog :
625         if (value!=0)   /* 0 => use default */
626             BOUNDCHECK(ZSTD_c_searchLog, value);
627         CCtxParams->cParams.searchLog = (U32)value;
628         return (size_t)value;
629 
630     case ZSTD_c_minMatch :
631         if (value!=0)   /* 0 => use default */
632             BOUNDCHECK(ZSTD_c_minMatch, value);
633         CCtxParams->cParams.minMatch = value;
634         return CCtxParams->cParams.minMatch;
635 
636     case ZSTD_c_targetLength :
637         BOUNDCHECK(ZSTD_c_targetLength, value);
638         CCtxParams->cParams.targetLength = value;
639         return CCtxParams->cParams.targetLength;
640 
641     case ZSTD_c_strategy :
642         if (value!=0)   /* 0 => use default */
643             BOUNDCHECK(ZSTD_c_strategy, value);
644         CCtxParams->cParams.strategy = (ZSTD_strategy)value;
645         return (size_t)CCtxParams->cParams.strategy;
646 
647     case ZSTD_c_contentSizeFlag :
648         /* Content size written in frame header _when known_ (default:1) */
649         DEBUGLOG(4, "set content size flag = %u", (value!=0));
650         CCtxParams->fParams.contentSizeFlag = value != 0;
651         return CCtxParams->fParams.contentSizeFlag;
652 
653     case ZSTD_c_checksumFlag :
654         /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
655         CCtxParams->fParams.checksumFlag = value != 0;
656         return CCtxParams->fParams.checksumFlag;
657 
658     case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
659         DEBUGLOG(4, "set dictIDFlag = %u", (value!=0));
660         CCtxParams->fParams.noDictIDFlag = !value;
661         return !CCtxParams->fParams.noDictIDFlag;
662 
663     case ZSTD_c_forceMaxWindow :
664         CCtxParams->forceWindow = (value != 0);
665         return CCtxParams->forceWindow;
666 
667     case ZSTD_c_forceAttachDict : {
668         const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value;
669         BOUNDCHECK(ZSTD_c_forceAttachDict, pref);
670         CCtxParams->attachDictPref = pref;
671         return CCtxParams->attachDictPref;
672     }
673 
674     case ZSTD_c_literalCompressionMode : {
675         const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value;
676         BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm);
677         CCtxParams->literalCompressionMode = lcm;
678         return CCtxParams->literalCompressionMode;
679     }
680 
681     case ZSTD_c_nbWorkers :
682         RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
683         return 0;
684 
685     case ZSTD_c_jobSize :
686         RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
687         return 0;
688 
689     case ZSTD_c_overlapLog :
690         RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
691         return 0;
692 
693     case ZSTD_c_rsyncable :
694         RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
695         return 0;
696 
697     case ZSTD_c_enableDedicatedDictSearch :
698         CCtxParams->enableDedicatedDictSearch = (value!=0);
699         return CCtxParams->enableDedicatedDictSearch;
700 
701     case ZSTD_c_enableLongDistanceMatching :
702         CCtxParams->ldmParams.enableLdm = (value!=0);
703         return CCtxParams->ldmParams.enableLdm;
704 
705     case ZSTD_c_ldmHashLog :
706         if (value!=0)   /* 0 ==> auto */
707             BOUNDCHECK(ZSTD_c_ldmHashLog, value);
708         CCtxParams->ldmParams.hashLog = value;
709         return CCtxParams->ldmParams.hashLog;
710 
711     case ZSTD_c_ldmMinMatch :
712         if (value!=0)   /* 0 ==> default */
713             BOUNDCHECK(ZSTD_c_ldmMinMatch, value);
714         CCtxParams->ldmParams.minMatchLength = value;
715         return CCtxParams->ldmParams.minMatchLength;
716 
717     case ZSTD_c_ldmBucketSizeLog :
718         if (value!=0)   /* 0 ==> default */
719             BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value);
720         CCtxParams->ldmParams.bucketSizeLog = value;
721         return CCtxParams->ldmParams.bucketSizeLog;
722 
723     case ZSTD_c_ldmHashRateLog :
724         if (value!=0)   /* 0 ==> default */
725             BOUNDCHECK(ZSTD_c_ldmHashRateLog, value);
726         CCtxParams->ldmParams.hashRateLog = value;
727         return CCtxParams->ldmParams.hashRateLog;
728 
729     case ZSTD_c_targetCBlockSize :
730         if (value!=0)   /* 0 ==> default */
731             BOUNDCHECK(ZSTD_c_targetCBlockSize, value);
732         CCtxParams->targetCBlockSize = value;
733         return CCtxParams->targetCBlockSize;
734 
735     case ZSTD_c_srcSizeHint :
736         if (value!=0)    /* 0 ==> default */
737             BOUNDCHECK(ZSTD_c_srcSizeHint, value);
738         CCtxParams->srcSizeHint = value;
739         return CCtxParams->srcSizeHint;
740 
741     case ZSTD_c_stableInBuffer:
742         BOUNDCHECK(ZSTD_c_stableInBuffer, value);
743         CCtxParams->inBufferMode = (ZSTD_bufferMode_e)value;
744         return CCtxParams->inBufferMode;
745 
746     case ZSTD_c_stableOutBuffer:
747         BOUNDCHECK(ZSTD_c_stableOutBuffer, value);
748         CCtxParams->outBufferMode = (ZSTD_bufferMode_e)value;
749         return CCtxParams->outBufferMode;
750 
751     case ZSTD_c_blockDelimiters:
752         BOUNDCHECK(ZSTD_c_blockDelimiters, value);
753         CCtxParams->blockDelimiters = (ZSTD_sequenceFormat_e)value;
754         return CCtxParams->blockDelimiters;
755 
756     case ZSTD_c_validateSequences:
757         BOUNDCHECK(ZSTD_c_validateSequences, value);
758         CCtxParams->validateSequences = value;
759         return CCtxParams->validateSequences;
760 
761     default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
762     }
763 }
764 
ZSTD_CCtx_getParameter(ZSTD_CCtx const * cctx,ZSTD_cParameter param,int * value)765 size_t ZSTD_CCtx_getParameter(ZSTD_CCtx const* cctx, ZSTD_cParameter param, int* value)
766 {
767     return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value);
768 }
769 
ZSTD_CCtxParams_getParameter(ZSTD_CCtx_params const * CCtxParams,ZSTD_cParameter param,int * value)770 size_t ZSTD_CCtxParams_getParameter(
771         ZSTD_CCtx_params const* CCtxParams, ZSTD_cParameter param, int* value)
772 {
773     switch(param)
774     {
775     case ZSTD_c_format :
776         *value = CCtxParams->format;
777         break;
778     case ZSTD_c_compressionLevel :
779         *value = CCtxParams->compressionLevel;
780         break;
781     case ZSTD_c_windowLog :
782         *value = (int)CCtxParams->cParams.windowLog;
783         break;
784     case ZSTD_c_hashLog :
785         *value = (int)CCtxParams->cParams.hashLog;
786         break;
787     case ZSTD_c_chainLog :
788         *value = (int)CCtxParams->cParams.chainLog;
789         break;
790     case ZSTD_c_searchLog :
791         *value = CCtxParams->cParams.searchLog;
792         break;
793     case ZSTD_c_minMatch :
794         *value = CCtxParams->cParams.minMatch;
795         break;
796     case ZSTD_c_targetLength :
797         *value = CCtxParams->cParams.targetLength;
798         break;
799     case ZSTD_c_strategy :
800         *value = (unsigned)CCtxParams->cParams.strategy;
801         break;
802     case ZSTD_c_contentSizeFlag :
803         *value = CCtxParams->fParams.contentSizeFlag;
804         break;
805     case ZSTD_c_checksumFlag :
806         *value = CCtxParams->fParams.checksumFlag;
807         break;
808     case ZSTD_c_dictIDFlag :
809         *value = !CCtxParams->fParams.noDictIDFlag;
810         break;
811     case ZSTD_c_forceMaxWindow :
812         *value = CCtxParams->forceWindow;
813         break;
814     case ZSTD_c_forceAttachDict :
815         *value = CCtxParams->attachDictPref;
816         break;
817     case ZSTD_c_literalCompressionMode :
818         *value = CCtxParams->literalCompressionMode;
819         break;
820     case ZSTD_c_nbWorkers :
821         assert(CCtxParams->nbWorkers == 0);
822         *value = CCtxParams->nbWorkers;
823         break;
824     case ZSTD_c_jobSize :
825         RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
826     case ZSTD_c_overlapLog :
827         RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
828     case ZSTD_c_rsyncable :
829         RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
830     case ZSTD_c_enableDedicatedDictSearch :
831         *value = CCtxParams->enableDedicatedDictSearch;
832         break;
833     case ZSTD_c_enableLongDistanceMatching :
834         *value = CCtxParams->ldmParams.enableLdm;
835         break;
836     case ZSTD_c_ldmHashLog :
837         *value = CCtxParams->ldmParams.hashLog;
838         break;
839     case ZSTD_c_ldmMinMatch :
840         *value = CCtxParams->ldmParams.minMatchLength;
841         break;
842     case ZSTD_c_ldmBucketSizeLog :
843         *value = CCtxParams->ldmParams.bucketSizeLog;
844         break;
845     case ZSTD_c_ldmHashRateLog :
846         *value = CCtxParams->ldmParams.hashRateLog;
847         break;
848     case ZSTD_c_targetCBlockSize :
849         *value = (int)CCtxParams->targetCBlockSize;
850         break;
851     case ZSTD_c_srcSizeHint :
852         *value = (int)CCtxParams->srcSizeHint;
853         break;
854     case ZSTD_c_stableInBuffer :
855         *value = (int)CCtxParams->inBufferMode;
856         break;
857     case ZSTD_c_stableOutBuffer :
858         *value = (int)CCtxParams->outBufferMode;
859         break;
860     case ZSTD_c_blockDelimiters :
861         *value = (int)CCtxParams->blockDelimiters;
862         break;
863     case ZSTD_c_validateSequences :
864         *value = (int)CCtxParams->validateSequences;
865         break;
866     default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
867     }
868     return 0;
869 }
870 
871 /* ZSTD_CCtx_setParametersUsingCCtxParams() :
872  *  just applies `params` into `cctx`
873  *  no action is performed, parameters are merely stored.
874  *  If ZSTDMT is enabled, parameters are pushed to cctx->mtctx.
875  *    This is possible even if a compression is ongoing.
876  *    In which case, new parameters will be applied on the fly, starting with next compression job.
877  */
ZSTD_CCtx_setParametersUsingCCtxParams(ZSTD_CCtx * cctx,const ZSTD_CCtx_params * params)878 size_t ZSTD_CCtx_setParametersUsingCCtxParams(
879         ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
880 {
881     DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams");
882     RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
883                     "The context is in the wrong stage!");
884     RETURN_ERROR_IF(cctx->cdict, stage_wrong,
885                     "Can't override parameters with cdict attached (some must "
886                     "be inherited from the cdict).");
887 
888     cctx->requestedParams = *params;
889     return 0;
890 }
891 
ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx * cctx,unsigned long long pledgedSrcSize)892 ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
893 {
894     DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize);
895     RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
896                     "Can't set pledgedSrcSize when not in init stage.");
897     cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
898     return 0;
899 }
900 
901 static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(
902         int const compressionLevel,
903         size_t const dictSize);
904 static int ZSTD_dedicatedDictSearch_isSupported(
905         const ZSTD_compressionParameters* cParams);
906 static void ZSTD_dedicatedDictSearch_revertCParams(
907         ZSTD_compressionParameters* cParams);
908 
909 /*
910  * Initializes the local dict using the requested parameters.
911  * NOTE: This does not use the pledged src size, because it may be used for more
912  * than one compression.
913  */
ZSTD_initLocalDict(ZSTD_CCtx * cctx)914 static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx)
915 {
916     ZSTD_localDict* const dl = &cctx->localDict;
917     if (dl->dict == NULL) {
918         /* No local dictionary. */
919         assert(dl->dictBuffer == NULL);
920         assert(dl->cdict == NULL);
921         assert(dl->dictSize == 0);
922         return 0;
923     }
924     if (dl->cdict != NULL) {
925         assert(cctx->cdict == dl->cdict);
926         /* Local dictionary already initialized. */
927         return 0;
928     }
929     assert(dl->dictSize > 0);
930     assert(cctx->cdict == NULL);
931     assert(cctx->prefixDict.dict == NULL);
932 
933     dl->cdict = ZSTD_createCDict_advanced2(
934             dl->dict,
935             dl->dictSize,
936             ZSTD_dlm_byRef,
937             dl->dictContentType,
938             &cctx->requestedParams,
939             cctx->customMem);
940     RETURN_ERROR_IF(!dl->cdict, memory_allocation, "ZSTD_createCDict_advanced failed");
941     cctx->cdict = dl->cdict;
942     return 0;
943 }
944 
ZSTD_CCtx_loadDictionary_advanced(ZSTD_CCtx * cctx,const void * dict,size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_dictContentType_e dictContentType)945 size_t ZSTD_CCtx_loadDictionary_advanced(
946         ZSTD_CCtx* cctx, const void* dict, size_t dictSize,
947         ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType)
948 {
949     RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
950                     "Can't load a dictionary when ctx is not in init stage.");
951     DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize);
952     ZSTD_clearAllDicts(cctx);  /* in case one already exists */
953     if (dict == NULL || dictSize == 0)  /* no dictionary mode */
954         return 0;
955     if (dictLoadMethod == ZSTD_dlm_byRef) {
956         cctx->localDict.dict = dict;
957     } else {
958         void* dictBuffer;
959         RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
960                         "no malloc for static CCtx");
961         dictBuffer = ZSTD_customMalloc(dictSize, cctx->customMem);
962         RETURN_ERROR_IF(!dictBuffer, memory_allocation, "NULL pointer!");
963         ZSTD_memcpy(dictBuffer, dict, dictSize);
964         cctx->localDict.dictBuffer = dictBuffer;
965         cctx->localDict.dict = dictBuffer;
966     }
967     cctx->localDict.dictSize = dictSize;
968     cctx->localDict.dictContentType = dictContentType;
969     return 0;
970 }
971 
ZSTD_CCtx_loadDictionary_byReference(ZSTD_CCtx * cctx,const void * dict,size_t dictSize)972 ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(
973       ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
974 {
975     return ZSTD_CCtx_loadDictionary_advanced(
976             cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
977 }
978 
ZSTD_CCtx_loadDictionary(ZSTD_CCtx * cctx,const void * dict,size_t dictSize)979 ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
980 {
981     return ZSTD_CCtx_loadDictionary_advanced(
982             cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
983 }
984 
985 
ZSTD_CCtx_refCDict(ZSTD_CCtx * cctx,const ZSTD_CDict * cdict)986 size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
987 {
988     RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
989                     "Can't ref a dict when ctx not in init stage.");
990     /* Free the existing local cdict (if any) to save memory. */
991     ZSTD_clearAllDicts(cctx);
992     cctx->cdict = cdict;
993     return 0;
994 }
995 
ZSTD_CCtx_refThreadPool(ZSTD_CCtx * cctx,ZSTD_threadPool * pool)996 size_t ZSTD_CCtx_refThreadPool(ZSTD_CCtx* cctx, ZSTD_threadPool* pool)
997 {
998     RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
999                     "Can't ref a pool when ctx not in init stage.");
1000     cctx->pool = pool;
1001     return 0;
1002 }
1003 
ZSTD_CCtx_refPrefix(ZSTD_CCtx * cctx,const void * prefix,size_t prefixSize)1004 size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
1005 {
1006     return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent);
1007 }
1008 
ZSTD_CCtx_refPrefix_advanced(ZSTD_CCtx * cctx,const void * prefix,size_t prefixSize,ZSTD_dictContentType_e dictContentType)1009 size_t ZSTD_CCtx_refPrefix_advanced(
1010         ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
1011 {
1012     RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
1013                     "Can't ref a prefix when ctx not in init stage.");
1014     ZSTD_clearAllDicts(cctx);
1015     if (prefix != NULL && prefixSize > 0) {
1016         cctx->prefixDict.dict = prefix;
1017         cctx->prefixDict.dictSize = prefixSize;
1018         cctx->prefixDict.dictContentType = dictContentType;
1019     }
1020     return 0;
1021 }
1022 
1023 /*! ZSTD_CCtx_reset() :
1024  *  Also dumps dictionary */
ZSTD_CCtx_reset(ZSTD_CCtx * cctx,ZSTD_ResetDirective reset)1025 size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset)
1026 {
1027     if ( (reset == ZSTD_reset_session_only)
1028       || (reset == ZSTD_reset_session_and_parameters) ) {
1029         cctx->streamStage = zcss_init;
1030         cctx->pledgedSrcSizePlusOne = 0;
1031     }
1032     if ( (reset == ZSTD_reset_parameters)
1033       || (reset == ZSTD_reset_session_and_parameters) ) {
1034         RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong,
1035                         "Can't reset parameters only when not in init stage.");
1036         ZSTD_clearAllDicts(cctx);
1037         return ZSTD_CCtxParams_reset(&cctx->requestedParams);
1038     }
1039     return 0;
1040 }
1041 
1042 
1043 /* ZSTD_checkCParams() :
1044     control CParam values remain within authorized range.
1045     @return : 0, or an error code if one value is beyond authorized range */
ZSTD_checkCParams(ZSTD_compressionParameters cParams)1046 size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
1047 {
1048     BOUNDCHECK(ZSTD_c_windowLog, (int)cParams.windowLog);
1049     BOUNDCHECK(ZSTD_c_chainLog,  (int)cParams.chainLog);
1050     BOUNDCHECK(ZSTD_c_hashLog,   (int)cParams.hashLog);
1051     BOUNDCHECK(ZSTD_c_searchLog, (int)cParams.searchLog);
1052     BOUNDCHECK(ZSTD_c_minMatch,  (int)cParams.minMatch);
1053     BOUNDCHECK(ZSTD_c_targetLength,(int)cParams.targetLength);
1054     BOUNDCHECK(ZSTD_c_strategy,  cParams.strategy);
1055     return 0;
1056 }
1057 
1058 /* ZSTD_clampCParams() :
1059  *  make CParam values within valid range.
1060  *  @return : valid CParams */
1061 static ZSTD_compressionParameters
ZSTD_clampCParams(ZSTD_compressionParameters cParams)1062 ZSTD_clampCParams(ZSTD_compressionParameters cParams)
1063 {
1064 #   define CLAMP_TYPE(cParam, val, type) {                                \
1065         ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);         \
1066         if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound;      \
1067         else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \
1068     }
1069 #   define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, unsigned)
1070     CLAMP(ZSTD_c_windowLog, cParams.windowLog);
1071     CLAMP(ZSTD_c_chainLog,  cParams.chainLog);
1072     CLAMP(ZSTD_c_hashLog,   cParams.hashLog);
1073     CLAMP(ZSTD_c_searchLog, cParams.searchLog);
1074     CLAMP(ZSTD_c_minMatch,  cParams.minMatch);
1075     CLAMP(ZSTD_c_targetLength,cParams.targetLength);
1076     CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy);
1077     return cParams;
1078 }
1079 
1080 /* ZSTD_cycleLog() :
1081  *  condition for correct operation : hashLog > 1 */
ZSTD_cycleLog(U32 hashLog,ZSTD_strategy strat)1082 U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
1083 {
1084     U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
1085     return hashLog - btScale;
1086 }
1087 
1088 /* ZSTD_dictAndWindowLog() :
1089  * Returns an adjusted window log that is large enough to fit the source and the dictionary.
1090  * The zstd format says that the entire dictionary is valid if one byte of the dictionary
1091  * is within the window. So the hashLog and chainLog should be large enough to reference both
1092  * the dictionary and the window. So we must use this adjusted dictAndWindowLog when downsizing
1093  * the hashLog and windowLog.
1094  * NOTE: srcSize must not be ZSTD_CONTENTSIZE_UNKNOWN.
1095  */
ZSTD_dictAndWindowLog(U32 windowLog,U64 srcSize,U64 dictSize)1096 static U32 ZSTD_dictAndWindowLog(U32 windowLog, U64 srcSize, U64 dictSize)
1097 {
1098     const U64 maxWindowSize = 1ULL << ZSTD_WINDOWLOG_MAX;
1099     /* No dictionary ==> No change */
1100     if (dictSize == 0) {
1101         return windowLog;
1102     }
1103     assert(windowLog <= ZSTD_WINDOWLOG_MAX);
1104     assert(srcSize != ZSTD_CONTENTSIZE_UNKNOWN); /* Handled in ZSTD_adjustCParams_internal() */
1105     {
1106         U64 const windowSize = 1ULL << windowLog;
1107         U64 const dictAndWindowSize = dictSize + windowSize;
1108         /* If the window size is already large enough to fit both the source and the dictionary
1109          * then just use the window size. Otherwise adjust so that it fits the dictionary and
1110          * the window.
1111          */
1112         if (windowSize >= dictSize + srcSize) {
1113             return windowLog; /* Window size large enough already */
1114         } else if (dictAndWindowSize >= maxWindowSize) {
1115             return ZSTD_WINDOWLOG_MAX; /* Larger than max window log */
1116         } else  {
1117             return ZSTD_highbit32((U32)dictAndWindowSize - 1) + 1;
1118         }
1119     }
1120 }
1121 
1122 /* ZSTD_adjustCParams_internal() :
1123  *  optimize `cPar` for a specified input (`srcSize` and `dictSize`).
1124  *  mostly downsize to reduce memory consumption and initialization latency.
1125  * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known.
1126  * `mode` is the mode for parameter adjustment. See docs for `ZSTD_cParamMode_e`.
1127  *  note : `srcSize==0` means 0!
1128  *  condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */
1129 static ZSTD_compressionParameters
ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,unsigned long long srcSize,size_t dictSize,ZSTD_cParamMode_e mode)1130 ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
1131                             unsigned long long srcSize,
1132                             size_t dictSize,
1133                             ZSTD_cParamMode_e mode)
1134 {
1135     const U64 minSrcSize = 513; /* (1<<9) + 1 */
1136     const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
1137     assert(ZSTD_checkCParams(cPar)==0);
1138 
1139     switch (mode) {
1140     case ZSTD_cpm_unknown:
1141     case ZSTD_cpm_noAttachDict:
1142         /* If we don't know the source size, don't make any
1143          * assumptions about it. We will already have selected
1144          * smaller parameters if a dictionary is in use.
1145          */
1146         break;
1147     case ZSTD_cpm_createCDict:
1148         /* Assume a small source size when creating a dictionary
1149          * with an unkown source size.
1150          */
1151         if (dictSize && srcSize == ZSTD_CONTENTSIZE_UNKNOWN)
1152             srcSize = minSrcSize;
1153         break;
1154     case ZSTD_cpm_attachDict:
1155         /* Dictionary has its own dedicated parameters which have
1156          * already been selected. We are selecting parameters
1157          * for only the source.
1158          */
1159         dictSize = 0;
1160         break;
1161     default:
1162         assert(0);
1163         break;
1164     }
1165 
1166     /* resize windowLog if input is small enough, to use less memory */
1167     if ( (srcSize < maxWindowResize)
1168       && (dictSize < maxWindowResize) )  {
1169         U32 const tSize = (U32)(srcSize + dictSize);
1170         static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN;
1171         U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN :
1172                             ZSTD_highbit32(tSize-1) + 1;
1173         if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
1174     }
1175     if (srcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
1176         U32 const dictAndWindowLog = ZSTD_dictAndWindowLog(cPar.windowLog, (U64)srcSize, (U64)dictSize);
1177         U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
1178         if (cPar.hashLog > dictAndWindowLog+1) cPar.hashLog = dictAndWindowLog+1;
1179         if (cycleLog > dictAndWindowLog)
1180             cPar.chainLog -= (cycleLog - dictAndWindowLog);
1181     }
1182 
1183     if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
1184         cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN;  /* minimum wlog required for valid frame header */
1185 
1186     return cPar;
1187 }
1188 
1189 ZSTD_compressionParameters
ZSTD_adjustCParams(ZSTD_compressionParameters cPar,unsigned long long srcSize,size_t dictSize)1190 ZSTD_adjustCParams(ZSTD_compressionParameters cPar,
1191                    unsigned long long srcSize,
1192                    size_t dictSize)
1193 {
1194     cPar = ZSTD_clampCParams(cPar);   /* resulting cPar is necessarily valid (all parameters within range) */
1195     if (srcSize == 0) srcSize = ZSTD_CONTENTSIZE_UNKNOWN;
1196     return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize, ZSTD_cpm_unknown);
1197 }
1198 
1199 static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode);
1200 static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode);
1201 
ZSTD_overrideCParams(ZSTD_compressionParameters * cParams,const ZSTD_compressionParameters * overrides)1202 static void ZSTD_overrideCParams(
1203               ZSTD_compressionParameters* cParams,
1204         const ZSTD_compressionParameters* overrides)
1205 {
1206     if (overrides->windowLog)    cParams->windowLog    = overrides->windowLog;
1207     if (overrides->hashLog)      cParams->hashLog      = overrides->hashLog;
1208     if (overrides->chainLog)     cParams->chainLog     = overrides->chainLog;
1209     if (overrides->searchLog)    cParams->searchLog    = overrides->searchLog;
1210     if (overrides->minMatch)     cParams->minMatch     = overrides->minMatch;
1211     if (overrides->targetLength) cParams->targetLength = overrides->targetLength;
1212     if (overrides->strategy)     cParams->strategy     = overrides->strategy;
1213 }
1214 
ZSTD_getCParamsFromCCtxParams(const ZSTD_CCtx_params * CCtxParams,U64 srcSizeHint,size_t dictSize,ZSTD_cParamMode_e mode)1215 ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
1216         const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode)
1217 {
1218     ZSTD_compressionParameters cParams;
1219     if (srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN && CCtxParams->srcSizeHint > 0) {
1220       srcSizeHint = CCtxParams->srcSizeHint;
1221     }
1222     cParams = ZSTD_getCParams_internal(CCtxParams->compressionLevel, srcSizeHint, dictSize, mode);
1223     if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
1224     ZSTD_overrideCParams(&cParams, &CCtxParams->cParams);
1225     assert(!ZSTD_checkCParams(cParams));
1226     /* srcSizeHint == 0 means 0 */
1227     return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize, mode);
1228 }
1229 
1230 static size_t
ZSTD_sizeof_matchState(const ZSTD_compressionParameters * const cParams,const U32 forCCtx)1231 ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
1232                        const U32 forCCtx)
1233 {
1234     size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
1235     size_t const hSize = ((size_t)1) << cParams->hashLog;
1236     U32    const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
1237     size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
1238     /* We don't use ZSTD_cwksp_alloc_size() here because the tables aren't
1239      * surrounded by redzones in ASAN. */
1240     size_t const tableSpace = chainSize * sizeof(U32)
1241                             + hSize * sizeof(U32)
1242                             + h3Size * sizeof(U32);
1243     size_t const optPotentialSpace =
1244         ZSTD_cwksp_alloc_size((MaxML+1) * sizeof(U32))
1245       + ZSTD_cwksp_alloc_size((MaxLL+1) * sizeof(U32))
1246       + ZSTD_cwksp_alloc_size((MaxOff+1) * sizeof(U32))
1247       + ZSTD_cwksp_alloc_size((1<<Litbits) * sizeof(U32))
1248       + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t))
1249       + ZSTD_cwksp_alloc_size((ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
1250     size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt))
1251                                 ? optPotentialSpace
1252                                 : 0;
1253     DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
1254                 (U32)chainSize, (U32)hSize, (U32)h3Size);
1255     return tableSpace + optSpace;
1256 }
1257 
ZSTD_estimateCCtxSize_usingCCtxParams_internal(const ZSTD_compressionParameters * cParams,const ldmParams_t * ldmParams,const int isStatic,const size_t buffInSize,const size_t buffOutSize,const U64 pledgedSrcSize)1258 static size_t ZSTD_estimateCCtxSize_usingCCtxParams_internal(
1259         const ZSTD_compressionParameters* cParams,
1260         const ldmParams_t* ldmParams,
1261         const int isStatic,
1262         const size_t buffInSize,
1263         const size_t buffOutSize,
1264         const U64 pledgedSrcSize)
1265 {
1266     size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << cParams->windowLog), pledgedSrcSize));
1267     size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
1268     U32    const divider = (cParams->minMatch==3) ? 3 : 4;
1269     size_t const maxNbSeq = blockSize / divider;
1270     size_t const tokenSpace = ZSTD_cwksp_alloc_size(WILDCOPY_OVERLENGTH + blockSize)
1271                             + ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(seqDef))
1272                             + 3 * ZSTD_cwksp_alloc_size(maxNbSeq * sizeof(BYTE));
1273     size_t const entropySpace = ZSTD_cwksp_alloc_size(ENTROPY_WORKSPACE_SIZE);
1274     size_t const blockStateSpace = 2 * ZSTD_cwksp_alloc_size(sizeof(ZSTD_compressedBlockState_t));
1275     size_t const matchStateSize = ZSTD_sizeof_matchState(cParams, /* forCCtx */ 1);
1276 
1277     size_t const ldmSpace = ZSTD_ldm_getTableSize(*ldmParams);
1278     size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(*ldmParams, blockSize);
1279     size_t const ldmSeqSpace = ldmParams->enableLdm ?
1280         ZSTD_cwksp_alloc_size(maxNbLdmSeq * sizeof(rawSeq)) : 0;
1281 
1282 
1283     size_t const bufferSpace = ZSTD_cwksp_alloc_size(buffInSize)
1284                              + ZSTD_cwksp_alloc_size(buffOutSize);
1285 
1286     size_t const cctxSpace = isStatic ? ZSTD_cwksp_alloc_size(sizeof(ZSTD_CCtx)) : 0;
1287 
1288     size_t const neededSpace =
1289         cctxSpace +
1290         entropySpace +
1291         blockStateSpace +
1292         ldmSpace +
1293         ldmSeqSpace +
1294         matchStateSize +
1295         tokenSpace +
1296         bufferSpace;
1297 
1298     DEBUGLOG(5, "estimate workspace : %u", (U32)neededSpace);
1299     return neededSpace;
1300 }
1301 
ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params * params)1302 size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
1303 {
1304     ZSTD_compressionParameters const cParams =
1305                 ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
1306 
1307     RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
1308     /* estimateCCtxSize is for one-shot compression. So no buffers should
1309      * be needed. However, we still allocate two 0-sized buffers, which can
1310      * take space under ASAN. */
1311     return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
1312         &cParams, &params->ldmParams, 1, 0, 0, ZSTD_CONTENTSIZE_UNKNOWN);
1313 }
1314 
ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)1315 size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
1316 {
1317     ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
1318     return ZSTD_estimateCCtxSize_usingCCtxParams(&params);
1319 }
1320 
ZSTD_estimateCCtxSize_internal(int compressionLevel)1321 static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
1322 {
1323     int tier = 0;
1324     size_t largestSize = 0;
1325     static const unsigned long long srcSizeTiers[4] = {16 KB, 128 KB, 256 KB, ZSTD_CONTENTSIZE_UNKNOWN};
1326     for (; tier < 4; ++tier) {
1327         /* Choose the set of cParams for a given level across all srcSizes that give the largest cctxSize */
1328         ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeTiers[tier], 0, ZSTD_cpm_noAttachDict);
1329         largestSize = MAX(ZSTD_estimateCCtxSize_usingCParams(cParams), largestSize);
1330     }
1331     return largestSize;
1332 }
1333 
ZSTD_estimateCCtxSize(int compressionLevel)1334 size_t ZSTD_estimateCCtxSize(int compressionLevel)
1335 {
1336     int level;
1337     size_t memBudget = 0;
1338     for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
1339         /* Ensure monotonically increasing memory usage as compression level increases */
1340         size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
1341         if (newMB > memBudget) memBudget = newMB;
1342     }
1343     return memBudget;
1344 }
1345 
ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params * params)1346 size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
1347 {
1348     RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
1349     {   ZSTD_compressionParameters const cParams =
1350                 ZSTD_getCParamsFromCCtxParams(params, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
1351         size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
1352         size_t const inBuffSize = (params->inBufferMode == ZSTD_bm_buffered)
1353                 ? ((size_t)1 << cParams.windowLog) + blockSize
1354                 : 0;
1355         size_t const outBuffSize = (params->outBufferMode == ZSTD_bm_buffered)
1356                 ? ZSTD_compressBound(blockSize) + 1
1357                 : 0;
1358 
1359         return ZSTD_estimateCCtxSize_usingCCtxParams_internal(
1360             &cParams, &params->ldmParams, 1, inBuffSize, outBuffSize,
1361             ZSTD_CONTENTSIZE_UNKNOWN);
1362     }
1363 }
1364 
ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)1365 size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
1366 {
1367     ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
1368     return ZSTD_estimateCStreamSize_usingCCtxParams(&params);
1369 }
1370 
ZSTD_estimateCStreamSize_internal(int compressionLevel)1371 static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
1372 {
1373     ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, 0, ZSTD_cpm_noAttachDict);
1374     return ZSTD_estimateCStreamSize_usingCParams(cParams);
1375 }
1376 
ZSTD_estimateCStreamSize(int compressionLevel)1377 size_t ZSTD_estimateCStreamSize(int compressionLevel)
1378 {
1379     int level;
1380     size_t memBudget = 0;
1381     for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
1382         size_t const newMB = ZSTD_estimateCStreamSize_internal(level);
1383         if (newMB > memBudget) memBudget = newMB;
1384     }
1385     return memBudget;
1386 }
1387 
1388 /* ZSTD_getFrameProgression():
1389  * tells how much data has been consumed (input) and produced (output) for current frame.
1390  * able to count progression inside worker threads (non-blocking mode).
1391  */
ZSTD_getFrameProgression(const ZSTD_CCtx * cctx)1392 ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx)
1393 {
1394     {   ZSTD_frameProgression fp;
1395         size_t const buffered = (cctx->inBuff == NULL) ? 0 :
1396                                 cctx->inBuffPos - cctx->inToCompress;
1397         if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress);
1398         assert(buffered <= ZSTD_BLOCKSIZE_MAX);
1399         fp.ingested = cctx->consumedSrcSize + buffered;
1400         fp.consumed = cctx->consumedSrcSize;
1401         fp.produced = cctx->producedCSize;
1402         fp.flushed  = cctx->producedCSize;   /* simplified; some data might still be left within streaming output buffer */
1403         fp.currentJobID = 0;
1404         fp.nbActiveWorkers = 0;
1405         return fp;
1406 }   }
1407 
1408 /*! ZSTD_toFlushNow()
1409  *  Only useful for multithreading scenarios currently (nbWorkers >= 1).
1410  */
ZSTD_toFlushNow(ZSTD_CCtx * cctx)1411 size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx)
1412 {
1413     (void)cctx;
1414     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 */
1415 }
1416 
ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1,ZSTD_compressionParameters cParams2)1417 static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1,
1418                                     ZSTD_compressionParameters cParams2)
1419 {
1420     (void)cParams1;
1421     (void)cParams2;
1422     assert(cParams1.windowLog    == cParams2.windowLog);
1423     assert(cParams1.chainLog     == cParams2.chainLog);
1424     assert(cParams1.hashLog      == cParams2.hashLog);
1425     assert(cParams1.searchLog    == cParams2.searchLog);
1426     assert(cParams1.minMatch     == cParams2.minMatch);
1427     assert(cParams1.targetLength == cParams2.targetLength);
1428     assert(cParams1.strategy     == cParams2.strategy);
1429 }
1430 
ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t * bs)1431 void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs)
1432 {
1433     int i;
1434     for (i = 0; i < ZSTD_REP_NUM; ++i)
1435         bs->rep[i] = repStartValue[i];
1436     bs->entropy.huf.repeatMode = HUF_repeat_none;
1437     bs->entropy.fse.offcode_repeatMode = FSE_repeat_none;
1438     bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none;
1439     bs->entropy.fse.litlength_repeatMode = FSE_repeat_none;
1440 }
1441 
1442 /*! ZSTD_invalidateMatchState()
1443  *  Invalidate all the matches in the match finder tables.
1444  *  Requires nextSrc and base to be set (can be NULL).
1445  */
ZSTD_invalidateMatchState(ZSTD_matchState_t * ms)1446 static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
1447 {
1448     ZSTD_window_clear(&ms->window);
1449 
1450     ms->nextToUpdate = ms->window.dictLimit;
1451     ms->loadedDictEnd = 0;
1452     ms->opt.litLengthSum = 0;  /* force reset of btopt stats */
1453     ms->dictMatchState = NULL;
1454 }
1455 
1456 /*
1457  * Controls, for this matchState reset, whether the tables need to be cleared /
1458  * prepared for the coming compression (ZSTDcrp_makeClean), or whether the
1459  * tables can be left unclean (ZSTDcrp_leaveDirty), because we know that a
1460  * subsequent operation will overwrite the table space anyways (e.g., copying
1461  * the matchState contents in from a CDict).
1462  */
1463 typedef enum {
1464     ZSTDcrp_makeClean,
1465     ZSTDcrp_leaveDirty
1466 } ZSTD_compResetPolicy_e;
1467 
1468 /*
1469  * Controls, for this matchState reset, whether indexing can continue where it
1470  * left off (ZSTDirp_continue), or whether it needs to be restarted from zero
1471  * (ZSTDirp_reset).
1472  */
1473 typedef enum {
1474     ZSTDirp_continue,
1475     ZSTDirp_reset
1476 } ZSTD_indexResetPolicy_e;
1477 
1478 typedef enum {
1479     ZSTD_resetTarget_CDict,
1480     ZSTD_resetTarget_CCtx
1481 } ZSTD_resetTarget_e;
1482 
1483 static size_t
ZSTD_reset_matchState(ZSTD_matchState_t * ms,ZSTD_cwksp * ws,const ZSTD_compressionParameters * cParams,const ZSTD_compResetPolicy_e crp,const ZSTD_indexResetPolicy_e forceResetIndex,const ZSTD_resetTarget_e forWho)1484 ZSTD_reset_matchState(ZSTD_matchState_t* ms,
1485                       ZSTD_cwksp* ws,
1486                 const ZSTD_compressionParameters* cParams,
1487                 const ZSTD_compResetPolicy_e crp,
1488                 const ZSTD_indexResetPolicy_e forceResetIndex,
1489                 const ZSTD_resetTarget_e forWho)
1490 {
1491     size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
1492     size_t const hSize = ((size_t)1) << cParams->hashLog;
1493     U32    const hashLog3 = ((forWho == ZSTD_resetTarget_CCtx) && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
1494     size_t const h3Size = hashLog3 ? ((size_t)1) << hashLog3 : 0;
1495 
1496     DEBUGLOG(4, "reset indices : %u", forceResetIndex == ZSTDirp_reset);
1497     if (forceResetIndex == ZSTDirp_reset) {
1498         ZSTD_window_init(&ms->window);
1499         ZSTD_cwksp_mark_tables_dirty(ws);
1500     }
1501 
1502     ms->hashLog3 = hashLog3;
1503 
1504     ZSTD_invalidateMatchState(ms);
1505 
1506     assert(!ZSTD_cwksp_reserve_failed(ws)); /* check that allocation hasn't already failed */
1507 
1508     ZSTD_cwksp_clear_tables(ws);
1509 
1510     DEBUGLOG(5, "reserving table space");
1511     /* table Space */
1512     ms->hashTable = (U32*)ZSTD_cwksp_reserve_table(ws, hSize * sizeof(U32));
1513     ms->chainTable = (U32*)ZSTD_cwksp_reserve_table(ws, chainSize * sizeof(U32));
1514     ms->hashTable3 = (U32*)ZSTD_cwksp_reserve_table(ws, h3Size * sizeof(U32));
1515     RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation,
1516                     "failed a workspace allocation in ZSTD_reset_matchState");
1517 
1518     DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_leaveDirty);
1519     if (crp!=ZSTDcrp_leaveDirty) {
1520         /* reset tables only */
1521         ZSTD_cwksp_clean_tables(ws);
1522     }
1523 
1524     /* opt parser space */
1525     if ((forWho == ZSTD_resetTarget_CCtx) && (cParams->strategy >= ZSTD_btopt)) {
1526         DEBUGLOG(4, "reserving optimal parser space");
1527         ms->opt.litFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (1<<Litbits) * sizeof(unsigned));
1528         ms->opt.litLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxLL+1) * sizeof(unsigned));
1529         ms->opt.matchLengthFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxML+1) * sizeof(unsigned));
1530         ms->opt.offCodeFreq = (unsigned*)ZSTD_cwksp_reserve_aligned(ws, (MaxOff+1) * sizeof(unsigned));
1531         ms->opt.matchTable = (ZSTD_match_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_match_t));
1532         ms->opt.priceTable = (ZSTD_optimal_t*)ZSTD_cwksp_reserve_aligned(ws, (ZSTD_OPT_NUM+1) * sizeof(ZSTD_optimal_t));
1533     }
1534 
1535     ms->cParams = *cParams;
1536 
1537     RETURN_ERROR_IF(ZSTD_cwksp_reserve_failed(ws), memory_allocation,
1538                     "failed a workspace allocation in ZSTD_reset_matchState");
1539 
1540     return 0;
1541 }
1542 
1543 /* ZSTD_indexTooCloseToMax() :
1544  * minor optimization : prefer memset() rather than reduceIndex()
1545  * which is measurably slow in some circumstances (reported for Visual Studio).
1546  * Works when re-using a context for a lot of smallish inputs :
1547  * if all inputs are smaller than ZSTD_INDEXOVERFLOW_MARGIN,
1548  * memset() will be triggered before reduceIndex().
1549  */
1550 #define ZSTD_INDEXOVERFLOW_MARGIN (16 MB)
ZSTD_indexTooCloseToMax(ZSTD_window_t w)1551 static int ZSTD_indexTooCloseToMax(ZSTD_window_t w)
1552 {
1553     return (size_t)(w.nextSrc - w.base) > (ZSTD_CURRENT_MAX - ZSTD_INDEXOVERFLOW_MARGIN);
1554 }
1555 
1556 /*! ZSTD_resetCCtx_internal() :
1557     note : `params` are assumed fully validated at this stage */
ZSTD_resetCCtx_internal(ZSTD_CCtx * zc,ZSTD_CCtx_params params,U64 const pledgedSrcSize,ZSTD_compResetPolicy_e const crp,ZSTD_buffered_policy_e const zbuff)1558 static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
1559                                       ZSTD_CCtx_params params,
1560                                       U64 const pledgedSrcSize,
1561                                       ZSTD_compResetPolicy_e const crp,
1562                                       ZSTD_buffered_policy_e const zbuff)
1563 {
1564     ZSTD_cwksp* const ws = &zc->workspace;
1565     DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
1566                 (U32)pledgedSrcSize, params.cParams.windowLog);
1567     assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
1568 
1569     zc->isFirstBlock = 1;
1570 
1571     if (params.ldmParams.enableLdm) {
1572         /* Adjust long distance matching parameters */
1573         ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
1574         assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
1575         assert(params.ldmParams.hashRateLog < 32);
1576     }
1577 
1578     {   size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
1579         size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
1580         U32    const divider = (params.cParams.minMatch==3) ? 3 : 4;
1581         size_t const maxNbSeq = blockSize / divider;
1582         size_t const buffOutSize = (zbuff == ZSTDb_buffered && params.outBufferMode == ZSTD_bm_buffered)
1583                 ? ZSTD_compressBound(blockSize) + 1
1584                 : 0;
1585         size_t const buffInSize = (zbuff == ZSTDb_buffered && params.inBufferMode == ZSTD_bm_buffered)
1586                 ? windowSize + blockSize
1587                 : 0;
1588         size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
1589 
1590         int const indexTooClose = ZSTD_indexTooCloseToMax(zc->blockState.matchState.window);
1591         ZSTD_indexResetPolicy_e needsIndexReset =
1592             (!indexTooClose && zc->initialized) ? ZSTDirp_continue : ZSTDirp_reset;
1593 
1594         size_t const neededSpace =
1595             ZSTD_estimateCCtxSize_usingCCtxParams_internal(
1596                 &params.cParams, &params.ldmParams, zc->staticSize != 0,
1597                 buffInSize, buffOutSize, pledgedSrcSize);
1598         FORWARD_IF_ERROR(neededSpace, "cctx size estimate failed!");
1599 
1600         if (!zc->staticSize) ZSTD_cwksp_bump_oversized_duration(ws, 0);
1601 
1602         /* Check if workspace is large enough, alloc a new one if needed */
1603         {
1604             int const workspaceTooSmall = ZSTD_cwksp_sizeof(ws) < neededSpace;
1605             int const workspaceWasteful = ZSTD_cwksp_check_wasteful(ws, neededSpace);
1606 
1607             DEBUGLOG(4, "Need %zu B workspace", neededSpace);
1608             DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
1609 
1610             if (workspaceTooSmall || workspaceWasteful) {
1611                 DEBUGLOG(4, "Resize workspaceSize from %zuKB to %zuKB",
1612                             ZSTD_cwksp_sizeof(ws) >> 10,
1613                             neededSpace >> 10);
1614 
1615                 RETURN_ERROR_IF(zc->staticSize, memory_allocation, "static cctx : no resize");
1616 
1617                 needsIndexReset = ZSTDirp_reset;
1618 
1619                 ZSTD_cwksp_free(ws, zc->customMem);
1620                 FORWARD_IF_ERROR(ZSTD_cwksp_create(ws, neededSpace, zc->customMem), "");
1621 
1622                 DEBUGLOG(5, "reserving object space");
1623                 /* Statically sized space.
1624                  * entropyWorkspace never moves,
1625                  * though prev/next block swap places */
1626                 assert(ZSTD_cwksp_check_available(ws, 2 * sizeof(ZSTD_compressedBlockState_t)));
1627                 zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t));
1628                 RETURN_ERROR_IF(zc->blockState.prevCBlock == NULL, memory_allocation, "couldn't allocate prevCBlock");
1629                 zc->blockState.nextCBlock = (ZSTD_compressedBlockState_t*) ZSTD_cwksp_reserve_object(ws, sizeof(ZSTD_compressedBlockState_t));
1630                 RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate nextCBlock");
1631                 zc->entropyWorkspace = (U32*) ZSTD_cwksp_reserve_object(ws, ENTROPY_WORKSPACE_SIZE);
1632                 RETURN_ERROR_IF(zc->blockState.nextCBlock == NULL, memory_allocation, "couldn't allocate entropyWorkspace");
1633         }   }
1634 
1635         ZSTD_cwksp_clear(ws);
1636 
1637         /* init params */
1638         zc->appliedParams = params;
1639         zc->blockState.matchState.cParams = params.cParams;
1640         zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
1641         zc->consumedSrcSize = 0;
1642         zc->producedCSize = 0;
1643         if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
1644             zc->appliedParams.fParams.contentSizeFlag = 0;
1645         DEBUGLOG(4, "pledged content size : %u ; flag : %u",
1646             (unsigned)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag);
1647         zc->blockSize = blockSize;
1648 
1649         xxh64_reset(&zc->xxhState, 0);
1650         zc->stage = ZSTDcs_init;
1651         zc->dictID = 0;
1652         zc->dictContentSize = 0;
1653 
1654         ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
1655 
1656         /* ZSTD_wildcopy() is used to copy into the literals buffer,
1657          * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes.
1658          */
1659         zc->seqStore.litStart = ZSTD_cwksp_reserve_buffer(ws, blockSize + WILDCOPY_OVERLENGTH);
1660         zc->seqStore.maxNbLit = blockSize;
1661 
1662         /* buffers */
1663         zc->bufferedPolicy = zbuff;
1664         zc->inBuffSize = buffInSize;
1665         zc->inBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffInSize);
1666         zc->outBuffSize = buffOutSize;
1667         zc->outBuff = (char*)ZSTD_cwksp_reserve_buffer(ws, buffOutSize);
1668 
1669         /* ldm bucketOffsets table */
1670         if (params.ldmParams.enableLdm) {
1671             /* TODO: avoid memset? */
1672             size_t const numBuckets =
1673                   ((size_t)1) << (params.ldmParams.hashLog -
1674                                   params.ldmParams.bucketSizeLog);
1675             zc->ldmState.bucketOffsets = ZSTD_cwksp_reserve_buffer(ws, numBuckets);
1676             ZSTD_memset(zc->ldmState.bucketOffsets, 0, numBuckets);
1677         }
1678 
1679         /* sequences storage */
1680         ZSTD_referenceExternalSequences(zc, NULL, 0);
1681         zc->seqStore.maxNbSeq = maxNbSeq;
1682         zc->seqStore.llCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE));
1683         zc->seqStore.mlCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE));
1684         zc->seqStore.ofCode = ZSTD_cwksp_reserve_buffer(ws, maxNbSeq * sizeof(BYTE));
1685         zc->seqStore.sequencesStart = (seqDef*)ZSTD_cwksp_reserve_aligned(ws, maxNbSeq * sizeof(seqDef));
1686 
1687         FORWARD_IF_ERROR(ZSTD_reset_matchState(
1688             &zc->blockState.matchState,
1689             ws,
1690             &params.cParams,
1691             crp,
1692             needsIndexReset,
1693             ZSTD_resetTarget_CCtx), "");
1694 
1695         /* ldm hash table */
1696         if (params.ldmParams.enableLdm) {
1697             /* TODO: avoid memset? */
1698             size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
1699             zc->ldmState.hashTable = (ldmEntry_t*)ZSTD_cwksp_reserve_aligned(ws, ldmHSize * sizeof(ldmEntry_t));
1700             ZSTD_memset(zc->ldmState.hashTable, 0, ldmHSize * sizeof(ldmEntry_t));
1701             zc->ldmSequences = (rawSeq*)ZSTD_cwksp_reserve_aligned(ws, maxNbLdmSeq * sizeof(rawSeq));
1702             zc->maxNbLdmSequences = maxNbLdmSeq;
1703 
1704             ZSTD_window_init(&zc->ldmState.window);
1705             ZSTD_window_clear(&zc->ldmState.window);
1706             zc->ldmState.loadedDictEnd = 0;
1707         }
1708 
1709         /* Due to alignment, when reusing a workspace, we can actually consume
1710          * up to 3 extra bytes for alignment. See the comments in zstd_cwksp.h
1711          */
1712         assert(ZSTD_cwksp_used(ws) >= neededSpace &&
1713                ZSTD_cwksp_used(ws) <= neededSpace + 3);
1714 
1715         DEBUGLOG(3, "wksp: finished allocating, %zd bytes remain available", ZSTD_cwksp_available_space(ws));
1716         zc->initialized = 1;
1717 
1718         return 0;
1719     }
1720 }
1721 
1722 /* ZSTD_invalidateRepCodes() :
1723  * ensures next compression will not use repcodes from previous block.
1724  * Note : only works with regular variant;
1725  *        do not use with extDict variant ! */
ZSTD_invalidateRepCodes(ZSTD_CCtx * cctx)1726 void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
1727     int i;
1728     for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0;
1729     assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window));
1730 }
1731 
1732 /* These are the approximate sizes for each strategy past which copying the
1733  * dictionary tables into the working context is faster than using them
1734  * in-place.
1735  */
1736 static const size_t attachDictSizeCutoffs[ZSTD_STRATEGY_MAX+1] = {
1737     8 KB,  /* unused */
1738     8 KB,  /* ZSTD_fast */
1739     16 KB, /* ZSTD_dfast */
1740     32 KB, /* ZSTD_greedy */
1741     32 KB, /* ZSTD_lazy */
1742     32 KB, /* ZSTD_lazy2 */
1743     32 KB, /* ZSTD_btlazy2 */
1744     32 KB, /* ZSTD_btopt */
1745     8 KB,  /* ZSTD_btultra */
1746     8 KB   /* ZSTD_btultra2 */
1747 };
1748 
ZSTD_shouldAttachDict(const ZSTD_CDict * cdict,const ZSTD_CCtx_params * params,U64 pledgedSrcSize)1749 static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict,
1750                                  const ZSTD_CCtx_params* params,
1751                                  U64 pledgedSrcSize)
1752 {
1753     size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy];
1754     int const dedicatedDictSearch = cdict->matchState.dedicatedDictSearch;
1755     return dedicatedDictSearch
1756         || ( ( pledgedSrcSize <= cutoff
1757             || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
1758             || params->attachDictPref == ZSTD_dictForceAttach )
1759           && params->attachDictPref != ZSTD_dictForceCopy
1760           && !params->forceWindow ); /* dictMatchState isn't correctly
1761                                       * handled in _enforceMaxDist */
1762 }
1763 
1764 static size_t
ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx * cctx,const ZSTD_CDict * cdict,ZSTD_CCtx_params params,U64 pledgedSrcSize,ZSTD_buffered_policy_e zbuff)1765 ZSTD_resetCCtx_byAttachingCDict(ZSTD_CCtx* cctx,
1766                         const ZSTD_CDict* cdict,
1767                         ZSTD_CCtx_params params,
1768                         U64 pledgedSrcSize,
1769                         ZSTD_buffered_policy_e zbuff)
1770 {
1771     {
1772         ZSTD_compressionParameters adjusted_cdict_cParams = cdict->matchState.cParams;
1773         unsigned const windowLog = params.cParams.windowLog;
1774         assert(windowLog != 0);
1775         /* Resize working context table params for input only, since the dict
1776          * has its own tables. */
1777         /* pledgedSrcSize == 0 means 0! */
1778 
1779         if (cdict->matchState.dedicatedDictSearch) {
1780             ZSTD_dedicatedDictSearch_revertCParams(&adjusted_cdict_cParams);
1781         }
1782 
1783         params.cParams = ZSTD_adjustCParams_internal(adjusted_cdict_cParams, pledgedSrcSize,
1784                                                      cdict->dictContentSize, ZSTD_cpm_attachDict);
1785         params.cParams.windowLog = windowLog;
1786         FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
1787                                                  ZSTDcrp_makeClean, zbuff), "");
1788         assert(cctx->appliedParams.cParams.strategy == adjusted_cdict_cParams.strategy);
1789     }
1790 
1791     {   const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc
1792                                   - cdict->matchState.window.base);
1793         const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit;
1794         if (cdictLen == 0) {
1795             /* don't even attach dictionaries with no contents */
1796             DEBUGLOG(4, "skipping attaching empty dictionary");
1797         } else {
1798             DEBUGLOG(4, "attaching dictionary into context");
1799             cctx->blockState.matchState.dictMatchState = &cdict->matchState;
1800 
1801             /* prep working match state so dict matches never have negative indices
1802              * when they are translated to the working context's index space. */
1803             if (cctx->blockState.matchState.window.dictLimit < cdictEnd) {
1804                 cctx->blockState.matchState.window.nextSrc =
1805                     cctx->blockState.matchState.window.base + cdictEnd;
1806                 ZSTD_window_clear(&cctx->blockState.matchState.window);
1807             }
1808             /* loadedDictEnd is expressed within the referential of the active context */
1809             cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit;
1810     }   }
1811 
1812     cctx->dictID = cdict->dictID;
1813     cctx->dictContentSize = cdict->dictContentSize;
1814 
1815     /* copy block state */
1816     ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1817 
1818     return 0;
1819 }
1820 
ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx * cctx,const ZSTD_CDict * cdict,ZSTD_CCtx_params params,U64 pledgedSrcSize,ZSTD_buffered_policy_e zbuff)1821 static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
1822                             const ZSTD_CDict* cdict,
1823                             ZSTD_CCtx_params params,
1824                             U64 pledgedSrcSize,
1825                             ZSTD_buffered_policy_e zbuff)
1826 {
1827     const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
1828 
1829     assert(!cdict->matchState.dedicatedDictSearch);
1830 
1831     DEBUGLOG(4, "copying dictionary into context");
1832 
1833     {   unsigned const windowLog = params.cParams.windowLog;
1834         assert(windowLog != 0);
1835         /* Copy only compression parameters related to tables. */
1836         params.cParams = *cdict_cParams;
1837         params.cParams.windowLog = windowLog;
1838         FORWARD_IF_ERROR(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
1839                                                  ZSTDcrp_leaveDirty, zbuff), "");
1840         assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
1841         assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog);
1842         assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog);
1843     }
1844 
1845     ZSTD_cwksp_mark_tables_dirty(&cctx->workspace);
1846 
1847     /* copy tables */
1848     {   size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
1849         size_t const hSize =  (size_t)1 << cdict_cParams->hashLog;
1850 
1851         ZSTD_memcpy(cctx->blockState.matchState.hashTable,
1852                cdict->matchState.hashTable,
1853                hSize * sizeof(U32));
1854         ZSTD_memcpy(cctx->blockState.matchState.chainTable,
1855                cdict->matchState.chainTable,
1856                chainSize * sizeof(U32));
1857     }
1858 
1859     /* Zero the hashTable3, since the cdict never fills it */
1860     {   int const h3log = cctx->blockState.matchState.hashLog3;
1861         size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
1862         assert(cdict->matchState.hashLog3 == 0);
1863         ZSTD_memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
1864     }
1865 
1866     ZSTD_cwksp_mark_tables_clean(&cctx->workspace);
1867 
1868     /* copy dictionary offsets */
1869     {   ZSTD_matchState_t const* srcMatchState = &cdict->matchState;
1870         ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState;
1871         dstMatchState->window       = srcMatchState->window;
1872         dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
1873         dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
1874     }
1875 
1876     cctx->dictID = cdict->dictID;
1877     cctx->dictContentSize = cdict->dictContentSize;
1878 
1879     /* copy block state */
1880     ZSTD_memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1881 
1882     return 0;
1883 }
1884 
1885 /* We have a choice between copying the dictionary context into the working
1886  * context, or referencing the dictionary context from the working context
1887  * in-place. We decide here which strategy to use. */
ZSTD_resetCCtx_usingCDict(ZSTD_CCtx * cctx,const ZSTD_CDict * cdict,const ZSTD_CCtx_params * params,U64 pledgedSrcSize,ZSTD_buffered_policy_e zbuff)1888 static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx,
1889                             const ZSTD_CDict* cdict,
1890                             const ZSTD_CCtx_params* params,
1891                             U64 pledgedSrcSize,
1892                             ZSTD_buffered_policy_e zbuff)
1893 {
1894 
1895     DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)",
1896                 (unsigned)pledgedSrcSize);
1897 
1898     if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) {
1899         return ZSTD_resetCCtx_byAttachingCDict(
1900             cctx, cdict, *params, pledgedSrcSize, zbuff);
1901     } else {
1902         return ZSTD_resetCCtx_byCopyingCDict(
1903             cctx, cdict, *params, pledgedSrcSize, zbuff);
1904     }
1905 }
1906 
1907 /*! ZSTD_copyCCtx_internal() :
1908  *  Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
1909  *  Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
1910  *  The "context", in this case, refers to the hash and chain tables,
1911  *  entropy tables, and dictionary references.
1912  * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx.
1913  * @return : 0, or an error code */
ZSTD_copyCCtx_internal(ZSTD_CCtx * dstCCtx,const ZSTD_CCtx * srcCCtx,ZSTD_frameParameters fParams,U64 pledgedSrcSize,ZSTD_buffered_policy_e zbuff)1914 static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1915                             const ZSTD_CCtx* srcCCtx,
1916                             ZSTD_frameParameters fParams,
1917                             U64 pledgedSrcSize,
1918                             ZSTD_buffered_policy_e zbuff)
1919 {
1920     DEBUGLOG(5, "ZSTD_copyCCtx_internal");
1921     RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong,
1922                     "Can't copy a ctx that's not in init stage.");
1923 
1924     ZSTD_memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
1925     {   ZSTD_CCtx_params params = dstCCtx->requestedParams;
1926         /* Copy only compression parameters related to tables. */
1927         params.cParams = srcCCtx->appliedParams.cParams;
1928         params.fParams = fParams;
1929         ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
1930                                 ZSTDcrp_leaveDirty, zbuff);
1931         assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog);
1932         assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy);
1933         assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog);
1934         assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog);
1935         assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3);
1936     }
1937 
1938     ZSTD_cwksp_mark_tables_dirty(&dstCCtx->workspace);
1939 
1940     /* copy tables */
1941     {   size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
1942         size_t const hSize =  (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
1943         int const h3log = srcCCtx->blockState.matchState.hashLog3;
1944         size_t const h3Size = h3log ? ((size_t)1 << h3log) : 0;
1945 
1946         ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable,
1947                srcCCtx->blockState.matchState.hashTable,
1948                hSize * sizeof(U32));
1949         ZSTD_memcpy(dstCCtx->blockState.matchState.chainTable,
1950                srcCCtx->blockState.matchState.chainTable,
1951                chainSize * sizeof(U32));
1952         ZSTD_memcpy(dstCCtx->blockState.matchState.hashTable3,
1953                srcCCtx->blockState.matchState.hashTable3,
1954                h3Size * sizeof(U32));
1955     }
1956 
1957     ZSTD_cwksp_mark_tables_clean(&dstCCtx->workspace);
1958 
1959     /* copy dictionary offsets */
1960     {
1961         const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState;
1962         ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState;
1963         dstMatchState->window       = srcMatchState->window;
1964         dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
1965         dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
1966     }
1967     dstCCtx->dictID = srcCCtx->dictID;
1968     dstCCtx->dictContentSize = srcCCtx->dictContentSize;
1969 
1970     /* copy block state */
1971     ZSTD_memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
1972 
1973     return 0;
1974 }
1975 
1976 /*! ZSTD_copyCCtx() :
1977  *  Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
1978  *  Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
1979  *  pledgedSrcSize==0 means "unknown".
1980 *   @return : 0, or an error code */
ZSTD_copyCCtx(ZSTD_CCtx * dstCCtx,const ZSTD_CCtx * srcCCtx,unsigned long long pledgedSrcSize)1981 size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
1982 {
1983     ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
1984     ZSTD_buffered_policy_e const zbuff = srcCCtx->bufferedPolicy;
1985     ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
1986     if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
1987     fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
1988 
1989     return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx,
1990                                 fParams, pledgedSrcSize,
1991                                 zbuff);
1992 }
1993 
1994 
1995 #define ZSTD_ROWSIZE 16
1996 /*! ZSTD_reduceTable() :
1997  *  reduce table indexes by `reducerValue`, or squash to zero.
1998  *  PreserveMark preserves "unsorted mark" for btlazy2 strategy.
1999  *  It must be set to a clear 0/1 value, to remove branch during inlining.
2000  *  Presume table size is a multiple of ZSTD_ROWSIZE
2001  *  to help auto-vectorization */
2002 FORCE_INLINE_TEMPLATE void
ZSTD_reduceTable_internal(U32 * const table,U32 const size,U32 const reducerValue,int const preserveMark)2003 ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark)
2004 {
2005     int const nbRows = (int)size / ZSTD_ROWSIZE;
2006     int cellNb = 0;
2007     int rowNb;
2008     assert((size & (ZSTD_ROWSIZE-1)) == 0);  /* multiple of ZSTD_ROWSIZE */
2009     assert(size < (1U<<31));   /* can be casted to int */
2010 
2011 
2012     for (rowNb=0 ; rowNb < nbRows ; rowNb++) {
2013         int column;
2014         for (column=0; column<ZSTD_ROWSIZE; column++) {
2015             if (preserveMark) {
2016                 U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0;
2017                 table[cellNb] += adder;
2018             }
2019             if (table[cellNb] < reducerValue) table[cellNb] = 0;
2020             else table[cellNb] -= reducerValue;
2021             cellNb++;
2022     }   }
2023 }
2024 
ZSTD_reduceTable(U32 * const table,U32 const size,U32 const reducerValue)2025 static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue)
2026 {
2027     ZSTD_reduceTable_internal(table, size, reducerValue, 0);
2028 }
2029 
ZSTD_reduceTable_btlazy2(U32 * const table,U32 const size,U32 const reducerValue)2030 static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue)
2031 {
2032     ZSTD_reduceTable_internal(table, size, reducerValue, 1);
2033 }
2034 
2035 /*! ZSTD_reduceIndex() :
2036 *   rescale all indexes to avoid future overflow (indexes are U32) */
ZSTD_reduceIndex(ZSTD_matchState_t * ms,ZSTD_CCtx_params const * params,const U32 reducerValue)2037 static void ZSTD_reduceIndex (ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const U32 reducerValue)
2038 {
2039     {   U32 const hSize = (U32)1 << params->cParams.hashLog;
2040         ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
2041     }
2042 
2043     if (params->cParams.strategy != ZSTD_fast) {
2044         U32 const chainSize = (U32)1 << params->cParams.chainLog;
2045         if (params->cParams.strategy == ZSTD_btlazy2)
2046             ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue);
2047         else
2048             ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue);
2049     }
2050 
2051     if (ms->hashLog3) {
2052         U32 const h3Size = (U32)1 << ms->hashLog3;
2053         ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue);
2054     }
2055 }
2056 
2057 
2058 /*-*******************************************************
2059 *  Block entropic compression
2060 *********************************************************/
2061 
2062 /* See doc/zstd_compression_format.md for detailed format description */
2063 
ZSTD_seqToCodes(const seqStore_t * seqStorePtr)2064 void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
2065 {
2066     const seqDef* const sequences = seqStorePtr->sequencesStart;
2067     BYTE* const llCodeTable = seqStorePtr->llCode;
2068     BYTE* const ofCodeTable = seqStorePtr->ofCode;
2069     BYTE* const mlCodeTable = seqStorePtr->mlCode;
2070     U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
2071     U32 u;
2072     assert(nbSeq <= seqStorePtr->maxNbSeq);
2073     for (u=0; u<nbSeq; u++) {
2074         U32 const llv = sequences[u].litLength;
2075         U32 const mlv = sequences[u].matchLength;
2076         llCodeTable[u] = (BYTE)ZSTD_LLcode(llv);
2077         ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
2078         mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv);
2079     }
2080     if (seqStorePtr->longLengthID==1)
2081         llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
2082     if (seqStorePtr->longLengthID==2)
2083         mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
2084 }
2085 
2086 /* ZSTD_useTargetCBlockSize():
2087  * Returns if target compressed block size param is being used.
2088  * If used, compression will do best effort to make a compressed block size to be around targetCBlockSize.
2089  * Returns 1 if true, 0 otherwise. */
ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params * cctxParams)2090 static int ZSTD_useTargetCBlockSize(const ZSTD_CCtx_params* cctxParams)
2091 {
2092     DEBUGLOG(5, "ZSTD_useTargetCBlockSize (targetCBlockSize=%zu)", cctxParams->targetCBlockSize);
2093     return (cctxParams->targetCBlockSize != 0);
2094 }
2095 
2096 /* ZSTD_entropyCompressSequences_internal():
2097  * actually compresses both literals and sequences */
2098 MEM_STATIC size_t
ZSTD_entropyCompressSequences_internal(seqStore_t * seqStorePtr,const ZSTD_entropyCTables_t * prevEntropy,ZSTD_entropyCTables_t * nextEntropy,const ZSTD_CCtx_params * cctxParams,void * dst,size_t dstCapacity,void * entropyWorkspace,size_t entropyWkspSize,const int bmi2)2099 ZSTD_entropyCompressSequences_internal(seqStore_t* seqStorePtr,
2100                           const ZSTD_entropyCTables_t* prevEntropy,
2101                                 ZSTD_entropyCTables_t* nextEntropy,
2102                           const ZSTD_CCtx_params* cctxParams,
2103                                 void* dst, size_t dstCapacity,
2104                                 void* entropyWorkspace, size_t entropyWkspSize,
2105                           const int bmi2)
2106 {
2107     const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
2108     ZSTD_strategy const strategy = cctxParams->cParams.strategy;
2109     unsigned* count = (unsigned*)entropyWorkspace;
2110     FSE_CTable* CTable_LitLength = nextEntropy->fse.litlengthCTable;
2111     FSE_CTable* CTable_OffsetBits = nextEntropy->fse.offcodeCTable;
2112     FSE_CTable* CTable_MatchLength = nextEntropy->fse.matchlengthCTable;
2113     U32 LLtype, Offtype, MLtype;   /* compressed, raw or rle */
2114     const seqDef* const sequences = seqStorePtr->sequencesStart;
2115     const BYTE* const ofCodeTable = seqStorePtr->ofCode;
2116     const BYTE* const llCodeTable = seqStorePtr->llCode;
2117     const BYTE* const mlCodeTable = seqStorePtr->mlCode;
2118     BYTE* const ostart = (BYTE*)dst;
2119     BYTE* const oend = ostart + dstCapacity;
2120     BYTE* op = ostart;
2121     size_t const nbSeq = (size_t)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
2122     BYTE* seqHead;
2123     BYTE* lastNCount = NULL;
2124 
2125     entropyWorkspace = count + (MaxSeq + 1);
2126     entropyWkspSize -= (MaxSeq + 1) * sizeof(*count);
2127 
2128     DEBUGLOG(4, "ZSTD_entropyCompressSequences_internal (nbSeq=%zu)", nbSeq);
2129     ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
2130     assert(entropyWkspSize >= HUF_WORKSPACE_SIZE);
2131 
2132     /* Compress literals */
2133     {   const BYTE* const literals = seqStorePtr->litStart;
2134         size_t const litSize = (size_t)(seqStorePtr->lit - literals);
2135         size_t const cSize = ZSTD_compressLiterals(
2136                                     &prevEntropy->huf, &nextEntropy->huf,
2137                                     cctxParams->cParams.strategy,
2138                                     ZSTD_disableLiteralsCompression(cctxParams),
2139                                     op, dstCapacity,
2140                                     literals, litSize,
2141                                     entropyWorkspace, entropyWkspSize,
2142                                     bmi2);
2143         FORWARD_IF_ERROR(cSize, "ZSTD_compressLiterals failed");
2144         assert(cSize <= dstCapacity);
2145         op += cSize;
2146     }
2147 
2148     /* Sequences Header */
2149     RETURN_ERROR_IF((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/,
2150                     dstSize_tooSmall, "Can't fit seq hdr in output buf!");
2151     if (nbSeq < 128) {
2152         *op++ = (BYTE)nbSeq;
2153     } else if (nbSeq < LONGNBSEQ) {
2154         op[0] = (BYTE)((nbSeq>>8) + 0x80);
2155         op[1] = (BYTE)nbSeq;
2156         op+=2;
2157     } else {
2158         op[0]=0xFF;
2159         MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ));
2160         op+=3;
2161     }
2162     assert(op <= oend);
2163     if (nbSeq==0) {
2164         /* Copy the old tables over as if we repeated them */
2165         ZSTD_memcpy(&nextEntropy->fse, &prevEntropy->fse, sizeof(prevEntropy->fse));
2166         return (size_t)(op - ostart);
2167     }
2168 
2169     /* seqHead : flags for FSE encoding type */
2170     seqHead = op++;
2171     assert(op <= oend);
2172 
2173     /* convert length/distances into codes */
2174     ZSTD_seqToCodes(seqStorePtr);
2175     /* build CTable for Literal Lengths */
2176     {   unsigned max = MaxLL;
2177         size_t const mostFrequent = HIST_countFast_wksp(count, &max, llCodeTable, nbSeq, entropyWorkspace, entropyWkspSize);   /* can't fail */
2178         DEBUGLOG(5, "Building LL table");
2179         nextEntropy->fse.litlength_repeatMode = prevEntropy->fse.litlength_repeatMode;
2180         LLtype = ZSTD_selectEncodingType(&nextEntropy->fse.litlength_repeatMode,
2181                                         count, max, mostFrequent, nbSeq,
2182                                         LLFSELog, prevEntropy->fse.litlengthCTable,
2183                                         LL_defaultNorm, LL_defaultNormLog,
2184                                         ZSTD_defaultAllowed, strategy);
2185         assert(set_basic < set_compressed && set_rle < set_compressed);
2186         assert(!(LLtype < set_compressed && nextEntropy->fse.litlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
2187         {   size_t const countSize = ZSTD_buildCTable(
2188                 op, (size_t)(oend - op),
2189                 CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
2190                 count, max, llCodeTable, nbSeq,
2191                 LL_defaultNorm, LL_defaultNormLog, MaxLL,
2192                 prevEntropy->fse.litlengthCTable,
2193                 sizeof(prevEntropy->fse.litlengthCTable),
2194                 entropyWorkspace, entropyWkspSize);
2195             FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for LitLens failed");
2196             if (LLtype == set_compressed)
2197                 lastNCount = op;
2198             op += countSize;
2199             assert(op <= oend);
2200     }   }
2201     /* build CTable for Offsets */
2202     {   unsigned max = MaxOff;
2203         size_t const mostFrequent = HIST_countFast_wksp(
2204             count, &max, ofCodeTable, nbSeq, entropyWorkspace, entropyWkspSize);  /* can't fail */
2205         /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
2206         ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
2207         DEBUGLOG(5, "Building OF table");
2208         nextEntropy->fse.offcode_repeatMode = prevEntropy->fse.offcode_repeatMode;
2209         Offtype = ZSTD_selectEncodingType(&nextEntropy->fse.offcode_repeatMode,
2210                                         count, max, mostFrequent, nbSeq,
2211                                         OffFSELog, prevEntropy->fse.offcodeCTable,
2212                                         OF_defaultNorm, OF_defaultNormLog,
2213                                         defaultPolicy, strategy);
2214         assert(!(Offtype < set_compressed && nextEntropy->fse.offcode_repeatMode != FSE_repeat_none)); /* We don't copy tables */
2215         {   size_t const countSize = ZSTD_buildCTable(
2216                 op, (size_t)(oend - op),
2217                 CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
2218                 count, max, ofCodeTable, nbSeq,
2219                 OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
2220                 prevEntropy->fse.offcodeCTable,
2221                 sizeof(prevEntropy->fse.offcodeCTable),
2222                 entropyWorkspace, entropyWkspSize);
2223             FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for Offsets failed");
2224             if (Offtype == set_compressed)
2225                 lastNCount = op;
2226             op += countSize;
2227             assert(op <= oend);
2228     }   }
2229     /* build CTable for MatchLengths */
2230     {   unsigned max = MaxML;
2231         size_t const mostFrequent = HIST_countFast_wksp(
2232             count, &max, mlCodeTable, nbSeq, entropyWorkspace, entropyWkspSize);   /* can't fail */
2233         DEBUGLOG(5, "Building ML table (remaining space : %i)", (int)(oend-op));
2234         nextEntropy->fse.matchlength_repeatMode = prevEntropy->fse.matchlength_repeatMode;
2235         MLtype = ZSTD_selectEncodingType(&nextEntropy->fse.matchlength_repeatMode,
2236                                         count, max, mostFrequent, nbSeq,
2237                                         MLFSELog, prevEntropy->fse.matchlengthCTable,
2238                                         ML_defaultNorm, ML_defaultNormLog,
2239                                         ZSTD_defaultAllowed, strategy);
2240         assert(!(MLtype < set_compressed && nextEntropy->fse.matchlength_repeatMode != FSE_repeat_none)); /* We don't copy tables */
2241         {   size_t const countSize = ZSTD_buildCTable(
2242                 op, (size_t)(oend - op),
2243                 CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
2244                 count, max, mlCodeTable, nbSeq,
2245                 ML_defaultNorm, ML_defaultNormLog, MaxML,
2246                 prevEntropy->fse.matchlengthCTable,
2247                 sizeof(prevEntropy->fse.matchlengthCTable),
2248                 entropyWorkspace, entropyWkspSize);
2249             FORWARD_IF_ERROR(countSize, "ZSTD_buildCTable for MatchLengths failed");
2250             if (MLtype == set_compressed)
2251                 lastNCount = op;
2252             op += countSize;
2253             assert(op <= oend);
2254     }   }
2255 
2256     *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
2257 
2258     {   size_t const bitstreamSize = ZSTD_encodeSequences(
2259                                         op, (size_t)(oend - op),
2260                                         CTable_MatchLength, mlCodeTable,
2261                                         CTable_OffsetBits, ofCodeTable,
2262                                         CTable_LitLength, llCodeTable,
2263                                         sequences, nbSeq,
2264                                         longOffsets, bmi2);
2265         FORWARD_IF_ERROR(bitstreamSize, "ZSTD_encodeSequences failed");
2266         op += bitstreamSize;
2267         assert(op <= oend);
2268         /* zstd versions <= 1.3.4 mistakenly report corruption when
2269          * FSE_readNCount() receives a buffer < 4 bytes.
2270          * Fixed by https://github.com/facebook/zstd/pull/1146.
2271          * This can happen when the last set_compressed table present is 2
2272          * bytes and the bitstream is only one byte.
2273          * In this exceedingly rare case, we will simply emit an uncompressed
2274          * block, since it isn't worth optimizing.
2275          */
2276         if (lastNCount && (op - lastNCount) < 4) {
2277             /* NCountSize >= 2 && bitstreamSize > 0 ==> lastCountSize == 3 */
2278             assert(op - lastNCount == 3);
2279             DEBUGLOG(5, "Avoiding bug in zstd decoder in versions <= 1.3.4 by "
2280                         "emitting an uncompressed block.");
2281             return 0;
2282         }
2283     }
2284 
2285     DEBUGLOG(5, "compressed block size : %u", (unsigned)(op - ostart));
2286     return (size_t)(op - ostart);
2287 }
2288 
2289 MEM_STATIC size_t
ZSTD_entropyCompressSequences(seqStore_t * seqStorePtr,const ZSTD_entropyCTables_t * prevEntropy,ZSTD_entropyCTables_t * nextEntropy,const ZSTD_CCtx_params * cctxParams,void * dst,size_t dstCapacity,size_t srcSize,void * entropyWorkspace,size_t entropyWkspSize,int bmi2)2290 ZSTD_entropyCompressSequences(seqStore_t* seqStorePtr,
2291                        const ZSTD_entropyCTables_t* prevEntropy,
2292                              ZSTD_entropyCTables_t* nextEntropy,
2293                        const ZSTD_CCtx_params* cctxParams,
2294                              void* dst, size_t dstCapacity,
2295                              size_t srcSize,
2296                              void* entropyWorkspace, size_t entropyWkspSize,
2297                              int bmi2)
2298 {
2299     size_t const cSize = ZSTD_entropyCompressSequences_internal(
2300                             seqStorePtr, prevEntropy, nextEntropy, cctxParams,
2301                             dst, dstCapacity,
2302                             entropyWorkspace, entropyWkspSize, bmi2);
2303     if (cSize == 0) return 0;
2304     /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block.
2305      * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block.
2306      */
2307     if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
2308         return 0;  /* block not compressed */
2309     FORWARD_IF_ERROR(cSize, "ZSTD_entropyCompressSequences_internal failed");
2310 
2311     /* Check compressibility */
2312     {   size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, cctxParams->cParams.strategy);
2313         if (cSize >= maxCSize) return 0;  /* block not compressed */
2314     }
2315     DEBUGLOG(4, "ZSTD_entropyCompressSequences() cSize: %zu\n", cSize);
2316     return cSize;
2317 }
2318 
2319 /* ZSTD_selectBlockCompressor() :
2320  * Not static, but internal use only (used by long distance matcher)
2321  * assumption : strat is a valid strategy */
ZSTD_selectBlockCompressor(ZSTD_strategy strat,ZSTD_dictMode_e dictMode)2322 ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, ZSTD_dictMode_e dictMode)
2323 {
2324     static const ZSTD_blockCompressor blockCompressor[4][ZSTD_STRATEGY_MAX+1] = {
2325         { ZSTD_compressBlock_fast  /* default for 0 */,
2326           ZSTD_compressBlock_fast,
2327           ZSTD_compressBlock_doubleFast,
2328           ZSTD_compressBlock_greedy,
2329           ZSTD_compressBlock_lazy,
2330           ZSTD_compressBlock_lazy2,
2331           ZSTD_compressBlock_btlazy2,
2332           ZSTD_compressBlock_btopt,
2333           ZSTD_compressBlock_btultra,
2334           ZSTD_compressBlock_btultra2 },
2335         { ZSTD_compressBlock_fast_extDict  /* default for 0 */,
2336           ZSTD_compressBlock_fast_extDict,
2337           ZSTD_compressBlock_doubleFast_extDict,
2338           ZSTD_compressBlock_greedy_extDict,
2339           ZSTD_compressBlock_lazy_extDict,
2340           ZSTD_compressBlock_lazy2_extDict,
2341           ZSTD_compressBlock_btlazy2_extDict,
2342           ZSTD_compressBlock_btopt_extDict,
2343           ZSTD_compressBlock_btultra_extDict,
2344           ZSTD_compressBlock_btultra_extDict },
2345         { ZSTD_compressBlock_fast_dictMatchState  /* default for 0 */,
2346           ZSTD_compressBlock_fast_dictMatchState,
2347           ZSTD_compressBlock_doubleFast_dictMatchState,
2348           ZSTD_compressBlock_greedy_dictMatchState,
2349           ZSTD_compressBlock_lazy_dictMatchState,
2350           ZSTD_compressBlock_lazy2_dictMatchState,
2351           ZSTD_compressBlock_btlazy2_dictMatchState,
2352           ZSTD_compressBlock_btopt_dictMatchState,
2353           ZSTD_compressBlock_btultra_dictMatchState,
2354           ZSTD_compressBlock_btultra_dictMatchState },
2355         { NULL  /* default for 0 */,
2356           NULL,
2357           NULL,
2358           ZSTD_compressBlock_greedy_dedicatedDictSearch,
2359           ZSTD_compressBlock_lazy_dedicatedDictSearch,
2360           ZSTD_compressBlock_lazy2_dedicatedDictSearch,
2361           NULL,
2362           NULL,
2363           NULL,
2364           NULL }
2365     };
2366     ZSTD_blockCompressor selectedCompressor;
2367     ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
2368 
2369     assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
2370     selectedCompressor = blockCompressor[(int)dictMode][(int)strat];
2371     assert(selectedCompressor != NULL);
2372     return selectedCompressor;
2373 }
2374 
ZSTD_storeLastLiterals(seqStore_t * seqStorePtr,const BYTE * anchor,size_t lastLLSize)2375 static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
2376                                    const BYTE* anchor, size_t lastLLSize)
2377 {
2378     ZSTD_memcpy(seqStorePtr->lit, anchor, lastLLSize);
2379     seqStorePtr->lit += lastLLSize;
2380 }
2381 
ZSTD_resetSeqStore(seqStore_t * ssPtr)2382 void ZSTD_resetSeqStore(seqStore_t* ssPtr)
2383 {
2384     ssPtr->lit = ssPtr->litStart;
2385     ssPtr->sequences = ssPtr->sequencesStart;
2386     ssPtr->longLengthID = 0;
2387 }
2388 
2389 typedef enum { ZSTDbss_compress, ZSTDbss_noCompress } ZSTD_buildSeqStore_e;
2390 
ZSTD_buildSeqStore(ZSTD_CCtx * zc,const void * src,size_t srcSize)2391 static size_t ZSTD_buildSeqStore(ZSTD_CCtx* zc, const void* src, size_t srcSize)
2392 {
2393     ZSTD_matchState_t* const ms = &zc->blockState.matchState;
2394     DEBUGLOG(5, "ZSTD_buildSeqStore (srcSize=%zu)", srcSize);
2395     assert(srcSize <= ZSTD_BLOCKSIZE_MAX);
2396     /* Assert that we have correctly flushed the ctx params into the ms's copy */
2397     ZSTD_assertEqualCParams(zc->appliedParams.cParams, ms->cParams);
2398     if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
2399         if (zc->appliedParams.cParams.strategy >= ZSTD_btopt) {
2400             ZSTD_ldm_skipRawSeqStoreBytes(&zc->externSeqStore, srcSize);
2401         } else {
2402             ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.minMatch);
2403         }
2404         return ZSTDbss_noCompress; /* don't even attempt compression below a certain srcSize */
2405     }
2406     ZSTD_resetSeqStore(&(zc->seqStore));
2407     /* required for optimal parser to read stats from dictionary */
2408     ms->opt.symbolCosts = &zc->blockState.prevCBlock->entropy;
2409     /* tell the optimal parser how we expect to compress literals */
2410     ms->opt.literalCompressionMode = zc->appliedParams.literalCompressionMode;
2411     /* a gap between an attached dict and the current window is not safe,
2412      * they must remain adjacent,
2413      * and when that stops being the case, the dict must be unset */
2414     assert(ms->dictMatchState == NULL || ms->loadedDictEnd == ms->window.dictLimit);
2415 
2416     /* limited update after a very long match */
2417     {   const BYTE* const base = ms->window.base;
2418         const BYTE* const istart = (const BYTE*)src;
2419         const U32 curr = (U32)(istart-base);
2420         if (sizeof(ptrdiff_t)==8) assert(istart - base < (ptrdiff_t)(U32)(-1));   /* ensure no overflow */
2421         if (curr > ms->nextToUpdate + 384)
2422             ms->nextToUpdate = curr - MIN(192, (U32)(curr - ms->nextToUpdate - 384));
2423     }
2424 
2425     /* select and store sequences */
2426     {   ZSTD_dictMode_e const dictMode = ZSTD_matchState_dictMode(ms);
2427         size_t lastLLSize;
2428         {   int i;
2429             for (i = 0; i < ZSTD_REP_NUM; ++i)
2430                 zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i];
2431         }
2432         if (zc->externSeqStore.pos < zc->externSeqStore.size) {
2433             assert(!zc->appliedParams.ldmParams.enableLdm);
2434             /* Updates ldmSeqStore.pos */
2435             lastLLSize =
2436                 ZSTD_ldm_blockCompress(&zc->externSeqStore,
2437                                        ms, &zc->seqStore,
2438                                        zc->blockState.nextCBlock->rep,
2439                                        src, srcSize);
2440             assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
2441         } else if (zc->appliedParams.ldmParams.enableLdm) {
2442             rawSeqStore_t ldmSeqStore = kNullRawSeqStore;
2443 
2444             ldmSeqStore.seq = zc->ldmSequences;
2445             ldmSeqStore.capacity = zc->maxNbLdmSequences;
2446             /* Updates ldmSeqStore.size */
2447             FORWARD_IF_ERROR(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore,
2448                                                &zc->appliedParams.ldmParams,
2449                                                src, srcSize), "");
2450             /* Updates ldmSeqStore.pos */
2451             lastLLSize =
2452                 ZSTD_ldm_blockCompress(&ldmSeqStore,
2453                                        ms, &zc->seqStore,
2454                                        zc->blockState.nextCBlock->rep,
2455                                        src, srcSize);
2456             assert(ldmSeqStore.pos == ldmSeqStore.size);
2457         } else {   /* not long range mode */
2458             ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, dictMode);
2459             ms->ldmSeqStore = NULL;
2460             lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, src, srcSize);
2461         }
2462         {   const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize;
2463             ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize);
2464     }   }
2465     return ZSTDbss_compress;
2466 }
2467 
ZSTD_copyBlockSequences(ZSTD_CCtx * zc)2468 static void ZSTD_copyBlockSequences(ZSTD_CCtx* zc)
2469 {
2470     const seqStore_t* seqStore = ZSTD_getSeqStore(zc);
2471     const seqDef* seqStoreSeqs = seqStore->sequencesStart;
2472     size_t seqStoreSeqSize = seqStore->sequences - seqStoreSeqs;
2473     size_t seqStoreLiteralsSize = (size_t)(seqStore->lit - seqStore->litStart);
2474     size_t literalsRead = 0;
2475     size_t lastLLSize;
2476 
2477     ZSTD_Sequence* outSeqs = &zc->seqCollector.seqStart[zc->seqCollector.seqIndex];
2478     size_t i;
2479     repcodes_t updatedRepcodes;
2480 
2481     assert(zc->seqCollector.seqIndex + 1 < zc->seqCollector.maxSequences);
2482     /* Ensure we have enough space for last literals "sequence" */
2483     assert(zc->seqCollector.maxSequences >= seqStoreSeqSize + 1);
2484     ZSTD_memcpy(updatedRepcodes.rep, zc->blockState.prevCBlock->rep, sizeof(repcodes_t));
2485     for (i = 0; i < seqStoreSeqSize; ++i) {
2486         U32 rawOffset = seqStoreSeqs[i].offset - ZSTD_REP_NUM;
2487         outSeqs[i].litLength = seqStoreSeqs[i].litLength;
2488         outSeqs[i].matchLength = seqStoreSeqs[i].matchLength + MINMATCH;
2489         outSeqs[i].rep = 0;
2490 
2491         if (i == seqStore->longLengthPos) {
2492             if (seqStore->longLengthID == 1) {
2493                 outSeqs[i].litLength += 0x10000;
2494             } else if (seqStore->longLengthID == 2) {
2495                 outSeqs[i].matchLength += 0x10000;
2496             }
2497         }
2498 
2499         if (seqStoreSeqs[i].offset <= ZSTD_REP_NUM) {
2500             /* Derive the correct offset corresponding to a repcode */
2501             outSeqs[i].rep = seqStoreSeqs[i].offset;
2502             if (outSeqs[i].litLength != 0) {
2503                 rawOffset = updatedRepcodes.rep[outSeqs[i].rep - 1];
2504             } else {
2505                 if (outSeqs[i].rep == 3) {
2506                     rawOffset = updatedRepcodes.rep[0] - 1;
2507                 } else {
2508                     rawOffset = updatedRepcodes.rep[outSeqs[i].rep];
2509                 }
2510             }
2511         }
2512         outSeqs[i].offset = rawOffset;
2513         /* seqStoreSeqs[i].offset == offCode+1, and ZSTD_updateRep() expects offCode
2514            so we provide seqStoreSeqs[i].offset - 1 */
2515         updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep,
2516                                          seqStoreSeqs[i].offset - 1,
2517                                          seqStoreSeqs[i].litLength == 0);
2518         literalsRead += outSeqs[i].litLength;
2519     }
2520     /* Insert last literals (if any exist) in the block as a sequence with ml == off == 0.
2521      * If there are no last literals, then we'll emit (of: 0, ml: 0, ll: 0), which is a marker
2522      * for the block boundary, according to the API.
2523      */
2524     assert(seqStoreLiteralsSize >= literalsRead);
2525     lastLLSize = seqStoreLiteralsSize - literalsRead;
2526     outSeqs[i].litLength = (U32)lastLLSize;
2527     outSeqs[i].matchLength = outSeqs[i].offset = outSeqs[i].rep = 0;
2528     seqStoreSeqSize++;
2529     zc->seqCollector.seqIndex += seqStoreSeqSize;
2530 }
2531 
ZSTD_generateSequences(ZSTD_CCtx * zc,ZSTD_Sequence * outSeqs,size_t outSeqsSize,const void * src,size_t srcSize)2532 size_t ZSTD_generateSequences(ZSTD_CCtx* zc, ZSTD_Sequence* outSeqs,
2533                               size_t outSeqsSize, const void* src, size_t srcSize)
2534 {
2535     const size_t dstCapacity = ZSTD_compressBound(srcSize);
2536     void* dst = ZSTD_customMalloc(dstCapacity, ZSTD_defaultCMem);
2537     SeqCollector seqCollector;
2538 
2539     RETURN_ERROR_IF(dst == NULL, memory_allocation, "NULL pointer!");
2540 
2541     seqCollector.collectSequences = 1;
2542     seqCollector.seqStart = outSeqs;
2543     seqCollector.seqIndex = 0;
2544     seqCollector.maxSequences = outSeqsSize;
2545     zc->seqCollector = seqCollector;
2546 
2547     ZSTD_compress2(zc, dst, dstCapacity, src, srcSize);
2548     ZSTD_customFree(dst, ZSTD_defaultCMem);
2549     return zc->seqCollector.seqIndex;
2550 }
2551 
ZSTD_mergeBlockDelimiters(ZSTD_Sequence * sequences,size_t seqsSize)2552 size_t ZSTD_mergeBlockDelimiters(ZSTD_Sequence* sequences, size_t seqsSize) {
2553     size_t in = 0;
2554     size_t out = 0;
2555     for (; in < seqsSize; ++in) {
2556         if (sequences[in].offset == 0 && sequences[in].matchLength == 0) {
2557             if (in != seqsSize - 1) {
2558                 sequences[in+1].litLength += sequences[in].litLength;
2559             }
2560         } else {
2561             sequences[out] = sequences[in];
2562             ++out;
2563         }
2564     }
2565     return out;
2566 }
2567 
2568 /* Unrolled loop to read four size_ts of input at a time. Returns 1 if is RLE, 0 if not. */
ZSTD_isRLE(const BYTE * src,size_t length)2569 static int ZSTD_isRLE(const BYTE* src, size_t length) {
2570     const BYTE* ip = src;
2571     const BYTE value = ip[0];
2572     const size_t valueST = (size_t)((U64)value * 0x0101010101010101ULL);
2573     const size_t unrollSize = sizeof(size_t) * 4;
2574     const size_t unrollMask = unrollSize - 1;
2575     const size_t prefixLength = length & unrollMask;
2576     size_t i;
2577     size_t u;
2578     if (length == 1) return 1;
2579     /* Check if prefix is RLE first before using unrolled loop */
2580     if (prefixLength && ZSTD_count(ip+1, ip, ip+prefixLength) != prefixLength-1) {
2581         return 0;
2582     }
2583     for (i = prefixLength; i != length; i += unrollSize) {
2584         for (u = 0; u < unrollSize; u += sizeof(size_t)) {
2585             if (MEM_readST(ip + i + u) != valueST) {
2586                 return 0;
2587             }
2588         }
2589     }
2590     return 1;
2591 }
2592 
2593 /* Returns true if the given block may be RLE.
2594  * This is just a heuristic based on the compressibility.
2595  * It may return both false positives and false negatives.
2596  */
ZSTD_maybeRLE(seqStore_t const * seqStore)2597 static int ZSTD_maybeRLE(seqStore_t const* seqStore)
2598 {
2599     size_t const nbSeqs = (size_t)(seqStore->sequences - seqStore->sequencesStart);
2600     size_t const nbLits = (size_t)(seqStore->lit - seqStore->litStart);
2601 
2602     return nbSeqs < 4 && nbLits < 10;
2603 }
2604 
ZSTD_confirmRepcodesAndEntropyTables(ZSTD_CCtx * zc)2605 static void ZSTD_confirmRepcodesAndEntropyTables(ZSTD_CCtx* zc)
2606 {
2607     ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock;
2608     zc->blockState.prevCBlock = zc->blockState.nextCBlock;
2609     zc->blockState.nextCBlock = tmp;
2610 }
2611 
ZSTD_compressBlock_internal(ZSTD_CCtx * zc,void * dst,size_t dstCapacity,const void * src,size_t srcSize,U32 frame)2612 static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
2613                                         void* dst, size_t dstCapacity,
2614                                         const void* src, size_t srcSize, U32 frame)
2615 {
2616     /* This the upper bound for the length of an rle block.
2617      * This isn't the actual upper bound. Finding the real threshold
2618      * needs further investigation.
2619      */
2620     const U32 rleMaxLength = 25;
2621     size_t cSize;
2622     const BYTE* ip = (const BYTE*)src;
2623     BYTE* op = (BYTE*)dst;
2624     DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
2625                 (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit,
2626                 (unsigned)zc->blockState.matchState.nextToUpdate);
2627 
2628     {   const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
2629         FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed");
2630         if (bss == ZSTDbss_noCompress) { cSize = 0; goto out; }
2631     }
2632 
2633     if (zc->seqCollector.collectSequences) {
2634         ZSTD_copyBlockSequences(zc);
2635         ZSTD_confirmRepcodesAndEntropyTables(zc);
2636         return 0;
2637     }
2638 
2639     /* encode sequences and literals */
2640     cSize = ZSTD_entropyCompressSequences(&zc->seqStore,
2641             &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
2642             &zc->appliedParams,
2643             dst, dstCapacity,
2644             srcSize,
2645             zc->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
2646             zc->bmi2);
2647 
2648     if (zc->seqCollector.collectSequences) {
2649         ZSTD_copyBlockSequences(zc);
2650         return 0;
2651     }
2652 
2653 
2654     if (frame &&
2655         /* We don't want to emit our first block as a RLE even if it qualifies because
2656          * doing so will cause the decoder (cli only) to throw a "should consume all input error."
2657          * This is only an issue for zstd <= v1.4.3
2658          */
2659         !zc->isFirstBlock &&
2660         cSize < rleMaxLength &&
2661         ZSTD_isRLE(ip, srcSize))
2662     {
2663         cSize = 1;
2664         op[0] = ip[0];
2665     }
2666 
2667 out:
2668     if (!ZSTD_isError(cSize) && cSize > 1) {
2669         ZSTD_confirmRepcodesAndEntropyTables(zc);
2670     }
2671     /* We check that dictionaries have offset codes available for the first
2672      * block. After the first block, the offcode table might not have large
2673      * enough codes to represent the offsets in the data.
2674      */
2675     if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
2676         zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
2677 
2678     return cSize;
2679 }
2680 
ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx * zc,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const size_t bss,U32 lastBlock)2681 static size_t ZSTD_compressBlock_targetCBlockSize_body(ZSTD_CCtx* zc,
2682                                void* dst, size_t dstCapacity,
2683                                const void* src, size_t srcSize,
2684                                const size_t bss, U32 lastBlock)
2685 {
2686     DEBUGLOG(6, "Attempting ZSTD_compressSuperBlock()");
2687     if (bss == ZSTDbss_compress) {
2688         if (/* We don't want to emit our first block as a RLE even if it qualifies because
2689             * doing so will cause the decoder (cli only) to throw a "should consume all input error."
2690             * This is only an issue for zstd <= v1.4.3
2691             */
2692             !zc->isFirstBlock &&
2693             ZSTD_maybeRLE(&zc->seqStore) &&
2694             ZSTD_isRLE((BYTE const*)src, srcSize))
2695         {
2696             return ZSTD_rleCompressBlock(dst, dstCapacity, *(BYTE const*)src, srcSize, lastBlock);
2697         }
2698         /* Attempt superblock compression.
2699          *
2700          * Note that compressed size of ZSTD_compressSuperBlock() is not bound by the
2701          * standard ZSTD_compressBound(). This is a problem, because even if we have
2702          * space now, taking an extra byte now could cause us to run out of space later
2703          * and violate ZSTD_compressBound().
2704          *
2705          * Define blockBound(blockSize) = blockSize + ZSTD_blockHeaderSize.
2706          *
2707          * In order to respect ZSTD_compressBound() we must attempt to emit a raw
2708          * uncompressed block in these cases:
2709          *   * cSize == 0: Return code for an uncompressed block.
2710          *   * cSize == dstSize_tooSmall: We may have expanded beyond blockBound(srcSize).
2711          *     ZSTD_noCompressBlock() will return dstSize_tooSmall if we are really out of
2712          *     output space.
2713          *   * cSize >= blockBound(srcSize): We have expanded the block too much so
2714          *     emit an uncompressed block.
2715          */
2716         {
2717             size_t const cSize = ZSTD_compressSuperBlock(zc, dst, dstCapacity, src, srcSize, lastBlock);
2718             if (cSize != ERROR(dstSize_tooSmall)) {
2719                 size_t const maxCSize = srcSize - ZSTD_minGain(srcSize, zc->appliedParams.cParams.strategy);
2720                 FORWARD_IF_ERROR(cSize, "ZSTD_compressSuperBlock failed");
2721                 if (cSize != 0 && cSize < maxCSize + ZSTD_blockHeaderSize) {
2722                     ZSTD_confirmRepcodesAndEntropyTables(zc);
2723                     return cSize;
2724                 }
2725             }
2726         }
2727     }
2728 
2729     DEBUGLOG(6, "Resorting to ZSTD_noCompressBlock()");
2730     /* Superblock compression failed, attempt to emit a single no compress block.
2731      * The decoder will be able to stream this block since it is uncompressed.
2732      */
2733     return ZSTD_noCompressBlock(dst, dstCapacity, src, srcSize, lastBlock);
2734 }
2735 
ZSTD_compressBlock_targetCBlockSize(ZSTD_CCtx * zc,void * dst,size_t dstCapacity,const void * src,size_t srcSize,U32 lastBlock)2736 static size_t ZSTD_compressBlock_targetCBlockSize(ZSTD_CCtx* zc,
2737                                void* dst, size_t dstCapacity,
2738                                const void* src, size_t srcSize,
2739                                U32 lastBlock)
2740 {
2741     size_t cSize = 0;
2742     const size_t bss = ZSTD_buildSeqStore(zc, src, srcSize);
2743     DEBUGLOG(5, "ZSTD_compressBlock_targetCBlockSize (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u, srcSize=%zu)",
2744                 (unsigned)dstCapacity, (unsigned)zc->blockState.matchState.window.dictLimit, (unsigned)zc->blockState.matchState.nextToUpdate, srcSize);
2745     FORWARD_IF_ERROR(bss, "ZSTD_buildSeqStore failed");
2746 
2747     cSize = ZSTD_compressBlock_targetCBlockSize_body(zc, dst, dstCapacity, src, srcSize, bss, lastBlock);
2748     FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize_body failed");
2749 
2750     if (zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
2751         zc->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
2752 
2753     return cSize;
2754 }
2755 
ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t * ms,ZSTD_cwksp * ws,ZSTD_CCtx_params const * params,void const * ip,void const * iend)2756 static void ZSTD_overflowCorrectIfNeeded(ZSTD_matchState_t* ms,
2757                                          ZSTD_cwksp* ws,
2758                                          ZSTD_CCtx_params const* params,
2759                                          void const* ip,
2760                                          void const* iend)
2761 {
2762     if (ZSTD_window_needOverflowCorrection(ms->window, iend)) {
2763         U32 const maxDist = (U32)1 << params->cParams.windowLog;
2764         U32 const cycleLog = ZSTD_cycleLog(params->cParams.chainLog, params->cParams.strategy);
2765         U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip);
2766         ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
2767         ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
2768         ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31);
2769         ZSTD_cwksp_mark_tables_dirty(ws);
2770         ZSTD_reduceIndex(ms, params, correction);
2771         ZSTD_cwksp_mark_tables_clean(ws);
2772         if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
2773         else ms->nextToUpdate -= correction;
2774         /* invalidate dictionaries on overflow correction */
2775         ms->loadedDictEnd = 0;
2776         ms->dictMatchState = NULL;
2777     }
2778 }
2779 
2780 /*! ZSTD_compress_frameChunk() :
2781 *   Compress a chunk of data into one or multiple blocks.
2782 *   All blocks will be terminated, all input will be consumed.
2783 *   Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2784 *   Frame is supposed already started (header already produced)
2785 *   @return : compressed size, or an error code
2786 */
ZSTD_compress_frameChunk(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,U32 lastFrameChunk)2787 static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
2788                                      void* dst, size_t dstCapacity,
2789                                const void* src, size_t srcSize,
2790                                      U32 lastFrameChunk)
2791 {
2792     size_t blockSize = cctx->blockSize;
2793     size_t remaining = srcSize;
2794     const BYTE* ip = (const BYTE*)src;
2795     BYTE* const ostart = (BYTE*)dst;
2796     BYTE* op = ostart;
2797     U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog;
2798 
2799     assert(cctx->appliedParams.cParams.windowLog <= ZSTD_WINDOWLOG_MAX);
2800 
2801     DEBUGLOG(4, "ZSTD_compress_frameChunk (blockSize=%u)", (unsigned)blockSize);
2802     if (cctx->appliedParams.fParams.checksumFlag && srcSize)
2803         xxh64_update(&cctx->xxhState, src, srcSize);
2804 
2805     while (remaining) {
2806         ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
2807         U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
2808 
2809         RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE,
2810                         dstSize_tooSmall,
2811                         "not enough space to store compressed block");
2812         if (remaining < blockSize) blockSize = remaining;
2813 
2814         ZSTD_overflowCorrectIfNeeded(
2815             ms, &cctx->workspace, &cctx->appliedParams, ip, ip + blockSize);
2816         ZSTD_checkDictValidity(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd, &ms->dictMatchState);
2817 
2818         /* Ensure hash/chain table insertion resumes no sooner than lowlimit */
2819         if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit;
2820 
2821         {   size_t cSize;
2822             if (ZSTD_useTargetCBlockSize(&cctx->appliedParams)) {
2823                 cSize = ZSTD_compressBlock_targetCBlockSize(cctx, op, dstCapacity, ip, blockSize, lastBlock);
2824                 FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_targetCBlockSize failed");
2825                 assert(cSize > 0);
2826                 assert(cSize <= blockSize + ZSTD_blockHeaderSize);
2827             } else {
2828                 cSize = ZSTD_compressBlock_internal(cctx,
2829                                         op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
2830                                         ip, blockSize, 1 /* frame */);
2831                 FORWARD_IF_ERROR(cSize, "ZSTD_compressBlock_internal failed");
2832 
2833                 if (cSize == 0) {  /* block is not compressible */
2834                     cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
2835                     FORWARD_IF_ERROR(cSize, "ZSTD_noCompressBlock failed");
2836                 } else {
2837                     U32 const cBlockHeader = cSize == 1 ?
2838                         lastBlock + (((U32)bt_rle)<<1) + (U32)(blockSize << 3) :
2839                         lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
2840                     MEM_writeLE24(op, cBlockHeader);
2841                     cSize += ZSTD_blockHeaderSize;
2842                 }
2843             }
2844 
2845 
2846             ip += blockSize;
2847             assert(remaining >= blockSize);
2848             remaining -= blockSize;
2849             op += cSize;
2850             assert(dstCapacity >= cSize);
2851             dstCapacity -= cSize;
2852             cctx->isFirstBlock = 0;
2853             DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u",
2854                         (unsigned)cSize);
2855     }   }
2856 
2857     if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
2858     return (size_t)(op-ostart);
2859 }
2860 
2861 
ZSTD_writeFrameHeader(void * dst,size_t dstCapacity,const ZSTD_CCtx_params * params,U64 pledgedSrcSize,U32 dictID)2862 static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
2863                                     const ZSTD_CCtx_params* params, U64 pledgedSrcSize, U32 dictID)
2864 {   BYTE* const op = (BYTE*)dst;
2865     U32   const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536);   /* 0-3 */
2866     U32   const dictIDSizeCode = params->fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength;   /* 0-3 */
2867     U32   const checksumFlag = params->fParams.checksumFlag>0;
2868     U32   const windowSize = (U32)1 << params->cParams.windowLog;
2869     U32   const singleSegment = params->fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
2870     BYTE  const windowLogByte = (BYTE)((params->cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2871     U32   const fcsCode = params->fParams.contentSizeFlag ?
2872                      (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0;  /* 0-3 */
2873     BYTE  const frameHeaderDescriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
2874     size_t pos=0;
2875 
2876     assert(!(params->fParams.contentSizeFlag && pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN));
2877     RETURN_ERROR_IF(dstCapacity < ZSTD_FRAMEHEADERSIZE_MAX, dstSize_tooSmall,
2878                     "dst buf is too small to fit worst-case frame header size.");
2879     DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
2880                 !params->fParams.noDictIDFlag, (unsigned)dictID, (unsigned)dictIDSizeCode);
2881     if (params->format == ZSTD_f_zstd1) {
2882         MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
2883         pos = 4;
2884     }
2885     op[pos++] = frameHeaderDescriptionByte;
2886     if (!singleSegment) op[pos++] = windowLogByte;
2887     switch(dictIDSizeCode)
2888     {
2889         default:
2890             assert(0); /* impossible */
2891             ZSTD_FALLTHROUGH;
2892         case 0 : break;
2893         case 1 : op[pos] = (BYTE)(dictID); pos++; break;
2894         case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
2895         case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2896     }
2897     switch(fcsCode)
2898     {
2899         default:
2900             assert(0); /* impossible */
2901             ZSTD_FALLTHROUGH;
2902         case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
2903         case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2904         case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
2905         case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
2906     }
2907     return pos;
2908 }
2909 
2910 /* ZSTD_writeSkippableFrame_advanced() :
2911  * Writes out a skippable frame with the specified magic number variant (16 are supported),
2912  * from ZSTD_MAGIC_SKIPPABLE_START to ZSTD_MAGIC_SKIPPABLE_START+15, and the desired source data.
2913  *
2914  * Returns the total number of bytes written, or a ZSTD error code.
2915  */
ZSTD_writeSkippableFrame(void * dst,size_t dstCapacity,const void * src,size_t srcSize,unsigned magicVariant)2916 size_t ZSTD_writeSkippableFrame(void* dst, size_t dstCapacity,
2917                                 const void* src, size_t srcSize, unsigned magicVariant) {
2918     BYTE* op = (BYTE*)dst;
2919     RETURN_ERROR_IF(dstCapacity < srcSize + ZSTD_SKIPPABLEHEADERSIZE /* Skippable frame overhead */,
2920                     dstSize_tooSmall, "Not enough room for skippable frame");
2921     RETURN_ERROR_IF(srcSize > (unsigned)0xFFFFFFFF, srcSize_wrong, "Src size too large for skippable frame");
2922     RETURN_ERROR_IF(magicVariant > 15, parameter_outOfBound, "Skippable frame magic number variant not supported");
2923 
2924     MEM_writeLE32(op, (U32)(ZSTD_MAGIC_SKIPPABLE_START + magicVariant));
2925     MEM_writeLE32(op+4, (U32)srcSize);
2926     ZSTD_memcpy(op+8, src, srcSize);
2927     return srcSize + ZSTD_SKIPPABLEHEADERSIZE;
2928 }
2929 
2930 /* ZSTD_writeLastEmptyBlock() :
2931  * output an empty Block with end-of-frame mark to complete a frame
2932  * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
2933  *           or an error code if `dstCapacity` is too small (<ZSTD_blockHeaderSize)
2934  */
ZSTD_writeLastEmptyBlock(void * dst,size_t dstCapacity)2935 size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity)
2936 {
2937     RETURN_ERROR_IF(dstCapacity < ZSTD_blockHeaderSize, dstSize_tooSmall,
2938                     "dst buf is too small to write frame trailer empty block.");
2939     {   U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1);  /* 0 size */
2940         MEM_writeLE24(dst, cBlockHeader24);
2941         return ZSTD_blockHeaderSize;
2942     }
2943 }
2944 
ZSTD_referenceExternalSequences(ZSTD_CCtx * cctx,rawSeq * seq,size_t nbSeq)2945 size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq)
2946 {
2947     RETURN_ERROR_IF(cctx->stage != ZSTDcs_init, stage_wrong,
2948                     "wrong cctx stage");
2949     RETURN_ERROR_IF(cctx->appliedParams.ldmParams.enableLdm,
2950                     parameter_unsupported,
2951                     "incompatible with ldm");
2952     cctx->externSeqStore.seq = seq;
2953     cctx->externSeqStore.size = nbSeq;
2954     cctx->externSeqStore.capacity = nbSeq;
2955     cctx->externSeqStore.pos = 0;
2956     cctx->externSeqStore.posInSequence = 0;
2957     return 0;
2958 }
2959 
2960 
ZSTD_compressContinue_internal(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,U32 frame,U32 lastFrameChunk)2961 static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
2962                               void* dst, size_t dstCapacity,
2963                         const void* src, size_t srcSize,
2964                                U32 frame, U32 lastFrameChunk)
2965 {
2966     ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
2967     size_t fhSize = 0;
2968 
2969     DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u",
2970                 cctx->stage, (unsigned)srcSize);
2971     RETURN_ERROR_IF(cctx->stage==ZSTDcs_created, stage_wrong,
2972                     "missing init (ZSTD_compressBegin)");
2973 
2974     if (frame && (cctx->stage==ZSTDcs_init)) {
2975         fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams,
2976                                        cctx->pledgedSrcSizePlusOne-1, cctx->dictID);
2977         FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed");
2978         assert(fhSize <= dstCapacity);
2979         dstCapacity -= fhSize;
2980         dst = (char*)dst + fhSize;
2981         cctx->stage = ZSTDcs_ongoing;
2982     }
2983 
2984     if (!srcSize) return fhSize;  /* do not generate an empty block if no input */
2985 
2986     if (!ZSTD_window_update(&ms->window, src, srcSize)) {
2987         ms->nextToUpdate = ms->window.dictLimit;
2988     }
2989     if (cctx->appliedParams.ldmParams.enableLdm) {
2990         ZSTD_window_update(&cctx->ldmState.window, src, srcSize);
2991     }
2992 
2993     if (!frame) {
2994         /* overflow check and correction for block mode */
2995         ZSTD_overflowCorrectIfNeeded(
2996             ms, &cctx->workspace, &cctx->appliedParams,
2997             src, (BYTE const*)src + srcSize);
2998     }
2999 
3000     DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (unsigned)cctx->blockSize);
3001     {   size_t const cSize = frame ?
3002                              ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
3003                              ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize, 0 /* frame */);
3004         FORWARD_IF_ERROR(cSize, "%s", frame ? "ZSTD_compress_frameChunk failed" : "ZSTD_compressBlock_internal failed");
3005         cctx->consumedSrcSize += srcSize;
3006         cctx->producedCSize += (cSize + fhSize);
3007         assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
3008         if (cctx->pledgedSrcSizePlusOne != 0) {  /* control src size */
3009             ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
3010             RETURN_ERROR_IF(
3011                 cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne,
3012                 srcSize_wrong,
3013                 "error : pledgedSrcSize = %u, while realSrcSize >= %u",
3014                 (unsigned)cctx->pledgedSrcSizePlusOne-1,
3015                 (unsigned)cctx->consumedSrcSize);
3016         }
3017         return cSize + fhSize;
3018     }
3019 }
3020 
ZSTD_compressContinue(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)3021 size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
3022                               void* dst, size_t dstCapacity,
3023                         const void* src, size_t srcSize)
3024 {
3025     DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (unsigned)srcSize);
3026     return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
3027 }
3028 
3029 
ZSTD_getBlockSize(const ZSTD_CCtx * cctx)3030 size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
3031 {
3032     ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams;
3033     assert(!ZSTD_checkCParams(cParams));
3034     return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog);
3035 }
3036 
ZSTD_compressBlock(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)3037 size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
3038 {
3039     DEBUGLOG(5, "ZSTD_compressBlock: srcSize = %u", (unsigned)srcSize);
3040     { size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
3041       RETURN_ERROR_IF(srcSize > blockSizeMax, srcSize_wrong, "input is larger than a block"); }
3042 
3043     return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
3044 }
3045 
3046 /*! ZSTD_loadDictionaryContent() :
3047  *  @return : 0, or an error code
3048  */
ZSTD_loadDictionaryContent(ZSTD_matchState_t * ms,ldmState_t * ls,ZSTD_cwksp * ws,ZSTD_CCtx_params const * params,const void * src,size_t srcSize,ZSTD_dictTableLoadMethod_e dtlm)3049 static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms,
3050                                          ldmState_t* ls,
3051                                          ZSTD_cwksp* ws,
3052                                          ZSTD_CCtx_params const* params,
3053                                          const void* src, size_t srcSize,
3054                                          ZSTD_dictTableLoadMethod_e dtlm)
3055 {
3056     const BYTE* ip = (const BYTE*) src;
3057     const BYTE* const iend = ip + srcSize;
3058 
3059     ZSTD_window_update(&ms->window, src, srcSize);
3060     ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base);
3061 
3062     if (params->ldmParams.enableLdm && ls != NULL) {
3063         ZSTD_window_update(&ls->window, src, srcSize);
3064         ls->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ls->window.base);
3065     }
3066 
3067     /* Assert that we the ms params match the params we're being given */
3068     ZSTD_assertEqualCParams(params->cParams, ms->cParams);
3069 
3070     if (srcSize <= HASH_READ_SIZE) return 0;
3071 
3072     while (iend - ip > HASH_READ_SIZE) {
3073         size_t const remaining = (size_t)(iend - ip);
3074         size_t const chunk = MIN(remaining, ZSTD_CHUNKSIZE_MAX);
3075         const BYTE* const ichunk = ip + chunk;
3076 
3077         ZSTD_overflowCorrectIfNeeded(ms, ws, params, ip, ichunk);
3078 
3079         if (params->ldmParams.enableLdm && ls != NULL)
3080             ZSTD_ldm_fillHashTable(ls, (const BYTE*)src, (const BYTE*)src + srcSize, &params->ldmParams);
3081 
3082         switch(params->cParams.strategy)
3083         {
3084         case ZSTD_fast:
3085             ZSTD_fillHashTable(ms, ichunk, dtlm);
3086             break;
3087         case ZSTD_dfast:
3088             ZSTD_fillDoubleHashTable(ms, ichunk, dtlm);
3089             break;
3090 
3091         case ZSTD_greedy:
3092         case ZSTD_lazy:
3093         case ZSTD_lazy2:
3094             if (chunk >= HASH_READ_SIZE && ms->dedicatedDictSearch) {
3095                 assert(chunk == remaining); /* must load everything in one go */
3096                 ZSTD_dedicatedDictSearch_lazy_loadDictionary(ms, ichunk-HASH_READ_SIZE);
3097             } else if (chunk >= HASH_READ_SIZE) {
3098                 ZSTD_insertAndFindFirstIndex(ms, ichunk-HASH_READ_SIZE);
3099             }
3100             break;
3101 
3102         case ZSTD_btlazy2:   /* we want the dictionary table fully sorted */
3103         case ZSTD_btopt:
3104         case ZSTD_btultra:
3105         case ZSTD_btultra2:
3106             if (chunk >= HASH_READ_SIZE)
3107                 ZSTD_updateTree(ms, ichunk-HASH_READ_SIZE, ichunk);
3108             break;
3109 
3110         default:
3111             assert(0);  /* not possible : not a valid strategy id */
3112         }
3113 
3114         ip = ichunk;
3115     }
3116 
3117     ms->nextToUpdate = (U32)(iend - ms->window.base);
3118     return 0;
3119 }
3120 
3121 
3122 /* Dictionaries that assign zero probability to symbols that show up causes problems
3123  * when FSE encoding. Mark dictionaries with zero probability symbols as FSE_repeat_check
3124  * and only dictionaries with 100% valid symbols can be assumed valid.
3125  */
ZSTD_dictNCountRepeat(short * normalizedCounter,unsigned dictMaxSymbolValue,unsigned maxSymbolValue)3126 static FSE_repeat ZSTD_dictNCountRepeat(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue)
3127 {
3128     U32 s;
3129     if (dictMaxSymbolValue < maxSymbolValue) {
3130         return FSE_repeat_check;
3131     }
3132     for (s = 0; s <= maxSymbolValue; ++s) {
3133         if (normalizedCounter[s] == 0) {
3134             return FSE_repeat_check;
3135         }
3136     }
3137     return FSE_repeat_valid;
3138 }
3139 
ZSTD_loadCEntropy(ZSTD_compressedBlockState_t * bs,void * workspace,const void * const dict,size_t dictSize)3140 size_t ZSTD_loadCEntropy(ZSTD_compressedBlockState_t* bs, void* workspace,
3141                          const void* const dict, size_t dictSize)
3142 {
3143     short offcodeNCount[MaxOff+1];
3144     unsigned offcodeMaxValue = MaxOff;
3145     const BYTE* dictPtr = (const BYTE*)dict;    /* skip magic num and dict ID */
3146     const BYTE* const dictEnd = dictPtr + dictSize;
3147     dictPtr += 8;
3148     bs->entropy.huf.repeatMode = HUF_repeat_check;
3149 
3150     {   unsigned maxSymbolValue = 255;
3151         unsigned hasZeroWeights = 1;
3152         size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.huf.CTable, &maxSymbolValue, dictPtr,
3153             dictEnd-dictPtr, &hasZeroWeights);
3154 
3155         /* We only set the loaded table as valid if it contains all non-zero
3156          * weights. Otherwise, we set it to check */
3157         if (!hasZeroWeights)
3158             bs->entropy.huf.repeatMode = HUF_repeat_valid;
3159 
3160         RETURN_ERROR_IF(HUF_isError(hufHeaderSize), dictionary_corrupted, "");
3161         RETURN_ERROR_IF(maxSymbolValue < 255, dictionary_corrupted, "");
3162         dictPtr += hufHeaderSize;
3163     }
3164 
3165     {   unsigned offcodeLog;
3166         size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
3167         RETURN_ERROR_IF(FSE_isError(offcodeHeaderSize), dictionary_corrupted, "");
3168         RETURN_ERROR_IF(offcodeLog > OffFSELog, dictionary_corrupted, "");
3169         /* fill all offset symbols to avoid garbage at end of table */
3170         RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
3171                 bs->entropy.fse.offcodeCTable,
3172                 offcodeNCount, MaxOff, offcodeLog,
3173                 workspace, HUF_WORKSPACE_SIZE)),
3174             dictionary_corrupted, "");
3175         /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
3176         dictPtr += offcodeHeaderSize;
3177     }
3178 
3179     {   short matchlengthNCount[MaxML+1];
3180         unsigned matchlengthMaxValue = MaxML, matchlengthLog;
3181         size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
3182         RETURN_ERROR_IF(FSE_isError(matchlengthHeaderSize), dictionary_corrupted, "");
3183         RETURN_ERROR_IF(matchlengthLog > MLFSELog, dictionary_corrupted, "");
3184         RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
3185                 bs->entropy.fse.matchlengthCTable,
3186                 matchlengthNCount, matchlengthMaxValue, matchlengthLog,
3187                 workspace, HUF_WORKSPACE_SIZE)),
3188             dictionary_corrupted, "");
3189         bs->entropy.fse.matchlength_repeatMode = ZSTD_dictNCountRepeat(matchlengthNCount, matchlengthMaxValue, MaxML);
3190         dictPtr += matchlengthHeaderSize;
3191     }
3192 
3193     {   short litlengthNCount[MaxLL+1];
3194         unsigned litlengthMaxValue = MaxLL, litlengthLog;
3195         size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
3196         RETURN_ERROR_IF(FSE_isError(litlengthHeaderSize), dictionary_corrupted, "");
3197         RETURN_ERROR_IF(litlengthLog > LLFSELog, dictionary_corrupted, "");
3198         RETURN_ERROR_IF(FSE_isError(FSE_buildCTable_wksp(
3199                 bs->entropy.fse.litlengthCTable,
3200                 litlengthNCount, litlengthMaxValue, litlengthLog,
3201                 workspace, HUF_WORKSPACE_SIZE)),
3202             dictionary_corrupted, "");
3203         bs->entropy.fse.litlength_repeatMode = ZSTD_dictNCountRepeat(litlengthNCount, litlengthMaxValue, MaxLL);
3204         dictPtr += litlengthHeaderSize;
3205     }
3206 
3207     RETURN_ERROR_IF(dictPtr+12 > dictEnd, dictionary_corrupted, "");
3208     bs->rep[0] = MEM_readLE32(dictPtr+0);
3209     bs->rep[1] = MEM_readLE32(dictPtr+4);
3210     bs->rep[2] = MEM_readLE32(dictPtr+8);
3211     dictPtr += 12;
3212 
3213     {   size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
3214         U32 offcodeMax = MaxOff;
3215         if (dictContentSize <= ((U32)-1) - 128 KB) {
3216             U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
3217             offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
3218         }
3219         /* All offset values <= dictContentSize + 128 KB must be representable for a valid table */
3220         bs->entropy.fse.offcode_repeatMode = ZSTD_dictNCountRepeat(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff));
3221 
3222         /* All repCodes must be <= dictContentSize and != 0 */
3223         {   U32 u;
3224             for (u=0; u<3; u++) {
3225                 RETURN_ERROR_IF(bs->rep[u] == 0, dictionary_corrupted, "");
3226                 RETURN_ERROR_IF(bs->rep[u] > dictContentSize, dictionary_corrupted, "");
3227     }   }   }
3228 
3229     return dictPtr - (const BYTE*)dict;
3230 }
3231 
3232 /* Dictionary format :
3233  * See :
3234  * https://github.com/facebook/zstd/blob/release/doc/zstd_compression_format.md#dictionary-format
3235  */
3236 /*! ZSTD_loadZstdDictionary() :
3237  * @return : dictID, or an error code
3238  *  assumptions : magic number supposed already checked
3239  *                dictSize supposed >= 8
3240  */
ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t * bs,ZSTD_matchState_t * ms,ZSTD_cwksp * ws,ZSTD_CCtx_params const * params,const void * dict,size_t dictSize,ZSTD_dictTableLoadMethod_e dtlm,void * workspace)3241 static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs,
3242                                       ZSTD_matchState_t* ms,
3243                                       ZSTD_cwksp* ws,
3244                                       ZSTD_CCtx_params const* params,
3245                                       const void* dict, size_t dictSize,
3246                                       ZSTD_dictTableLoadMethod_e dtlm,
3247                                       void* workspace)
3248 {
3249     const BYTE* dictPtr = (const BYTE*)dict;
3250     const BYTE* const dictEnd = dictPtr + dictSize;
3251     size_t dictID;
3252     size_t eSize;
3253 
3254     ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
3255     assert(dictSize >= 8);
3256     assert(MEM_readLE32(dictPtr) == ZSTD_MAGIC_DICTIONARY);
3257 
3258     dictID = params->fParams.noDictIDFlag ? 0 :  MEM_readLE32(dictPtr + 4 /* skip magic number */ );
3259     eSize = ZSTD_loadCEntropy(bs, workspace, dict, dictSize);
3260     FORWARD_IF_ERROR(eSize, "ZSTD_loadCEntropy failed");
3261     dictPtr += eSize;
3262 
3263     {
3264         size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
3265         FORWARD_IF_ERROR(ZSTD_loadDictionaryContent(
3266             ms, NULL, ws, params, dictPtr, dictContentSize, dtlm), "");
3267     }
3268     return dictID;
3269 }
3270 
3271 /* ZSTD_compress_insertDictionary() :
3272 *   @return : dictID, or an error code */
3273 static size_t
ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t * bs,ZSTD_matchState_t * ms,ldmState_t * ls,ZSTD_cwksp * ws,const ZSTD_CCtx_params * params,const void * dict,size_t dictSize,ZSTD_dictContentType_e dictContentType,ZSTD_dictTableLoadMethod_e dtlm,void * workspace)3274 ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs,
3275                                ZSTD_matchState_t* ms,
3276                                ldmState_t* ls,
3277                                ZSTD_cwksp* ws,
3278                          const ZSTD_CCtx_params* params,
3279                          const void* dict, size_t dictSize,
3280                                ZSTD_dictContentType_e dictContentType,
3281                                ZSTD_dictTableLoadMethod_e dtlm,
3282                                void* workspace)
3283 {
3284     DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize);
3285     if ((dict==NULL) || (dictSize<8)) {
3286         RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, "");
3287         return 0;
3288     }
3289 
3290     ZSTD_reset_compressedBlockState(bs);
3291 
3292     /* dict restricted modes */
3293     if (dictContentType == ZSTD_dct_rawContent)
3294         return ZSTD_loadDictionaryContent(ms, ls, ws, params, dict, dictSize, dtlm);
3295 
3296     if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
3297         if (dictContentType == ZSTD_dct_auto) {
3298             DEBUGLOG(4, "raw content dictionary detected");
3299             return ZSTD_loadDictionaryContent(
3300                 ms, ls, ws, params, dict, dictSize, dtlm);
3301         }
3302         RETURN_ERROR_IF(dictContentType == ZSTD_dct_fullDict, dictionary_wrong, "");
3303         assert(0);   /* impossible */
3304     }
3305 
3306     /* dict as full zstd dictionary */
3307     return ZSTD_loadZstdDictionary(
3308         bs, ms, ws, params, dict, dictSize, dtlm, workspace);
3309 }
3310 
3311 #define ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF (128 KB)
3312 #define ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER (6ULL)
3313 
3314 /*! ZSTD_compressBegin_internal() :
3315  * @return : 0, or an error code */
ZSTD_compressBegin_internal(ZSTD_CCtx * cctx,const void * dict,size_t dictSize,ZSTD_dictContentType_e dictContentType,ZSTD_dictTableLoadMethod_e dtlm,const ZSTD_CDict * cdict,const ZSTD_CCtx_params * params,U64 pledgedSrcSize,ZSTD_buffered_policy_e zbuff)3316 static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
3317                                     const void* dict, size_t dictSize,
3318                                     ZSTD_dictContentType_e dictContentType,
3319                                     ZSTD_dictTableLoadMethod_e dtlm,
3320                                     const ZSTD_CDict* cdict,
3321                                     const ZSTD_CCtx_params* params, U64 pledgedSrcSize,
3322                                     ZSTD_buffered_policy_e zbuff)
3323 {
3324     DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params->cParams.windowLog);
3325     /* params are supposed to be fully validated at this point */
3326     assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
3327     assert(!((dict) && (cdict)));  /* either dict or cdict, not both */
3328     if ( (cdict)
3329       && (cdict->dictContentSize > 0)
3330       && ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF
3331         || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER
3332         || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
3333         || cdict->compressionLevel == 0)
3334       && (params->attachDictPref != ZSTD_dictForceLoad) ) {
3335         return ZSTD_resetCCtx_usingCDict(cctx, cdict, params, pledgedSrcSize, zbuff);
3336     }
3337 
3338     FORWARD_IF_ERROR( ZSTD_resetCCtx_internal(cctx, *params, pledgedSrcSize,
3339                                      ZSTDcrp_makeClean, zbuff) , "");
3340     {   size_t const dictID = cdict ?
3341                 ZSTD_compress_insertDictionary(
3342                         cctx->blockState.prevCBlock, &cctx->blockState.matchState,
3343                         &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, cdict->dictContent,
3344                         cdict->dictContentSize, cdict->dictContentType, dtlm,
3345                         cctx->entropyWorkspace)
3346               : ZSTD_compress_insertDictionary(
3347                         cctx->blockState.prevCBlock, &cctx->blockState.matchState,
3348                         &cctx->ldmState, &cctx->workspace, &cctx->appliedParams, dict, dictSize,
3349                         dictContentType, dtlm, cctx->entropyWorkspace);
3350         FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed");
3351         assert(dictID <= UINT_MAX);
3352         cctx->dictID = (U32)dictID;
3353         cctx->dictContentSize = cdict ? cdict->dictContentSize : dictSize;
3354     }
3355     return 0;
3356 }
3357 
ZSTD_compressBegin_advanced_internal(ZSTD_CCtx * cctx,const void * dict,size_t dictSize,ZSTD_dictContentType_e dictContentType,ZSTD_dictTableLoadMethod_e dtlm,const ZSTD_CDict * cdict,const ZSTD_CCtx_params * params,unsigned long long pledgedSrcSize)3358 size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
3359                                     const void* dict, size_t dictSize,
3360                                     ZSTD_dictContentType_e dictContentType,
3361                                     ZSTD_dictTableLoadMethod_e dtlm,
3362                                     const ZSTD_CDict* cdict,
3363                                     const ZSTD_CCtx_params* params,
3364                                     unsigned long long pledgedSrcSize)
3365 {
3366     DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params->cParams.windowLog);
3367     /* compression parameters verification and optimization */
3368     FORWARD_IF_ERROR( ZSTD_checkCParams(params->cParams) , "");
3369     return ZSTD_compressBegin_internal(cctx,
3370                                        dict, dictSize, dictContentType, dtlm,
3371                                        cdict,
3372                                        params, pledgedSrcSize,
3373                                        ZSTDb_not_buffered);
3374 }
3375 
3376 /*! ZSTD_compressBegin_advanced() :
3377 *   @return : 0, or an error code */
ZSTD_compressBegin_advanced(ZSTD_CCtx * cctx,const void * dict,size_t dictSize,ZSTD_parameters params,unsigned long long pledgedSrcSize)3378 size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
3379                              const void* dict, size_t dictSize,
3380                                    ZSTD_parameters params, unsigned long long pledgedSrcSize)
3381 {
3382     ZSTD_CCtx_params cctxParams;
3383     ZSTD_CCtxParams_init_internal(&cctxParams, &params, ZSTD_NO_CLEVEL);
3384     return ZSTD_compressBegin_advanced_internal(cctx,
3385                                             dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast,
3386                                             NULL /*cdict*/,
3387                                             &cctxParams, pledgedSrcSize);
3388 }
3389 
ZSTD_compressBegin_usingDict(ZSTD_CCtx * cctx,const void * dict,size_t dictSize,int compressionLevel)3390 size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
3391 {
3392     ZSTD_CCtx_params cctxParams;
3393     {
3394         ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_noAttachDict);
3395         ZSTD_CCtxParams_init_internal(&cctxParams, &params, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel);
3396     }
3397     DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (unsigned)dictSize);
3398     return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
3399                                        &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
3400 }
3401 
ZSTD_compressBegin(ZSTD_CCtx * cctx,int compressionLevel)3402 size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
3403 {
3404     return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
3405 }
3406 
3407 
3408 /*! ZSTD_writeEpilogue() :
3409 *   Ends a frame.
3410 *   @return : nb of bytes written into dst (or an error code) */
ZSTD_writeEpilogue(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity)3411 static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
3412 {
3413     BYTE* const ostart = (BYTE*)dst;
3414     BYTE* op = ostart;
3415     size_t fhSize = 0;
3416 
3417     DEBUGLOG(4, "ZSTD_writeEpilogue");
3418     RETURN_ERROR_IF(cctx->stage == ZSTDcs_created, stage_wrong, "init missing");
3419 
3420     /* special case : empty frame */
3421     if (cctx->stage == ZSTDcs_init) {
3422         fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, &cctx->appliedParams, 0, 0);
3423         FORWARD_IF_ERROR(fhSize, "ZSTD_writeFrameHeader failed");
3424         dstCapacity -= fhSize;
3425         op += fhSize;
3426         cctx->stage = ZSTDcs_ongoing;
3427     }
3428 
3429     if (cctx->stage != ZSTDcs_ending) {
3430         /* write one last empty block, make it the "last" block */
3431         U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
3432         RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for epilogue");
3433         MEM_writeLE32(op, cBlockHeader24);
3434         op += ZSTD_blockHeaderSize;
3435         dstCapacity -= ZSTD_blockHeaderSize;
3436     }
3437 
3438     if (cctx->appliedParams.fParams.checksumFlag) {
3439         U32 const checksum = (U32) xxh64_digest(&cctx->xxhState);
3440         RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum");
3441         DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", (unsigned)checksum);
3442         MEM_writeLE32(op, checksum);
3443         op += 4;
3444     }
3445 
3446     cctx->stage = ZSTDcs_created;  /* return to "created but no init" status */
3447     return op-ostart;
3448 }
3449 
ZSTD_CCtx_trace(ZSTD_CCtx * cctx,size_t extraCSize)3450 void ZSTD_CCtx_trace(ZSTD_CCtx* cctx, size_t extraCSize)
3451 {
3452     (void)cctx;
3453     (void)extraCSize;
3454 }
3455 
ZSTD_compressEnd(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)3456 size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
3457                          void* dst, size_t dstCapacity,
3458                    const void* src, size_t srcSize)
3459 {
3460     size_t endResult;
3461     size_t const cSize = ZSTD_compressContinue_internal(cctx,
3462                                 dst, dstCapacity, src, srcSize,
3463                                 1 /* frame mode */, 1 /* last chunk */);
3464     FORWARD_IF_ERROR(cSize, "ZSTD_compressContinue_internal failed");
3465     endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
3466     FORWARD_IF_ERROR(endResult, "ZSTD_writeEpilogue failed");
3467     assert(!(cctx->appliedParams.fParams.contentSizeFlag && cctx->pledgedSrcSizePlusOne == 0));
3468     if (cctx->pledgedSrcSizePlusOne != 0) {  /* control src size */
3469         ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN == (unsigned long long)-1);
3470         DEBUGLOG(4, "end of frame : controlling src size");
3471         RETURN_ERROR_IF(
3472             cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1,
3473             srcSize_wrong,
3474              "error : pledgedSrcSize = %u, while realSrcSize = %u",
3475             (unsigned)cctx->pledgedSrcSizePlusOne-1,
3476             (unsigned)cctx->consumedSrcSize);
3477     }
3478     ZSTD_CCtx_trace(cctx, endResult);
3479     return cSize + endResult;
3480 }
3481 
ZSTD_compress_advanced(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const void * dict,size_t dictSize,ZSTD_parameters params)3482 size_t ZSTD_compress_advanced (ZSTD_CCtx* cctx,
3483                                void* dst, size_t dstCapacity,
3484                          const void* src, size_t srcSize,
3485                          const void* dict,size_t dictSize,
3486                                ZSTD_parameters params)
3487 {
3488     ZSTD_CCtx_params cctxParams;
3489     DEBUGLOG(4, "ZSTD_compress_advanced");
3490     FORWARD_IF_ERROR(ZSTD_checkCParams(params.cParams), "");
3491     ZSTD_CCtxParams_init_internal(&cctxParams, &params, ZSTD_NO_CLEVEL);
3492     return ZSTD_compress_advanced_internal(cctx,
3493                                            dst, dstCapacity,
3494                                            src, srcSize,
3495                                            dict, dictSize,
3496                                            &cctxParams);
3497 }
3498 
3499 /* Internal */
ZSTD_compress_advanced_internal(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const void * dict,size_t dictSize,const ZSTD_CCtx_params * params)3500 size_t ZSTD_compress_advanced_internal(
3501         ZSTD_CCtx* cctx,
3502         void* dst, size_t dstCapacity,
3503         const void* src, size_t srcSize,
3504         const void* dict,size_t dictSize,
3505         const ZSTD_CCtx_params* params)
3506 {
3507     DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)", (unsigned)srcSize);
3508     FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx,
3509                          dict, dictSize, ZSTD_dct_auto, ZSTD_dtlm_fast, NULL,
3510                          params, srcSize, ZSTDb_not_buffered) , "");
3511     return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
3512 }
3513 
ZSTD_compress_usingDict(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const void * dict,size_t dictSize,int compressionLevel)3514 size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx,
3515                                void* dst, size_t dstCapacity,
3516                          const void* src, size_t srcSize,
3517                          const void* dict, size_t dictSize,
3518                                int compressionLevel)
3519 {
3520     ZSTD_CCtx_params cctxParams;
3521     {
3522         ZSTD_parameters const params = ZSTD_getParams_internal(compressionLevel, srcSize, dict ? dictSize : 0, ZSTD_cpm_noAttachDict);
3523         assert(params.fParams.contentSizeFlag == 1);
3524         ZSTD_CCtxParams_init_internal(&cctxParams, &params, (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT: compressionLevel);
3525     }
3526     DEBUGLOG(4, "ZSTD_compress_usingDict (srcSize=%u)", (unsigned)srcSize);
3527     return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, &cctxParams);
3528 }
3529 
ZSTD_compressCCtx(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,int compressionLevel)3530 size_t ZSTD_compressCCtx(ZSTD_CCtx* cctx,
3531                          void* dst, size_t dstCapacity,
3532                    const void* src, size_t srcSize,
3533                          int compressionLevel)
3534 {
3535     DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (unsigned)srcSize);
3536     assert(cctx != NULL);
3537     return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
3538 }
3539 
ZSTD_compress(void * dst,size_t dstCapacity,const void * src,size_t srcSize,int compressionLevel)3540 size_t ZSTD_compress(void* dst, size_t dstCapacity,
3541                const void* src, size_t srcSize,
3542                      int compressionLevel)
3543 {
3544     size_t result;
3545     ZSTD_CCtx* cctx = ZSTD_createCCtx();
3546     RETURN_ERROR_IF(!cctx, memory_allocation, "ZSTD_createCCtx failed");
3547     result = ZSTD_compressCCtx(cctx, dst, dstCapacity, src, srcSize, compressionLevel);
3548     ZSTD_freeCCtx(cctx);
3549     return result;
3550 }
3551 
3552 
3553 /* =====  Dictionary API  ===== */
3554 
3555 /*! ZSTD_estimateCDictSize_advanced() :
3556  *  Estimate amount of memory that will be needed to create a dictionary with following arguments */
ZSTD_estimateCDictSize_advanced(size_t dictSize,ZSTD_compressionParameters cParams,ZSTD_dictLoadMethod_e dictLoadMethod)3557 size_t ZSTD_estimateCDictSize_advanced(
3558         size_t dictSize, ZSTD_compressionParameters cParams,
3559         ZSTD_dictLoadMethod_e dictLoadMethod)
3560 {
3561     DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (unsigned)sizeof(ZSTD_CDict));
3562     return ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
3563          + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
3564          + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0)
3565          + (dictLoadMethod == ZSTD_dlm_byRef ? 0
3566             : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void *))));
3567 }
3568 
ZSTD_estimateCDictSize(size_t dictSize,int compressionLevel)3569 size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
3570 {
3571     ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3572     return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
3573 }
3574 
ZSTD_sizeof_CDict(const ZSTD_CDict * cdict)3575 size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
3576 {
3577     if (cdict==NULL) return 0;   /* support sizeof on NULL */
3578     DEBUGLOG(5, "sizeof(*cdict) : %u", (unsigned)sizeof(*cdict));
3579     /* cdict may be in the workspace */
3580     return (cdict->workspace.workspace == cdict ? 0 : sizeof(*cdict))
3581         + ZSTD_cwksp_sizeof(&cdict->workspace);
3582 }
3583 
ZSTD_initCDict_internal(ZSTD_CDict * cdict,const void * dictBuffer,size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_dictContentType_e dictContentType,ZSTD_CCtx_params params)3584 static size_t ZSTD_initCDict_internal(
3585                     ZSTD_CDict* cdict,
3586               const void* dictBuffer, size_t dictSize,
3587                     ZSTD_dictLoadMethod_e dictLoadMethod,
3588                     ZSTD_dictContentType_e dictContentType,
3589                     ZSTD_CCtx_params params)
3590 {
3591     DEBUGLOG(3, "ZSTD_initCDict_internal (dictContentType:%u)", (unsigned)dictContentType);
3592     assert(!ZSTD_checkCParams(params.cParams));
3593     cdict->matchState.cParams = params.cParams;
3594     cdict->matchState.dedicatedDictSearch = params.enableDedicatedDictSearch;
3595     if (cdict->matchState.dedicatedDictSearch && dictSize > ZSTD_CHUNKSIZE_MAX) {
3596         cdict->matchState.dedicatedDictSearch = 0;
3597     }
3598     if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
3599         cdict->dictContent = dictBuffer;
3600     } else {
3601          void *internalBuffer = ZSTD_cwksp_reserve_object(&cdict->workspace, ZSTD_cwksp_align(dictSize, sizeof(void*)));
3602         RETURN_ERROR_IF(!internalBuffer, memory_allocation, "NULL pointer!");
3603         cdict->dictContent = internalBuffer;
3604         ZSTD_memcpy(internalBuffer, dictBuffer, dictSize);
3605     }
3606     cdict->dictContentSize = dictSize;
3607     cdict->dictContentType = dictContentType;
3608 
3609     cdict->entropyWorkspace = (U32*)ZSTD_cwksp_reserve_object(&cdict->workspace, HUF_WORKSPACE_SIZE);
3610 
3611 
3612     /* Reset the state to no dictionary */
3613     ZSTD_reset_compressedBlockState(&cdict->cBlockState);
3614     FORWARD_IF_ERROR(ZSTD_reset_matchState(
3615         &cdict->matchState,
3616         &cdict->workspace,
3617         &params.cParams,
3618         ZSTDcrp_makeClean,
3619         ZSTDirp_reset,
3620         ZSTD_resetTarget_CDict), "");
3621     /* (Maybe) load the dictionary
3622      * Skips loading the dictionary if it is < 8 bytes.
3623      */
3624     {   params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
3625         params.fParams.contentSizeFlag = 1;
3626         {   size_t const dictID = ZSTD_compress_insertDictionary(
3627                     &cdict->cBlockState, &cdict->matchState, NULL, &cdict->workspace,
3628                     &params, cdict->dictContent, cdict->dictContentSize,
3629                     dictContentType, ZSTD_dtlm_full, cdict->entropyWorkspace);
3630             FORWARD_IF_ERROR(dictID, "ZSTD_compress_insertDictionary failed");
3631             assert(dictID <= (size_t)(U32)-1);
3632             cdict->dictID = (U32)dictID;
3633         }
3634     }
3635 
3636     return 0;
3637 }
3638 
ZSTD_createCDict_advanced_internal(size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_compressionParameters cParams,ZSTD_customMem customMem)3639 static ZSTD_CDict* ZSTD_createCDict_advanced_internal(size_t dictSize,
3640                                       ZSTD_dictLoadMethod_e dictLoadMethod,
3641                                       ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
3642 {
3643     if ((!customMem.customAlloc) ^ (!customMem.customFree)) return NULL;
3644 
3645     {   size_t const workspaceSize =
3646             ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict)) +
3647             ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE) +
3648             ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0) +
3649             (dictLoadMethod == ZSTD_dlm_byRef ? 0
3650              : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))));
3651         void* const workspace = ZSTD_customMalloc(workspaceSize, customMem);
3652         ZSTD_cwksp ws;
3653         ZSTD_CDict* cdict;
3654 
3655         if (!workspace) {
3656             ZSTD_customFree(workspace, customMem);
3657             return NULL;
3658         }
3659 
3660         ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_dynamic_alloc);
3661 
3662         cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
3663         assert(cdict != NULL);
3664         ZSTD_cwksp_move(&cdict->workspace, &ws);
3665         cdict->customMem = customMem;
3666         cdict->compressionLevel = ZSTD_NO_CLEVEL; /* signals advanced API usage */
3667 
3668         return cdict;
3669     }
3670 }
3671 
ZSTD_createCDict_advanced(const void * dictBuffer,size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_dictContentType_e dictContentType,ZSTD_compressionParameters cParams,ZSTD_customMem customMem)3672 ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
3673                                       ZSTD_dictLoadMethod_e dictLoadMethod,
3674                                       ZSTD_dictContentType_e dictContentType,
3675                                       ZSTD_compressionParameters cParams,
3676                                       ZSTD_customMem customMem)
3677 {
3678     ZSTD_CCtx_params cctxParams;
3679     ZSTD_memset(&cctxParams, 0, sizeof(cctxParams));
3680     ZSTD_CCtxParams_init(&cctxParams, 0);
3681     cctxParams.cParams = cParams;
3682     cctxParams.customMem = customMem;
3683     return ZSTD_createCDict_advanced2(
3684         dictBuffer, dictSize,
3685         dictLoadMethod, dictContentType,
3686         &cctxParams, customMem);
3687 }
3688 
ZSTD_createCDict_advanced2(const void * dict,size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_dictContentType_e dictContentType,const ZSTD_CCtx_params * originalCctxParams,ZSTD_customMem customMem)3689 ZSTDLIB_API ZSTD_CDict* ZSTD_createCDict_advanced2(
3690         const void* dict, size_t dictSize,
3691         ZSTD_dictLoadMethod_e dictLoadMethod,
3692         ZSTD_dictContentType_e dictContentType,
3693         const ZSTD_CCtx_params* originalCctxParams,
3694         ZSTD_customMem customMem)
3695 {
3696     ZSTD_CCtx_params cctxParams = *originalCctxParams;
3697     ZSTD_compressionParameters cParams;
3698     ZSTD_CDict* cdict;
3699 
3700     DEBUGLOG(3, "ZSTD_createCDict_advanced2, mode %u", (unsigned)dictContentType);
3701     if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
3702 
3703     if (cctxParams.enableDedicatedDictSearch) {
3704         cParams = ZSTD_dedicatedDictSearch_getCParams(
3705             cctxParams.compressionLevel, dictSize);
3706         ZSTD_overrideCParams(&cParams, &cctxParams.cParams);
3707     } else {
3708         cParams = ZSTD_getCParamsFromCCtxParams(
3709             &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3710     }
3711 
3712     if (!ZSTD_dedicatedDictSearch_isSupported(&cParams)) {
3713         /* Fall back to non-DDSS params */
3714         cctxParams.enableDedicatedDictSearch = 0;
3715         cParams = ZSTD_getCParamsFromCCtxParams(
3716             &cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3717     }
3718 
3719     cctxParams.cParams = cParams;
3720 
3721     cdict = ZSTD_createCDict_advanced_internal(dictSize,
3722                         dictLoadMethod, cctxParams.cParams,
3723                         customMem);
3724 
3725     if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3726                                     dict, dictSize,
3727                                     dictLoadMethod, dictContentType,
3728                                     cctxParams) )) {
3729         ZSTD_freeCDict(cdict);
3730         return NULL;
3731     }
3732 
3733     return cdict;
3734 }
3735 
ZSTD_createCDict(const void * dict,size_t dictSize,int compressionLevel)3736 ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
3737 {
3738     ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3739     ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize,
3740                                                   ZSTD_dlm_byCopy, ZSTD_dct_auto,
3741                                                   cParams, ZSTD_defaultCMem);
3742     if (cdict)
3743         cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
3744     return cdict;
3745 }
3746 
ZSTD_createCDict_byReference(const void * dict,size_t dictSize,int compressionLevel)3747 ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
3748 {
3749     ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize, ZSTD_cpm_createCDict);
3750     ZSTD_CDict* const cdict = ZSTD_createCDict_advanced(dict, dictSize,
3751                                      ZSTD_dlm_byRef, ZSTD_dct_auto,
3752                                      cParams, ZSTD_defaultCMem);
3753     if (cdict)
3754         cdict->compressionLevel = (compressionLevel == 0) ? ZSTD_CLEVEL_DEFAULT : compressionLevel;
3755     return cdict;
3756 }
3757 
ZSTD_freeCDict(ZSTD_CDict * cdict)3758 size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
3759 {
3760     if (cdict==NULL) return 0;   /* support free on NULL */
3761     {   ZSTD_customMem const cMem = cdict->customMem;
3762         int cdictInWorkspace = ZSTD_cwksp_owns_buffer(&cdict->workspace, cdict);
3763         ZSTD_cwksp_free(&cdict->workspace, cMem);
3764         if (!cdictInWorkspace) {
3765             ZSTD_customFree(cdict, cMem);
3766         }
3767         return 0;
3768     }
3769 }
3770 
3771 /*! ZSTD_initStaticCDict_advanced() :
3772  *  Generate a digested dictionary in provided memory area.
3773  *  workspace: The memory area to emplace the dictionary into.
3774  *             Provided pointer must 8-bytes aligned.
3775  *             It must outlive dictionary usage.
3776  *  workspaceSize: Use ZSTD_estimateCDictSize()
3777  *                 to determine how large workspace must be.
3778  *  cParams : use ZSTD_getCParams() to transform a compression level
3779  *            into its relevants cParams.
3780  * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
3781  *  Note : there is no corresponding "free" function.
3782  *         Since workspace was allocated externally, it must be freed externally.
3783  */
ZSTD_initStaticCDict(void * workspace,size_t workspaceSize,const void * dict,size_t dictSize,ZSTD_dictLoadMethod_e dictLoadMethod,ZSTD_dictContentType_e dictContentType,ZSTD_compressionParameters cParams)3784 const ZSTD_CDict* ZSTD_initStaticCDict(
3785                                  void* workspace, size_t workspaceSize,
3786                            const void* dict, size_t dictSize,
3787                                  ZSTD_dictLoadMethod_e dictLoadMethod,
3788                                  ZSTD_dictContentType_e dictContentType,
3789                                  ZSTD_compressionParameters cParams)
3790 {
3791     size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
3792     size_t const neededSize = ZSTD_cwksp_alloc_size(sizeof(ZSTD_CDict))
3793                             + (dictLoadMethod == ZSTD_dlm_byRef ? 0
3794                                : ZSTD_cwksp_alloc_size(ZSTD_cwksp_align(dictSize, sizeof(void*))))
3795                             + ZSTD_cwksp_alloc_size(HUF_WORKSPACE_SIZE)
3796                             + matchStateSize;
3797     ZSTD_CDict* cdict;
3798     ZSTD_CCtx_params params;
3799 
3800     if ((size_t)workspace & 7) return NULL;  /* 8-aligned */
3801 
3802     {
3803         ZSTD_cwksp ws;
3804         ZSTD_cwksp_init(&ws, workspace, workspaceSize, ZSTD_cwksp_static_alloc);
3805         cdict = (ZSTD_CDict*)ZSTD_cwksp_reserve_object(&ws, sizeof(ZSTD_CDict));
3806         if (cdict == NULL) return NULL;
3807         ZSTD_cwksp_move(&cdict->workspace, &ws);
3808     }
3809 
3810     DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u",
3811         (unsigned)workspaceSize, (unsigned)neededSize, (unsigned)(workspaceSize < neededSize));
3812     if (workspaceSize < neededSize) return NULL;
3813 
3814     ZSTD_CCtxParams_init(&params, 0);
3815     params.cParams = cParams;
3816 
3817     if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3818                                               dict, dictSize,
3819                                               dictLoadMethod, dictContentType,
3820                                               params) ))
3821         return NULL;
3822 
3823     return cdict;
3824 }
3825 
ZSTD_getCParamsFromCDict(const ZSTD_CDict * cdict)3826 ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict)
3827 {
3828     assert(cdict != NULL);
3829     return cdict->matchState.cParams;
3830 }
3831 
3832 /*! ZSTD_getDictID_fromCDict() :
3833  *  Provides the dictID of the dictionary loaded into `cdict`.
3834  *  If @return == 0, the dictionary is not conformant to Zstandard specification, or empty.
3835  *  Non-conformant dictionaries can still be loaded, but as content-only dictionaries. */
ZSTD_getDictID_fromCDict(const ZSTD_CDict * cdict)3836 unsigned ZSTD_getDictID_fromCDict(const ZSTD_CDict* cdict)
3837 {
3838     if (cdict==NULL) return 0;
3839     return cdict->dictID;
3840 }
3841 
3842 
3843 /* ZSTD_compressBegin_usingCDict_advanced() :
3844  * cdict must be != NULL */
ZSTD_compressBegin_usingCDict_advanced(ZSTD_CCtx * const cctx,const ZSTD_CDict * const cdict,ZSTD_frameParameters const fParams,unsigned long long const pledgedSrcSize)3845 size_t ZSTD_compressBegin_usingCDict_advanced(
3846     ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
3847     ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
3848 {
3849     ZSTD_CCtx_params cctxParams;
3850     DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
3851     RETURN_ERROR_IF(cdict==NULL, dictionary_wrong, "NULL pointer!");
3852     /* Initialize the cctxParams from the cdict */
3853     {
3854         ZSTD_parameters params;
3855         params.fParams = fParams;
3856         params.cParams = ( pledgedSrcSize < ZSTD_USE_CDICT_PARAMS_SRCSIZE_CUTOFF
3857                         || pledgedSrcSize < cdict->dictContentSize * ZSTD_USE_CDICT_PARAMS_DICTSIZE_MULTIPLIER
3858                         || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
3859                         || cdict->compressionLevel == 0 ) ?
3860                 ZSTD_getCParamsFromCDict(cdict)
3861               : ZSTD_getCParams(cdict->compressionLevel,
3862                                 pledgedSrcSize,
3863                                 cdict->dictContentSize);
3864         ZSTD_CCtxParams_init_internal(&cctxParams, &params, cdict->compressionLevel);
3865     }
3866     /* Increase window log to fit the entire dictionary and source if the
3867      * source size is known. Limit the increase to 19, which is the
3868      * window log for compression level 1 with the largest source size.
3869      */
3870     if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
3871         U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19);
3872         U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1;
3873         cctxParams.cParams.windowLog = MAX(cctxParams.cParams.windowLog, limitedSrcLog);
3874     }
3875     return ZSTD_compressBegin_internal(cctx,
3876                                         NULL, 0, ZSTD_dct_auto, ZSTD_dtlm_fast,
3877                                         cdict,
3878                                         &cctxParams, pledgedSrcSize,
3879                                         ZSTDb_not_buffered);
3880 }
3881 
3882 /* ZSTD_compressBegin_usingCDict() :
3883  * pledgedSrcSize=0 means "unknown"
3884  * if pledgedSrcSize>0, it will enable contentSizeFlag */
ZSTD_compressBegin_usingCDict(ZSTD_CCtx * cctx,const ZSTD_CDict * cdict)3885 size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
3886 {
3887     ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
3888     DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
3889     return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN);
3890 }
3891 
ZSTD_compress_usingCDict_advanced(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const ZSTD_CDict * cdict,ZSTD_frameParameters fParams)3892 size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
3893                                 void* dst, size_t dstCapacity,
3894                                 const void* src, size_t srcSize,
3895                                 const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
3896 {
3897     FORWARD_IF_ERROR(ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize), "");   /* will check if cdict != NULL */
3898     return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
3899 }
3900 
3901 /*! ZSTD_compress_usingCDict() :
3902  *  Compression using a digested Dictionary.
3903  *  Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
3904  *  Note that compression parameters are decided at CDict creation time
3905  *  while frame parameters are hardcoded */
ZSTD_compress_usingCDict(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize,const ZSTD_CDict * cdict)3906 size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
3907                                 void* dst, size_t dstCapacity,
3908                                 const void* src, size_t srcSize,
3909                                 const ZSTD_CDict* cdict)
3910 {
3911     ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
3912     return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
3913 }
3914 
3915 
3916 
3917 /* ******************************************************************
3918 *  Streaming
3919 ********************************************************************/
3920 
ZSTD_createCStream(void)3921 ZSTD_CStream* ZSTD_createCStream(void)
3922 {
3923     DEBUGLOG(3, "ZSTD_createCStream");
3924     return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
3925 }
3926 
ZSTD_initStaticCStream(void * workspace,size_t workspaceSize)3927 ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize)
3928 {
3929     return ZSTD_initStaticCCtx(workspace, workspaceSize);
3930 }
3931 
ZSTD_createCStream_advanced(ZSTD_customMem customMem)3932 ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
3933 {   /* CStream and CCtx are now same object */
3934     return ZSTD_createCCtx_advanced(customMem);
3935 }
3936 
ZSTD_freeCStream(ZSTD_CStream * zcs)3937 size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
3938 {
3939     return ZSTD_freeCCtx(zcs);   /* same object */
3940 }
3941 
3942 
3943 
3944 /*======   Initialization   ======*/
3945 
ZSTD_CStreamInSize(void)3946 size_t ZSTD_CStreamInSize(void)  { return ZSTD_BLOCKSIZE_MAX; }
3947 
ZSTD_CStreamOutSize(void)3948 size_t ZSTD_CStreamOutSize(void)
3949 {
3950     return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
3951 }
3952 
ZSTD_getCParamMode(ZSTD_CDict const * cdict,ZSTD_CCtx_params const * params,U64 pledgedSrcSize)3953 static ZSTD_cParamMode_e ZSTD_getCParamMode(ZSTD_CDict const* cdict, ZSTD_CCtx_params const* params, U64 pledgedSrcSize)
3954 {
3955     if (cdict != NULL && ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize))
3956         return ZSTD_cpm_attachDict;
3957     else
3958         return ZSTD_cpm_noAttachDict;
3959 }
3960 
3961 /* ZSTD_resetCStream():
3962  * pledgedSrcSize == 0 means "unknown" */
ZSTD_resetCStream(ZSTD_CStream * zcs,unsigned long long pss)3963 size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pss)
3964 {
3965     /* temporary : 0 interpreted as "unknown" during transition period.
3966      * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN.
3967      * 0 will be interpreted as "empty" in the future.
3968      */
3969     U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;
3970     DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (unsigned)pledgedSrcSize);
3971     FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
3972     FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
3973     return 0;
3974 }
3975 
3976 /*! ZSTD_initCStream_internal() :
3977  *  Note : for lib/compress only. Used by zstdmt_compress.c.
3978  *  Assumption 1 : params are valid
3979  *  Assumption 2 : either dict, or cdict, is defined, not both */
ZSTD_initCStream_internal(ZSTD_CStream * zcs,const void * dict,size_t dictSize,const ZSTD_CDict * cdict,const ZSTD_CCtx_params * params,unsigned long long pledgedSrcSize)3980 size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
3981                     const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
3982                     const ZSTD_CCtx_params* params,
3983                     unsigned long long pledgedSrcSize)
3984 {
3985     DEBUGLOG(4, "ZSTD_initCStream_internal");
3986     FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
3987     FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
3988     assert(!ZSTD_isError(ZSTD_checkCParams(params->cParams)));
3989     zcs->requestedParams = *params;
3990     assert(!((dict) && (cdict)));  /* either dict or cdict, not both */
3991     if (dict) {
3992         FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
3993     } else {
3994         /* Dictionary is cleared if !cdict */
3995         FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , "");
3996     }
3997     return 0;
3998 }
3999 
4000 /* ZSTD_initCStream_usingCDict_advanced() :
4001  * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream * zcs,const ZSTD_CDict * cdict,ZSTD_frameParameters fParams,unsigned long long pledgedSrcSize)4002 size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
4003                                             const ZSTD_CDict* cdict,
4004                                             ZSTD_frameParameters fParams,
4005                                             unsigned long long pledgedSrcSize)
4006 {
4007     DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced");
4008     FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
4009     FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
4010     zcs->requestedParams.fParams = fParams;
4011     FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , "");
4012     return 0;
4013 }
4014 
4015 /* note : cdict must outlive compression session */
ZSTD_initCStream_usingCDict(ZSTD_CStream * zcs,const ZSTD_CDict * cdict)4016 size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
4017 {
4018     DEBUGLOG(4, "ZSTD_initCStream_usingCDict");
4019     FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
4020     FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, cdict) , "");
4021     return 0;
4022 }
4023 
4024 
4025 /* ZSTD_initCStream_advanced() :
4026  * pledgedSrcSize must be exact.
4027  * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
4028  * dict is loaded with default parameters ZSTD_dct_auto and ZSTD_dlm_byCopy. */
ZSTD_initCStream_advanced(ZSTD_CStream * zcs,const void * dict,size_t dictSize,ZSTD_parameters params,unsigned long long pss)4029 size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
4030                                  const void* dict, size_t dictSize,
4031                                  ZSTD_parameters params, unsigned long long pss)
4032 {
4033     /* for compatibility with older programs relying on this behavior.
4034      * Users should now specify ZSTD_CONTENTSIZE_UNKNOWN.
4035      * This line will be removed in the future.
4036      */
4037     U64 const pledgedSrcSize = (pss==0 && params.fParams.contentSizeFlag==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;
4038     DEBUGLOG(4, "ZSTD_initCStream_advanced");
4039     FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
4040     FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
4041     FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) , "");
4042     ZSTD_CCtxParams_setZstdParams(&zcs->requestedParams, &params);
4043     FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
4044     return 0;
4045 }
4046 
ZSTD_initCStream_usingDict(ZSTD_CStream * zcs,const void * dict,size_t dictSize,int compressionLevel)4047 size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
4048 {
4049     DEBUGLOG(4, "ZSTD_initCStream_usingDict");
4050     FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
4051     FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , "");
4052     FORWARD_IF_ERROR( ZSTD_CCtx_loadDictionary(zcs, dict, dictSize) , "");
4053     return 0;
4054 }
4055 
ZSTD_initCStream_srcSize(ZSTD_CStream * zcs,int compressionLevel,unsigned long long pss)4056 size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss)
4057 {
4058     /* temporary : 0 interpreted as "unknown" during transition period.
4059      * Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN.
4060      * 0 will be interpreted as "empty" in the future.
4061      */
4062     U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss;
4063     DEBUGLOG(4, "ZSTD_initCStream_srcSize");
4064     FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
4065     FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , "");
4066     FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , "");
4067     FORWARD_IF_ERROR( ZSTD_CCtx_setPledgedSrcSize(zcs, pledgedSrcSize) , "");
4068     return 0;
4069 }
4070 
ZSTD_initCStream(ZSTD_CStream * zcs,int compressionLevel)4071 size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
4072 {
4073     DEBUGLOG(4, "ZSTD_initCStream");
4074     FORWARD_IF_ERROR( ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only) , "");
4075     FORWARD_IF_ERROR( ZSTD_CCtx_refCDict(zcs, NULL) , "");
4076     FORWARD_IF_ERROR( ZSTD_CCtx_setParameter(zcs, ZSTD_c_compressionLevel, compressionLevel) , "");
4077     return 0;
4078 }
4079 
4080 /*======   Compression   ======*/
4081 
ZSTD_nextInputSizeHint(const ZSTD_CCtx * cctx)4082 static size_t ZSTD_nextInputSizeHint(const ZSTD_CCtx* cctx)
4083 {
4084     size_t hintInSize = cctx->inBuffTarget - cctx->inBuffPos;
4085     if (hintInSize==0) hintInSize = cctx->blockSize;
4086     return hintInSize;
4087 }
4088 
4089 /* ZSTD_compressStream_generic():
4090  *  internal function for all *compressStream*() variants
4091  *  non-static, because can be called from zstdmt_compress.c
4092  * @return : hint size for next input */
ZSTD_compressStream_generic(ZSTD_CStream * zcs,ZSTD_outBuffer * output,ZSTD_inBuffer * input,ZSTD_EndDirective const flushMode)4093 static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
4094                                           ZSTD_outBuffer* output,
4095                                           ZSTD_inBuffer* input,
4096                                           ZSTD_EndDirective const flushMode)
4097 {
4098     const char* const istart = (const char*)input->src;
4099     const char* const iend = input->size != 0 ? istart + input->size : istart;
4100     const char* ip = input->pos != 0 ? istart + input->pos : istart;
4101     char* const ostart = (char*)output->dst;
4102     char* const oend = output->size != 0 ? ostart + output->size : ostart;
4103     char* op = output->pos != 0 ? ostart + output->pos : ostart;
4104     U32 someMoreWork = 1;
4105 
4106     /* check expectations */
4107     DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (unsigned)flushMode);
4108     if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) {
4109         assert(zcs->inBuff != NULL);
4110         assert(zcs->inBuffSize > 0);
4111     }
4112     if (zcs->appliedParams.outBufferMode == ZSTD_bm_buffered) {
4113         assert(zcs->outBuff !=  NULL);
4114         assert(zcs->outBuffSize > 0);
4115     }
4116     assert(output->pos <= output->size);
4117     assert(input->pos <= input->size);
4118     assert((U32)flushMode <= (U32)ZSTD_e_end);
4119 
4120     while (someMoreWork) {
4121         switch(zcs->streamStage)
4122         {
4123         case zcss_init:
4124             RETURN_ERROR(init_missing, "call ZSTD_initCStream() first!");
4125 
4126         case zcss_load:
4127             if ( (flushMode == ZSTD_e_end)
4128               && ( (size_t)(oend-op) >= ZSTD_compressBound(iend-ip)     /* Enough output space */
4129                 || zcs->appliedParams.outBufferMode == ZSTD_bm_stable)  /* OR we are allowed to return dstSizeTooSmall */
4130               && (zcs->inBuffPos == 0) ) {
4131                 /* shortcut to compression pass directly into output buffer */
4132                 size_t const cSize = ZSTD_compressEnd(zcs,
4133                                                 op, oend-op, ip, iend-ip);
4134                 DEBUGLOG(4, "ZSTD_compressEnd : cSize=%u", (unsigned)cSize);
4135                 FORWARD_IF_ERROR(cSize, "ZSTD_compressEnd failed");
4136                 ip = iend;
4137                 op += cSize;
4138                 zcs->frameEnded = 1;
4139                 ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
4140                 someMoreWork = 0; break;
4141             }
4142             /* complete loading into inBuffer in buffered mode */
4143             if (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered) {
4144                 size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
4145                 size_t const loaded = ZSTD_limitCopy(
4146                                         zcs->inBuff + zcs->inBuffPos, toLoad,
4147                                         ip, iend-ip);
4148                 zcs->inBuffPos += loaded;
4149                 if (loaded != 0)
4150                     ip += loaded;
4151                 if ( (flushMode == ZSTD_e_continue)
4152                   && (zcs->inBuffPos < zcs->inBuffTarget) ) {
4153                     /* not enough input to fill full block : stop here */
4154                     someMoreWork = 0; break;
4155                 }
4156                 if ( (flushMode == ZSTD_e_flush)
4157                   && (zcs->inBuffPos == zcs->inToCompress) ) {
4158                     /* empty */
4159                     someMoreWork = 0; break;
4160                 }
4161             }
4162             /* compress current block (note : this stage cannot be stopped in the middle) */
4163             DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
4164             {   int const inputBuffered = (zcs->appliedParams.inBufferMode == ZSTD_bm_buffered);
4165                 void* cDst;
4166                 size_t cSize;
4167                 size_t oSize = oend-op;
4168                 size_t const iSize = inputBuffered
4169                     ? zcs->inBuffPos - zcs->inToCompress
4170                     : MIN((size_t)(iend - ip), zcs->blockSize);
4171                 if (oSize >= ZSTD_compressBound(iSize) || zcs->appliedParams.outBufferMode == ZSTD_bm_stable)
4172                     cDst = op;   /* compress into output buffer, to skip flush stage */
4173                 else
4174                     cDst = zcs->outBuff, oSize = zcs->outBuffSize;
4175                 if (inputBuffered) {
4176                     unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
4177                     cSize = lastBlock ?
4178                             ZSTD_compressEnd(zcs, cDst, oSize,
4179                                         zcs->inBuff + zcs->inToCompress, iSize) :
4180                             ZSTD_compressContinue(zcs, cDst, oSize,
4181                                         zcs->inBuff + zcs->inToCompress, iSize);
4182                     FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed");
4183                     zcs->frameEnded = lastBlock;
4184                     /* prepare next block */
4185                     zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
4186                     if (zcs->inBuffTarget > zcs->inBuffSize)
4187                         zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
4188                     DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
4189                             (unsigned)zcs->inBuffTarget, (unsigned)zcs->inBuffSize);
4190                     if (!lastBlock)
4191                         assert(zcs->inBuffTarget <= zcs->inBuffSize);
4192                     zcs->inToCompress = zcs->inBuffPos;
4193                 } else {
4194                     unsigned const lastBlock = (ip + iSize == iend);
4195                     assert(flushMode == ZSTD_e_end /* Already validated */);
4196                     cSize = lastBlock ?
4197                             ZSTD_compressEnd(zcs, cDst, oSize, ip, iSize) :
4198                             ZSTD_compressContinue(zcs, cDst, oSize, ip, iSize);
4199                     /* Consume the input prior to error checking to mirror buffered mode. */
4200                     if (iSize > 0)
4201                         ip += iSize;
4202                     FORWARD_IF_ERROR(cSize, "%s", lastBlock ? "ZSTD_compressEnd failed" : "ZSTD_compressContinue failed");
4203                     zcs->frameEnded = lastBlock;
4204                     if (lastBlock)
4205                         assert(ip == iend);
4206                 }
4207                 if (cDst == op) {  /* no need to flush */
4208                     op += cSize;
4209                     if (zcs->frameEnded) {
4210                         DEBUGLOG(5, "Frame completed directly in outBuffer");
4211                         someMoreWork = 0;
4212                         ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
4213                     }
4214                     break;
4215                 }
4216                 zcs->outBuffContentSize = cSize;
4217                 zcs->outBuffFlushedSize = 0;
4218                 zcs->streamStage = zcss_flush; /* pass-through to flush stage */
4219             }
4220 	    ZSTD_FALLTHROUGH;
4221         case zcss_flush:
4222             DEBUGLOG(5, "flush stage");
4223             assert(zcs->appliedParams.outBufferMode == ZSTD_bm_buffered);
4224             {   size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
4225                 size_t const flushed = ZSTD_limitCopy(op, (size_t)(oend-op),
4226                             zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
4227                 DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u",
4228                             (unsigned)toFlush, (unsigned)(oend-op), (unsigned)flushed);
4229                 if (flushed)
4230                     op += flushed;
4231                 zcs->outBuffFlushedSize += flushed;
4232                 if (toFlush!=flushed) {
4233                     /* flush not fully completed, presumably because dst is too small */
4234                     assert(op==oend);
4235                     someMoreWork = 0;
4236                     break;
4237                 }
4238                 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
4239                 if (zcs->frameEnded) {
4240                     DEBUGLOG(5, "Frame completed on flush");
4241                     someMoreWork = 0;
4242                     ZSTD_CCtx_reset(zcs, ZSTD_reset_session_only);
4243                     break;
4244                 }
4245                 zcs->streamStage = zcss_load;
4246                 break;
4247             }
4248 
4249         default: /* impossible */
4250             assert(0);
4251         }
4252     }
4253 
4254     input->pos = ip - istart;
4255     output->pos = op - ostart;
4256     if (zcs->frameEnded) return 0;
4257     return ZSTD_nextInputSizeHint(zcs);
4258 }
4259 
ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx * cctx)4260 static size_t ZSTD_nextInputSizeHint_MTorST(const ZSTD_CCtx* cctx)
4261 {
4262     return ZSTD_nextInputSizeHint(cctx);
4263 
4264 }
4265 
ZSTD_compressStream(ZSTD_CStream * zcs,ZSTD_outBuffer * output,ZSTD_inBuffer * input)4266 size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
4267 {
4268     FORWARD_IF_ERROR( ZSTD_compressStream2(zcs, output, input, ZSTD_e_continue) , "");
4269     return ZSTD_nextInputSizeHint_MTorST(zcs);
4270 }
4271 
4272 /* After a compression call set the expected input/output buffer.
4273  * This is validated at the start of the next compression call.
4274  */
ZSTD_setBufferExpectations(ZSTD_CCtx * cctx,ZSTD_outBuffer const * output,ZSTD_inBuffer const * input)4275 static void ZSTD_setBufferExpectations(ZSTD_CCtx* cctx, ZSTD_outBuffer const* output, ZSTD_inBuffer const* input)
4276 {
4277     if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) {
4278         cctx->expectedInBuffer = *input;
4279     }
4280     if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) {
4281         cctx->expectedOutBufferSize = output->size - output->pos;
4282     }
4283 }
4284 
4285 /* Validate that the input/output buffers match the expectations set by
4286  * ZSTD_setBufferExpectations.
4287  */
ZSTD_checkBufferStability(ZSTD_CCtx const * cctx,ZSTD_outBuffer const * output,ZSTD_inBuffer const * input,ZSTD_EndDirective endOp)4288 static size_t ZSTD_checkBufferStability(ZSTD_CCtx const* cctx,
4289                                         ZSTD_outBuffer const* output,
4290                                         ZSTD_inBuffer const* input,
4291                                         ZSTD_EndDirective endOp)
4292 {
4293     if (cctx->appliedParams.inBufferMode == ZSTD_bm_stable) {
4294         ZSTD_inBuffer const expect = cctx->expectedInBuffer;
4295         if (expect.src != input->src || expect.pos != input->pos || expect.size != input->size)
4296             RETURN_ERROR(srcBuffer_wrong, "ZSTD_c_stableInBuffer enabled but input differs!");
4297         if (endOp != ZSTD_e_end)
4298             RETURN_ERROR(srcBuffer_wrong, "ZSTD_c_stableInBuffer can only be used with ZSTD_e_end!");
4299     }
4300     if (cctx->appliedParams.outBufferMode == ZSTD_bm_stable) {
4301         size_t const outBufferSize = output->size - output->pos;
4302         if (cctx->expectedOutBufferSize != outBufferSize)
4303             RETURN_ERROR(dstBuffer_wrong, "ZSTD_c_stableOutBuffer enabled but output size differs!");
4304     }
4305     return 0;
4306 }
4307 
ZSTD_CCtx_init_compressStream2(ZSTD_CCtx * cctx,ZSTD_EndDirective endOp,size_t inSize)4308 static size_t ZSTD_CCtx_init_compressStream2(ZSTD_CCtx* cctx,
4309                                              ZSTD_EndDirective endOp,
4310                                              size_t inSize) {
4311     ZSTD_CCtx_params params = cctx->requestedParams;
4312     ZSTD_prefixDict const prefixDict = cctx->prefixDict;
4313     FORWARD_IF_ERROR( ZSTD_initLocalDict(cctx) , ""); /* Init the local dict if present. */
4314     ZSTD_memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));   /* single usage */
4315     assert(prefixDict.dict==NULL || cctx->cdict==NULL);    /* only one can be set */
4316     if (cctx->cdict)
4317         params.compressionLevel = cctx->cdict->compressionLevel; /* let cdict take priority in terms of compression level */
4318     DEBUGLOG(4, "ZSTD_compressStream2 : transparent init stage");
4319     if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = inSize + 1;  /* auto-fix pledgedSrcSize */
4320     {
4321         size_t const dictSize = prefixDict.dict
4322                 ? prefixDict.dictSize
4323                 : (cctx->cdict ? cctx->cdict->dictContentSize : 0);
4324         ZSTD_cParamMode_e const mode = ZSTD_getCParamMode(cctx->cdict, &params, cctx->pledgedSrcSizePlusOne - 1);
4325         params.cParams = ZSTD_getCParamsFromCCtxParams(
4326                 &params, cctx->pledgedSrcSizePlusOne-1,
4327                 dictSize, mode);
4328     }
4329 
4330     if (ZSTD_CParams_shouldEnableLdm(&params.cParams)) {
4331         /* Enable LDM by default for optimal parser and window size >= 128MB */
4332         DEBUGLOG(4, "LDM enabled by default (window size >= 128MB, strategy >= btopt)");
4333         params.ldmParams.enableLdm = 1;
4334     }
4335 
4336     {   U64 const pledgedSrcSize = cctx->pledgedSrcSizePlusOne - 1;
4337         assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
4338         FORWARD_IF_ERROR( ZSTD_compressBegin_internal(cctx,
4339                 prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType, ZSTD_dtlm_fast,
4340                 cctx->cdict,
4341                 &params, pledgedSrcSize,
4342                 ZSTDb_buffered) , "");
4343         assert(cctx->appliedParams.nbWorkers == 0);
4344         cctx->inToCompress = 0;
4345         cctx->inBuffPos = 0;
4346         if (cctx->appliedParams.inBufferMode == ZSTD_bm_buffered) {
4347             /* for small input: avoid automatic flush on reaching end of block, since
4348             * it would require to add a 3-bytes null block to end frame
4349             */
4350             cctx->inBuffTarget = cctx->blockSize + (cctx->blockSize == pledgedSrcSize);
4351         } else {
4352             cctx->inBuffTarget = 0;
4353         }
4354         cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
4355         cctx->streamStage = zcss_load;
4356         cctx->frameEnded = 0;
4357     }
4358     return 0;
4359 }
4360 
ZSTD_compressStream2(ZSTD_CCtx * cctx,ZSTD_outBuffer * output,ZSTD_inBuffer * input,ZSTD_EndDirective endOp)4361 size_t ZSTD_compressStream2( ZSTD_CCtx* cctx,
4362                              ZSTD_outBuffer* output,
4363                              ZSTD_inBuffer* input,
4364                              ZSTD_EndDirective endOp)
4365 {
4366     DEBUGLOG(5, "ZSTD_compressStream2, endOp=%u ", (unsigned)endOp);
4367     /* check conditions */
4368     RETURN_ERROR_IF(output->pos > output->size, dstSize_tooSmall, "invalid output buffer");
4369     RETURN_ERROR_IF(input->pos  > input->size, srcSize_wrong, "invalid input buffer");
4370     RETURN_ERROR_IF((U32)endOp > (U32)ZSTD_e_end, parameter_outOfBound, "invalid endDirective");
4371     assert(cctx != NULL);
4372 
4373     /* transparent initialization stage */
4374     if (cctx->streamStage == zcss_init) {
4375         FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, endOp, input->size), "CompressStream2 initialization failed");
4376         ZSTD_setBufferExpectations(cctx, output, input);    /* Set initial buffer expectations now that we've initialized */
4377     }
4378     /* end of transparent initialization stage */
4379 
4380     FORWARD_IF_ERROR(ZSTD_checkBufferStability(cctx, output, input, endOp), "invalid buffers");
4381     /* compression stage */
4382     FORWARD_IF_ERROR( ZSTD_compressStream_generic(cctx, output, input, endOp) , "");
4383     DEBUGLOG(5, "completed ZSTD_compressStream2");
4384     ZSTD_setBufferExpectations(cctx, output, input);
4385     return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
4386 }
4387 
ZSTD_compressStream2_simpleArgs(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,size_t * dstPos,const void * src,size_t srcSize,size_t * srcPos,ZSTD_EndDirective endOp)4388 size_t ZSTD_compressStream2_simpleArgs (
4389                             ZSTD_CCtx* cctx,
4390                             void* dst, size_t dstCapacity, size_t* dstPos,
4391                       const void* src, size_t srcSize, size_t* srcPos,
4392                             ZSTD_EndDirective endOp)
4393 {
4394     ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
4395     ZSTD_inBuffer  input  = { src, srcSize, *srcPos };
4396     /* ZSTD_compressStream2() will check validity of dstPos and srcPos */
4397     size_t const cErr = ZSTD_compressStream2(cctx, &output, &input, endOp);
4398     *dstPos = output.pos;
4399     *srcPos = input.pos;
4400     return cErr;
4401 }
4402 
ZSTD_compress2(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const void * src,size_t srcSize)4403 size_t ZSTD_compress2(ZSTD_CCtx* cctx,
4404                       void* dst, size_t dstCapacity,
4405                       const void* src, size_t srcSize)
4406 {
4407     ZSTD_bufferMode_e const originalInBufferMode = cctx->requestedParams.inBufferMode;
4408     ZSTD_bufferMode_e const originalOutBufferMode = cctx->requestedParams.outBufferMode;
4409     DEBUGLOG(4, "ZSTD_compress2 (srcSize=%u)", (unsigned)srcSize);
4410     ZSTD_CCtx_reset(cctx, ZSTD_reset_session_only);
4411     /* Enable stable input/output buffers. */
4412     cctx->requestedParams.inBufferMode = ZSTD_bm_stable;
4413     cctx->requestedParams.outBufferMode = ZSTD_bm_stable;
4414     {   size_t oPos = 0;
4415         size_t iPos = 0;
4416         size_t const result = ZSTD_compressStream2_simpleArgs(cctx,
4417                                         dst, dstCapacity, &oPos,
4418                                         src, srcSize, &iPos,
4419                                         ZSTD_e_end);
4420         /* Reset to the original values. */
4421         cctx->requestedParams.inBufferMode = originalInBufferMode;
4422         cctx->requestedParams.outBufferMode = originalOutBufferMode;
4423         FORWARD_IF_ERROR(result, "ZSTD_compressStream2_simpleArgs failed");
4424         if (result != 0) {  /* compression not completed, due to lack of output space */
4425             assert(oPos == dstCapacity);
4426             RETURN_ERROR(dstSize_tooSmall, "");
4427         }
4428         assert(iPos == srcSize);   /* all input is expected consumed */
4429         return oPos;
4430     }
4431 }
4432 
4433 typedef struct {
4434     U32 idx;             /* Index in array of ZSTD_Sequence */
4435     U32 posInSequence;   /* Position within sequence at idx */
4436     size_t posInSrc;        /* Number of bytes given by sequences provided so far */
4437 } ZSTD_sequencePosition;
4438 
4439 /* Returns a ZSTD error code if sequence is not valid */
ZSTD_validateSequence(U32 offCode,U32 matchLength,size_t posInSrc,U32 windowLog,size_t dictSize,U32 minMatch)4440 static size_t ZSTD_validateSequence(U32 offCode, U32 matchLength,
4441                                     size_t posInSrc, U32 windowLog, size_t dictSize, U32 minMatch) {
4442     size_t offsetBound;
4443     U32 windowSize = 1 << windowLog;
4444     /* posInSrc represents the amount of data the the decoder would decode up to this point.
4445      * As long as the amount of data decoded is less than or equal to window size, offsets may be
4446      * larger than the total length of output decoded in order to reference the dict, even larger than
4447      * window size. After output surpasses windowSize, we're limited to windowSize offsets again.
4448      */
4449     offsetBound = posInSrc > windowSize ? (size_t)windowSize : posInSrc + (size_t)dictSize;
4450     RETURN_ERROR_IF(offCode > offsetBound + ZSTD_REP_MOVE, corruption_detected, "Offset too large!");
4451     RETURN_ERROR_IF(matchLength < minMatch, corruption_detected, "Matchlength too small");
4452     return 0;
4453 }
4454 
4455 /* Returns an offset code, given a sequence's raw offset, the ongoing repcode array, and whether litLength == 0 */
ZSTD_finalizeOffCode(U32 rawOffset,const U32 rep[ZSTD_REP_NUM],U32 ll0)4456 static U32 ZSTD_finalizeOffCode(U32 rawOffset, const U32 rep[ZSTD_REP_NUM], U32 ll0) {
4457     U32 offCode = rawOffset + ZSTD_REP_MOVE;
4458     U32 repCode = 0;
4459 
4460     if (!ll0 && rawOffset == rep[0]) {
4461         repCode = 1;
4462     } else if (rawOffset == rep[1]) {
4463         repCode = 2 - ll0;
4464     } else if (rawOffset == rep[2]) {
4465         repCode = 3 - ll0;
4466     } else if (ll0 && rawOffset == rep[0] - 1) {
4467         repCode = 3;
4468     }
4469     if (repCode) {
4470         /* ZSTD_storeSeq expects a number in the range [0, 2] to represent a repcode */
4471         offCode = repCode - 1;
4472     }
4473     return offCode;
4474 }
4475 
4476 /* Returns 0 on success, and a ZSTD_error otherwise. This function scans through an array of
4477  * ZSTD_Sequence, storing the sequences it finds, until it reaches a block delimiter.
4478  */
ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx * cctx,ZSTD_sequencePosition * seqPos,const ZSTD_Sequence * const inSeqs,size_t inSeqsSize,const void * src,size_t blockSize)4479 static size_t ZSTD_copySequencesToSeqStoreExplicitBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos,
4480                                                              const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
4481                                                              const void* src, size_t blockSize) {
4482     U32 idx = seqPos->idx;
4483     BYTE const* ip = (BYTE const*)(src);
4484     const BYTE* const iend = ip + blockSize;
4485     repcodes_t updatedRepcodes;
4486     U32 dictSize;
4487     U32 litLength;
4488     U32 matchLength;
4489     U32 ll0;
4490     U32 offCode;
4491 
4492     if (cctx->cdict) {
4493         dictSize = (U32)cctx->cdict->dictContentSize;
4494     } else if (cctx->prefixDict.dict) {
4495         dictSize = (U32)cctx->prefixDict.dictSize;
4496     } else {
4497         dictSize = 0;
4498     }
4499     ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t));
4500     for (; (inSeqs[idx].matchLength != 0 || inSeqs[idx].offset != 0) && idx < inSeqsSize; ++idx) {
4501         litLength = inSeqs[idx].litLength;
4502         matchLength = inSeqs[idx].matchLength;
4503         ll0 = litLength == 0;
4504         offCode = ZSTD_finalizeOffCode(inSeqs[idx].offset, updatedRepcodes.rep, ll0);
4505         updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep, offCode, ll0);
4506 
4507         DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offCode, matchLength, litLength);
4508         if (cctx->appliedParams.validateSequences) {
4509             seqPos->posInSrc += litLength + matchLength;
4510             FORWARD_IF_ERROR(ZSTD_validateSequence(offCode, matchLength, seqPos->posInSrc,
4511                                                 cctx->appliedParams.cParams.windowLog, dictSize,
4512                                                 cctx->appliedParams.cParams.minMatch),
4513                                                 "Sequence validation failed");
4514         }
4515         RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation,
4516                         "Not enough memory allocated. Try adjusting ZSTD_c_minMatch.");
4517         ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offCode, matchLength - MINMATCH);
4518         ip += matchLength + litLength;
4519     }
4520     ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t));
4521 
4522     if (inSeqs[idx].litLength) {
4523         DEBUGLOG(6, "Storing last literals of size: %u", inSeqs[idx].litLength);
4524         ZSTD_storeLastLiterals(&cctx->seqStore, ip, inSeqs[idx].litLength);
4525         ip += inSeqs[idx].litLength;
4526         seqPos->posInSrc += inSeqs[idx].litLength;
4527     }
4528     RETURN_ERROR_IF(ip != iend, corruption_detected, "Blocksize doesn't agree with block delimiter!");
4529     seqPos->idx = idx+1;
4530     return 0;
4531 }
4532 
4533 /* Returns the number of bytes to move the current read position back by. Only non-zero
4534  * if we ended up splitting a sequence. Otherwise, it may return a ZSTD error if something
4535  * went wrong.
4536  *
4537  * This function will attempt to scan through blockSize bytes represented by the sequences
4538  * in inSeqs, storing any (partial) sequences.
4539  *
4540  * Occasionally, we may want to change the actual number of bytes we consumed from inSeqs to
4541  * avoid splitting a match, or to avoid splitting a match such that it would produce a match
4542  * smaller than MINMATCH. In this case, we return the number of bytes that we didn't read from this block.
4543  */
ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx * cctx,ZSTD_sequencePosition * seqPos,const ZSTD_Sequence * const inSeqs,size_t inSeqsSize,const void * src,size_t blockSize)4544 static size_t ZSTD_copySequencesToSeqStoreNoBlockDelim(ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos,
4545                                                        const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
4546                                                        const void* src, size_t blockSize) {
4547     U32 idx = seqPos->idx;
4548     U32 startPosInSequence = seqPos->posInSequence;
4549     U32 endPosInSequence = seqPos->posInSequence + (U32)blockSize;
4550     size_t dictSize;
4551     BYTE const* ip = (BYTE const*)(src);
4552     BYTE const* iend = ip + blockSize;  /* May be adjusted if we decide to process fewer than blockSize bytes */
4553     repcodes_t updatedRepcodes;
4554     U32 bytesAdjustment = 0;
4555     U32 finalMatchSplit = 0;
4556     U32 litLength;
4557     U32 matchLength;
4558     U32 rawOffset;
4559     U32 offCode;
4560 
4561     if (cctx->cdict) {
4562         dictSize = cctx->cdict->dictContentSize;
4563     } else if (cctx->prefixDict.dict) {
4564         dictSize = cctx->prefixDict.dictSize;
4565     } else {
4566         dictSize = 0;
4567     }
4568     DEBUGLOG(5, "ZSTD_copySequencesToSeqStore: idx: %u PIS: %u blockSize: %zu", idx, startPosInSequence, blockSize);
4569     DEBUGLOG(5, "Start seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength);
4570     ZSTD_memcpy(updatedRepcodes.rep, cctx->blockState.prevCBlock->rep, sizeof(repcodes_t));
4571     while (endPosInSequence && idx < inSeqsSize && !finalMatchSplit) {
4572         const ZSTD_Sequence currSeq = inSeqs[idx];
4573         litLength = currSeq.litLength;
4574         matchLength = currSeq.matchLength;
4575         rawOffset = currSeq.offset;
4576 
4577         /* Modify the sequence depending on where endPosInSequence lies */
4578         if (endPosInSequence >= currSeq.litLength + currSeq.matchLength) {
4579             if (startPosInSequence >= litLength) {
4580                 startPosInSequence -= litLength;
4581                 litLength = 0;
4582                 matchLength -= startPosInSequence;
4583             } else {
4584                 litLength -= startPosInSequence;
4585             }
4586             /* Move to the next sequence */
4587             endPosInSequence -= currSeq.litLength + currSeq.matchLength;
4588             startPosInSequence = 0;
4589             idx++;
4590         } else {
4591             /* This is the final (partial) sequence we're adding from inSeqs, and endPosInSequence
4592                does not reach the end of the match. So, we have to split the sequence */
4593             DEBUGLOG(6, "Require a split: diff: %u, idx: %u PIS: %u",
4594                      currSeq.litLength + currSeq.matchLength - endPosInSequence, idx, endPosInSequence);
4595             if (endPosInSequence > litLength) {
4596                 U32 firstHalfMatchLength;
4597                 litLength = startPosInSequence >= litLength ? 0 : litLength - startPosInSequence;
4598                 firstHalfMatchLength = endPosInSequence - startPosInSequence - litLength;
4599                 if (matchLength > blockSize && firstHalfMatchLength >= cctx->appliedParams.cParams.minMatch) {
4600                     /* Only ever split the match if it is larger than the block size */
4601                     U32 secondHalfMatchLength = currSeq.matchLength + currSeq.litLength - endPosInSequence;
4602                     if (secondHalfMatchLength < cctx->appliedParams.cParams.minMatch) {
4603                         /* Move the endPosInSequence backward so that it creates match of minMatch length */
4604                         endPosInSequence -= cctx->appliedParams.cParams.minMatch - secondHalfMatchLength;
4605                         bytesAdjustment = cctx->appliedParams.cParams.minMatch - secondHalfMatchLength;
4606                         firstHalfMatchLength -= bytesAdjustment;
4607                     }
4608                     matchLength = firstHalfMatchLength;
4609                     /* Flag that we split the last match - after storing the sequence, exit the loop,
4610                        but keep the value of endPosInSequence */
4611                     finalMatchSplit = 1;
4612                 } else {
4613                     /* Move the position in sequence backwards so that we don't split match, and break to store
4614                      * the last literals. We use the original currSeq.litLength as a marker for where endPosInSequence
4615                      * should go. We prefer to do this whenever it is not necessary to split the match, or if doing so
4616                      * would cause the first half of the match to be too small
4617                      */
4618                     bytesAdjustment = endPosInSequence - currSeq.litLength;
4619                     endPosInSequence = currSeq.litLength;
4620                     break;
4621                 }
4622             } else {
4623                 /* This sequence ends inside the literals, break to store the last literals */
4624                 break;
4625             }
4626         }
4627         /* Check if this offset can be represented with a repcode */
4628         {   U32 ll0 = (litLength == 0);
4629             offCode = ZSTD_finalizeOffCode(rawOffset, updatedRepcodes.rep, ll0);
4630             updatedRepcodes = ZSTD_updateRep(updatedRepcodes.rep, offCode, ll0);
4631         }
4632 
4633         if (cctx->appliedParams.validateSequences) {
4634             seqPos->posInSrc += litLength + matchLength;
4635             FORWARD_IF_ERROR(ZSTD_validateSequence(offCode, matchLength, seqPos->posInSrc,
4636                                                    cctx->appliedParams.cParams.windowLog, dictSize,
4637                                                    cctx->appliedParams.cParams.minMatch),
4638                                                    "Sequence validation failed");
4639         }
4640         DEBUGLOG(6, "Storing sequence: (of: %u, ml: %u, ll: %u)", offCode, matchLength, litLength);
4641         RETURN_ERROR_IF(idx - seqPos->idx > cctx->seqStore.maxNbSeq, memory_allocation,
4642                         "Not enough memory allocated. Try adjusting ZSTD_c_minMatch.");
4643         ZSTD_storeSeq(&cctx->seqStore, litLength, ip, iend, offCode, matchLength - MINMATCH);
4644         ip += matchLength + litLength;
4645     }
4646     DEBUGLOG(5, "Ending seq: idx: %u (of: %u ml: %u ll: %u)", idx, inSeqs[idx].offset, inSeqs[idx].matchLength, inSeqs[idx].litLength);
4647     assert(idx == inSeqsSize || endPosInSequence <= inSeqs[idx].litLength + inSeqs[idx].matchLength);
4648     seqPos->idx = idx;
4649     seqPos->posInSequence = endPosInSequence;
4650     ZSTD_memcpy(cctx->blockState.nextCBlock->rep, updatedRepcodes.rep, sizeof(repcodes_t));
4651 
4652     iend -= bytesAdjustment;
4653     if (ip != iend) {
4654         /* Store any last literals */
4655         U32 lastLLSize = (U32)(iend - ip);
4656         assert(ip <= iend);
4657         DEBUGLOG(6, "Storing last literals of size: %u", lastLLSize);
4658         ZSTD_storeLastLiterals(&cctx->seqStore, ip, lastLLSize);
4659         seqPos->posInSrc += lastLLSize;
4660     }
4661 
4662     return bytesAdjustment;
4663 }
4664 
4665 typedef size_t (*ZSTD_sequenceCopier) (ZSTD_CCtx* cctx, ZSTD_sequencePosition* seqPos,
4666                                        const ZSTD_Sequence* const inSeqs, size_t inSeqsSize,
4667                                        const void* src, size_t blockSize);
ZSTD_selectSequenceCopier(ZSTD_sequenceFormat_e mode)4668 static ZSTD_sequenceCopier ZSTD_selectSequenceCopier(ZSTD_sequenceFormat_e mode) {
4669     ZSTD_sequenceCopier sequenceCopier = NULL;
4670     assert(ZSTD_cParam_withinBounds(ZSTD_c_blockDelimiters, mode));
4671     if (mode == ZSTD_sf_explicitBlockDelimiters) {
4672         return ZSTD_copySequencesToSeqStoreExplicitBlockDelim;
4673     } else if (mode == ZSTD_sf_noBlockDelimiters) {
4674         return ZSTD_copySequencesToSeqStoreNoBlockDelim;
4675     }
4676     assert(sequenceCopier != NULL);
4677     return sequenceCopier;
4678 }
4679 
4680 /* Compress, block-by-block, all of the sequences given.
4681  *
4682  * Returns the cumulative size of all compressed blocks (including their headers), otherwise a ZSTD error.
4683  */
ZSTD_compressSequences_internal(ZSTD_CCtx * cctx,void * dst,size_t dstCapacity,const ZSTD_Sequence * inSeqs,size_t inSeqsSize,const void * src,size_t srcSize)4684 static size_t ZSTD_compressSequences_internal(ZSTD_CCtx* cctx,
4685                                               void* dst, size_t dstCapacity,
4686                                               const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
4687                                               const void* src, size_t srcSize) {
4688     size_t cSize = 0;
4689     U32 lastBlock;
4690     size_t blockSize;
4691     size_t compressedSeqsSize;
4692     size_t remaining = srcSize;
4693     ZSTD_sequencePosition seqPos = {0, 0, 0};
4694 
4695     BYTE const* ip = (BYTE const*)src;
4696     BYTE* op = (BYTE*)dst;
4697     ZSTD_sequenceCopier sequenceCopier = ZSTD_selectSequenceCopier(cctx->appliedParams.blockDelimiters);
4698 
4699     DEBUGLOG(4, "ZSTD_compressSequences_internal srcSize: %zu, inSeqsSize: %zu", srcSize, inSeqsSize);
4700     /* Special case: empty frame */
4701     if (remaining == 0) {
4702         U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1);
4703         RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "No room for empty frame block header");
4704         MEM_writeLE32(op, cBlockHeader24);
4705         op += ZSTD_blockHeaderSize;
4706         dstCapacity -= ZSTD_blockHeaderSize;
4707         cSize += ZSTD_blockHeaderSize;
4708     }
4709 
4710     while (remaining) {
4711         size_t cBlockSize;
4712         size_t additionalByteAdjustment;
4713         lastBlock = remaining <= cctx->blockSize;
4714         blockSize = lastBlock ? (U32)remaining : (U32)cctx->blockSize;
4715         ZSTD_resetSeqStore(&cctx->seqStore);
4716         DEBUGLOG(4, "Working on new block. Blocksize: %zu", blockSize);
4717 
4718         additionalByteAdjustment = sequenceCopier(cctx, &seqPos, inSeqs, inSeqsSize, ip, blockSize);
4719         FORWARD_IF_ERROR(additionalByteAdjustment, "Bad sequence copy");
4720         blockSize -= additionalByteAdjustment;
4721 
4722         /* If blocks are too small, emit as a nocompress block */
4723         if (blockSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
4724             cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
4725             FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed");
4726             DEBUGLOG(4, "Block too small, writing out nocompress block: cSize: %zu", cBlockSize);
4727             cSize += cBlockSize;
4728             ip += blockSize;
4729             op += cBlockSize;
4730             remaining -= blockSize;
4731             dstCapacity -= cBlockSize;
4732             continue;
4733         }
4734 
4735         compressedSeqsSize = ZSTD_entropyCompressSequences(&cctx->seqStore,
4736                                 &cctx->blockState.prevCBlock->entropy, &cctx->blockState.nextCBlock->entropy,
4737                                 &cctx->appliedParams,
4738                                 op + ZSTD_blockHeaderSize /* Leave space for block header */, dstCapacity - ZSTD_blockHeaderSize,
4739                                 blockSize,
4740                                 cctx->entropyWorkspace, ENTROPY_WORKSPACE_SIZE /* statically allocated in resetCCtx */,
4741                                 cctx->bmi2);
4742         FORWARD_IF_ERROR(compressedSeqsSize, "Compressing sequences of block failed");
4743         DEBUGLOG(4, "Compressed sequences size: %zu", compressedSeqsSize);
4744 
4745         if (!cctx->isFirstBlock &&
4746             ZSTD_maybeRLE(&cctx->seqStore) &&
4747             ZSTD_isRLE((BYTE const*)src, srcSize)) {
4748             /* We don't want to emit our first block as a RLE even if it qualifies because
4749             * doing so will cause the decoder (cli only) to throw a "should consume all input error."
4750             * This is only an issue for zstd <= v1.4.3
4751             */
4752             compressedSeqsSize = 1;
4753         }
4754 
4755         if (compressedSeqsSize == 0) {
4756             /* ZSTD_noCompressBlock writes the block header as well */
4757             cBlockSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize, lastBlock);
4758             FORWARD_IF_ERROR(cBlockSize, "Nocompress block failed");
4759             DEBUGLOG(4, "Writing out nocompress block, size: %zu", cBlockSize);
4760         } else if (compressedSeqsSize == 1) {
4761             cBlockSize = ZSTD_rleCompressBlock(op, dstCapacity, *ip, blockSize, lastBlock);
4762             FORWARD_IF_ERROR(cBlockSize, "RLE compress block failed");
4763             DEBUGLOG(4, "Writing out RLE block, size: %zu", cBlockSize);
4764         } else {
4765             U32 cBlockHeader;
4766             /* Error checking and repcodes update */
4767             ZSTD_confirmRepcodesAndEntropyTables(cctx);
4768             if (cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode == FSE_repeat_valid)
4769                 cctx->blockState.prevCBlock->entropy.fse.offcode_repeatMode = FSE_repeat_check;
4770 
4771             /* Write block header into beginning of block*/
4772             cBlockHeader = lastBlock + (((U32)bt_compressed)<<1) + (U32)(compressedSeqsSize << 3);
4773             MEM_writeLE24(op, cBlockHeader);
4774             cBlockSize = ZSTD_blockHeaderSize + compressedSeqsSize;
4775             DEBUGLOG(4, "Writing out compressed block, size: %zu", cBlockSize);
4776         }
4777 
4778         cSize += cBlockSize;
4779         DEBUGLOG(4, "cSize running total: %zu", cSize);
4780 
4781         if (lastBlock) {
4782             break;
4783         } else {
4784             ip += blockSize;
4785             op += cBlockSize;
4786             remaining -= blockSize;
4787             dstCapacity -= cBlockSize;
4788             cctx->isFirstBlock = 0;
4789         }
4790     }
4791 
4792     return cSize;
4793 }
4794 
ZSTD_compressSequences(ZSTD_CCtx * const cctx,void * dst,size_t dstCapacity,const ZSTD_Sequence * inSeqs,size_t inSeqsSize,const void * src,size_t srcSize)4795 size_t ZSTD_compressSequences(ZSTD_CCtx* const cctx, void* dst, size_t dstCapacity,
4796                               const ZSTD_Sequence* inSeqs, size_t inSeqsSize,
4797                               const void* src, size_t srcSize) {
4798     BYTE* op = (BYTE*)dst;
4799     size_t cSize = 0;
4800     size_t compressedBlocksSize = 0;
4801     size_t frameHeaderSize = 0;
4802 
4803     /* Transparent initialization stage, same as compressStream2() */
4804     DEBUGLOG(3, "ZSTD_compressSequences()");
4805     assert(cctx != NULL);
4806     FORWARD_IF_ERROR(ZSTD_CCtx_init_compressStream2(cctx, ZSTD_e_end, srcSize), "CCtx initialization failed");
4807     /* Begin writing output, starting with frame header */
4808     frameHeaderSize = ZSTD_writeFrameHeader(op, dstCapacity, &cctx->appliedParams, srcSize, cctx->dictID);
4809     op += frameHeaderSize;
4810     dstCapacity -= frameHeaderSize;
4811     cSize += frameHeaderSize;
4812     if (cctx->appliedParams.fParams.checksumFlag && srcSize) {
4813         xxh64_update(&cctx->xxhState, src, srcSize);
4814     }
4815     /* cSize includes block header size and compressed sequences size */
4816     compressedBlocksSize = ZSTD_compressSequences_internal(cctx,
4817                                                            op, dstCapacity,
4818                                                            inSeqs, inSeqsSize,
4819                                                            src, srcSize);
4820     FORWARD_IF_ERROR(compressedBlocksSize, "Compressing blocks failed!");
4821     cSize += compressedBlocksSize;
4822     dstCapacity -= compressedBlocksSize;
4823 
4824     if (cctx->appliedParams.fParams.checksumFlag) {
4825         U32 const checksum = (U32) xxh64_digest(&cctx->xxhState);
4826         RETURN_ERROR_IF(dstCapacity<4, dstSize_tooSmall, "no room for checksum");
4827         DEBUGLOG(4, "Write checksum : %08X", (unsigned)checksum);
4828         MEM_writeLE32((char*)dst + cSize, checksum);
4829         cSize += 4;
4830     }
4831 
4832     DEBUGLOG(3, "Final compressed size: %zu", cSize);
4833     return cSize;
4834 }
4835 
4836 /*======   Finalize   ======*/
4837 
4838 /*! ZSTD_flushStream() :
4839  * @return : amount of data remaining to flush */
ZSTD_flushStream(ZSTD_CStream * zcs,ZSTD_outBuffer * output)4840 size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
4841 {
4842     ZSTD_inBuffer input = { NULL, 0, 0 };
4843     return ZSTD_compressStream2(zcs, output, &input, ZSTD_e_flush);
4844 }
4845 
4846 
ZSTD_endStream(ZSTD_CStream * zcs,ZSTD_outBuffer * output)4847 size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
4848 {
4849     ZSTD_inBuffer input = { NULL, 0, 0 };
4850     size_t const remainingToFlush = ZSTD_compressStream2(zcs, output, &input, ZSTD_e_end);
4851     FORWARD_IF_ERROR( remainingToFlush , "ZSTD_compressStream2 failed");
4852     if (zcs->appliedParams.nbWorkers > 0) return remainingToFlush;   /* minimal estimation */
4853     /* single thread mode : attempt to calculate remaining to flush more precisely */
4854     {   size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE;
4855         size_t const checksumSize = (size_t)(zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4);
4856         size_t const toFlush = remainingToFlush + lastBlockSize + checksumSize;
4857         DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (unsigned)toFlush);
4858         return toFlush;
4859     }
4860 }
4861 
4862 
4863 /*-=====  Pre-defined compression levels  =====-*/
4864 
4865 #define ZSTD_MAX_CLEVEL     22
ZSTD_maxCLevel(void)4866 int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
ZSTD_minCLevel(void)4867 int ZSTD_minCLevel(void) { return (int)-ZSTD_TARGETLENGTH_MAX; }
4868 
4869 static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
4870 {   /* "default" - for any srcSize > 256 KB */
4871     /* W,  C,  H,  S,  L, TL, strat */
4872     { 19, 12, 13,  1,  6,  1, ZSTD_fast    },  /* base for negative levels */
4873     { 19, 13, 14,  1,  7,  0, ZSTD_fast    },  /* level  1 */
4874     { 20, 15, 16,  1,  6,  0, ZSTD_fast    },  /* level  2 */
4875     { 21, 16, 17,  1,  5,  0, ZSTD_dfast   },  /* level  3 */
4876     { 21, 18, 18,  1,  5,  0, ZSTD_dfast   },  /* level  4 */
4877     { 21, 18, 19,  2,  5,  2, ZSTD_greedy  },  /* level  5 */
4878     { 21, 19, 19,  3,  5,  4, ZSTD_greedy  },  /* level  6 */
4879     { 21, 19, 19,  3,  5,  8, ZSTD_lazy    },  /* level  7 */
4880     { 21, 19, 19,  3,  5, 16, ZSTD_lazy2   },  /* level  8 */
4881     { 21, 19, 20,  4,  5, 16, ZSTD_lazy2   },  /* level  9 */
4882     { 22, 20, 21,  4,  5, 16, ZSTD_lazy2   },  /* level 10 */
4883     { 22, 21, 22,  4,  5, 16, ZSTD_lazy2   },  /* level 11 */
4884     { 22, 21, 22,  5,  5, 16, ZSTD_lazy2   },  /* level 12 */
4885     { 22, 21, 22,  5,  5, 32, ZSTD_btlazy2 },  /* level 13 */
4886     { 22, 22, 23,  5,  5, 32, ZSTD_btlazy2 },  /* level 14 */
4887     { 22, 23, 23,  6,  5, 32, ZSTD_btlazy2 },  /* level 15 */
4888     { 22, 22, 22,  5,  5, 48, ZSTD_btopt   },  /* level 16 */
4889     { 23, 23, 22,  5,  4, 64, ZSTD_btopt   },  /* level 17 */
4890     { 23, 23, 22,  6,  3, 64, ZSTD_btultra },  /* level 18 */
4891     { 23, 24, 22,  7,  3,256, ZSTD_btultra2},  /* level 19 */
4892     { 25, 25, 23,  7,  3,256, ZSTD_btultra2},  /* level 20 */
4893     { 26, 26, 24,  7,  3,512, ZSTD_btultra2},  /* level 21 */
4894     { 27, 27, 25,  9,  3,999, ZSTD_btultra2},  /* level 22 */
4895 },
4896 {   /* for srcSize <= 256 KB */
4897     /* W,  C,  H,  S,  L,  T, strat */
4898     { 18, 12, 13,  1,  5,  1, ZSTD_fast    },  /* base for negative levels */
4899     { 18, 13, 14,  1,  6,  0, ZSTD_fast    },  /* level  1 */
4900     { 18, 14, 14,  1,  5,  0, ZSTD_dfast   },  /* level  2 */
4901     { 18, 16, 16,  1,  4,  0, ZSTD_dfast   },  /* level  3 */
4902     { 18, 16, 17,  2,  5,  2, ZSTD_greedy  },  /* level  4.*/
4903     { 18, 18, 18,  3,  5,  2, ZSTD_greedy  },  /* level  5.*/
4904     { 18, 18, 19,  3,  5,  4, ZSTD_lazy    },  /* level  6.*/
4905     { 18, 18, 19,  4,  4,  4, ZSTD_lazy    },  /* level  7 */
4906     { 18, 18, 19,  4,  4,  8, ZSTD_lazy2   },  /* level  8 */
4907     { 18, 18, 19,  5,  4,  8, ZSTD_lazy2   },  /* level  9 */
4908     { 18, 18, 19,  6,  4,  8, ZSTD_lazy2   },  /* level 10 */
4909     { 18, 18, 19,  5,  4, 12, ZSTD_btlazy2 },  /* level 11.*/
4910     { 18, 19, 19,  7,  4, 12, ZSTD_btlazy2 },  /* level 12.*/
4911     { 18, 18, 19,  4,  4, 16, ZSTD_btopt   },  /* level 13 */
4912     { 18, 18, 19,  4,  3, 32, ZSTD_btopt   },  /* level 14.*/
4913     { 18, 18, 19,  6,  3,128, ZSTD_btopt   },  /* level 15.*/
4914     { 18, 19, 19,  6,  3,128, ZSTD_btultra },  /* level 16.*/
4915     { 18, 19, 19,  8,  3,256, ZSTD_btultra },  /* level 17.*/
4916     { 18, 19, 19,  6,  3,128, ZSTD_btultra2},  /* level 18.*/
4917     { 18, 19, 19,  8,  3,256, ZSTD_btultra2},  /* level 19.*/
4918     { 18, 19, 19, 10,  3,512, ZSTD_btultra2},  /* level 20.*/
4919     { 18, 19, 19, 12,  3,512, ZSTD_btultra2},  /* level 21.*/
4920     { 18, 19, 19, 13,  3,999, ZSTD_btultra2},  /* level 22.*/
4921 },
4922 {   /* for srcSize <= 128 KB */
4923     /* W,  C,  H,  S,  L,  T, strat */
4924     { 17, 12, 12,  1,  5,  1, ZSTD_fast    },  /* base for negative levels */
4925     { 17, 12, 13,  1,  6,  0, ZSTD_fast    },  /* level  1 */
4926     { 17, 13, 15,  1,  5,  0, ZSTD_fast    },  /* level  2 */
4927     { 17, 15, 16,  2,  5,  0, ZSTD_dfast   },  /* level  3 */
4928     { 17, 17, 17,  2,  4,  0, ZSTD_dfast   },  /* level  4 */
4929     { 17, 16, 17,  3,  4,  2, ZSTD_greedy  },  /* level  5 */
4930     { 17, 17, 17,  3,  4,  4, ZSTD_lazy    },  /* level  6 */
4931     { 17, 17, 17,  3,  4,  8, ZSTD_lazy2   },  /* level  7 */
4932     { 17, 17, 17,  4,  4,  8, ZSTD_lazy2   },  /* level  8 */
4933     { 17, 17, 17,  5,  4,  8, ZSTD_lazy2   },  /* level  9 */
4934     { 17, 17, 17,  6,  4,  8, ZSTD_lazy2   },  /* level 10 */
4935     { 17, 17, 17,  5,  4,  8, ZSTD_btlazy2 },  /* level 11 */
4936     { 17, 18, 17,  7,  4, 12, ZSTD_btlazy2 },  /* level 12 */
4937     { 17, 18, 17,  3,  4, 12, ZSTD_btopt   },  /* level 13.*/
4938     { 17, 18, 17,  4,  3, 32, ZSTD_btopt   },  /* level 14.*/
4939     { 17, 18, 17,  6,  3,256, ZSTD_btopt   },  /* level 15.*/
4940     { 17, 18, 17,  6,  3,128, ZSTD_btultra },  /* level 16.*/
4941     { 17, 18, 17,  8,  3,256, ZSTD_btultra },  /* level 17.*/
4942     { 17, 18, 17, 10,  3,512, ZSTD_btultra },  /* level 18.*/
4943     { 17, 18, 17,  5,  3,256, ZSTD_btultra2},  /* level 19.*/
4944     { 17, 18, 17,  7,  3,512, ZSTD_btultra2},  /* level 20.*/
4945     { 17, 18, 17,  9,  3,512, ZSTD_btultra2},  /* level 21.*/
4946     { 17, 18, 17, 11,  3,999, ZSTD_btultra2},  /* level 22.*/
4947 },
4948 {   /* for srcSize <= 16 KB */
4949     /* W,  C,  H,  S,  L,  T, strat */
4950     { 14, 12, 13,  1,  5,  1, ZSTD_fast    },  /* base for negative levels */
4951     { 14, 14, 15,  1,  5,  0, ZSTD_fast    },  /* level  1 */
4952     { 14, 14, 15,  1,  4,  0, ZSTD_fast    },  /* level  2 */
4953     { 14, 14, 15,  2,  4,  0, ZSTD_dfast   },  /* level  3 */
4954     { 14, 14, 14,  4,  4,  2, ZSTD_greedy  },  /* level  4 */
4955     { 14, 14, 14,  3,  4,  4, ZSTD_lazy    },  /* level  5.*/
4956     { 14, 14, 14,  4,  4,  8, ZSTD_lazy2   },  /* level  6 */
4957     { 14, 14, 14,  6,  4,  8, ZSTD_lazy2   },  /* level  7 */
4958     { 14, 14, 14,  8,  4,  8, ZSTD_lazy2   },  /* level  8.*/
4959     { 14, 15, 14,  5,  4,  8, ZSTD_btlazy2 },  /* level  9.*/
4960     { 14, 15, 14,  9,  4,  8, ZSTD_btlazy2 },  /* level 10.*/
4961     { 14, 15, 14,  3,  4, 12, ZSTD_btopt   },  /* level 11.*/
4962     { 14, 15, 14,  4,  3, 24, ZSTD_btopt   },  /* level 12.*/
4963     { 14, 15, 14,  5,  3, 32, ZSTD_btultra },  /* level 13.*/
4964     { 14, 15, 15,  6,  3, 64, ZSTD_btultra },  /* level 14.*/
4965     { 14, 15, 15,  7,  3,256, ZSTD_btultra },  /* level 15.*/
4966     { 14, 15, 15,  5,  3, 48, ZSTD_btultra2},  /* level 16.*/
4967     { 14, 15, 15,  6,  3,128, ZSTD_btultra2},  /* level 17.*/
4968     { 14, 15, 15,  7,  3,256, ZSTD_btultra2},  /* level 18.*/
4969     { 14, 15, 15,  8,  3,256, ZSTD_btultra2},  /* level 19.*/
4970     { 14, 15, 15,  8,  3,512, ZSTD_btultra2},  /* level 20.*/
4971     { 14, 15, 15,  9,  3,512, ZSTD_btultra2},  /* level 21.*/
4972     { 14, 15, 15, 10,  3,999, ZSTD_btultra2},  /* level 22.*/
4973 },
4974 };
4975 
ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel,size_t const dictSize)4976 static ZSTD_compressionParameters ZSTD_dedicatedDictSearch_getCParams(int const compressionLevel, size_t const dictSize)
4977 {
4978     ZSTD_compressionParameters cParams = ZSTD_getCParams_internal(compressionLevel, 0, dictSize, ZSTD_cpm_createCDict);
4979     switch (cParams.strategy) {
4980         case ZSTD_fast:
4981         case ZSTD_dfast:
4982             break;
4983         case ZSTD_greedy:
4984         case ZSTD_lazy:
4985         case ZSTD_lazy2:
4986             cParams.hashLog += ZSTD_LAZY_DDSS_BUCKET_LOG;
4987             break;
4988         case ZSTD_btlazy2:
4989         case ZSTD_btopt:
4990         case ZSTD_btultra:
4991         case ZSTD_btultra2:
4992             break;
4993     }
4994     return cParams;
4995 }
4996 
ZSTD_dedicatedDictSearch_isSupported(ZSTD_compressionParameters const * cParams)4997 static int ZSTD_dedicatedDictSearch_isSupported(
4998         ZSTD_compressionParameters const* cParams)
4999 {
5000     return (cParams->strategy >= ZSTD_greedy)
5001         && (cParams->strategy <= ZSTD_lazy2)
5002         && (cParams->hashLog >= cParams->chainLog)
5003         && (cParams->chainLog <= 24);
5004 }
5005 
5006 /*
5007  * Reverses the adjustment applied to cparams when enabling dedicated dict
5008  * search. This is used to recover the params set to be used in the working
5009  * context. (Otherwise, those tables would also grow.)
5010  */
ZSTD_dedicatedDictSearch_revertCParams(ZSTD_compressionParameters * cParams)5011 static void ZSTD_dedicatedDictSearch_revertCParams(
5012         ZSTD_compressionParameters* cParams) {
5013     switch (cParams->strategy) {
5014         case ZSTD_fast:
5015         case ZSTD_dfast:
5016             break;
5017         case ZSTD_greedy:
5018         case ZSTD_lazy:
5019         case ZSTD_lazy2:
5020             cParams->hashLog -= ZSTD_LAZY_DDSS_BUCKET_LOG;
5021             break;
5022         case ZSTD_btlazy2:
5023         case ZSTD_btopt:
5024         case ZSTD_btultra:
5025         case ZSTD_btultra2:
5026             break;
5027     }
5028 }
5029 
ZSTD_getCParamRowSize(U64 srcSizeHint,size_t dictSize,ZSTD_cParamMode_e mode)5030 static U64 ZSTD_getCParamRowSize(U64 srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode)
5031 {
5032     switch (mode) {
5033     case ZSTD_cpm_unknown:
5034     case ZSTD_cpm_noAttachDict:
5035     case ZSTD_cpm_createCDict:
5036         break;
5037     case ZSTD_cpm_attachDict:
5038         dictSize = 0;
5039         break;
5040     default:
5041         assert(0);
5042         break;
5043     }
5044     {   int const unknown = srcSizeHint == ZSTD_CONTENTSIZE_UNKNOWN;
5045         size_t const addedSize = unknown && dictSize > 0 ? 500 : 0;
5046         return unknown && dictSize == 0 ? ZSTD_CONTENTSIZE_UNKNOWN : srcSizeHint+dictSize+addedSize;
5047     }
5048 }
5049 
5050 /*! ZSTD_getCParams_internal() :
5051  * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
5052  *  Note: srcSizeHint 0 means 0, use ZSTD_CONTENTSIZE_UNKNOWN for unknown.
5053  *        Use dictSize == 0 for unknown or unused.
5054  *  Note: `mode` controls how we treat the `dictSize`. See docs for `ZSTD_cParamMode_e`. */
ZSTD_getCParams_internal(int compressionLevel,unsigned long long srcSizeHint,size_t dictSize,ZSTD_cParamMode_e mode)5055 static ZSTD_compressionParameters ZSTD_getCParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode)
5056 {
5057     U64 const rSize = ZSTD_getCParamRowSize(srcSizeHint, dictSize, mode);
5058     U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB);
5059     int row;
5060     DEBUGLOG(5, "ZSTD_getCParams_internal (cLevel=%i)", compressionLevel);
5061 
5062     /* row */
5063     if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT;   /* 0 == default */
5064     else if (compressionLevel < 0) row = 0;   /* entry 0 is baseline for fast mode */
5065     else if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL;
5066     else row = compressionLevel;
5067 
5068     {   ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
5069         /* acceleration factor */
5070         if (compressionLevel < 0) {
5071             int const clampedCompressionLevel = MAX(ZSTD_minCLevel(), compressionLevel);
5072             cp.targetLength = (unsigned)(-clampedCompressionLevel);
5073         }
5074         /* refine parameters based on srcSize & dictSize */
5075         return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize, mode);
5076     }
5077 }
5078 
5079 /*! ZSTD_getCParams() :
5080  * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
5081  *  Size values are optional, provide 0 if not known or unused */
ZSTD_getCParams(int compressionLevel,unsigned long long srcSizeHint,size_t dictSize)5082 ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
5083 {
5084     if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
5085     return ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown);
5086 }
5087 
5088 /*! ZSTD_getParams() :
5089  *  same idea as ZSTD_getCParams()
5090  * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`).
5091  *  Fields of `ZSTD_frameParameters` are set to default values */
ZSTD_getParams_internal(int compressionLevel,unsigned long long srcSizeHint,size_t dictSize,ZSTD_cParamMode_e mode)5092 static ZSTD_parameters ZSTD_getParams_internal(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize, ZSTD_cParamMode_e mode) {
5093     ZSTD_parameters params;
5094     ZSTD_compressionParameters const cParams = ZSTD_getCParams_internal(compressionLevel, srcSizeHint, dictSize, mode);
5095     DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel);
5096     ZSTD_memset(&params, 0, sizeof(params));
5097     params.cParams = cParams;
5098     params.fParams.contentSizeFlag = 1;
5099     return params;
5100 }
5101 
5102 /*! ZSTD_getParams() :
5103  *  same idea as ZSTD_getCParams()
5104  * @return a `ZSTD_parameters` structure (instead of `ZSTD_compressionParameters`).
5105  *  Fields of `ZSTD_frameParameters` are set to default values */
ZSTD_getParams(int compressionLevel,unsigned long long srcSizeHint,size_t dictSize)5106 ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
5107     if (srcSizeHint == 0) srcSizeHint = ZSTD_CONTENTSIZE_UNKNOWN;
5108     return ZSTD_getParams_internal(compressionLevel, srcSizeHint, dictSize, ZSTD_cpm_unknown);
5109 }
5110