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