blob: 2e163c8bf3d4ef7def8c505ff45c9d9ed5501024 [file] [log] [blame]
William Kurkianea869482019-04-09 15:16:11 -04001/*
2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under both the BSD-style license (found in the
6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7 * in the COPYING file in the root directory of this source tree).
8 * You may select, at your option, one of the above-listed licenses.
9 */
10
William Kurkianea869482019-04-09 15:16:11 -040011/*-*************************************
12* Dependencies
13***************************************/
Abhilash S.L3b494632019-07-16 15:51:09 +053014#include <limits.h> /* INT_MAX */
William Kurkianea869482019-04-09 15:16:11 -040015#include <string.h> /* memset */
16#include "cpu.h"
17#include "mem.h"
Abhilash S.L3b494632019-07-16 15:51:09 +053018#include "hist.h" /* HIST_countFast_wksp */
William Kurkianea869482019-04-09 15:16:11 -040019#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
20#include "fse.h"
21#define HUF_STATIC_LINKING_ONLY
22#include "huf.h"
23#include "zstd_compress_internal.h"
24#include "zstd_fast.h"
25#include "zstd_double_fast.h"
26#include "zstd_lazy.h"
27#include "zstd_opt.h"
28#include "zstd_ldm.h"
29
30
31/*-*************************************
32* Helper functions
33***************************************/
34size_t ZSTD_compressBound(size_t srcSize) {
35 return ZSTD_COMPRESSBOUND(srcSize);
36}
37
38
39/*-*************************************
40* Context memory management
41***************************************/
42struct ZSTD_CDict_s {
43 void* dictBuffer;
44 const void* dictContent;
45 size_t dictContentSize;
46 void* workspace;
47 size_t workspaceSize;
48 ZSTD_matchState_t matchState;
49 ZSTD_compressedBlockState_t cBlockState;
William Kurkianea869482019-04-09 15:16:11 -040050 ZSTD_customMem customMem;
51 U32 dictID;
52}; /* typedef'd to ZSTD_CDict within "zstd.h" */
53
54ZSTD_CCtx* ZSTD_createCCtx(void)
55{
56 return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
57}
58
Abhilash S.L3b494632019-07-16 15:51:09 +053059static void ZSTD_initCCtx(ZSTD_CCtx* cctx, ZSTD_customMem memManager)
60{
61 assert(cctx != NULL);
62 memset(cctx, 0, sizeof(*cctx));
63 cctx->customMem = memManager;
64 cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
65 { size_t const err = ZSTD_CCtx_reset(cctx, ZSTD_reset_parameters);
66 assert(!ZSTD_isError(err));
67 (void)err;
68 }
69}
70
William Kurkianea869482019-04-09 15:16:11 -040071ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
72{
73 ZSTD_STATIC_ASSERT(zcss_init==0);
74 ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
75 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
Abhilash S.L3b494632019-07-16 15:51:09 +053076 { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
William Kurkianea869482019-04-09 15:16:11 -040077 if (!cctx) return NULL;
Abhilash S.L3b494632019-07-16 15:51:09 +053078 ZSTD_initCCtx(cctx, customMem);
William Kurkianea869482019-04-09 15:16:11 -040079 return cctx;
80 }
81}
82
83ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
84{
85 ZSTD_CCtx* const cctx = (ZSTD_CCtx*) workspace;
86 if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
87 if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
88 memset(workspace, 0, workspaceSize); /* may be a bit generous, could memset be smaller ? */
89 cctx->staticSize = workspaceSize;
90 cctx->workSpace = (void*)(cctx+1);
91 cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
92
93 /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
94 if (cctx->workSpaceSize < HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t)) return NULL;
95 assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */
96 cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)cctx->workSpace;
97 cctx->blockState.nextCBlock = cctx->blockState.prevCBlock + 1;
98 {
99 void* const ptr = cctx->blockState.nextCBlock + 1;
100 cctx->entropyWorkspace = (U32*)ptr;
101 }
102 cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
103 return cctx;
104}
105
Abhilash S.L3b494632019-07-16 15:51:09 +0530106/**
107 * Clears and frees all of the dictionaries in the CCtx.
108 */
109static void ZSTD_clearAllDicts(ZSTD_CCtx* cctx)
William Kurkianea869482019-04-09 15:16:11 -0400110{
Abhilash S.L3b494632019-07-16 15:51:09 +0530111 ZSTD_free(cctx->localDict.dictBuffer, cctx->customMem);
112 ZSTD_freeCDict(cctx->localDict.cdict);
113 memset(&cctx->localDict, 0, sizeof(cctx->localDict));
114 memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict));
115 cctx->cdict = NULL;
116}
117
118static size_t ZSTD_sizeof_localDict(ZSTD_localDict dict)
119{
120 size_t const bufferSize = dict.dictBuffer != NULL ? dict.dictSize : 0;
121 size_t const cdictSize = ZSTD_sizeof_CDict(dict.cdict);
122 return bufferSize + cdictSize;
123}
124
125static void ZSTD_freeCCtxContent(ZSTD_CCtx* cctx)
126{
127 assert(cctx != NULL);
128 assert(cctx->staticSize == 0);
William Kurkianea869482019-04-09 15:16:11 -0400129 ZSTD_free(cctx->workSpace, cctx->customMem); cctx->workSpace = NULL;
Abhilash S.L3b494632019-07-16 15:51:09 +0530130 ZSTD_clearAllDicts(cctx);
William Kurkianea869482019-04-09 15:16:11 -0400131#ifdef ZSTD_MULTITHREAD
132 ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL;
133#endif
Abhilash S.L3b494632019-07-16 15:51:09 +0530134}
135
136size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
137{
138 if (cctx==NULL) return 0; /* support free on NULL */
139 RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
140 "not compatible with static CCtx");
141 ZSTD_freeCCtxContent(cctx);
William Kurkianea869482019-04-09 15:16:11 -0400142 ZSTD_free(cctx, cctx->customMem);
Abhilash S.L3b494632019-07-16 15:51:09 +0530143 return 0;
William Kurkianea869482019-04-09 15:16:11 -0400144}
145
146
147static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx)
148{
149#ifdef ZSTD_MULTITHREAD
150 return ZSTDMT_sizeof_CCtx(cctx->mtctx);
151#else
Abhilash S.L3b494632019-07-16 15:51:09 +0530152 (void)cctx;
William Kurkianea869482019-04-09 15:16:11 -0400153 return 0;
154#endif
155}
156
157
158size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
159{
160 if (cctx==NULL) return 0; /* support sizeof on NULL */
161 return sizeof(*cctx) + cctx->workSpaceSize
Abhilash S.L3b494632019-07-16 15:51:09 +0530162 + ZSTD_sizeof_localDict(cctx->localDict)
William Kurkianea869482019-04-09 15:16:11 -0400163 + ZSTD_sizeof_mtctx(cctx);
164}
165
166size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
167{
168 return ZSTD_sizeof_CCtx(zcs); /* same object */
169}
170
171/* private API call, for dictBuilder only */
172const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
173
William Kurkianea869482019-04-09 15:16:11 -0400174static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
175 ZSTD_compressionParameters cParams)
176{
177 ZSTD_CCtx_params cctxParams;
178 memset(&cctxParams, 0, sizeof(cctxParams));
179 cctxParams.cParams = cParams;
180 cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
181 assert(!ZSTD_checkCParams(cParams));
182 cctxParams.fParams.contentSizeFlag = 1;
183 return cctxParams;
184}
185
186static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
187 ZSTD_customMem customMem)
188{
189 ZSTD_CCtx_params* params;
190 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
191 params = (ZSTD_CCtx_params*)ZSTD_calloc(
192 sizeof(ZSTD_CCtx_params), customMem);
193 if (!params) { return NULL; }
194 params->customMem = customMem;
195 params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
196 params->fParams.contentSizeFlag = 1;
197 return params;
198}
199
200ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
201{
202 return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem);
203}
204
205size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
206{
207 if (params == NULL) { return 0; }
208 ZSTD_free(params, params->customMem);
209 return 0;
210}
211
212size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params)
213{
214 return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
215}
216
217size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
Abhilash S.L3b494632019-07-16 15:51:09 +0530218 RETURN_ERROR_IF(!cctxParams, GENERIC);
William Kurkianea869482019-04-09 15:16:11 -0400219 memset(cctxParams, 0, sizeof(*cctxParams));
220 cctxParams->compressionLevel = compressionLevel;
221 cctxParams->fParams.contentSizeFlag = 1;
222 return 0;
223}
224
225size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
226{
Abhilash S.L3b494632019-07-16 15:51:09 +0530227 RETURN_ERROR_IF(!cctxParams, GENERIC);
228 FORWARD_IF_ERROR( ZSTD_checkCParams(params.cParams) );
William Kurkianea869482019-04-09 15:16:11 -0400229 memset(cctxParams, 0, sizeof(*cctxParams));
230 cctxParams->cParams = params.cParams;
231 cctxParams->fParams = params.fParams;
232 cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
233 assert(!ZSTD_checkCParams(params.cParams));
234 return 0;
235}
236
237/* ZSTD_assignParamsToCCtxParams() :
238 * params is presumed valid at this stage */
239static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
240 ZSTD_CCtx_params cctxParams, ZSTD_parameters params)
241{
242 ZSTD_CCtx_params ret = cctxParams;
243 ret.cParams = params.cParams;
244 ret.fParams = params.fParams;
245 ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
246 assert(!ZSTD_checkCParams(params.cParams));
247 return ret;
248}
249
Abhilash S.L3b494632019-07-16 15:51:09 +0530250ZSTD_bounds ZSTD_cParam_getBounds(ZSTD_cParameter param)
251{
252 ZSTD_bounds bounds = { 0, 0, 0 };
253
254 switch(param)
255 {
256 case ZSTD_c_compressionLevel:
257 bounds.lowerBound = ZSTD_minCLevel();
258 bounds.upperBound = ZSTD_maxCLevel();
259 return bounds;
260
261 case ZSTD_c_windowLog:
262 bounds.lowerBound = ZSTD_WINDOWLOG_MIN;
263 bounds.upperBound = ZSTD_WINDOWLOG_MAX;
264 return bounds;
265
266 case ZSTD_c_hashLog:
267 bounds.lowerBound = ZSTD_HASHLOG_MIN;
268 bounds.upperBound = ZSTD_HASHLOG_MAX;
269 return bounds;
270
271 case ZSTD_c_chainLog:
272 bounds.lowerBound = ZSTD_CHAINLOG_MIN;
273 bounds.upperBound = ZSTD_CHAINLOG_MAX;
274 return bounds;
275
276 case ZSTD_c_searchLog:
277 bounds.lowerBound = ZSTD_SEARCHLOG_MIN;
278 bounds.upperBound = ZSTD_SEARCHLOG_MAX;
279 return bounds;
280
281 case ZSTD_c_minMatch:
282 bounds.lowerBound = ZSTD_MINMATCH_MIN;
283 bounds.upperBound = ZSTD_MINMATCH_MAX;
284 return bounds;
285
286 case ZSTD_c_targetLength:
287 bounds.lowerBound = ZSTD_TARGETLENGTH_MIN;
288 bounds.upperBound = ZSTD_TARGETLENGTH_MAX;
289 return bounds;
290
291 case ZSTD_c_strategy:
292 bounds.lowerBound = ZSTD_STRATEGY_MIN;
293 bounds.upperBound = ZSTD_STRATEGY_MAX;
294 return bounds;
295
296 case ZSTD_c_contentSizeFlag:
297 bounds.lowerBound = 0;
298 bounds.upperBound = 1;
299 return bounds;
300
301 case ZSTD_c_checksumFlag:
302 bounds.lowerBound = 0;
303 bounds.upperBound = 1;
304 return bounds;
305
306 case ZSTD_c_dictIDFlag:
307 bounds.lowerBound = 0;
308 bounds.upperBound = 1;
309 return bounds;
310
311 case ZSTD_c_nbWorkers:
312 bounds.lowerBound = 0;
313#ifdef ZSTD_MULTITHREAD
314 bounds.upperBound = ZSTDMT_NBWORKERS_MAX;
315#else
316 bounds.upperBound = 0;
317#endif
318 return bounds;
319
320 case ZSTD_c_jobSize:
321 bounds.lowerBound = 0;
322#ifdef ZSTD_MULTITHREAD
323 bounds.upperBound = ZSTDMT_JOBSIZE_MAX;
324#else
325 bounds.upperBound = 0;
326#endif
327 return bounds;
328
329 case ZSTD_c_overlapLog:
330 bounds.lowerBound = ZSTD_OVERLAPLOG_MIN;
331 bounds.upperBound = ZSTD_OVERLAPLOG_MAX;
332 return bounds;
333
334 case ZSTD_c_enableLongDistanceMatching:
335 bounds.lowerBound = 0;
336 bounds.upperBound = 1;
337 return bounds;
338
339 case ZSTD_c_ldmHashLog:
340 bounds.lowerBound = ZSTD_LDM_HASHLOG_MIN;
341 bounds.upperBound = ZSTD_LDM_HASHLOG_MAX;
342 return bounds;
343
344 case ZSTD_c_ldmMinMatch:
345 bounds.lowerBound = ZSTD_LDM_MINMATCH_MIN;
346 bounds.upperBound = ZSTD_LDM_MINMATCH_MAX;
347 return bounds;
348
349 case ZSTD_c_ldmBucketSizeLog:
350 bounds.lowerBound = ZSTD_LDM_BUCKETSIZELOG_MIN;
351 bounds.upperBound = ZSTD_LDM_BUCKETSIZELOG_MAX;
352 return bounds;
353
354 case ZSTD_c_ldmHashRateLog:
355 bounds.lowerBound = ZSTD_LDM_HASHRATELOG_MIN;
356 bounds.upperBound = ZSTD_LDM_HASHRATELOG_MAX;
357 return bounds;
358
359 /* experimental parameters */
360 case ZSTD_c_rsyncable:
361 bounds.lowerBound = 0;
362 bounds.upperBound = 1;
363 return bounds;
364
365 case ZSTD_c_forceMaxWindow :
366 bounds.lowerBound = 0;
367 bounds.upperBound = 1;
368 return bounds;
369
370 case ZSTD_c_format:
371 ZSTD_STATIC_ASSERT(ZSTD_f_zstd1 < ZSTD_f_zstd1_magicless);
372 bounds.lowerBound = ZSTD_f_zstd1;
373 bounds.upperBound = ZSTD_f_zstd1_magicless; /* note : how to ensure at compile time that this is the highest value enum ? */
374 return bounds;
375
376 case ZSTD_c_forceAttachDict:
377 ZSTD_STATIC_ASSERT(ZSTD_dictDefaultAttach < ZSTD_dictForceCopy);
378 bounds.lowerBound = ZSTD_dictDefaultAttach;
379 bounds.upperBound = ZSTD_dictForceCopy; /* note : how to ensure at compile time that this is the highest value enum ? */
380 return bounds;
381
382 case ZSTD_c_literalCompressionMode:
383 ZSTD_STATIC_ASSERT(ZSTD_lcm_auto < ZSTD_lcm_huffman && ZSTD_lcm_huffman < ZSTD_lcm_uncompressed);
384 bounds.lowerBound = ZSTD_lcm_auto;
385 bounds.upperBound = ZSTD_lcm_uncompressed;
386 return bounds;
387
388 default:
389 { ZSTD_bounds const boundError = { ERROR(parameter_unsupported), 0, 0 };
390 return boundError;
391 }
392 }
393}
394
395/* ZSTD_cParam_withinBounds:
396 * @return 1 if value is within cParam bounds,
397 * 0 otherwise */
398static int ZSTD_cParam_withinBounds(ZSTD_cParameter cParam, int value)
399{
400 ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);
401 if (ZSTD_isError(bounds.error)) return 0;
402 if (value < bounds.lowerBound) return 0;
403 if (value > bounds.upperBound) return 0;
404 return 1;
405}
406
407/* ZSTD_cParam_clampBounds:
408 * Clamps the value into the bounded range.
409 */
410static size_t ZSTD_cParam_clampBounds(ZSTD_cParameter cParam, int* value)
411{
412 ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam);
413 if (ZSTD_isError(bounds.error)) return bounds.error;
414 if (*value < bounds.lowerBound) *value = bounds.lowerBound;
415 if (*value > bounds.upperBound) *value = bounds.upperBound;
416 return 0;
417}
418
419#define BOUNDCHECK(cParam, val) { \
420 RETURN_ERROR_IF(!ZSTD_cParam_withinBounds(cParam,val), \
421 parameter_outOfBound); \
422}
William Kurkianea869482019-04-09 15:16:11 -0400423
424
425static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
426{
427 switch(param)
428 {
Abhilash S.L3b494632019-07-16 15:51:09 +0530429 case ZSTD_c_compressionLevel:
430 case ZSTD_c_hashLog:
431 case ZSTD_c_chainLog:
432 case ZSTD_c_searchLog:
433 case ZSTD_c_minMatch:
434 case ZSTD_c_targetLength:
435 case ZSTD_c_strategy:
William Kurkianea869482019-04-09 15:16:11 -0400436 return 1;
437
Abhilash S.L3b494632019-07-16 15:51:09 +0530438 case ZSTD_c_format:
439 case ZSTD_c_windowLog:
440 case ZSTD_c_contentSizeFlag:
441 case ZSTD_c_checksumFlag:
442 case ZSTD_c_dictIDFlag:
443 case ZSTD_c_forceMaxWindow :
444 case ZSTD_c_nbWorkers:
445 case ZSTD_c_jobSize:
446 case ZSTD_c_overlapLog:
447 case ZSTD_c_rsyncable:
448 case ZSTD_c_enableLongDistanceMatching:
449 case ZSTD_c_ldmHashLog:
450 case ZSTD_c_ldmMinMatch:
451 case ZSTD_c_ldmBucketSizeLog:
452 case ZSTD_c_ldmHashRateLog:
453 case ZSTD_c_forceAttachDict:
454 case ZSTD_c_literalCompressionMode:
William Kurkianea869482019-04-09 15:16:11 -0400455 default:
456 return 0;
457 }
458}
459
Abhilash S.L3b494632019-07-16 15:51:09 +0530460size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int value)
William Kurkianea869482019-04-09 15:16:11 -0400461{
Abhilash S.L3b494632019-07-16 15:51:09 +0530462 DEBUGLOG(4, "ZSTD_CCtx_setParameter (%i, %i)", (int)param, value);
William Kurkianea869482019-04-09 15:16:11 -0400463 if (cctx->streamStage != zcss_init) {
464 if (ZSTD_isUpdateAuthorized(param)) {
465 cctx->cParamsChanged = 1;
466 } else {
Abhilash S.L3b494632019-07-16 15:51:09 +0530467 RETURN_ERROR(stage_wrong);
William Kurkianea869482019-04-09 15:16:11 -0400468 } }
469
470 switch(param)
471 {
Abhilash S.L3b494632019-07-16 15:51:09 +0530472 case ZSTD_c_nbWorkers:
473 RETURN_ERROR_IF((value!=0) && cctx->staticSize, parameter_unsupported,
474 "MT not compatible with static alloc");
475 break;
William Kurkianea869482019-04-09 15:16:11 -0400476
Abhilash S.L3b494632019-07-16 15:51:09 +0530477 case ZSTD_c_compressionLevel:
478 case ZSTD_c_windowLog:
479 case ZSTD_c_hashLog:
480 case ZSTD_c_chainLog:
481 case ZSTD_c_searchLog:
482 case ZSTD_c_minMatch:
483 case ZSTD_c_targetLength:
484 case ZSTD_c_strategy:
485 case ZSTD_c_ldmHashRateLog:
486 case ZSTD_c_format:
487 case ZSTD_c_contentSizeFlag:
488 case ZSTD_c_checksumFlag:
489 case ZSTD_c_dictIDFlag:
490 case ZSTD_c_forceMaxWindow:
491 case ZSTD_c_forceAttachDict:
492 case ZSTD_c_literalCompressionMode:
493 case ZSTD_c_jobSize:
494 case ZSTD_c_overlapLog:
495 case ZSTD_c_rsyncable:
496 case ZSTD_c_enableLongDistanceMatching:
497 case ZSTD_c_ldmHashLog:
498 case ZSTD_c_ldmMinMatch:
499 case ZSTD_c_ldmBucketSizeLog:
500 break;
William Kurkianea869482019-04-09 15:16:11 -0400501
Abhilash S.L3b494632019-07-16 15:51:09 +0530502 default: RETURN_ERROR(parameter_unsupported);
William Kurkianea869482019-04-09 15:16:11 -0400503 }
Abhilash S.L3b494632019-07-16 15:51:09 +0530504 return ZSTD_CCtxParams_setParameter(&cctx->requestedParams, param, value);
William Kurkianea869482019-04-09 15:16:11 -0400505}
506
Abhilash S.L3b494632019-07-16 15:51:09 +0530507size_t ZSTD_CCtxParams_setParameter(ZSTD_CCtx_params* CCtxParams,
508 ZSTD_cParameter param, int value)
William Kurkianea869482019-04-09 15:16:11 -0400509{
Abhilash S.L3b494632019-07-16 15:51:09 +0530510 DEBUGLOG(4, "ZSTD_CCtxParams_setParameter (%i, %i)", (int)param, value);
William Kurkianea869482019-04-09 15:16:11 -0400511 switch(param)
512 {
Abhilash S.L3b494632019-07-16 15:51:09 +0530513 case ZSTD_c_format :
514 BOUNDCHECK(ZSTD_c_format, value);
William Kurkianea869482019-04-09 15:16:11 -0400515 CCtxParams->format = (ZSTD_format_e)value;
516 return (size_t)CCtxParams->format;
517
Abhilash S.L3b494632019-07-16 15:51:09 +0530518 case ZSTD_c_compressionLevel : {
519 FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value));
520 if (value) { /* 0 : does not change current level */
521 CCtxParams->compressionLevel = value;
William Kurkianea869482019-04-09 15:16:11 -0400522 }
523 if (CCtxParams->compressionLevel >= 0) return CCtxParams->compressionLevel;
524 return 0; /* return type (size_t) cannot represent negative values */
525 }
526
Abhilash S.L3b494632019-07-16 15:51:09 +0530527 case ZSTD_c_windowLog :
528 if (value!=0) /* 0 => use default */
529 BOUNDCHECK(ZSTD_c_windowLog, value);
William Kurkianea869482019-04-09 15:16:11 -0400530 CCtxParams->cParams.windowLog = value;
531 return CCtxParams->cParams.windowLog;
532
Abhilash S.L3b494632019-07-16 15:51:09 +0530533 case ZSTD_c_hashLog :
534 if (value!=0) /* 0 => use default */
535 BOUNDCHECK(ZSTD_c_hashLog, value);
William Kurkianea869482019-04-09 15:16:11 -0400536 CCtxParams->cParams.hashLog = value;
537 return CCtxParams->cParams.hashLog;
538
Abhilash S.L3b494632019-07-16 15:51:09 +0530539 case ZSTD_c_chainLog :
540 if (value!=0) /* 0 => use default */
541 BOUNDCHECK(ZSTD_c_chainLog, value);
William Kurkianea869482019-04-09 15:16:11 -0400542 CCtxParams->cParams.chainLog = value;
543 return CCtxParams->cParams.chainLog;
544
Abhilash S.L3b494632019-07-16 15:51:09 +0530545 case ZSTD_c_searchLog :
546 if (value!=0) /* 0 => use default */
547 BOUNDCHECK(ZSTD_c_searchLog, value);
William Kurkianea869482019-04-09 15:16:11 -0400548 CCtxParams->cParams.searchLog = value;
549 return value;
550
Abhilash S.L3b494632019-07-16 15:51:09 +0530551 case ZSTD_c_minMatch :
552 if (value!=0) /* 0 => use default */
553 BOUNDCHECK(ZSTD_c_minMatch, value);
554 CCtxParams->cParams.minMatch = value;
555 return CCtxParams->cParams.minMatch;
William Kurkianea869482019-04-09 15:16:11 -0400556
Abhilash S.L3b494632019-07-16 15:51:09 +0530557 case ZSTD_c_targetLength :
558 BOUNDCHECK(ZSTD_c_targetLength, value);
William Kurkianea869482019-04-09 15:16:11 -0400559 CCtxParams->cParams.targetLength = value;
560 return CCtxParams->cParams.targetLength;
561
Abhilash S.L3b494632019-07-16 15:51:09 +0530562 case ZSTD_c_strategy :
563 if (value!=0) /* 0 => use default */
564 BOUNDCHECK(ZSTD_c_strategy, value);
William Kurkianea869482019-04-09 15:16:11 -0400565 CCtxParams->cParams.strategy = (ZSTD_strategy)value;
566 return (size_t)CCtxParams->cParams.strategy;
567
Abhilash S.L3b494632019-07-16 15:51:09 +0530568 case ZSTD_c_contentSizeFlag :
William Kurkianea869482019-04-09 15:16:11 -0400569 /* Content size written in frame header _when known_ (default:1) */
Abhilash S.L3b494632019-07-16 15:51:09 +0530570 DEBUGLOG(4, "set content size flag = %u", (value!=0));
571 CCtxParams->fParams.contentSizeFlag = value != 0;
William Kurkianea869482019-04-09 15:16:11 -0400572 return CCtxParams->fParams.contentSizeFlag;
573
Abhilash S.L3b494632019-07-16 15:51:09 +0530574 case ZSTD_c_checksumFlag :
William Kurkianea869482019-04-09 15:16:11 -0400575 /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
Abhilash S.L3b494632019-07-16 15:51:09 +0530576 CCtxParams->fParams.checksumFlag = value != 0;
William Kurkianea869482019-04-09 15:16:11 -0400577 return CCtxParams->fParams.checksumFlag;
578
Abhilash S.L3b494632019-07-16 15:51:09 +0530579 case ZSTD_c_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
580 DEBUGLOG(4, "set dictIDFlag = %u", (value!=0));
William Kurkianea869482019-04-09 15:16:11 -0400581 CCtxParams->fParams.noDictIDFlag = !value;
582 return !CCtxParams->fParams.noDictIDFlag;
583
Abhilash S.L3b494632019-07-16 15:51:09 +0530584 case ZSTD_c_forceMaxWindow :
585 CCtxParams->forceWindow = (value != 0);
William Kurkianea869482019-04-09 15:16:11 -0400586 return CCtxParams->forceWindow;
587
Abhilash S.L3b494632019-07-16 15:51:09 +0530588 case ZSTD_c_forceAttachDict : {
589 const ZSTD_dictAttachPref_e pref = (ZSTD_dictAttachPref_e)value;
590 BOUNDCHECK(ZSTD_c_forceAttachDict, pref);
591 CCtxParams->attachDictPref = pref;
592 return CCtxParams->attachDictPref;
593 }
594
595 case ZSTD_c_literalCompressionMode : {
596 const ZSTD_literalCompressionMode_e lcm = (ZSTD_literalCompressionMode_e)value;
597 BOUNDCHECK(ZSTD_c_literalCompressionMode, lcm);
598 CCtxParams->literalCompressionMode = lcm;
599 return CCtxParams->literalCompressionMode;
600 }
601
602 case ZSTD_c_nbWorkers :
William Kurkianea869482019-04-09 15:16:11 -0400603#ifndef ZSTD_MULTITHREAD
Abhilash S.L3b494632019-07-16 15:51:09 +0530604 RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
William Kurkianea869482019-04-09 15:16:11 -0400605 return 0;
606#else
Abhilash S.L3b494632019-07-16 15:51:09 +0530607 FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value));
608 CCtxParams->nbWorkers = value;
609 return CCtxParams->nbWorkers;
William Kurkianea869482019-04-09 15:16:11 -0400610#endif
611
Abhilash S.L3b494632019-07-16 15:51:09 +0530612 case ZSTD_c_jobSize :
William Kurkianea869482019-04-09 15:16:11 -0400613#ifndef ZSTD_MULTITHREAD
Abhilash S.L3b494632019-07-16 15:51:09 +0530614 RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
615 return 0;
William Kurkianea869482019-04-09 15:16:11 -0400616#else
Abhilash S.L3b494632019-07-16 15:51:09 +0530617 /* Adjust to the minimum non-default value. */
618 if (value != 0 && value < ZSTDMT_JOBSIZE_MIN)
619 value = ZSTDMT_JOBSIZE_MIN;
620 FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(param, &value));
621 assert(value >= 0);
622 CCtxParams->jobSize = value;
623 return CCtxParams->jobSize;
William Kurkianea869482019-04-09 15:16:11 -0400624#endif
625
Abhilash S.L3b494632019-07-16 15:51:09 +0530626 case ZSTD_c_overlapLog :
William Kurkianea869482019-04-09 15:16:11 -0400627#ifndef ZSTD_MULTITHREAD
Abhilash S.L3b494632019-07-16 15:51:09 +0530628 RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
629 return 0;
William Kurkianea869482019-04-09 15:16:11 -0400630#else
Abhilash S.L3b494632019-07-16 15:51:09 +0530631 FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value));
632 CCtxParams->overlapLog = value;
633 return CCtxParams->overlapLog;
William Kurkianea869482019-04-09 15:16:11 -0400634#endif
635
Abhilash S.L3b494632019-07-16 15:51:09 +0530636 case ZSTD_c_rsyncable :
637#ifndef ZSTD_MULTITHREAD
638 RETURN_ERROR_IF(value!=0, parameter_unsupported, "not compiled with multithreading");
639 return 0;
640#else
641 FORWARD_IF_ERROR(ZSTD_cParam_clampBounds(ZSTD_c_overlapLog, &value));
642 CCtxParams->rsyncable = value;
643 return CCtxParams->rsyncable;
644#endif
645
646 case ZSTD_c_enableLongDistanceMatching :
647 CCtxParams->ldmParams.enableLdm = (value!=0);
William Kurkianea869482019-04-09 15:16:11 -0400648 return CCtxParams->ldmParams.enableLdm;
649
Abhilash S.L3b494632019-07-16 15:51:09 +0530650 case ZSTD_c_ldmHashLog :
651 if (value!=0) /* 0 ==> auto */
652 BOUNDCHECK(ZSTD_c_ldmHashLog, value);
William Kurkianea869482019-04-09 15:16:11 -0400653 CCtxParams->ldmParams.hashLog = value;
654 return CCtxParams->ldmParams.hashLog;
655
Abhilash S.L3b494632019-07-16 15:51:09 +0530656 case ZSTD_c_ldmMinMatch :
657 if (value!=0) /* 0 ==> default */
658 BOUNDCHECK(ZSTD_c_ldmMinMatch, value);
William Kurkianea869482019-04-09 15:16:11 -0400659 CCtxParams->ldmParams.minMatchLength = value;
660 return CCtxParams->ldmParams.minMatchLength;
661
Abhilash S.L3b494632019-07-16 15:51:09 +0530662 case ZSTD_c_ldmBucketSizeLog :
663 if (value!=0) /* 0 ==> default */
664 BOUNDCHECK(ZSTD_c_ldmBucketSizeLog, value);
William Kurkianea869482019-04-09 15:16:11 -0400665 CCtxParams->ldmParams.bucketSizeLog = value;
666 return CCtxParams->ldmParams.bucketSizeLog;
667
Abhilash S.L3b494632019-07-16 15:51:09 +0530668 case ZSTD_c_ldmHashRateLog :
669 RETURN_ERROR_IF(value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN,
670 parameter_outOfBound);
671 CCtxParams->ldmParams.hashRateLog = value;
672 return CCtxParams->ldmParams.hashRateLog;
William Kurkianea869482019-04-09 15:16:11 -0400673
Abhilash S.L3b494632019-07-16 15:51:09 +0530674 default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
William Kurkianea869482019-04-09 15:16:11 -0400675 }
676}
677
Abhilash S.L3b494632019-07-16 15:51:09 +0530678size_t ZSTD_CCtx_getParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, int* value)
679{
680 return ZSTD_CCtxParams_getParameter(&cctx->requestedParams, param, value);
681}
682
683size_t ZSTD_CCtxParams_getParameter(
684 ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, int* value)
685{
686 switch(param)
687 {
688 case ZSTD_c_format :
689 *value = CCtxParams->format;
690 break;
691 case ZSTD_c_compressionLevel :
692 *value = CCtxParams->compressionLevel;
693 break;
694 case ZSTD_c_windowLog :
695 *value = CCtxParams->cParams.windowLog;
696 break;
697 case ZSTD_c_hashLog :
698 *value = CCtxParams->cParams.hashLog;
699 break;
700 case ZSTD_c_chainLog :
701 *value = CCtxParams->cParams.chainLog;
702 break;
703 case ZSTD_c_searchLog :
704 *value = CCtxParams->cParams.searchLog;
705 break;
706 case ZSTD_c_minMatch :
707 *value = CCtxParams->cParams.minMatch;
708 break;
709 case ZSTD_c_targetLength :
710 *value = CCtxParams->cParams.targetLength;
711 break;
712 case ZSTD_c_strategy :
713 *value = (unsigned)CCtxParams->cParams.strategy;
714 break;
715 case ZSTD_c_contentSizeFlag :
716 *value = CCtxParams->fParams.contentSizeFlag;
717 break;
718 case ZSTD_c_checksumFlag :
719 *value = CCtxParams->fParams.checksumFlag;
720 break;
721 case ZSTD_c_dictIDFlag :
722 *value = !CCtxParams->fParams.noDictIDFlag;
723 break;
724 case ZSTD_c_forceMaxWindow :
725 *value = CCtxParams->forceWindow;
726 break;
727 case ZSTD_c_forceAttachDict :
728 *value = CCtxParams->attachDictPref;
729 break;
730 case ZSTD_c_literalCompressionMode :
731 *value = CCtxParams->literalCompressionMode;
732 break;
733 case ZSTD_c_nbWorkers :
734#ifndef ZSTD_MULTITHREAD
735 assert(CCtxParams->nbWorkers == 0);
736#endif
737 *value = CCtxParams->nbWorkers;
738 break;
739 case ZSTD_c_jobSize :
740#ifndef ZSTD_MULTITHREAD
741 RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
742#else
743 assert(CCtxParams->jobSize <= INT_MAX);
744 *value = (int)CCtxParams->jobSize;
745 break;
746#endif
747 case ZSTD_c_overlapLog :
748#ifndef ZSTD_MULTITHREAD
749 RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
750#else
751 *value = CCtxParams->overlapLog;
752 break;
753#endif
754 case ZSTD_c_rsyncable :
755#ifndef ZSTD_MULTITHREAD
756 RETURN_ERROR(parameter_unsupported, "not compiled with multithreading");
757#else
758 *value = CCtxParams->rsyncable;
759 break;
760#endif
761 case ZSTD_c_enableLongDistanceMatching :
762 *value = CCtxParams->ldmParams.enableLdm;
763 break;
764 case ZSTD_c_ldmHashLog :
765 *value = CCtxParams->ldmParams.hashLog;
766 break;
767 case ZSTD_c_ldmMinMatch :
768 *value = CCtxParams->ldmParams.minMatchLength;
769 break;
770 case ZSTD_c_ldmBucketSizeLog :
771 *value = CCtxParams->ldmParams.bucketSizeLog;
772 break;
773 case ZSTD_c_ldmHashRateLog :
774 *value = CCtxParams->ldmParams.hashRateLog;
775 break;
776 default: RETURN_ERROR(parameter_unsupported, "unknown parameter");
777 }
778 return 0;
779}
780
William Kurkianea869482019-04-09 15:16:11 -0400781/** ZSTD_CCtx_setParametersUsingCCtxParams() :
782 * just applies `params` into `cctx`
783 * no action is performed, parameters are merely stored.
784 * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx.
785 * This is possible even if a compression is ongoing.
786 * In which case, new parameters will be applied on the fly, starting with next compression job.
787 */
788size_t ZSTD_CCtx_setParametersUsingCCtxParams(
789 ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
790{
Abhilash S.L3b494632019-07-16 15:51:09 +0530791 DEBUGLOG(4, "ZSTD_CCtx_setParametersUsingCCtxParams");
792 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong);
793 RETURN_ERROR_IF(cctx->cdict, stage_wrong);
William Kurkianea869482019-04-09 15:16:11 -0400794
795 cctx->requestedParams = *params;
796 return 0;
797}
798
799ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
800{
801 DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize);
Abhilash S.L3b494632019-07-16 15:51:09 +0530802 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong);
William Kurkianea869482019-04-09 15:16:11 -0400803 cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
804 return 0;
805}
806
Abhilash S.L3b494632019-07-16 15:51:09 +0530807/**
808 * Initializes the local dict using the requested parameters.
809 * NOTE: This does not use the pledged src size, because it may be used for more
810 * than one compression.
811 */
812static size_t ZSTD_initLocalDict(ZSTD_CCtx* cctx)
813{
814 ZSTD_localDict* const dl = &cctx->localDict;
815 ZSTD_compressionParameters const cParams = ZSTD_getCParamsFromCCtxParams(
816 &cctx->requestedParams, 0, dl->dictSize);
817 if (dl->dict == NULL) {
818 /* No local dictionary. */
819 assert(dl->dictBuffer == NULL);
820 assert(dl->cdict == NULL);
821 assert(dl->dictSize == 0);
822 return 0;
823 }
824 if (dl->cdict != NULL) {
825 assert(cctx->cdict == dl->cdict);
826 /* Local dictionary already initialized. */
827 return 0;
828 }
829 assert(dl->dictSize > 0);
830 assert(cctx->cdict == NULL);
831 assert(cctx->prefixDict.dict == NULL);
832
833 dl->cdict = ZSTD_createCDict_advanced(
834 dl->dict,
835 dl->dictSize,
836 ZSTD_dlm_byRef,
837 dl->dictContentType,
838 cParams,
839 cctx->customMem);
840 RETURN_ERROR_IF(!dl->cdict, memory_allocation);
841 cctx->cdict = dl->cdict;
842 return 0;
843}
844
William Kurkianea869482019-04-09 15:16:11 -0400845size_t ZSTD_CCtx_loadDictionary_advanced(
846 ZSTD_CCtx* cctx, const void* dict, size_t dictSize,
847 ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType)
848{
Abhilash S.L3b494632019-07-16 15:51:09 +0530849 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong);
850 RETURN_ERROR_IF(cctx->staticSize, memory_allocation,
851 "no malloc for static CCtx");
William Kurkianea869482019-04-09 15:16:11 -0400852 DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize);
Abhilash S.L3b494632019-07-16 15:51:09 +0530853 ZSTD_clearAllDicts(cctx); /* in case one already exists */
854 if (dict == NULL || dictSize == 0) /* no dictionary mode */
855 return 0;
856 if (dictLoadMethod == ZSTD_dlm_byRef) {
857 cctx->localDict.dict = dict;
William Kurkianea869482019-04-09 15:16:11 -0400858 } else {
Abhilash S.L3b494632019-07-16 15:51:09 +0530859 void* dictBuffer = ZSTD_malloc(dictSize, cctx->customMem);
860 RETURN_ERROR_IF(!dictBuffer, memory_allocation);
861 memcpy(dictBuffer, dict, dictSize);
862 cctx->localDict.dictBuffer = dictBuffer;
863 cctx->localDict.dict = dictBuffer;
William Kurkianea869482019-04-09 15:16:11 -0400864 }
Abhilash S.L3b494632019-07-16 15:51:09 +0530865 cctx->localDict.dictSize = dictSize;
866 cctx->localDict.dictContentType = dictContentType;
William Kurkianea869482019-04-09 15:16:11 -0400867 return 0;
868}
869
870ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(
871 ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
872{
873 return ZSTD_CCtx_loadDictionary_advanced(
874 cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
875}
876
877ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
878{
879 return ZSTD_CCtx_loadDictionary_advanced(
880 cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
881}
882
883
884size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
885{
Abhilash S.L3b494632019-07-16 15:51:09 +0530886 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong);
887 /* Free the existing local cdict (if any) to save memory. */
888 ZSTD_clearAllDicts(cctx);
William Kurkianea869482019-04-09 15:16:11 -0400889 cctx->cdict = cdict;
William Kurkianea869482019-04-09 15:16:11 -0400890 return 0;
891}
892
893size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
894{
895 return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent);
896}
897
898size_t ZSTD_CCtx_refPrefix_advanced(
899 ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
900{
Abhilash S.L3b494632019-07-16 15:51:09 +0530901 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong);
902 ZSTD_clearAllDicts(cctx);
William Kurkianea869482019-04-09 15:16:11 -0400903 cctx->prefixDict.dict = prefix;
904 cctx->prefixDict.dictSize = prefixSize;
905 cctx->prefixDict.dictContentType = dictContentType;
906 return 0;
907}
908
William Kurkianea869482019-04-09 15:16:11 -0400909/*! ZSTD_CCtx_reset() :
910 * Also dumps dictionary */
Abhilash S.L3b494632019-07-16 15:51:09 +0530911size_t ZSTD_CCtx_reset(ZSTD_CCtx* cctx, ZSTD_ResetDirective reset)
William Kurkianea869482019-04-09 15:16:11 -0400912{
Abhilash S.L3b494632019-07-16 15:51:09 +0530913 if ( (reset == ZSTD_reset_session_only)
914 || (reset == ZSTD_reset_session_and_parameters) ) {
915 cctx->streamStage = zcss_init;
916 cctx->pledgedSrcSizePlusOne = 0;
917 }
918 if ( (reset == ZSTD_reset_parameters)
919 || (reset == ZSTD_reset_session_and_parameters) ) {
920 RETURN_ERROR_IF(cctx->streamStage != zcss_init, stage_wrong);
921 ZSTD_clearAllDicts(cctx);
922 return ZSTD_CCtxParams_reset(&cctx->requestedParams);
923 }
924 return 0;
William Kurkianea869482019-04-09 15:16:11 -0400925}
926
Abhilash S.L3b494632019-07-16 15:51:09 +0530927
William Kurkianea869482019-04-09 15:16:11 -0400928/** ZSTD_checkCParams() :
929 control CParam values remain within authorized range.
930 @return : 0, or an error code if one value is beyond authorized range */
931size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
932{
Abhilash S.L3b494632019-07-16 15:51:09 +0530933 BOUNDCHECK(ZSTD_c_windowLog, cParams.windowLog);
934 BOUNDCHECK(ZSTD_c_chainLog, cParams.chainLog);
935 BOUNDCHECK(ZSTD_c_hashLog, cParams.hashLog);
936 BOUNDCHECK(ZSTD_c_searchLog, cParams.searchLog);
937 BOUNDCHECK(ZSTD_c_minMatch, cParams.minMatch);
938 BOUNDCHECK(ZSTD_c_targetLength,cParams.targetLength);
939 BOUNDCHECK(ZSTD_c_strategy, cParams.strategy);
William Kurkianea869482019-04-09 15:16:11 -0400940 return 0;
941}
942
943/** ZSTD_clampCParams() :
944 * make CParam values within valid range.
945 * @return : valid CParams */
Abhilash S.L3b494632019-07-16 15:51:09 +0530946static ZSTD_compressionParameters
947ZSTD_clampCParams(ZSTD_compressionParameters cParams)
William Kurkianea869482019-04-09 15:16:11 -0400948{
Abhilash S.L3b494632019-07-16 15:51:09 +0530949# define CLAMP_TYPE(cParam, val, type) { \
950 ZSTD_bounds const bounds = ZSTD_cParam_getBounds(cParam); \
951 if ((int)val<bounds.lowerBound) val=(type)bounds.lowerBound; \
952 else if ((int)val>bounds.upperBound) val=(type)bounds.upperBound; \
William Kurkianea869482019-04-09 15:16:11 -0400953 }
Abhilash S.L3b494632019-07-16 15:51:09 +0530954# define CLAMP(cParam, val) CLAMP_TYPE(cParam, val, int)
955 CLAMP(ZSTD_c_windowLog, cParams.windowLog);
956 CLAMP(ZSTD_c_chainLog, cParams.chainLog);
957 CLAMP(ZSTD_c_hashLog, cParams.hashLog);
958 CLAMP(ZSTD_c_searchLog, cParams.searchLog);
959 CLAMP(ZSTD_c_minMatch, cParams.minMatch);
960 CLAMP(ZSTD_c_targetLength,cParams.targetLength);
961 CLAMP_TYPE(ZSTD_c_strategy,cParams.strategy, ZSTD_strategy);
William Kurkianea869482019-04-09 15:16:11 -0400962 return cParams;
963}
964
965/** ZSTD_cycleLog() :
966 * condition for correct operation : hashLog > 1 */
967static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
968{
969 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
970 return hashLog - btScale;
971}
972
973/** ZSTD_adjustCParams_internal() :
Abhilash S.L3b494632019-07-16 15:51:09 +0530974 * optimize `cPar` for a specified input (`srcSize` and `dictSize`).
975 * mostly downsize to reduce memory consumption and initialization latency.
976 * `srcSize` can be ZSTD_CONTENTSIZE_UNKNOWN when not known.
977 * note : for the time being, `srcSize==0` means "unknown" too, for compatibility with older convention.
978 * condition : cPar is presumed validated (can be checked using ZSTD_checkCParams()). */
979static ZSTD_compressionParameters
980ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar,
981 unsigned long long srcSize,
982 size_t dictSize)
William Kurkianea869482019-04-09 15:16:11 -0400983{
984 static const U64 minSrcSize = 513; /* (1<<9) + 1 */
985 static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
986 assert(ZSTD_checkCParams(cPar)==0);
987
Abhilash S.L3b494632019-07-16 15:51:09 +0530988 if (dictSize && (srcSize+1<2) /* ZSTD_CONTENTSIZE_UNKNOWN and 0 mean "unknown" */ )
William Kurkianea869482019-04-09 15:16:11 -0400989 srcSize = minSrcSize; /* presumed small when there is a dictionary */
990 else if (srcSize == 0)
991 srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */
992
993 /* resize windowLog if input is small enough, to use less memory */
994 if ( (srcSize < maxWindowResize)
995 && (dictSize < maxWindowResize) ) {
996 U32 const tSize = (U32)(srcSize + dictSize);
997 static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN;
998 U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN :
999 ZSTD_highbit32(tSize-1) + 1;
1000 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
1001 }
Abhilash S.L3b494632019-07-16 15:51:09 +05301002 if (cPar.hashLog > cPar.windowLog+1) cPar.hashLog = cPar.windowLog+1;
William Kurkianea869482019-04-09 15:16:11 -04001003 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
1004 if (cycleLog > cPar.windowLog)
1005 cPar.chainLog -= (cycleLog - cPar.windowLog);
1006 }
1007
1008 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
Abhilash S.L3b494632019-07-16 15:51:09 +05301009 cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* minimum wlog required for valid frame header */
William Kurkianea869482019-04-09 15:16:11 -04001010
1011 return cPar;
1012}
1013
Abhilash S.L3b494632019-07-16 15:51:09 +05301014ZSTD_compressionParameters
1015ZSTD_adjustCParams(ZSTD_compressionParameters cPar,
1016 unsigned long long srcSize,
1017 size_t dictSize)
William Kurkianea869482019-04-09 15:16:11 -04001018{
Abhilash S.L3b494632019-07-16 15:51:09 +05301019 cPar = ZSTD_clampCParams(cPar); /* resulting cPar is necessarily valid (all parameters within range) */
William Kurkianea869482019-04-09 15:16:11 -04001020 return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
1021}
1022
Abhilash S.L3b494632019-07-16 15:51:09 +05301023ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
1024 const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
1025{
1026 ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize);
1027 if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
1028 if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog;
1029 if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog;
1030 if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog;
1031 if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog;
1032 if (CCtxParams->cParams.minMatch) cParams.minMatch = CCtxParams->cParams.minMatch;
1033 if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength;
1034 if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy;
1035 assert(!ZSTD_checkCParams(cParams));
1036 return ZSTD_adjustCParams_internal(cParams, srcSizeHint, dictSize);
1037}
1038
1039static size_t
1040ZSTD_sizeof_matchState(const ZSTD_compressionParameters* const cParams,
1041 const U32 forCCtx)
William Kurkianea869482019-04-09 15:16:11 -04001042{
1043 size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
1044 size_t const hSize = ((size_t)1) << cParams->hashLog;
Abhilash S.L3b494632019-07-16 15:51:09 +05301045 U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
William Kurkianea869482019-04-09 15:16:11 -04001046 size_t const h3Size = ((size_t)1) << hashLog3;
1047 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
1048 size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
1049 + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
Abhilash S.L3b494632019-07-16 15:51:09 +05301050 size_t const optSpace = (forCCtx && (cParams->strategy >= ZSTD_btopt))
William Kurkianea869482019-04-09 15:16:11 -04001051 ? optPotentialSpace
1052 : 0;
1053 DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
1054 (U32)chainSize, (U32)hSize, (U32)h3Size);
1055 return tableSpace + optSpace;
1056}
1057
1058size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
1059{
Abhilash S.L3b494632019-07-16 15:51:09 +05301060 RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
William Kurkianea869482019-04-09 15:16:11 -04001061 { ZSTD_compressionParameters const cParams =
1062 ZSTD_getCParamsFromCCtxParams(params, 0, 0);
1063 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
Abhilash S.L3b494632019-07-16 15:51:09 +05301064 U32 const divider = (cParams.minMatch==3) ? 3 : 4;
William Kurkianea869482019-04-09 15:16:11 -04001065 size_t const maxNbSeq = blockSize / divider;
Abhilash S.L3b494632019-07-16 15:51:09 +05301066 size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq;
William Kurkianea869482019-04-09 15:16:11 -04001067 size_t const entropySpace = HUF_WORKSPACE_SIZE;
1068 size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
1069 size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1);
1070
1071 size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams);
1072 size_t const ldmSeqSpace = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq);
1073
1074 size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace +
1075 matchStateSize + ldmSpace + ldmSeqSpace;
1076
1077 DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
1078 DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace);
1079 return sizeof(ZSTD_CCtx) + neededSpace;
1080 }
1081}
1082
1083size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
1084{
1085 ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
1086 return ZSTD_estimateCCtxSize_usingCCtxParams(&params);
1087}
1088
1089static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
1090{
1091 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
1092 return ZSTD_estimateCCtxSize_usingCParams(cParams);
1093}
1094
1095size_t ZSTD_estimateCCtxSize(int compressionLevel)
1096{
1097 int level;
1098 size_t memBudget = 0;
Abhilash S.L3b494632019-07-16 15:51:09 +05301099 for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
William Kurkianea869482019-04-09 15:16:11 -04001100 size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
1101 if (newMB > memBudget) memBudget = newMB;
1102 }
1103 return memBudget;
1104}
1105
1106size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
1107{
Abhilash S.L3b494632019-07-16 15:51:09 +05301108 RETURN_ERROR_IF(params->nbWorkers > 0, GENERIC, "Estimate CCtx size is supported for single-threaded compression only.");
1109 { ZSTD_compressionParameters const cParams =
1110 ZSTD_getCParamsFromCCtxParams(params, 0, 0);
1111 size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
1112 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
1113 size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
William Kurkianea869482019-04-09 15:16:11 -04001114 size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
1115 size_t const streamingSize = inBuffSize + outBuffSize;
1116
1117 return CCtxSize + streamingSize;
1118 }
1119}
1120
1121size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
1122{
1123 ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
1124 return ZSTD_estimateCStreamSize_usingCCtxParams(&params);
1125}
1126
Abhilash S.L3b494632019-07-16 15:51:09 +05301127static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel)
1128{
William Kurkianea869482019-04-09 15:16:11 -04001129 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
1130 return ZSTD_estimateCStreamSize_usingCParams(cParams);
1131}
1132
Abhilash S.L3b494632019-07-16 15:51:09 +05301133size_t ZSTD_estimateCStreamSize(int compressionLevel)
1134{
William Kurkianea869482019-04-09 15:16:11 -04001135 int level;
1136 size_t memBudget = 0;
Abhilash S.L3b494632019-07-16 15:51:09 +05301137 for (level=MIN(compressionLevel, 1); level<=compressionLevel; level++) {
William Kurkianea869482019-04-09 15:16:11 -04001138 size_t const newMB = ZSTD_estimateCStreamSize_internal(level);
1139 if (newMB > memBudget) memBudget = newMB;
1140 }
1141 return memBudget;
1142}
1143
1144/* ZSTD_getFrameProgression():
1145 * tells how much data has been consumed (input) and produced (output) for current frame.
1146 * able to count progression inside worker threads (non-blocking mode).
1147 */
1148ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx)
1149{
1150#ifdef ZSTD_MULTITHREAD
1151 if (cctx->appliedParams.nbWorkers > 0) {
1152 return ZSTDMT_getFrameProgression(cctx->mtctx);
1153 }
1154#endif
1155 { ZSTD_frameProgression fp;
1156 size_t const buffered = (cctx->inBuff == NULL) ? 0 :
1157 cctx->inBuffPos - cctx->inToCompress;
1158 if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress);
1159 assert(buffered <= ZSTD_BLOCKSIZE_MAX);
1160 fp.ingested = cctx->consumedSrcSize + buffered;
1161 fp.consumed = cctx->consumedSrcSize;
1162 fp.produced = cctx->producedCSize;
Abhilash S.L3b494632019-07-16 15:51:09 +05301163 fp.flushed = cctx->producedCSize; /* simplified; some data might still be left within streaming output buffer */
1164 fp.currentJobID = 0;
1165 fp.nbActiveWorkers = 0;
William Kurkianea869482019-04-09 15:16:11 -04001166 return fp;
1167} }
1168
Abhilash S.L3b494632019-07-16 15:51:09 +05301169/*! ZSTD_toFlushNow()
1170 * Only useful for multithreading scenarios currently (nbWorkers >= 1).
1171 */
1172size_t ZSTD_toFlushNow(ZSTD_CCtx* cctx)
1173{
1174#ifdef ZSTD_MULTITHREAD
1175 if (cctx->appliedParams.nbWorkers > 0) {
1176 return ZSTDMT_toFlushNow(cctx->mtctx);
1177 }
1178#endif
1179 (void)cctx;
1180 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 */
1181}
1182
1183
William Kurkianea869482019-04-09 15:16:11 -04001184
1185static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
1186 ZSTD_compressionParameters cParams2)
1187{
1188 return (cParams1.hashLog == cParams2.hashLog)
1189 & (cParams1.chainLog == cParams2.chainLog)
1190 & (cParams1.strategy == cParams2.strategy) /* opt parser space */
Abhilash S.L3b494632019-07-16 15:51:09 +05301191 & ((cParams1.minMatch==3) == (cParams2.minMatch==3)); /* hashlog3 space */
1192}
1193
1194static void ZSTD_assertEqualCParams(ZSTD_compressionParameters cParams1,
1195 ZSTD_compressionParameters cParams2)
1196{
1197 (void)cParams1;
1198 (void)cParams2;
1199 assert(cParams1.windowLog == cParams2.windowLog);
1200 assert(cParams1.chainLog == cParams2.chainLog);
1201 assert(cParams1.hashLog == cParams2.hashLog);
1202 assert(cParams1.searchLog == cParams2.searchLog);
1203 assert(cParams1.minMatch == cParams2.minMatch);
1204 assert(cParams1.targetLength == cParams2.targetLength);
1205 assert(cParams1.strategy == cParams2.strategy);
William Kurkianea869482019-04-09 15:16:11 -04001206}
1207
1208/** The parameters are equivalent if ldm is not enabled in both sets or
1209 * all the parameters are equivalent. */
1210static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1,
1211 ldmParams_t ldmParams2)
1212{
1213 return (!ldmParams1.enableLdm && !ldmParams2.enableLdm) ||
1214 (ldmParams1.enableLdm == ldmParams2.enableLdm &&
1215 ldmParams1.hashLog == ldmParams2.hashLog &&
1216 ldmParams1.bucketSizeLog == ldmParams2.bucketSizeLog &&
1217 ldmParams1.minMatchLength == ldmParams2.minMatchLength &&
Abhilash S.L3b494632019-07-16 15:51:09 +05301218 ldmParams1.hashRateLog == ldmParams2.hashRateLog);
William Kurkianea869482019-04-09 15:16:11 -04001219}
1220
1221typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
1222
1223/* ZSTD_sufficientBuff() :
1224 * check internal buffers exist for streaming if buffPol == ZSTDb_buffered .
1225 * Note : they are assumed to be correctly sized if ZSTD_equivalentCParams()==1 */
Abhilash S.L3b494632019-07-16 15:51:09 +05301226static U32 ZSTD_sufficientBuff(size_t bufferSize1, size_t maxNbSeq1,
1227 size_t maxNbLit1,
William Kurkianea869482019-04-09 15:16:11 -04001228 ZSTD_buffered_policy_e buffPol2,
1229 ZSTD_compressionParameters cParams2,
1230 U64 pledgedSrcSize)
1231{
1232 size_t const windowSize2 = MAX(1, (size_t)MIN(((U64)1 << cParams2.windowLog), pledgedSrcSize));
1233 size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2);
Abhilash S.L3b494632019-07-16 15:51:09 +05301234 size_t const maxNbSeq2 = blockSize2 / ((cParams2.minMatch == 3) ? 3 : 4);
1235 size_t const maxNbLit2 = blockSize2;
William Kurkianea869482019-04-09 15:16:11 -04001236 size_t const neededBufferSize2 = (buffPol2==ZSTDb_buffered) ? windowSize2 + blockSize2 : 0;
Abhilash S.L3b494632019-07-16 15:51:09 +05301237 DEBUGLOG(4, "ZSTD_sufficientBuff: is neededBufferSize2=%u <= bufferSize1=%u",
1238 (U32)neededBufferSize2, (U32)bufferSize1);
1239 DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbSeq2=%u <= maxNbSeq1=%u",
1240 (U32)maxNbSeq2, (U32)maxNbSeq1);
1241 DEBUGLOG(4, "ZSTD_sufficientBuff: is maxNbLit2=%u <= maxNbLit1=%u",
1242 (U32)maxNbLit2, (U32)maxNbLit1);
1243 return (maxNbLit2 <= maxNbLit1)
1244 & (maxNbSeq2 <= maxNbSeq1)
William Kurkianea869482019-04-09 15:16:11 -04001245 & (neededBufferSize2 <= bufferSize1);
1246}
1247
1248/** Equivalence for resetCCtx purposes */
1249static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
1250 ZSTD_CCtx_params params2,
Abhilash S.L3b494632019-07-16 15:51:09 +05301251 size_t buffSize1,
1252 size_t maxNbSeq1, size_t maxNbLit1,
William Kurkianea869482019-04-09 15:16:11 -04001253 ZSTD_buffered_policy_e buffPol2,
1254 U64 pledgedSrcSize)
1255{
1256 DEBUGLOG(4, "ZSTD_equivalentParams: pledgedSrcSize=%u", (U32)pledgedSrcSize);
Abhilash S.L3b494632019-07-16 15:51:09 +05301257 if (!ZSTD_equivalentCParams(params1.cParams, params2.cParams)) {
1258 DEBUGLOG(4, "ZSTD_equivalentCParams() == 0");
1259 return 0;
1260 }
1261 if (!ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams)) {
1262 DEBUGLOG(4, "ZSTD_equivalentLdmParams() == 0");
1263 return 0;
1264 }
1265 if (!ZSTD_sufficientBuff(buffSize1, maxNbSeq1, maxNbLit1, buffPol2,
1266 params2.cParams, pledgedSrcSize)) {
1267 DEBUGLOG(4, "ZSTD_sufficientBuff() == 0");
1268 return 0;
1269 }
1270 return 1;
William Kurkianea869482019-04-09 15:16:11 -04001271}
1272
1273static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs)
1274{
1275 int i;
1276 for (i = 0; i < ZSTD_REP_NUM; ++i)
1277 bs->rep[i] = repStartValue[i];
Abhilash S.L3b494632019-07-16 15:51:09 +05301278 bs->entropy.huf.repeatMode = HUF_repeat_none;
1279 bs->entropy.fse.offcode_repeatMode = FSE_repeat_none;
1280 bs->entropy.fse.matchlength_repeatMode = FSE_repeat_none;
1281 bs->entropy.fse.litlength_repeatMode = FSE_repeat_none;
William Kurkianea869482019-04-09 15:16:11 -04001282}
1283
1284/*! ZSTD_invalidateMatchState()
1285 * Invalidate all the matches in the match finder tables.
1286 * Requires nextSrc and base to be set (can be NULL).
1287 */
1288static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
1289{
1290 ZSTD_window_clear(&ms->window);
1291
Abhilash S.L3b494632019-07-16 15:51:09 +05301292 ms->nextToUpdate = ms->window.dictLimit;
1293 ms->nextToUpdate3 = ms->window.dictLimit;
William Kurkianea869482019-04-09 15:16:11 -04001294 ms->loadedDictEnd = 0;
1295 ms->opt.litLengthSum = 0; /* force reset of btopt stats */
Abhilash S.L3b494632019-07-16 15:51:09 +05301296 ms->dictMatchState = NULL;
William Kurkianea869482019-04-09 15:16:11 -04001297}
1298
1299/*! ZSTD_continueCCtx() :
1300 * reuse CCtx without reset (note : requires no dictionary) */
1301static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize)
1302{
1303 size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
1304 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
1305 DEBUGLOG(4, "ZSTD_continueCCtx: re-use context in place");
1306
1307 cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */
1308 cctx->appliedParams = params;
Abhilash S.L3b494632019-07-16 15:51:09 +05301309 cctx->blockState.matchState.cParams = params.cParams;
William Kurkianea869482019-04-09 15:16:11 -04001310 cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
1311 cctx->consumedSrcSize = 0;
1312 cctx->producedCSize = 0;
1313 if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
1314 cctx->appliedParams.fParams.contentSizeFlag = 0;
1315 DEBUGLOG(4, "pledged content size : %u ; flag : %u",
1316 (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
1317 cctx->stage = ZSTDcs_init;
1318 cctx->dictID = 0;
1319 if (params.ldmParams.enableLdm)
1320 ZSTD_window_clear(&cctx->ldmState.window);
1321 ZSTD_referenceExternalSequences(cctx, NULL, 0);
1322 ZSTD_invalidateMatchState(&cctx->blockState.matchState);
1323 ZSTD_reset_compressedBlockState(cctx->blockState.prevCBlock);
1324 XXH64_reset(&cctx->xxhState, 0);
1325 return 0;
1326}
1327
1328typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
1329
Abhilash S.L3b494632019-07-16 15:51:09 +05301330static void*
1331ZSTD_reset_matchState(ZSTD_matchState_t* ms,
1332 void* ptr,
1333 const ZSTD_compressionParameters* cParams,
1334 ZSTD_compResetPolicy_e const crp, U32 const forCCtx)
William Kurkianea869482019-04-09 15:16:11 -04001335{
1336 size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
1337 size_t const hSize = ((size_t)1) << cParams->hashLog;
Abhilash S.L3b494632019-07-16 15:51:09 +05301338 U32 const hashLog3 = (forCCtx && cParams->minMatch==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
William Kurkianea869482019-04-09 15:16:11 -04001339 size_t const h3Size = ((size_t)1) << hashLog3;
1340 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
1341
1342 assert(((size_t)ptr & 3) == 0);
1343
1344 ms->hashLog3 = hashLog3;
1345 memset(&ms->window, 0, sizeof(ms->window));
Abhilash S.L3b494632019-07-16 15:51:09 +05301346 ms->window.dictLimit = 1; /* start from 1, so that 1st position is valid */
1347 ms->window.lowLimit = 1; /* it ensures first and later CCtx usages compress the same */
1348 ms->window.nextSrc = ms->window.base + 1; /* see issue #1241 */
William Kurkianea869482019-04-09 15:16:11 -04001349 ZSTD_invalidateMatchState(ms);
1350
1351 /* opt parser space */
Abhilash S.L3b494632019-07-16 15:51:09 +05301352 if (forCCtx && (cParams->strategy >= ZSTD_btopt)) {
William Kurkianea869482019-04-09 15:16:11 -04001353 DEBUGLOG(4, "reserving optimal parser space");
Abhilash S.L3b494632019-07-16 15:51:09 +05301354 ms->opt.litFreq = (unsigned*)ptr;
William Kurkianea869482019-04-09 15:16:11 -04001355 ms->opt.litLengthFreq = ms->opt.litFreq + (1<<Litbits);
1356 ms->opt.matchLengthFreq = ms->opt.litLengthFreq + (MaxLL+1);
1357 ms->opt.offCodeFreq = ms->opt.matchLengthFreq + (MaxML+1);
1358 ptr = ms->opt.offCodeFreq + (MaxOff+1);
1359 ms->opt.matchTable = (ZSTD_match_t*)ptr;
1360 ptr = ms->opt.matchTable + ZSTD_OPT_NUM+1;
1361 ms->opt.priceTable = (ZSTD_optimal_t*)ptr;
1362 ptr = ms->opt.priceTable + ZSTD_OPT_NUM+1;
1363 }
1364
1365 /* table Space */
1366 DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset);
1367 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
1368 if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
1369 ms->hashTable = (U32*)(ptr);
1370 ms->chainTable = ms->hashTable + hSize;
1371 ms->hashTable3 = ms->chainTable + chainSize;
1372 ptr = ms->hashTable3 + h3Size;
1373
Abhilash S.L3b494632019-07-16 15:51:09 +05301374 ms->cParams = *cParams;
1375
William Kurkianea869482019-04-09 15:16:11 -04001376 assert(((size_t)ptr & 3) == 0);
1377 return ptr;
1378}
1379
Abhilash S.L3b494632019-07-16 15:51:09 +05301380#define ZSTD_WORKSPACETOOLARGE_FACTOR 3 /* define "workspace is too large" as this number of times larger than needed */
1381#define ZSTD_WORKSPACETOOLARGE_MAXDURATION 128 /* when workspace is continuously too large
1382 * during at least this number of times,
1383 * context's memory usage is considered wasteful,
1384 * because it's sized to handle a worst case scenario which rarely happens.
1385 * In which case, resize it down to free some memory */
1386
William Kurkianea869482019-04-09 15:16:11 -04001387/*! ZSTD_resetCCtx_internal() :
1388 note : `params` are assumed fully validated at this stage */
1389static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
Abhilash S.L3b494632019-07-16 15:51:09 +05301390 ZSTD_CCtx_params params,
1391 U64 pledgedSrcSize,
William Kurkianea869482019-04-09 15:16:11 -04001392 ZSTD_compResetPolicy_e const crp,
1393 ZSTD_buffered_policy_e const zbuff)
1394{
1395 DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
1396 (U32)pledgedSrcSize, params.cParams.windowLog);
1397 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
1398
1399 if (crp == ZSTDcrp_continue) {
1400 if (ZSTD_equivalentParams(zc->appliedParams, params,
Abhilash S.L3b494632019-07-16 15:51:09 +05301401 zc->inBuffSize,
1402 zc->seqStore.maxNbSeq, zc->seqStore.maxNbLit,
1403 zbuff, pledgedSrcSize)) {
1404 DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%zu)",
1405 zc->appliedParams.cParams.windowLog, zc->blockSize);
1406 zc->workSpaceOversizedDuration += (zc->workSpaceOversizedDuration > 0); /* if it was too large, it still is */
1407 if (zc->workSpaceOversizedDuration <= ZSTD_WORKSPACETOOLARGE_MAXDURATION)
1408 return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
William Kurkianea869482019-04-09 15:16:11 -04001409 } }
1410 DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx");
1411
1412 if (params.ldmParams.enableLdm) {
1413 /* Adjust long distance matching parameters */
William Kurkianea869482019-04-09 15:16:11 -04001414 ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
1415 assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
Abhilash S.L3b494632019-07-16 15:51:09 +05301416 assert(params.ldmParams.hashRateLog < 32);
1417 zc->ldmState.hashPower = ZSTD_rollingHash_primePower(params.ldmParams.minMatchLength);
William Kurkianea869482019-04-09 15:16:11 -04001418 }
1419
1420 { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
1421 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
Abhilash S.L3b494632019-07-16 15:51:09 +05301422 U32 const divider = (params.cParams.minMatch==3) ? 3 : 4;
William Kurkianea869482019-04-09 15:16:11 -04001423 size_t const maxNbSeq = blockSize / divider;
Abhilash S.L3b494632019-07-16 15:51:09 +05301424 size_t const tokenSpace = WILDCOPY_OVERLENGTH + blockSize + 11*maxNbSeq;
William Kurkianea869482019-04-09 15:16:11 -04001425 size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
1426 size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
1427 size_t const matchStateSize = ZSTD_sizeof_matchState(&params.cParams, /* forCCtx */ 1);
1428 size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
Abhilash S.L3b494632019-07-16 15:51:09 +05301429 void* ptr; /* used to partition workSpace */
William Kurkianea869482019-04-09 15:16:11 -04001430
1431 /* Check if workSpace is large enough, alloc a new one if needed */
1432 { size_t const entropySpace = HUF_WORKSPACE_SIZE;
1433 size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
1434 size_t const bufferSpace = buffInSize + buffOutSize;
1435 size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams);
1436 size_t const ldmSeqSpace = maxNbLdmSeq * sizeof(rawSeq);
1437
1438 size_t const neededSpace = entropySpace + blockStateSpace + ldmSpace +
1439 ldmSeqSpace + matchStateSize + tokenSpace +
1440 bufferSpace;
William Kurkianea869482019-04-09 15:16:11 -04001441
Abhilash S.L3b494632019-07-16 15:51:09 +05301442 int const workSpaceTooSmall = zc->workSpaceSize < neededSpace;
1443 int const workSpaceTooLarge = zc->workSpaceSize > ZSTD_WORKSPACETOOLARGE_FACTOR * neededSpace;
1444 int const workSpaceWasteful = workSpaceTooLarge && (zc->workSpaceOversizedDuration > ZSTD_WORKSPACETOOLARGE_MAXDURATION);
1445 zc->workSpaceOversizedDuration = workSpaceTooLarge ? zc->workSpaceOversizedDuration+1 : 0;
1446
1447 DEBUGLOG(4, "Need %zuKB workspace, including %zuKB for match state, and %zuKB for buffers",
1448 neededSpace>>10, matchStateSize>>10, bufferSpace>>10);
1449 DEBUGLOG(4, "windowSize: %zu - blockSize: %zu", windowSize, blockSize);
1450
1451 if (workSpaceTooSmall || workSpaceWasteful) {
1452 DEBUGLOG(4, "Need to resize workSpaceSize from %zuKB to %zuKB",
1453 zc->workSpaceSize >> 10,
1454 neededSpace >> 10);
1455
1456 RETURN_ERROR_IF(zc->staticSize, memory_allocation, "static cctx : no resize");
William Kurkianea869482019-04-09 15:16:11 -04001457
1458 zc->workSpaceSize = 0;
1459 ZSTD_free(zc->workSpace, zc->customMem);
1460 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
Abhilash S.L3b494632019-07-16 15:51:09 +05301461 RETURN_ERROR_IF(zc->workSpace == NULL, memory_allocation);
William Kurkianea869482019-04-09 15:16:11 -04001462 zc->workSpaceSize = neededSpace;
Abhilash S.L3b494632019-07-16 15:51:09 +05301463 zc->workSpaceOversizedDuration = 0;
William Kurkianea869482019-04-09 15:16:11 -04001464
Abhilash S.L3b494632019-07-16 15:51:09 +05301465 /* Statically sized space.
1466 * entropyWorkspace never moves,
1467 * though prev/next block swap places */
William Kurkianea869482019-04-09 15:16:11 -04001468 assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */
1469 assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_compressedBlockState_t));
1470 zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)zc->workSpace;
1471 zc->blockState.nextCBlock = zc->blockState.prevCBlock + 1;
1472 ptr = zc->blockState.nextCBlock + 1;
1473 zc->entropyWorkspace = (U32*)ptr;
1474 } }
1475
1476 /* init params */
1477 zc->appliedParams = params;
Abhilash S.L3b494632019-07-16 15:51:09 +05301478 zc->blockState.matchState.cParams = params.cParams;
William Kurkianea869482019-04-09 15:16:11 -04001479 zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
1480 zc->consumedSrcSize = 0;
1481 zc->producedCSize = 0;
1482 if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
1483 zc->appliedParams.fParams.contentSizeFlag = 0;
1484 DEBUGLOG(4, "pledged content size : %u ; flag : %u",
Abhilash S.L3b494632019-07-16 15:51:09 +05301485 (unsigned)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag);
William Kurkianea869482019-04-09 15:16:11 -04001486 zc->blockSize = blockSize;
1487
1488 XXH64_reset(&zc->xxhState, 0);
1489 zc->stage = ZSTDcs_init;
1490 zc->dictID = 0;
1491
1492 ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
1493
1494 ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32;
1495
1496 /* ldm hash table */
1497 /* initialize bucketOffsets table later for pointer alignment */
1498 if (params.ldmParams.enableLdm) {
1499 size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
1500 memset(ptr, 0, ldmHSize * sizeof(ldmEntry_t));
1501 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
1502 zc->ldmState.hashTable = (ldmEntry_t*)ptr;
1503 ptr = zc->ldmState.hashTable + ldmHSize;
1504 zc->ldmSequences = (rawSeq*)ptr;
1505 ptr = zc->ldmSequences + maxNbLdmSeq;
1506 zc->maxNbLdmSequences = maxNbLdmSeq;
1507
1508 memset(&zc->ldmState.window, 0, sizeof(zc->ldmState.window));
1509 }
1510 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
1511
1512 ptr = ZSTD_reset_matchState(&zc->blockState.matchState, ptr, &params.cParams, crp, /* forCCtx */ 1);
1513
1514 /* sequences storage */
Abhilash S.L3b494632019-07-16 15:51:09 +05301515 zc->seqStore.maxNbSeq = maxNbSeq;
William Kurkianea869482019-04-09 15:16:11 -04001516 zc->seqStore.sequencesStart = (seqDef*)ptr;
1517 ptr = zc->seqStore.sequencesStart + maxNbSeq;
1518 zc->seqStore.llCode = (BYTE*) ptr;
1519 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
1520 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
1521 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
Abhilash S.L3b494632019-07-16 15:51:09 +05301522 /* ZSTD_wildcopy() is used to copy into the literals buffer,
1523 * so we have to oversize the buffer by WILDCOPY_OVERLENGTH bytes.
1524 */
1525 zc->seqStore.maxNbLit = blockSize;
1526 ptr = zc->seqStore.litStart + blockSize + WILDCOPY_OVERLENGTH;
William Kurkianea869482019-04-09 15:16:11 -04001527
1528 /* ldm bucketOffsets table */
1529 if (params.ldmParams.enableLdm) {
1530 size_t const ldmBucketSize =
1531 ((size_t)1) << (params.ldmParams.hashLog -
1532 params.ldmParams.bucketSizeLog);
1533 memset(ptr, 0, ldmBucketSize);
1534 zc->ldmState.bucketOffsets = (BYTE*)ptr;
1535 ptr = zc->ldmState.bucketOffsets + ldmBucketSize;
1536 ZSTD_window_clear(&zc->ldmState.window);
1537 }
1538 ZSTD_referenceExternalSequences(zc, NULL, 0);
1539
1540 /* buffers */
1541 zc->inBuffSize = buffInSize;
1542 zc->inBuff = (char*)ptr;
1543 zc->outBuffSize = buffOutSize;
1544 zc->outBuff = zc->inBuff + buffInSize;
1545
1546 return 0;
1547 }
1548}
1549
1550/* ZSTD_invalidateRepCodes() :
1551 * ensures next compression will not use repcodes from previous block.
1552 * Note : only works with regular variant;
1553 * do not use with extDict variant ! */
1554void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
1555 int i;
1556 for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0;
1557 assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window));
1558}
1559
Abhilash S.L3b494632019-07-16 15:51:09 +05301560/* These are the approximate sizes for each strategy past which copying the
1561 * dictionary tables into the working context is faster than using them
1562 * in-place.
1563 */
1564static const size_t attachDictSizeCutoffs[ZSTD_STRATEGY_MAX+1] = {
1565 8 KB, /* unused */
1566 8 KB, /* ZSTD_fast */
1567 16 KB, /* ZSTD_dfast */
1568 32 KB, /* ZSTD_greedy */
1569 32 KB, /* ZSTD_lazy */
1570 32 KB, /* ZSTD_lazy2 */
1571 32 KB, /* ZSTD_btlazy2 */
1572 32 KB, /* ZSTD_btopt */
1573 8 KB, /* ZSTD_btultra */
1574 8 KB /* ZSTD_btultra2 */
1575};
1576
1577static int ZSTD_shouldAttachDict(const ZSTD_CDict* cdict,
1578 ZSTD_CCtx_params params,
1579 U64 pledgedSrcSize)
1580{
1581 size_t cutoff = attachDictSizeCutoffs[cdict->matchState.cParams.strategy];
1582 return ( pledgedSrcSize <= cutoff
1583 || pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN
1584 || params.attachDictPref == ZSTD_dictForceAttach )
1585 && params.attachDictPref != ZSTD_dictForceCopy
1586 && !params.forceWindow; /* dictMatchState isn't correctly
1587 * handled in _enforceMaxDist */
1588}
1589
1590static size_t ZSTD_resetCCtx_byAttachingCDict(
1591 ZSTD_CCtx* cctx,
1592 const ZSTD_CDict* cdict,
1593 ZSTD_CCtx_params params,
1594 U64 pledgedSrcSize,
1595 ZSTD_buffered_policy_e zbuff)
1596{
1597 {
1598 const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
1599 unsigned const windowLog = params.cParams.windowLog;
1600 assert(windowLog != 0);
1601 /* Resize working context table params for input only, since the dict
1602 * has its own tables. */
1603 params.cParams = ZSTD_adjustCParams_internal(*cdict_cParams, pledgedSrcSize, 0);
1604 params.cParams.windowLog = windowLog;
1605 ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
1606 ZSTDcrp_continue, zbuff);
1607 assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
1608 }
1609
1610 {
1611 const U32 cdictEnd = (U32)( cdict->matchState.window.nextSrc
1612 - cdict->matchState.window.base);
1613 const U32 cdictLen = cdictEnd - cdict->matchState.window.dictLimit;
1614 if (cdictLen == 0) {
1615 /* don't even attach dictionaries with no contents */
1616 DEBUGLOG(4, "skipping attaching empty dictionary");
1617 } else {
1618 DEBUGLOG(4, "attaching dictionary into context");
1619 cctx->blockState.matchState.dictMatchState = &cdict->matchState;
1620
1621 /* prep working match state so dict matches never have negative indices
1622 * when they are translated to the working context's index space. */
1623 if (cctx->blockState.matchState.window.dictLimit < cdictEnd) {
1624 cctx->blockState.matchState.window.nextSrc =
1625 cctx->blockState.matchState.window.base + cdictEnd;
1626 ZSTD_window_clear(&cctx->blockState.matchState.window);
1627 }
1628 cctx->blockState.matchState.loadedDictEnd = cctx->blockState.matchState.window.dictLimit;
1629 }
1630 }
1631
1632 cctx->dictID = cdict->dictID;
1633
1634 /* copy block state */
1635 memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1636
1637 return 0;
1638}
1639
1640static size_t ZSTD_resetCCtx_byCopyingCDict(ZSTD_CCtx* cctx,
William Kurkianea869482019-04-09 15:16:11 -04001641 const ZSTD_CDict* cdict,
Abhilash S.L3b494632019-07-16 15:51:09 +05301642 ZSTD_CCtx_params params,
William Kurkianea869482019-04-09 15:16:11 -04001643 U64 pledgedSrcSize,
1644 ZSTD_buffered_policy_e zbuff)
1645{
Abhilash S.L3b494632019-07-16 15:51:09 +05301646 const ZSTD_compressionParameters *cdict_cParams = &cdict->matchState.cParams;
1647
1648 DEBUGLOG(4, "copying dictionary into context");
1649
1650 { unsigned const windowLog = params.cParams.windowLog;
1651 assert(windowLog != 0);
William Kurkianea869482019-04-09 15:16:11 -04001652 /* Copy only compression parameters related to tables. */
Abhilash S.L3b494632019-07-16 15:51:09 +05301653 params.cParams = *cdict_cParams;
1654 params.cParams.windowLog = windowLog;
William Kurkianea869482019-04-09 15:16:11 -04001655 ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
1656 ZSTDcrp_noMemset, zbuff);
Abhilash S.L3b494632019-07-16 15:51:09 +05301657 assert(cctx->appliedParams.cParams.strategy == cdict_cParams->strategy);
1658 assert(cctx->appliedParams.cParams.hashLog == cdict_cParams->hashLog);
1659 assert(cctx->appliedParams.cParams.chainLog == cdict_cParams->chainLog);
William Kurkianea869482019-04-09 15:16:11 -04001660 }
1661
1662 /* copy tables */
Abhilash S.L3b494632019-07-16 15:51:09 +05301663 { size_t const chainSize = (cdict_cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict_cParams->chainLog);
1664 size_t const hSize = (size_t)1 << cdict_cParams->hashLog;
William Kurkianea869482019-04-09 15:16:11 -04001665 size_t const tableSpace = (chainSize + hSize) * sizeof(U32);
1666 assert((U32*)cctx->blockState.matchState.chainTable == (U32*)cctx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */
1667 assert((U32*)cctx->blockState.matchState.hashTable3 == (U32*)cctx->blockState.matchState.chainTable + chainSize);
1668 assert((U32*)cdict->matchState.chainTable == (U32*)cdict->matchState.hashTable + hSize); /* chainTable must follow hashTable */
1669 assert((U32*)cdict->matchState.hashTable3 == (U32*)cdict->matchState.chainTable + chainSize);
1670 memcpy(cctx->blockState.matchState.hashTable, cdict->matchState.hashTable, tableSpace); /* presumes all tables follow each other */
1671 }
Abhilash S.L3b494632019-07-16 15:51:09 +05301672
William Kurkianea869482019-04-09 15:16:11 -04001673 /* Zero the hashTable3, since the cdict never fills it */
1674 { size_t const h3Size = (size_t)1 << cctx->blockState.matchState.hashLog3;
1675 assert(cdict->matchState.hashLog3 == 0);
1676 memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
1677 }
1678
1679 /* copy dictionary offsets */
Abhilash S.L3b494632019-07-16 15:51:09 +05301680 { ZSTD_matchState_t const* srcMatchState = &cdict->matchState;
William Kurkianea869482019-04-09 15:16:11 -04001681 ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState;
1682 dstMatchState->window = srcMatchState->window;
1683 dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
1684 dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
1685 dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
1686 }
Abhilash S.L3b494632019-07-16 15:51:09 +05301687
William Kurkianea869482019-04-09 15:16:11 -04001688 cctx->dictID = cdict->dictID;
1689
1690 /* copy block state */
1691 memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1692
1693 return 0;
1694}
1695
Abhilash S.L3b494632019-07-16 15:51:09 +05301696/* We have a choice between copying the dictionary context into the working
1697 * context, or referencing the dictionary context from the working context
1698 * in-place. We decide here which strategy to use. */
1699static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx,
1700 const ZSTD_CDict* cdict,
1701 ZSTD_CCtx_params params,
1702 U64 pledgedSrcSize,
1703 ZSTD_buffered_policy_e zbuff)
1704{
1705
1706 DEBUGLOG(4, "ZSTD_resetCCtx_usingCDict (pledgedSrcSize=%u)",
1707 (unsigned)pledgedSrcSize);
1708
1709 if (ZSTD_shouldAttachDict(cdict, params, pledgedSrcSize)) {
1710 return ZSTD_resetCCtx_byAttachingCDict(
1711 cctx, cdict, params, pledgedSrcSize, zbuff);
1712 } else {
1713 return ZSTD_resetCCtx_byCopyingCDict(
1714 cctx, cdict, params, pledgedSrcSize, zbuff);
1715 }
1716}
1717
William Kurkianea869482019-04-09 15:16:11 -04001718/*! ZSTD_copyCCtx_internal() :
1719 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
1720 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
1721 * The "context", in this case, refers to the hash and chain tables,
1722 * entropy tables, and dictionary references.
1723 * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx.
1724 * @return : 0, or an error code */
1725static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1726 const ZSTD_CCtx* srcCCtx,
1727 ZSTD_frameParameters fParams,
1728 U64 pledgedSrcSize,
1729 ZSTD_buffered_policy_e zbuff)
1730{
1731 DEBUGLOG(5, "ZSTD_copyCCtx_internal");
Abhilash S.L3b494632019-07-16 15:51:09 +05301732 RETURN_ERROR_IF(srcCCtx->stage!=ZSTDcs_init, stage_wrong);
William Kurkianea869482019-04-09 15:16:11 -04001733
1734 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
1735 { ZSTD_CCtx_params params = dstCCtx->requestedParams;
1736 /* Copy only compression parameters related to tables. */
1737 params.cParams = srcCCtx->appliedParams.cParams;
1738 params.fParams = fParams;
1739 ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
1740 ZSTDcrp_noMemset, zbuff);
1741 assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog);
1742 assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy);
1743 assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog);
1744 assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog);
1745 assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3);
1746 }
1747
1748 /* copy tables */
1749 { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
1750 size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
1751 size_t const h3Size = (size_t)1 << srcCCtx->blockState.matchState.hashLog3;
1752 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
1753 assert((U32*)dstCCtx->blockState.matchState.chainTable == (U32*)dstCCtx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */
1754 assert((U32*)dstCCtx->blockState.matchState.hashTable3 == (U32*)dstCCtx->blockState.matchState.chainTable + chainSize);
1755 memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, tableSpace); /* presumes all tables follow each other */
1756 }
1757
1758 /* copy dictionary offsets */
1759 {
Abhilash S.L3b494632019-07-16 15:51:09 +05301760 const ZSTD_matchState_t* srcMatchState = &srcCCtx->blockState.matchState;
William Kurkianea869482019-04-09 15:16:11 -04001761 ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState;
1762 dstMatchState->window = srcMatchState->window;
1763 dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
1764 dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
1765 dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
1766 }
1767 dstCCtx->dictID = srcCCtx->dictID;
1768
1769 /* copy block state */
1770 memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
1771
1772 return 0;
1773}
1774
1775/*! ZSTD_copyCCtx() :
1776 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
1777 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
1778 * pledgedSrcSize==0 means "unknown".
1779* @return : 0, or an error code */
1780size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
1781{
1782 ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
1783 ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
1784 ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
1785 if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
1786 fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
1787
1788 return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx,
1789 fParams, pledgedSrcSize,
1790 zbuff);
1791}
1792
1793
1794#define ZSTD_ROWSIZE 16
1795/*! ZSTD_reduceTable() :
1796 * reduce table indexes by `reducerValue`, or squash to zero.
1797 * PreserveMark preserves "unsorted mark" for btlazy2 strategy.
1798 * It must be set to a clear 0/1 value, to remove branch during inlining.
1799 * Presume table size is a multiple of ZSTD_ROWSIZE
1800 * to help auto-vectorization */
1801FORCE_INLINE_TEMPLATE void
1802ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark)
1803{
1804 int const nbRows = (int)size / ZSTD_ROWSIZE;
1805 int cellNb = 0;
1806 int rowNb;
1807 assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */
1808 assert(size < (1U<<31)); /* can be casted to int */
1809 for (rowNb=0 ; rowNb < nbRows ; rowNb++) {
1810 int column;
1811 for (column=0; column<ZSTD_ROWSIZE; column++) {
1812 if (preserveMark) {
1813 U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0;
1814 table[cellNb] += adder;
1815 }
1816 if (table[cellNb] < reducerValue) table[cellNb] = 0;
1817 else table[cellNb] -= reducerValue;
1818 cellNb++;
1819 } }
1820}
1821
1822static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue)
1823{
1824 ZSTD_reduceTable_internal(table, size, reducerValue, 0);
1825}
1826
1827static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue)
1828{
1829 ZSTD_reduceTable_internal(table, size, reducerValue, 1);
1830}
1831
1832/*! ZSTD_reduceIndex() :
1833* rescale all indexes to avoid future overflow (indexes are U32) */
1834static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
1835{
1836 ZSTD_matchState_t* const ms = &zc->blockState.matchState;
1837 { U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog;
1838 ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
1839 }
1840
1841 if (zc->appliedParams.cParams.strategy != ZSTD_fast) {
1842 U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog;
1843 if (zc->appliedParams.cParams.strategy == ZSTD_btlazy2)
1844 ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue);
1845 else
1846 ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue);
1847 }
1848
1849 if (ms->hashLog3) {
1850 U32 const h3Size = (U32)1 << ms->hashLog3;
1851 ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue);
1852 }
1853}
1854
1855
1856/*-*******************************************************
1857* Block entropic compression
1858*********************************************************/
1859
1860/* See doc/zstd_compression_format.md for detailed format description */
1861
Abhilash S.L3b494632019-07-16 15:51:09 +05301862static size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize, U32 lastBlock)
William Kurkianea869482019-04-09 15:16:11 -04001863{
Abhilash S.L3b494632019-07-16 15:51:09 +05301864 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(srcSize << 3);
1865 RETURN_ERROR_IF(srcSize + ZSTD_blockHeaderSize > dstCapacity,
1866 dstSize_tooSmall);
1867 MEM_writeLE24(dst, cBlockHeader24);
William Kurkianea869482019-04-09 15:16:11 -04001868 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
Abhilash S.L3b494632019-07-16 15:51:09 +05301869 return ZSTD_blockHeaderSize + srcSize;
William Kurkianea869482019-04-09 15:16:11 -04001870}
1871
William Kurkianea869482019-04-09 15:16:11 -04001872static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
1873{
1874 BYTE* const ostart = (BYTE* const)dst;
1875 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
1876
Abhilash S.L3b494632019-07-16 15:51:09 +05301877 RETURN_ERROR_IF(srcSize + flSize > dstCapacity, dstSize_tooSmall);
William Kurkianea869482019-04-09 15:16:11 -04001878
1879 switch(flSize)
1880 {
1881 case 1: /* 2 - 1 - 5 */
1882 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
1883 break;
1884 case 2: /* 2 - 2 - 12 */
1885 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
1886 break;
1887 case 3: /* 2 - 2 - 20 */
1888 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
1889 break;
1890 default: /* not necessary : flSize is {1,2,3} */
1891 assert(0);
1892 }
1893
1894 memcpy(ostart + flSize, src, srcSize);
1895 return srcSize + flSize;
1896}
1897
1898static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
1899{
1900 BYTE* const ostart = (BYTE* const)dst;
1901 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
1902
1903 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
1904
1905 switch(flSize)
1906 {
1907 case 1: /* 2 - 1 - 5 */
1908 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
1909 break;
1910 case 2: /* 2 - 2 - 12 */
1911 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
1912 break;
1913 case 3: /* 2 - 2 - 20 */
1914 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
1915 break;
1916 default: /* not necessary : flSize is {1,2,3} */
1917 assert(0);
1918 }
1919
1920 ostart[flSize] = *(const BYTE*)src;
1921 return flSize+1;
1922}
1923
1924
Abhilash S.L3b494632019-07-16 15:51:09 +05301925/* ZSTD_minGain() :
1926 * minimum compression required
1927 * to generate a compress block or a compressed literals section.
1928 * note : use same formula for both situations */
1929static size_t ZSTD_minGain(size_t srcSize, ZSTD_strategy strat)
1930{
1931 U32 const minlog = (strat>=ZSTD_btultra) ? (U32)(strat) - 1 : 6;
1932 ZSTD_STATIC_ASSERT(ZSTD_btultra == 8);
1933 assert(ZSTD_cParam_withinBounds(ZSTD_c_strategy, strat));
1934 return (srcSize >> minlog) + 2;
1935}
William Kurkianea869482019-04-09 15:16:11 -04001936
Abhilash S.L3b494632019-07-16 15:51:09 +05301937static size_t ZSTD_compressLiterals (ZSTD_hufCTables_t const* prevHuf,
1938 ZSTD_hufCTables_t* nextHuf,
William Kurkianea869482019-04-09 15:16:11 -04001939 ZSTD_strategy strategy, int disableLiteralCompression,
1940 void* dst, size_t dstCapacity,
1941 const void* src, size_t srcSize,
Abhilash S.L3b494632019-07-16 15:51:09 +05301942 void* workspace, size_t wkspSize,
1943 const int bmi2)
William Kurkianea869482019-04-09 15:16:11 -04001944{
Abhilash S.L3b494632019-07-16 15:51:09 +05301945 size_t const minGain = ZSTD_minGain(srcSize, strategy);
William Kurkianea869482019-04-09 15:16:11 -04001946 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
1947 BYTE* const ostart = (BYTE*)dst;
1948 U32 singleStream = srcSize < 256;
1949 symbolEncodingType_e hType = set_compressed;
1950 size_t cLitSize;
1951
1952 DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i)",
1953 disableLiteralCompression);
1954
1955 /* Prepare nextEntropy assuming reusing the existing table */
Abhilash S.L3b494632019-07-16 15:51:09 +05301956 memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
William Kurkianea869482019-04-09 15:16:11 -04001957
1958 if (disableLiteralCompression)
1959 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
1960
1961 /* small ? don't even attempt compression (speed opt) */
1962# define COMPRESS_LITERALS_SIZE_MIN 63
Abhilash S.L3b494632019-07-16 15:51:09 +05301963 { size_t const minLitSize = (prevHuf->repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
William Kurkianea869482019-04-09 15:16:11 -04001964 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
1965 }
1966
Abhilash S.L3b494632019-07-16 15:51:09 +05301967 RETURN_ERROR_IF(dstCapacity < lhSize+1, dstSize_tooSmall, "not enough space for compression");
1968 { HUF_repeat repeat = prevHuf->repeatMode;
William Kurkianea869482019-04-09 15:16:11 -04001969 int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
1970 if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
1971 cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Abhilash S.L3b494632019-07-16 15:51:09 +05301972 workspace, wkspSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2)
William Kurkianea869482019-04-09 15:16:11 -04001973 : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Abhilash S.L3b494632019-07-16 15:51:09 +05301974 workspace, wkspSize, (HUF_CElt*)nextHuf->CTable, &repeat, preferRepeat, bmi2);
William Kurkianea869482019-04-09 15:16:11 -04001975 if (repeat != HUF_repeat_none) {
1976 /* reused the existing table */
1977 hType = set_repeat;
1978 }
1979 }
1980
1981 if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
Abhilash S.L3b494632019-07-16 15:51:09 +05301982 memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
William Kurkianea869482019-04-09 15:16:11 -04001983 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
1984 }
1985 if (cLitSize==1) {
Abhilash S.L3b494632019-07-16 15:51:09 +05301986 memcpy(nextHuf, prevHuf, sizeof(*prevHuf));
William Kurkianea869482019-04-09 15:16:11 -04001987 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
1988 }
1989
1990 if (hType == set_compressed) {
1991 /* using a newly constructed table */
Abhilash S.L3b494632019-07-16 15:51:09 +05301992 nextHuf->repeatMode = HUF_repeat_check;
William Kurkianea869482019-04-09 15:16:11 -04001993 }
1994
1995 /* Build header */
1996 switch(lhSize)
1997 {
1998 case 3: /* 2 - 2 - 10 - 10 */
1999 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
2000 MEM_writeLE24(ostart, lhc);
2001 break;
2002 }
2003 case 4: /* 2 - 2 - 14 - 14 */
2004 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
2005 MEM_writeLE32(ostart, lhc);
2006 break;
2007 }
2008 case 5: /* 2 - 2 - 18 - 18 */
2009 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
2010 MEM_writeLE32(ostart, lhc);
2011 ostart[4] = (BYTE)(cLitSize >> 10);
2012 break;
2013 }
2014 default: /* not possible : lhSize is {3,4,5} */
2015 assert(0);
2016 }
2017 return lhSize+cLitSize;
2018}
2019
2020
2021void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
2022{
2023 const seqDef* const sequences = seqStorePtr->sequencesStart;
2024 BYTE* const llCodeTable = seqStorePtr->llCode;
2025 BYTE* const ofCodeTable = seqStorePtr->ofCode;
2026 BYTE* const mlCodeTable = seqStorePtr->mlCode;
2027 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
2028 U32 u;
Abhilash S.L3b494632019-07-16 15:51:09 +05302029 assert(nbSeq <= seqStorePtr->maxNbSeq);
William Kurkianea869482019-04-09 15:16:11 -04002030 for (u=0; u<nbSeq; u++) {
2031 U32 const llv = sequences[u].litLength;
2032 U32 const mlv = sequences[u].matchLength;
2033 llCodeTable[u] = (BYTE)ZSTD_LLcode(llv);
2034 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
2035 mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv);
2036 }
2037 if (seqStorePtr->longLengthID==1)
2038 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
2039 if (seqStorePtr->longLengthID==2)
2040 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
2041}
2042
Abhilash S.L3b494632019-07-16 15:51:09 +05302043
2044/**
2045 * -log2(x / 256) lookup table for x in [0, 256).
2046 * If x == 0: Return 0
2047 * Else: Return floor(-log2(x / 256) * 256)
2048 */
2049static unsigned const kInverseProbabilityLog256[256] = {
2050 0, 2048, 1792, 1642, 1536, 1453, 1386, 1329, 1280, 1236, 1197, 1162,
2051 1130, 1100, 1073, 1047, 1024, 1001, 980, 960, 941, 923, 906, 889,
2052 874, 859, 844, 830, 817, 804, 791, 779, 768, 756, 745, 734,
2053 724, 714, 704, 694, 685, 676, 667, 658, 650, 642, 633, 626,
2054 618, 610, 603, 595, 588, 581, 574, 567, 561, 554, 548, 542,
2055 535, 529, 523, 517, 512, 506, 500, 495, 489, 484, 478, 473,
2056