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