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