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