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