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