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