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