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