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