comparison contrib/python-zstandard/zstd/compress/zstd_compress.c @ 37495:b1fb341d8a61

zstandard: vendor python-zstandard 0.9.0 This was just released. It features a number of goodies. More info at https://gregoryszorc.com/blog/2018/04/09/release-of-python-zstandard-0.9/. The clang-format ignore list was updated to reflect the new source of files. The project contains a vendored copy of zstandard 1.3.4. The old version was 1.1.3. One of the changes between those versions is that zstandard is now dual licensed BSD + GPLv2 and the patent rights grant has been removed. Good riddance. The API should be backwards compatible. So no changes in core should be needed. However, there were a number of changes in the library that we'll want to adapt to. Those will be addressed in subsequent commits. Differential Revision: https://phab.mercurial-scm.org/D3198
author Gregory Szorc <gregory.szorc@gmail.com>
date Mon, 09 Apr 2018 10:13:29 -0700
parents c32454d69b85
children 73fef626dae3
comparison
equal deleted inserted replaced
37494:1ce7a55b09d1 37495:b1fb341d8a61
1 /** 1 /*
2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. 2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
5 * This source code is licensed under the BSD-style license found in the 5 * This source code is licensed under both the BSD-style license (found in the
6 * LICENSE file in the root directory of this source tree. An additional grant 6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found
7 * of patent rights can be found in the PATENTS file in the same directory. 7 * in the COPYING file in the root directory of this source tree).
8 * You may select, at your option, one of the above-listed licenses.
8 */ 9 */
10
11
12 /*-*************************************
13 * Tuning parameters
14 ***************************************/
15 #ifndef ZSTD_CLEVEL_DEFAULT
16 # define ZSTD_CLEVEL_DEFAULT 3
17 #endif
9 18
10 19
11 /*-************************************* 20 /*-*************************************
12 * Dependencies 21 * Dependencies
13 ***************************************/ 22 ***************************************/
14 #include <string.h> /* memset */ 23 #include <string.h> /* memset */
24 #include "cpu.h"
15 #include "mem.h" 25 #include "mem.h"
16 #define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
17 #include "xxhash.h" /* XXH_reset, update, digest */
18 #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */ 26 #define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
19 #include "fse.h" 27 #include "fse.h"
20 #define HUF_STATIC_LINKING_ONLY 28 #define HUF_STATIC_LINKING_ONLY
21 #include "huf.h" 29 #include "huf.h"
22 #include "zstd_internal.h" /* includes zstd.h */ 30 #include "zstd_compress_internal.h"
23 31 #include "zstd_fast.h"
24 32 #include "zstd_double_fast.h"
25 /*-************************************* 33 #include "zstd_lazy.h"
26 * Constants 34 #include "zstd_opt.h"
27 ***************************************/ 35 #include "zstd_ldm.h"
28 static const U32 g_searchStrength = 8; /* control skip over incompressible data */
29 #define HASH_READ_SIZE 8
30 typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
31 36
32 37
33 /*-************************************* 38 /*-*************************************
34 * Helper functions 39 * Helper functions
35 ***************************************/ 40 ***************************************/
36 #define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; } 41 size_t ZSTD_compressBound(size_t srcSize) {
37 size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; } 42 return ZSTD_COMPRESSBOUND(srcSize);
38
39
40 /*-*************************************
41 * Sequence storage
42 ***************************************/
43 static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
44 {
45 ssPtr->lit = ssPtr->litStart;
46 ssPtr->sequences = ssPtr->sequencesStart;
47 ssPtr->longLengthID = 0;
48 } 43 }
49 44
50 45
51 /*-************************************* 46 /*-*************************************
52 * Context memory management 47 * Context memory management
53 ***************************************/ 48 ***************************************/
54 struct ZSTD_CCtx_s { 49 struct ZSTD_CDict_s {
55 const BYTE* nextSrc; /* next block here to continue on current prefix */ 50 void* dictBuffer;
56 const BYTE* base; /* All regular indexes relative to this position */ 51 const void* dictContent;
57 const BYTE* dictBase; /* extDict indexes relative to this position */ 52 size_t dictContentSize;
58 U32 dictLimit; /* below that point, need extDict */ 53 void* workspace;
59 U32 lowLimit; /* below that point, no more data */ 54 size_t workspaceSize;
60 U32 nextToUpdate; /* index from which to continue dictionary update */ 55 ZSTD_matchState_t matchState;
61 U32 nextToUpdate3; /* index from which to continue dictionary update */ 56 ZSTD_compressedBlockState_t cBlockState;
62 U32 hashLog3; /* dispatch table : larger == faster, more memory */ 57 ZSTD_compressionParameters cParams;
63 U32 loadedDictEnd; /* index of end of dictionary */
64 U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
65 ZSTD_compressionStage_e stage;
66 U32 rep[ZSTD_REP_NUM];
67 U32 repToConfirm[ZSTD_REP_NUM];
68 U32 dictID;
69 ZSTD_parameters params;
70 void* workSpace;
71 size_t workSpaceSize;
72 size_t blockSize;
73 U64 frameContentSize;
74 XXH64_state_t xxhState;
75 ZSTD_customMem customMem; 58 ZSTD_customMem customMem;
76 59 U32 dictID;
77 seqStore_t seqStore; /* sequences storage ptrs */ 60 }; /* typedef'd to ZSTD_CDict within "zstd.h" */
78 U32* hashTable;
79 U32* hashTable3;
80 U32* chainTable;
81 HUF_CElt* hufTable;
82 U32 flagStaticTables;
83 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
84 FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
85 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
86 unsigned tmpCounters[1024];
87 };
88 61
89 ZSTD_CCtx* ZSTD_createCCtx(void) 62 ZSTD_CCtx* ZSTD_createCCtx(void)
90 { 63 {
91 return ZSTD_createCCtx_advanced(defaultCustomMem); 64 return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
92 } 65 }
93 66
94 ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem) 67 ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
95 { 68 {
96 ZSTD_CCtx* cctx; 69 ZSTD_STATIC_ASSERT(zcss_init==0);
97 70 ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
98 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem; 71 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
99 if (!customMem.customAlloc || !customMem.customFree) return NULL; 72 { ZSTD_CCtx* const cctx = (ZSTD_CCtx*)ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
100 73 if (!cctx) return NULL;
101 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem); 74 cctx->customMem = customMem;
102 if (!cctx) return NULL; 75 cctx->requestedParams.compressionLevel = ZSTD_CLEVEL_DEFAULT;
103 memset(cctx, 0, sizeof(ZSTD_CCtx)); 76 cctx->requestedParams.fParams.contentSizeFlag = 1;
104 cctx->customMem = customMem; 77 cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
78 return cctx;
79 }
80 }
81
82 ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
83 {
84 ZSTD_CCtx* const cctx = (ZSTD_CCtx*) workspace;
85 if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
86 if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
87 memset(workspace, 0, workspaceSize); /* may be a bit generous, could memset be smaller ? */
88 cctx->staticSize = workspaceSize;
89 cctx->workSpace = (void*)(cctx+1);
90 cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
91
92 /* statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
93 if (cctx->workSpaceSize < HUF_WORKSPACE_SIZE + 2 * sizeof(ZSTD_compressedBlockState_t)) return NULL;
94 assert(((size_t)cctx->workSpace & (sizeof(void*)-1)) == 0); /* ensure correct alignment */
95 cctx->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)cctx->workSpace;
96 cctx->blockState.nextCBlock = cctx->blockState.prevCBlock + 1;
97 {
98 void* const ptr = cctx->blockState.nextCBlock + 1;
99 cctx->entropyWorkspace = (U32*)ptr;
100 }
101 cctx->bmi2 = ZSTD_cpuid_bmi2(ZSTD_cpuid());
105 return cctx; 102 return cctx;
106 } 103 }
107 104
108 size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx) 105 size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
109 { 106 {
110 if (cctx==NULL) return 0; /* support free on NULL */ 107 if (cctx==NULL) return 0; /* support free on NULL */
111 ZSTD_free(cctx->workSpace, cctx->customMem); 108 if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */
109 ZSTD_free(cctx->workSpace, cctx->customMem); cctx->workSpace = NULL;
110 ZSTD_freeCDict(cctx->cdictLocal); cctx->cdictLocal = NULL;
111 #ifdef ZSTD_MULTITHREAD
112 ZSTDMT_freeCCtx(cctx->mtctx); cctx->mtctx = NULL;
113 #endif
112 ZSTD_free(cctx, cctx->customMem); 114 ZSTD_free(cctx, cctx->customMem);
113 return 0; /* reserved as a potential error code in the future */ 115 return 0; /* reserved as a potential error code in the future */
114 } 116 }
115 117
118
119 static size_t ZSTD_sizeof_mtctx(const ZSTD_CCtx* cctx)
120 {
121 #ifdef ZSTD_MULTITHREAD
122 return ZSTDMT_sizeof_CCtx(cctx->mtctx);
123 #else
124 (void) cctx;
125 return 0;
126 #endif
127 }
128
129
116 size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx) 130 size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
117 { 131 {
118 if (cctx==NULL) return 0; /* support sizeof on NULL */ 132 if (cctx==NULL) return 0; /* support sizeof on NULL */
119 return sizeof(*cctx) + cctx->workSpaceSize; 133 return sizeof(*cctx) + cctx->workSpaceSize
120 } 134 + ZSTD_sizeof_CDict(cctx->cdictLocal)
121 135 + ZSTD_sizeof_mtctx(cctx);
122 size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value) 136 }
137
138 size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
139 {
140 return ZSTD_sizeof_CCtx(zcs); /* same object */
141 }
142
143 /* private API call, for dictBuilder only */
144 const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
145
146 ZSTD_compressionParameters ZSTD_getCParamsFromCCtxParams(
147 const ZSTD_CCtx_params* CCtxParams, U64 srcSizeHint, size_t dictSize)
148 {
149 ZSTD_compressionParameters cParams = ZSTD_getCParams(CCtxParams->compressionLevel, srcSizeHint, dictSize);
150 if (CCtxParams->ldmParams.enableLdm) cParams.windowLog = ZSTD_LDM_DEFAULT_WINDOW_LOG;
151 if (CCtxParams->cParams.windowLog) cParams.windowLog = CCtxParams->cParams.windowLog;
152 if (CCtxParams->cParams.hashLog) cParams.hashLog = CCtxParams->cParams.hashLog;
153 if (CCtxParams->cParams.chainLog) cParams.chainLog = CCtxParams->cParams.chainLog;
154 if (CCtxParams->cParams.searchLog) cParams.searchLog = CCtxParams->cParams.searchLog;
155 if (CCtxParams->cParams.searchLength) cParams.searchLength = CCtxParams->cParams.searchLength;
156 if (CCtxParams->cParams.targetLength) cParams.targetLength = CCtxParams->cParams.targetLength;
157 if (CCtxParams->cParams.strategy) cParams.strategy = CCtxParams->cParams.strategy;
158 return cParams;
159 }
160
161 static ZSTD_CCtx_params ZSTD_makeCCtxParamsFromCParams(
162 ZSTD_compressionParameters cParams)
163 {
164 ZSTD_CCtx_params cctxParams;
165 memset(&cctxParams, 0, sizeof(cctxParams));
166 cctxParams.cParams = cParams;
167 cctxParams.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
168 assert(!ZSTD_checkCParams(cParams));
169 cctxParams.fParams.contentSizeFlag = 1;
170 return cctxParams;
171 }
172
173 static ZSTD_CCtx_params* ZSTD_createCCtxParams_advanced(
174 ZSTD_customMem customMem)
175 {
176 ZSTD_CCtx_params* params;
177 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
178 params = (ZSTD_CCtx_params*)ZSTD_calloc(
179 sizeof(ZSTD_CCtx_params), customMem);
180 if (!params) { return NULL; }
181 params->customMem = customMem;
182 params->compressionLevel = ZSTD_CLEVEL_DEFAULT;
183 params->fParams.contentSizeFlag = 1;
184 return params;
185 }
186
187 ZSTD_CCtx_params* ZSTD_createCCtxParams(void)
188 {
189 return ZSTD_createCCtxParams_advanced(ZSTD_defaultCMem);
190 }
191
192 size_t ZSTD_freeCCtxParams(ZSTD_CCtx_params* params)
193 {
194 if (params == NULL) { return 0; }
195 ZSTD_free(params, params->customMem);
196 return 0;
197 }
198
199 size_t ZSTD_CCtxParams_reset(ZSTD_CCtx_params* params)
200 {
201 return ZSTD_CCtxParams_init(params, ZSTD_CLEVEL_DEFAULT);
202 }
203
204 size_t ZSTD_CCtxParams_init(ZSTD_CCtx_params* cctxParams, int compressionLevel) {
205 if (!cctxParams) { return ERROR(GENERIC); }
206 memset(cctxParams, 0, sizeof(*cctxParams));
207 cctxParams->compressionLevel = compressionLevel;
208 cctxParams->fParams.contentSizeFlag = 1;
209 return 0;
210 }
211
212 size_t ZSTD_CCtxParams_init_advanced(ZSTD_CCtx_params* cctxParams, ZSTD_parameters params)
213 {
214 if (!cctxParams) { return ERROR(GENERIC); }
215 CHECK_F( ZSTD_checkCParams(params.cParams) );
216 memset(cctxParams, 0, sizeof(*cctxParams));
217 cctxParams->cParams = params.cParams;
218 cctxParams->fParams = params.fParams;
219 cctxParams->compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
220 assert(!ZSTD_checkCParams(params.cParams));
221 return 0;
222 }
223
224 /* ZSTD_assignParamsToCCtxParams() :
225 * params is presumed valid at this stage */
226 static ZSTD_CCtx_params ZSTD_assignParamsToCCtxParams(
227 ZSTD_CCtx_params cctxParams, ZSTD_parameters params)
228 {
229 ZSTD_CCtx_params ret = cctxParams;
230 ret.cParams = params.cParams;
231 ret.fParams = params.fParams;
232 ret.compressionLevel = ZSTD_CLEVEL_DEFAULT; /* should not matter, as all cParams are presumed properly defined */
233 assert(!ZSTD_checkCParams(params.cParams));
234 return ret;
235 }
236
237 #define CLAMPCHECK(val,min,max) { \
238 if (((val)<(min)) | ((val)>(max))) { \
239 return ERROR(parameter_outOfBound); \
240 } }
241
242
243 static int ZSTD_isUpdateAuthorized(ZSTD_cParameter param)
123 { 244 {
124 switch(param) 245 switch(param)
125 { 246 {
126 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0; 247 case ZSTD_p_compressionLevel:
127 default: return ERROR(parameter_unknown); 248 case ZSTD_p_hashLog:
128 } 249 case ZSTD_p_chainLog:
129 } 250 case ZSTD_p_searchLog:
130 251 case ZSTD_p_minMatch:
131 const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */ 252 case ZSTD_p_targetLength:
132 { 253 case ZSTD_p_compressionStrategy:
133 return &(ctx->seqStore); 254 case ZSTD_p_compressLiterals:
134 } 255 return 1;
135 256
136 static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) 257 case ZSTD_p_format:
137 { 258 case ZSTD_p_windowLog:
138 return cctx->params; 259 case ZSTD_p_contentSizeFlag:
139 } 260 case ZSTD_p_checksumFlag:
140 261 case ZSTD_p_dictIDFlag:
141 262 case ZSTD_p_forceMaxWindow :
142 /** ZSTD_checkParams() : 263 case ZSTD_p_nbWorkers:
143 ensure param values remain within authorized range. 264 case ZSTD_p_jobSize:
265 case ZSTD_p_overlapSizeLog:
266 case ZSTD_p_enableLongDistanceMatching:
267 case ZSTD_p_ldmHashLog:
268 case ZSTD_p_ldmMinMatch:
269 case ZSTD_p_ldmBucketSizeLog:
270 case ZSTD_p_ldmHashEveryLog:
271 default:
272 return 0;
273 }
274 }
275
276 size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value)
277 {
278 DEBUGLOG(4, "ZSTD_CCtx_setParameter (%u, %u)", (U32)param, value);
279 if (cctx->streamStage != zcss_init) {
280 if (ZSTD_isUpdateAuthorized(param)) {
281 cctx->cParamsChanged = 1;
282 } else {
283 return ERROR(stage_wrong);
284 } }
285
286 switch(param)
287 {
288 case ZSTD_p_format :
289 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
290
291 case ZSTD_p_compressionLevel:
292 if (cctx->cdict) return ERROR(stage_wrong);
293 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
294
295 case ZSTD_p_windowLog:
296 case ZSTD_p_hashLog:
297 case ZSTD_p_chainLog:
298 case ZSTD_p_searchLog:
299 case ZSTD_p_minMatch:
300 case ZSTD_p_targetLength:
301 case ZSTD_p_compressionStrategy:
302 if (cctx->cdict) return ERROR(stage_wrong);
303 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
304
305 case ZSTD_p_compressLiterals:
306 case ZSTD_p_contentSizeFlag:
307 case ZSTD_p_checksumFlag:
308 case ZSTD_p_dictIDFlag:
309 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
310
311 case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize,
312 * even when referencing into Dictionary content.
313 * default : 0 when using a CDict, 1 when using a Prefix */
314 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
315
316 case ZSTD_p_nbWorkers:
317 if ((value>0) && cctx->staticSize) {
318 return ERROR(parameter_unsupported); /* MT not compatible with static alloc */
319 }
320 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
321
322 case ZSTD_p_jobSize:
323 case ZSTD_p_overlapSizeLog:
324 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
325
326 case ZSTD_p_enableLongDistanceMatching:
327 case ZSTD_p_ldmHashLog:
328 case ZSTD_p_ldmMinMatch:
329 case ZSTD_p_ldmBucketSizeLog:
330 case ZSTD_p_ldmHashEveryLog:
331 if (cctx->cdict) return ERROR(stage_wrong);
332 return ZSTD_CCtxParam_setParameter(&cctx->requestedParams, param, value);
333
334 default: return ERROR(parameter_unsupported);
335 }
336 }
337
338 size_t ZSTD_CCtxParam_setParameter(
339 ZSTD_CCtx_params* CCtxParams, ZSTD_cParameter param, unsigned value)
340 {
341 DEBUGLOG(4, "ZSTD_CCtxParam_setParameter (%u, %u)", (U32)param, value);
342 switch(param)
343 {
344 case ZSTD_p_format :
345 if (value > (unsigned)ZSTD_f_zstd1_magicless)
346 return ERROR(parameter_unsupported);
347 CCtxParams->format = (ZSTD_format_e)value;
348 return (size_t)CCtxParams->format;
349
350 case ZSTD_p_compressionLevel : {
351 int cLevel = (int)value; /* cast expected to restore negative sign */
352 if (cLevel > ZSTD_maxCLevel()) cLevel = ZSTD_maxCLevel();
353 if (cLevel) { /* 0 : does not change current level */
354 CCtxParams->disableLiteralCompression = (cLevel<0); /* negative levels disable huffman */
355 CCtxParams->compressionLevel = cLevel;
356 }
357 if (CCtxParams->compressionLevel >= 0) return CCtxParams->compressionLevel;
358 return 0; /* return type (size_t) cannot represent negative values */
359 }
360
361 case ZSTD_p_windowLog :
362 if (value>0) /* 0 => use default */
363 CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
364 CCtxParams->cParams.windowLog = value;
365 return CCtxParams->cParams.windowLog;
366
367 case ZSTD_p_hashLog :
368 if (value>0) /* 0 => use default */
369 CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
370 CCtxParams->cParams.hashLog = value;
371 return CCtxParams->cParams.hashLog;
372
373 case ZSTD_p_chainLog :
374 if (value>0) /* 0 => use default */
375 CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
376 CCtxParams->cParams.chainLog = value;
377 return CCtxParams->cParams.chainLog;
378
379 case ZSTD_p_searchLog :
380 if (value>0) /* 0 => use default */
381 CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
382 CCtxParams->cParams.searchLog = value;
383 return value;
384
385 case ZSTD_p_minMatch :
386 if (value>0) /* 0 => use default */
387 CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
388 CCtxParams->cParams.searchLength = value;
389 return CCtxParams->cParams.searchLength;
390
391 case ZSTD_p_targetLength :
392 /* all values are valid. 0 => use default */
393 CCtxParams->cParams.targetLength = value;
394 return CCtxParams->cParams.targetLength;
395
396 case ZSTD_p_compressionStrategy :
397 if (value>0) /* 0 => use default */
398 CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
399 CCtxParams->cParams.strategy = (ZSTD_strategy)value;
400 return (size_t)CCtxParams->cParams.strategy;
401
402 case ZSTD_p_compressLiterals:
403 CCtxParams->disableLiteralCompression = !value;
404 return !CCtxParams->disableLiteralCompression;
405
406 case ZSTD_p_contentSizeFlag :
407 /* Content size written in frame header _when known_ (default:1) */
408 DEBUGLOG(4, "set content size flag = %u", (value>0));
409 CCtxParams->fParams.contentSizeFlag = value > 0;
410 return CCtxParams->fParams.contentSizeFlag;
411
412 case ZSTD_p_checksumFlag :
413 /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
414 CCtxParams->fParams.checksumFlag = value > 0;
415 return CCtxParams->fParams.checksumFlag;
416
417 case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
418 DEBUGLOG(4, "set dictIDFlag = %u", (value>0));
419 CCtxParams->fParams.noDictIDFlag = !value;
420 return !CCtxParams->fParams.noDictIDFlag;
421
422 case ZSTD_p_forceMaxWindow :
423 CCtxParams->forceWindow = (value > 0);
424 return CCtxParams->forceWindow;
425
426 case ZSTD_p_nbWorkers :
427 #ifndef ZSTD_MULTITHREAD
428 if (value>0) return ERROR(parameter_unsupported);
429 return 0;
430 #else
431 return ZSTDMT_CCtxParam_setNbWorkers(CCtxParams, value);
432 #endif
433
434 case ZSTD_p_jobSize :
435 #ifndef ZSTD_MULTITHREAD
436 return ERROR(parameter_unsupported);
437 #else
438 return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_jobSize, value);
439 #endif
440
441 case ZSTD_p_overlapSizeLog :
442 #ifndef ZSTD_MULTITHREAD
443 return ERROR(parameter_unsupported);
444 #else
445 return ZSTDMT_CCtxParam_setMTCtxParameter(CCtxParams, ZSTDMT_p_overlapSectionLog, value);
446 #endif
447
448 case ZSTD_p_enableLongDistanceMatching :
449 CCtxParams->ldmParams.enableLdm = (value>0);
450 return CCtxParams->ldmParams.enableLdm;
451
452 case ZSTD_p_ldmHashLog :
453 if (value>0) /* 0 ==> auto */
454 CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
455 CCtxParams->ldmParams.hashLog = value;
456 return CCtxParams->ldmParams.hashLog;
457
458 case ZSTD_p_ldmMinMatch :
459 if (value>0) /* 0 ==> default */
460 CLAMPCHECK(value, ZSTD_LDM_MINMATCH_MIN, ZSTD_LDM_MINMATCH_MAX);
461 CCtxParams->ldmParams.minMatchLength = value;
462 return CCtxParams->ldmParams.minMatchLength;
463
464 case ZSTD_p_ldmBucketSizeLog :
465 if (value > ZSTD_LDM_BUCKETSIZELOG_MAX)
466 return ERROR(parameter_outOfBound);
467 CCtxParams->ldmParams.bucketSizeLog = value;
468 return CCtxParams->ldmParams.bucketSizeLog;
469
470 case ZSTD_p_ldmHashEveryLog :
471 if (value > ZSTD_WINDOWLOG_MAX - ZSTD_HASHLOG_MIN)
472 return ERROR(parameter_outOfBound);
473 CCtxParams->ldmParams.hashEveryLog = value;
474 return CCtxParams->ldmParams.hashEveryLog;
475
476 default: return ERROR(parameter_unsupported);
477 }
478 }
479
480 /** ZSTD_CCtx_setParametersUsingCCtxParams() :
481 * just applies `params` into `cctx`
482 * no action is performed, parameters are merely stored.
483 * If ZSTDMT is enabled, parameters are pushed to cctx->mtctx.
484 * This is possible even if a compression is ongoing.
485 * In which case, new parameters will be applied on the fly, starting with next compression job.
486 */
487 size_t ZSTD_CCtx_setParametersUsingCCtxParams(
488 ZSTD_CCtx* cctx, const ZSTD_CCtx_params* params)
489 {
490 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
491 if (cctx->cdict) return ERROR(stage_wrong);
492
493 cctx->requestedParams = *params;
494 return 0;
495 }
496
497 ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
498 {
499 DEBUGLOG(4, "ZSTD_CCtx_setPledgedSrcSize to %u bytes", (U32)pledgedSrcSize);
500 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
501 cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
502 return 0;
503 }
504
505 size_t ZSTD_CCtx_loadDictionary_advanced(
506 ZSTD_CCtx* cctx, const void* dict, size_t dictSize,
507 ZSTD_dictLoadMethod_e dictLoadMethod, ZSTD_dictContentType_e dictContentType)
508 {
509 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
510 if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
511 DEBUGLOG(4, "ZSTD_CCtx_loadDictionary_advanced (size: %u)", (U32)dictSize);
512 ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */
513 if (dict==NULL || dictSize==0) { /* no dictionary mode */
514 cctx->cdictLocal = NULL;
515 cctx->cdict = NULL;
516 } else {
517 ZSTD_compressionParameters const cParams =
518 ZSTD_getCParamsFromCCtxParams(&cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, dictSize);
519 cctx->cdictLocal = ZSTD_createCDict_advanced(
520 dict, dictSize,
521 dictLoadMethod, dictContentType,
522 cParams, cctx->customMem);
523 cctx->cdict = cctx->cdictLocal;
524 if (cctx->cdictLocal == NULL)
525 return ERROR(memory_allocation);
526 }
527 return 0;
528 }
529
530 ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary_byReference(
531 ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
532 {
533 return ZSTD_CCtx_loadDictionary_advanced(
534 cctx, dict, dictSize, ZSTD_dlm_byRef, ZSTD_dct_auto);
535 }
536
537 ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
538 {
539 return ZSTD_CCtx_loadDictionary_advanced(
540 cctx, dict, dictSize, ZSTD_dlm_byCopy, ZSTD_dct_auto);
541 }
542
543
544 size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
545 {
546 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
547 cctx->cdict = cdict;
548 memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* exclusive */
549 return 0;
550 }
551
552 size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
553 {
554 return ZSTD_CCtx_refPrefix_advanced(cctx, prefix, prefixSize, ZSTD_dct_rawContent);
555 }
556
557 size_t ZSTD_CCtx_refPrefix_advanced(
558 ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize, ZSTD_dictContentType_e dictContentType)
559 {
560 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
561 cctx->cdict = NULL; /* prefix discards any prior cdict */
562 cctx->prefixDict.dict = prefix;
563 cctx->prefixDict.dictSize = prefixSize;
564 cctx->prefixDict.dictContentType = dictContentType;
565 return 0;
566 }
567
568 static void ZSTD_startNewCompression(ZSTD_CCtx* cctx)
569 {
570 cctx->streamStage = zcss_init;
571 cctx->pledgedSrcSizePlusOne = 0;
572 }
573
574 /*! ZSTD_CCtx_reset() :
575 * Also dumps dictionary */
576 void ZSTD_CCtx_reset(ZSTD_CCtx* cctx)
577 {
578 ZSTD_startNewCompression(cctx);
579 cctx->cdict = NULL;
580 }
581
582 /** ZSTD_checkCParams() :
583 control CParam values remain within authorized range.
144 @return : 0, or an error code if one value is beyond authorized range */ 584 @return : 0, or an error code if one value is beyond authorized range */
145 size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams) 585 size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
146 { 586 {
147 # define CLAMPCHECK(val,min,max) { if ((val<min) | (val>max)) return ERROR(compressionParameter_unsupported); }
148 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX); 587 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
149 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX); 588 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
150 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX); 589 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
151 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX); 590 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
152 { U32 const searchLengthMin = ((cParams.strategy == ZSTD_fast) | (cParams.strategy == ZSTD_greedy)) ? ZSTD_SEARCHLENGTH_MIN+1 : ZSTD_SEARCHLENGTH_MIN; 591 CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
153 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1; 592 if ((U32)(cParams.targetLength) < ZSTD_TARGETLENGTH_MIN)
154 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); } 593 return ERROR(parameter_unsupported);
155 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX); 594 if ((U32)(cParams.strategy) > (U32)ZSTD_btultra)
156 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2) return ERROR(compressionParameter_unsupported); 595 return ERROR(parameter_unsupported);
157 return 0; 596 return 0;
158 } 597 }
159 598
599 /** ZSTD_clampCParams() :
600 * make CParam values within valid range.
601 * @return : valid CParams */
602 static ZSTD_compressionParameters ZSTD_clampCParams(ZSTD_compressionParameters cParams)
603 {
604 # define CLAMP(val,min,max) { \
605 if (val<min) val=min; \
606 else if (val>max) val=max; \
607 }
608 CLAMP(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
609 CLAMP(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
610 CLAMP(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
611 CLAMP(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
612 CLAMP(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
613 if ((U32)(cParams.targetLength) < ZSTD_TARGETLENGTH_MIN) cParams.targetLength = ZSTD_TARGETLENGTH_MIN;
614 if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) cParams.strategy = ZSTD_btultra;
615 return cParams;
616 }
160 617
161 /** ZSTD_cycleLog() : 618 /** ZSTD_cycleLog() :
162 * condition for correct operation : hashLog > 1 */ 619 * condition for correct operation : hashLog > 1 */
163 static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat) 620 static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
164 { 621 {
165 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2); 622 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
166 return hashLog - btScale; 623 return hashLog - btScale;
167 } 624 }
168 625
169 /** ZSTD_adjustCParams() : 626 /** ZSTD_adjustCParams_internal() :
170 optimize `cPar` for a given input (`srcSize` and `dictSize`). 627 optimize `cPar` for a given input (`srcSize` and `dictSize`).
171 mostly downsizing to reduce memory consumption and initialization. 628 mostly downsizing to reduce memory consumption and initialization latency.
172 Both `srcSize` and `dictSize` are optional (use 0 if unknown), 629 Both `srcSize` and `dictSize` are optional (use 0 if unknown).
173 but if both are 0, no optimization can be done. 630 Note : cPar is considered validated at this stage. Use ZSTD_checkCParams() to ensure that condition. */
174 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */ 631 ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
175 ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize) 632 {
176 { 633 static const U64 minSrcSize = 513; /* (1<<9) + 1 */
177 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */ 634 static const U64 maxWindowResize = 1ULL << (ZSTD_WINDOWLOG_MAX-1);
178 635 assert(ZSTD_checkCParams(cPar)==0);
179 /* resize params, to use less memory when necessary */ 636
180 { U32 const minSrcSize = (srcSize==0) ? 500 : 0; 637 if (dictSize && (srcSize+1<2) /* srcSize unknown */ )
181 U64 const rSize = srcSize + dictSize + minSrcSize; 638 srcSize = minSrcSize; /* presumed small when there is a dictionary */
182 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) { 639 else if (srcSize == 0)
183 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1); 640 srcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* 0 == unknown : presumed large */
184 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog; 641
185 } } 642 /* resize windowLog if input is small enough, to use less memory */
643 if ( (srcSize < maxWindowResize)
644 && (dictSize < maxWindowResize) ) {
645 U32 const tSize = (U32)(srcSize + dictSize);
646 static U32 const hashSizeMin = 1 << ZSTD_HASHLOG_MIN;
647 U32 const srcLog = (tSize < hashSizeMin) ? ZSTD_HASHLOG_MIN :
648 ZSTD_highbit32(tSize-1) + 1;
649 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
650 }
186 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog; 651 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
187 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy); 652 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
188 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog); 653 if (cycleLog > cPar.windowLog)
189 } 654 cPar.chainLog -= (cycleLog - cPar.windowLog);
190 655 }
191 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */ 656
657 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN)
658 cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
192 659
193 return cPar; 660 return cPar;
194 } 661 }
195 662
196 663 ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
197 size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams) 664 {
198 { 665 cPar = ZSTD_clampCParams(cPar);
199 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog); 666 return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
200 U32 const divider = (cParams.searchLength==3) ? 3 : 4; 667 }
201 size_t const maxNbSeq = blockSize / divider; 668
202 size_t const tokenSpace = blockSize + 11*maxNbSeq; 669 static size_t ZSTD_sizeof_matchState(ZSTD_compressionParameters const* cParams, const U32 forCCtx)
203 670 {
204 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog); 671 size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
205 size_t const hSize = ((size_t)1) << cParams.hashLog; 672 size_t const hSize = ((size_t)1) << cParams->hashLog;
206 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog); 673 U32 const hashLog3 = (forCCtx && cParams->searchLength==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
207 size_t const h3Size = ((size_t)1) << hashLog3; 674 size_t const h3Size = ((size_t)1) << hashLog3;
208 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 675 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
209 676 size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
210 size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32) 677 + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
211 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t)); 678 size_t const optSpace = (forCCtx && ((cParams->strategy == ZSTD_btopt) ||
212 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace 679 (cParams->strategy == ZSTD_btultra)))
213 + (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0); 680 ? optPotentialSpace
214 681 : 0;
215 return sizeof(ZSTD_CCtx) + neededSpace; 682 DEBUGLOG(4, "chainSize: %u - hSize: %u - h3Size: %u",
216 } 683 (U32)chainSize, (U32)hSize, (U32)h3Size);
217 684 return tableSpace + optSpace;
218 685 }
219 static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2) 686
220 { 687 size_t ZSTD_estimateCCtxSize_usingCCtxParams(const ZSTD_CCtx_params* params)
221 return (param1.cParams.hashLog == param2.cParams.hashLog) 688 {
222 & (param1.cParams.chainLog == param2.cParams.chainLog) 689 /* Estimate CCtx size is supported for single-threaded compression only. */
223 & (param1.cParams.strategy == param2.cParams.strategy) 690 if (params->nbWorkers > 0) { return ERROR(GENERIC); }
224 & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3)); 691 { ZSTD_compressionParameters const cParams =
692 ZSTD_getCParamsFromCCtxParams(params, 0, 0);
693 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
694 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
695 size_t const maxNbSeq = blockSize / divider;
696 size_t const tokenSpace = blockSize + 11*maxNbSeq;
697 size_t const entropySpace = HUF_WORKSPACE_SIZE;
698 size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
699 size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 1);
700
701 size_t const ldmSpace = ZSTD_ldm_getTableSize(params->ldmParams);
702 size_t const ldmSeqSpace = ZSTD_ldm_getMaxNbSeq(params->ldmParams, blockSize) * sizeof(rawSeq);
703
704 size_t const neededSpace = entropySpace + blockStateSpace + tokenSpace +
705 matchStateSize + ldmSpace + ldmSeqSpace;
706
707 DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
708 DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace);
709 return sizeof(ZSTD_CCtx) + neededSpace;
710 }
711 }
712
713 size_t ZSTD_estimateCCtxSize_usingCParams(ZSTD_compressionParameters cParams)
714 {
715 ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
716 return ZSTD_estimateCCtxSize_usingCCtxParams(&params);
717 }
718
719 static size_t ZSTD_estimateCCtxSize_internal(int compressionLevel)
720 {
721 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
722 return ZSTD_estimateCCtxSize_usingCParams(cParams);
723 }
724
725 size_t ZSTD_estimateCCtxSize(int compressionLevel)
726 {
727 int level;
728 size_t memBudget = 0;
729 for (level=1; level<=compressionLevel; level++) {
730 size_t const newMB = ZSTD_estimateCCtxSize_internal(level);
731 if (newMB > memBudget) memBudget = newMB;
732 }
733 return memBudget;
734 }
735
736 size_t ZSTD_estimateCStreamSize_usingCCtxParams(const ZSTD_CCtx_params* params)
737 {
738 if (params->nbWorkers > 0) { return ERROR(GENERIC); }
739 { size_t const CCtxSize = ZSTD_estimateCCtxSize_usingCCtxParams(params);
740 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params->cParams.windowLog);
741 size_t const inBuffSize = ((size_t)1 << params->cParams.windowLog) + blockSize;
742 size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
743 size_t const streamingSize = inBuffSize + outBuffSize;
744
745 return CCtxSize + streamingSize;
746 }
747 }
748
749 size_t ZSTD_estimateCStreamSize_usingCParams(ZSTD_compressionParameters cParams)
750 {
751 ZSTD_CCtx_params const params = ZSTD_makeCCtxParamsFromCParams(cParams);
752 return ZSTD_estimateCStreamSize_usingCCtxParams(&params);
753 }
754
755 static size_t ZSTD_estimateCStreamSize_internal(int compressionLevel) {
756 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
757 return ZSTD_estimateCStreamSize_usingCParams(cParams);
758 }
759
760 size_t ZSTD_estimateCStreamSize(int compressionLevel) {
761 int level;
762 size_t memBudget = 0;
763 for (level=1; level<=compressionLevel; level++) {
764 size_t const newMB = ZSTD_estimateCStreamSize_internal(level);
765 if (newMB > memBudget) memBudget = newMB;
766 }
767 return memBudget;
768 }
769
770 /* ZSTD_getFrameProgression():
771 * tells how much data has been consumed (input) and produced (output) for current frame.
772 * able to count progression inside worker threads (non-blocking mode).
773 */
774 ZSTD_frameProgression ZSTD_getFrameProgression(const ZSTD_CCtx* cctx)
775 {
776 #ifdef ZSTD_MULTITHREAD
777 if (cctx->appliedParams.nbWorkers > 0) {
778 return ZSTDMT_getFrameProgression(cctx->mtctx);
779 }
780 #endif
781 { ZSTD_frameProgression fp;
782 size_t const buffered = (cctx->inBuff == NULL) ? 0 :
783 cctx->inBuffPos - cctx->inToCompress;
784 if (buffered) assert(cctx->inBuffPos >= cctx->inToCompress);
785 assert(buffered <= ZSTD_BLOCKSIZE_MAX);
786 fp.ingested = cctx->consumedSrcSize + buffered;
787 fp.consumed = cctx->consumedSrcSize;
788 fp.produced = cctx->producedCSize;
789 return fp;
790 } }
791
792
793 static U32 ZSTD_equivalentCParams(ZSTD_compressionParameters cParams1,
794 ZSTD_compressionParameters cParams2)
795 {
796 return (cParams1.hashLog == cParams2.hashLog)
797 & (cParams1.chainLog == cParams2.chainLog)
798 & (cParams1.strategy == cParams2.strategy) /* opt parser space */
799 & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */
800 }
801
802 /** The parameters are equivalent if ldm is not enabled in both sets or
803 * all the parameters are equivalent. */
804 static U32 ZSTD_equivalentLdmParams(ldmParams_t ldmParams1,
805 ldmParams_t ldmParams2)
806 {
807 return (!ldmParams1.enableLdm && !ldmParams2.enableLdm) ||
808 (ldmParams1.enableLdm == ldmParams2.enableLdm &&
809 ldmParams1.hashLog == ldmParams2.hashLog &&
810 ldmParams1.bucketSizeLog == ldmParams2.bucketSizeLog &&
811 ldmParams1.minMatchLength == ldmParams2.minMatchLength &&
812 ldmParams1.hashEveryLog == ldmParams2.hashEveryLog);
813 }
814
815 typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
816
817 /* ZSTD_sufficientBuff() :
818 * check internal buffers exist for streaming if buffPol == ZSTDb_buffered .
819 * Note : they are assumed to be correctly sized if ZSTD_equivalentCParams()==1 */
820 static U32 ZSTD_sufficientBuff(size_t bufferSize1, size_t blockSize1,
821 ZSTD_buffered_policy_e buffPol2,
822 ZSTD_compressionParameters cParams2,
823 U64 pledgedSrcSize)
824 {
825 size_t const windowSize2 = MAX(1, (size_t)MIN(((U64)1 << cParams2.windowLog), pledgedSrcSize));
826 size_t const blockSize2 = MIN(ZSTD_BLOCKSIZE_MAX, windowSize2);
827 size_t const neededBufferSize2 = (buffPol2==ZSTDb_buffered) ? windowSize2 + blockSize2 : 0;
828 DEBUGLOG(4, "ZSTD_sufficientBuff: is windowSize2=%u <= wlog1=%u",
829 (U32)windowSize2, cParams2.windowLog);
830 DEBUGLOG(4, "ZSTD_sufficientBuff: is blockSize2=%u <= blockSize1=%u",
831 (U32)blockSize2, (U32)blockSize1);
832 return (blockSize2 <= blockSize1) /* seqStore space depends on blockSize */
833 & (neededBufferSize2 <= bufferSize1);
834 }
835
836 /** Equivalence for resetCCtx purposes */
837 static U32 ZSTD_equivalentParams(ZSTD_CCtx_params params1,
838 ZSTD_CCtx_params params2,
839 size_t buffSize1, size_t blockSize1,
840 ZSTD_buffered_policy_e buffPol2,
841 U64 pledgedSrcSize)
842 {
843 DEBUGLOG(4, "ZSTD_equivalentParams: pledgedSrcSize=%u", (U32)pledgedSrcSize);
844 return ZSTD_equivalentCParams(params1.cParams, params2.cParams) &&
845 ZSTD_equivalentLdmParams(params1.ldmParams, params2.ldmParams) &&
846 ZSTD_sufficientBuff(buffSize1, blockSize1, buffPol2, params2.cParams, pledgedSrcSize);
847 }
848
849 static void ZSTD_reset_compressedBlockState(ZSTD_compressedBlockState_t* bs)
850 {
851 int i;
852 for (i = 0; i < ZSTD_REP_NUM; ++i)
853 bs->rep[i] = repStartValue[i];
854 bs->entropy.hufCTable_repeatMode = HUF_repeat_none;
855 bs->entropy.offcode_repeatMode = FSE_repeat_none;
856 bs->entropy.matchlength_repeatMode = FSE_repeat_none;
857 bs->entropy.litlength_repeatMode = FSE_repeat_none;
858 }
859
860 /*! ZSTD_invalidateMatchState()
861 * Invalidate all the matches in the match finder tables.
862 * Requires nextSrc and base to be set (can be NULL).
863 */
864 static void ZSTD_invalidateMatchState(ZSTD_matchState_t* ms)
865 {
866 ZSTD_window_clear(&ms->window);
867
868 ms->nextToUpdate = ms->window.dictLimit + 1;
869 ms->loadedDictEnd = 0;
870 ms->opt.litLengthSum = 0; /* force reset of btopt stats */
225 } 871 }
226 872
227 /*! ZSTD_continueCCtx() : 873 /*! ZSTD_continueCCtx() :
228 reuse CCtx without reset (note : requires no dictionary) */ 874 * reuse CCtx without reset (note : requires no dictionary) */
229 static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize) 875 static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_CCtx_params params, U64 pledgedSrcSize)
230 { 876 {
231 U32 const end = (U32)(cctx->nextSrc - cctx->base); 877 size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
232 cctx->params = params; 878 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
233 cctx->frameContentSize = frameContentSize; 879 DEBUGLOG(4, "ZSTD_continueCCtx: re-use context in place");
234 cctx->lowLimit = end; 880
235 cctx->dictLimit = end; 881 cctx->blockSize = blockSize; /* previous block size could be different even for same windowLog, due to pledgedSrcSize */
236 cctx->nextToUpdate = end+1; 882 cctx->appliedParams = params;
883 cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
884 cctx->consumedSrcSize = 0;
885 cctx->producedCSize = 0;
886 if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
887 cctx->appliedParams.fParams.contentSizeFlag = 0;
888 DEBUGLOG(4, "pledged content size : %u ; flag : %u",
889 (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
237 cctx->stage = ZSTDcs_init; 890 cctx->stage = ZSTDcs_init;
238 cctx->dictID = 0; 891 cctx->dictID = 0;
239 cctx->loadedDictEnd = 0; 892 if (params.ldmParams.enableLdm)
240 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; } 893 ZSTD_window_clear(&cctx->ldmState.window);
241 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */ 894 ZSTD_referenceExternalSequences(cctx, NULL, 0);
895 ZSTD_invalidateMatchState(&cctx->blockState.matchState);
896 ZSTD_reset_compressedBlockState(cctx->blockState.prevCBlock);
242 XXH64_reset(&cctx->xxhState, 0); 897 XXH64_reset(&cctx->xxhState, 0);
243 return 0; 898 return 0;
244 } 899 }
245 900
246 typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e; 901 typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
247 902
248 /*! ZSTD_resetCCtx_advanced() : 903 static void* ZSTD_reset_matchState(ZSTD_matchState_t* ms, void* ptr, ZSTD_compressionParameters const* cParams, ZSTD_compResetPolicy_e const crp, U32 const forCCtx)
249 note : 'params' must be validated */ 904 {
250 static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc, 905 size_t const chainSize = (cParams->strategy == ZSTD_fast) ? 0 : ((size_t)1 << cParams->chainLog);
251 ZSTD_parameters params, U64 frameContentSize, 906 size_t const hSize = ((size_t)1) << cParams->hashLog;
252 ZSTD_compResetPolicy_e const crp) 907 U32 const hashLog3 = (forCCtx && cParams->searchLength==3) ? MIN(ZSTD_HASHLOG3_MAX, cParams->windowLog) : 0;
253 { 908 size_t const h3Size = ((size_t)1) << hashLog3;
254 if (crp == ZSTDcrp_continue) 909 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
255 if (ZSTD_equivalentParams(params, zc->params)) 910
256 return ZSTD_continueCCtx(zc, params, frameContentSize); 911 assert(((size_t)ptr & 3) == 0);
257 912
258 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog); 913 ms->hashLog3 = hashLog3;
914 memset(&ms->window, 0, sizeof(ms->window));
915 ZSTD_invalidateMatchState(ms);
916
917 /* opt parser space */
918 if (forCCtx && ((cParams->strategy == ZSTD_btopt) | (cParams->strategy == ZSTD_btultra))) {
919 DEBUGLOG(4, "reserving optimal parser space");
920 ms->opt.litFreq = (U32*)ptr;
921 ms->opt.litLengthFreq = ms->opt.litFreq + (1<<Litbits);
922 ms->opt.matchLengthFreq = ms->opt.litLengthFreq + (MaxLL+1);
923 ms->opt.offCodeFreq = ms->opt.matchLengthFreq + (MaxML+1);
924 ptr = ms->opt.offCodeFreq + (MaxOff+1);
925 ms->opt.matchTable = (ZSTD_match_t*)ptr;
926 ptr = ms->opt.matchTable + ZSTD_OPT_NUM+1;
927 ms->opt.priceTable = (ZSTD_optimal_t*)ptr;
928 ptr = ms->opt.priceTable + ZSTD_OPT_NUM+1;
929 }
930
931 /* table Space */
932 DEBUGLOG(4, "reset table : %u", crp!=ZSTDcrp_noMemset);
933 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
934 if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
935 ms->hashTable = (U32*)(ptr);
936 ms->chainTable = ms->hashTable + hSize;
937 ms->hashTable3 = ms->chainTable + chainSize;
938 ptr = ms->hashTable3 + h3Size;
939
940 assert(((size_t)ptr & 3) == 0);
941 return ptr;
942 }
943
944 /*! ZSTD_resetCCtx_internal() :
945 note : `params` are assumed fully validated at this stage */
946 static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
947 ZSTD_CCtx_params params, U64 pledgedSrcSize,
948 ZSTD_compResetPolicy_e const crp,
949 ZSTD_buffered_policy_e const zbuff)
950 {
951 DEBUGLOG(4, "ZSTD_resetCCtx_internal: pledgedSrcSize=%u, wlog=%u",
952 (U32)pledgedSrcSize, params.cParams.windowLog);
953 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
954
955 if (crp == ZSTDcrp_continue) {
956 if (ZSTD_equivalentParams(zc->appliedParams, params,
957 zc->inBuffSize, zc->blockSize,
958 zbuff, pledgedSrcSize)) {
959 DEBUGLOG(4, "ZSTD_equivalentParams()==1 -> continue mode (wLog1=%u, blockSize1=%u)",
960 zc->appliedParams.cParams.windowLog, (U32)zc->blockSize);
961 return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
962 } }
963 DEBUGLOG(4, "ZSTD_equivalentParams()==0 -> reset CCtx");
964
965 if (params.ldmParams.enableLdm) {
966 /* Adjust long distance matching parameters */
967 params.ldmParams.windowLog = params.cParams.windowLog;
968 ZSTD_ldm_adjustParameters(&params.ldmParams, &params.cParams);
969 assert(params.ldmParams.hashLog >= params.ldmParams.bucketSizeLog);
970 assert(params.ldmParams.hashEveryLog < 32);
971 zc->ldmState.hashPower =
972 ZSTD_ldm_getHashPower(params.ldmParams.minMatchLength);
973 }
974
975 { size_t const windowSize = MAX(1, (size_t)MIN(((U64)1 << params.cParams.windowLog), pledgedSrcSize));
976 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, windowSize);
259 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4; 977 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
260 size_t const maxNbSeq = blockSize / divider; 978 size_t const maxNbSeq = blockSize / divider;
261 size_t const tokenSpace = blockSize + 11*maxNbSeq; 979 size_t const tokenSpace = blockSize + 11*maxNbSeq;
262 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog); 980 size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
263 size_t const hSize = ((size_t)1) << params.cParams.hashLog; 981 size_t const buffInSize = (zbuff==ZSTDb_buffered) ? windowSize + blockSize : 0;
264 U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog); 982 size_t const matchStateSize = ZSTD_sizeof_matchState(&params.cParams, /* forCCtx */ 1);
265 size_t const h3Size = ((size_t)1) << hashLog3; 983 size_t const maxNbLdmSeq = ZSTD_ldm_getMaxNbSeq(params.ldmParams, blockSize);
266 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
267 void* ptr; 984 void* ptr;
268 985
269 /* Check if workSpace is large enough, alloc a new one if needed */ 986 /* Check if workSpace is large enough, alloc a new one if needed */
270 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32) 987 { size_t const entropySpace = HUF_WORKSPACE_SIZE;
271 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t)); 988 size_t const blockStateSpace = 2 * sizeof(ZSTD_compressedBlockState_t);
272 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace 989 size_t const bufferSpace = buffInSize + buffOutSize;
273 + (((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) ? optSpace : 0); 990 size_t const ldmSpace = ZSTD_ldm_getTableSize(params.ldmParams);
274 if (zc->workSpaceSize < neededSpace) { 991 size_t const ldmSeqSpace = maxNbLdmSeq * sizeof(rawSeq);
992
993 size_t const neededSpace = entropySpace + blockStateSpace + ldmSpace +
994 ldmSeqSpace + matchStateSize + tokenSpace +
995 bufferSpace;
996 DEBUGLOG(4, "Need %uKB workspace, including %uKB for match state, and %uKB for buffers",
997 (U32)(neededSpace>>10), (U32)(matchStateSize>>10), (U32)(bufferSpace>>10));
998 DEBUGLOG(4, "windowSize: %u - blockSize: %u", (U32)windowSize, (U32)blockSize);
999
1000 if (zc->workSpaceSize < neededSpace) { /* too small : resize */
1001 DEBUGLOG(4, "Need to update workSpaceSize from %uK to %uK",
1002 (unsigned)(zc->workSpaceSize>>10),
1003 (unsigned)(neededSpace>>10));
1004 /* static cctx : no resize, error out */
1005 if (zc->staticSize) return ERROR(memory_allocation);
1006
1007 zc->workSpaceSize = 0;
275 ZSTD_free(zc->workSpace, zc->customMem); 1008 ZSTD_free(zc->workSpace, zc->customMem);
276 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem); 1009 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
277 if (zc->workSpace == NULL) return ERROR(memory_allocation); 1010 if (zc->workSpace == NULL) return ERROR(memory_allocation);
278 zc->workSpaceSize = neededSpace; 1011 zc->workSpaceSize = neededSpace;
1012 ptr = zc->workSpace;
1013
1014 /* Statically sized space. entropyWorkspace never moves (but prev/next block swap places) */
1015 assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */
1016 assert(zc->workSpaceSize >= 2 * sizeof(ZSTD_compressedBlockState_t));
1017 zc->blockState.prevCBlock = (ZSTD_compressedBlockState_t*)zc->workSpace;
1018 zc->blockState.nextCBlock = zc->blockState.prevCBlock + 1;
1019 ptr = zc->blockState.nextCBlock + 1;
1020 zc->entropyWorkspace = (U32*)ptr;
279 } } 1021 } }
280 1022
281 if (crp!=ZSTDcrp_noMemset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */ 1023 /* init params */
1024 zc->appliedParams = params;
1025 zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
1026 zc->consumedSrcSize = 0;
1027 zc->producedCSize = 0;
1028 if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
1029 zc->appliedParams.fParams.contentSizeFlag = 0;
1030 DEBUGLOG(4, "pledged content size : %u ; flag : %u",
1031 (U32)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag);
1032 zc->blockSize = blockSize;
1033
282 XXH64_reset(&zc->xxhState, 0); 1034 XXH64_reset(&zc->xxhState, 0);
283 zc->hashLog3 = hashLog3; 1035 zc->stage = ZSTDcs_init;
284 zc->hashTable = (U32*)(zc->workSpace); 1036 zc->dictID = 0;
285 zc->chainTable = zc->hashTable + hSize; 1037
286 zc->hashTable3 = zc->chainTable + chainSize; 1038 ZSTD_reset_compressedBlockState(zc->blockState.prevCBlock);
287 ptr = zc->hashTable3 + h3Size; 1039
288 zc->hufTable = (HUF_CElt*)ptr; 1040 ptr = zc->entropyWorkspace + HUF_WORKSPACE_SIZE_U32;
289 zc->flagStaticTables = 0; 1041
290 ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */ 1042 /* ldm hash table */
291 1043 /* initialize bucketOffsets table later for pointer alignment */
292 zc->nextToUpdate = 1; 1044 if (params.ldmParams.enableLdm) {
293 zc->nextSrc = NULL; 1045 size_t const ldmHSize = ((size_t)1) << params.ldmParams.hashLog;
294 zc->base = NULL; 1046 memset(ptr, 0, ldmHSize * sizeof(ldmEntry_t));
295 zc->dictBase = NULL; 1047 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
296 zc->dictLimit = 0; 1048 zc->ldmState.hashTable = (ldmEntry_t*)ptr;
297 zc->lowLimit = 0; 1049 ptr = zc->ldmState.hashTable + ldmHSize;
298 zc->params = params; 1050 zc->ldmSequences = (rawSeq*)ptr;
299 zc->blockSize = blockSize; 1051 ptr = zc->ldmSequences + maxNbLdmSeq;
300 zc->frameContentSize = frameContentSize; 1052 zc->maxNbLdmSequences = maxNbLdmSeq;
301 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; } 1053
302 1054 memset(&zc->ldmState.window, 0, sizeof(zc->ldmState.window));
303 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) {
304 zc->seqStore.litFreq = (U32*)ptr;
305 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
306 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
307 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
308 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
309 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
310 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
311 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
312 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
313 zc->seqStore.litLengthSum = 0;
314 } 1055 }
1056 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
1057
1058 ptr = ZSTD_reset_matchState(&zc->blockState.matchState, ptr, &params.cParams, crp, /* forCCtx */ 1);
1059
1060 /* sequences storage */
315 zc->seqStore.sequencesStart = (seqDef*)ptr; 1061 zc->seqStore.sequencesStart = (seqDef*)ptr;
316 ptr = zc->seqStore.sequencesStart + maxNbSeq; 1062 ptr = zc->seqStore.sequencesStart + maxNbSeq;
317 zc->seqStore.llCode = (BYTE*) ptr; 1063 zc->seqStore.llCode = (BYTE*) ptr;
318 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq; 1064 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
319 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq; 1065 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
320 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq; 1066 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
321 1067 ptr = zc->seqStore.litStart + blockSize;
322 zc->stage = ZSTDcs_init; 1068
323 zc->dictID = 0; 1069 /* ldm bucketOffsets table */
324 zc->loadedDictEnd = 0; 1070 if (params.ldmParams.enableLdm) {
1071 size_t const ldmBucketSize =
1072 ((size_t)1) << (params.ldmParams.hashLog -
1073 params.ldmParams.bucketSizeLog);
1074 memset(ptr, 0, ldmBucketSize);
1075 zc->ldmState.bucketOffsets = (BYTE*)ptr;
1076 ptr = zc->ldmState.bucketOffsets + ldmBucketSize;
1077 ZSTD_window_clear(&zc->ldmState.window);
1078 }
1079 ZSTD_referenceExternalSequences(zc, NULL, 0);
1080
1081 /* buffers */
1082 zc->inBuffSize = buffInSize;
1083 zc->inBuff = (char*)ptr;
1084 zc->outBuffSize = buffOutSize;
1085 zc->outBuff = zc->inBuff + buffInSize;
325 1086
326 return 0; 1087 return 0;
327 } 1088 }
328 } 1089 }
329 1090
331 * ensures next compression will not use repcodes from previous block. 1092 * ensures next compression will not use repcodes from previous block.
332 * Note : only works with regular variant; 1093 * Note : only works with regular variant;
333 * do not use with extDict variant ! */ 1094 * do not use with extDict variant ! */
334 void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) { 1095 void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
335 int i; 1096 int i;
336 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0; 1097 for (i=0; i<ZSTD_REP_NUM; i++) cctx->blockState.prevCBlock->rep[i] = 0;
1098 assert(!ZSTD_window_hasExtDict(cctx->blockState.matchState.window));
1099 }
1100
1101 static size_t ZSTD_resetCCtx_usingCDict(ZSTD_CCtx* cctx,
1102 const ZSTD_CDict* cdict,
1103 unsigned windowLog,
1104 ZSTD_frameParameters fParams,
1105 U64 pledgedSrcSize,
1106 ZSTD_buffered_policy_e zbuff)
1107 {
1108 { ZSTD_CCtx_params params = cctx->requestedParams;
1109 /* Copy only compression parameters related to tables. */
1110 params.cParams = cdict->cParams;
1111 if (windowLog) params.cParams.windowLog = windowLog;
1112 params.fParams = fParams;
1113 ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
1114 ZSTDcrp_noMemset, zbuff);
1115 assert(cctx->appliedParams.cParams.strategy == cdict->cParams.strategy);
1116 assert(cctx->appliedParams.cParams.hashLog == cdict->cParams.hashLog);
1117 assert(cctx->appliedParams.cParams.chainLog == cdict->cParams.chainLog);
1118 }
1119
1120 /* copy tables */
1121 { size_t const chainSize = (cdict->cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << cdict->cParams.chainLog);
1122 size_t const hSize = (size_t)1 << cdict->cParams.hashLog;
1123 size_t const tableSpace = (chainSize + hSize) * sizeof(U32);
1124 assert((U32*)cctx->blockState.matchState.chainTable == (U32*)cctx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */
1125 assert((U32*)cctx->blockState.matchState.hashTable3 == (U32*)cctx->blockState.matchState.chainTable + chainSize);
1126 assert((U32*)cdict->matchState.chainTable == (U32*)cdict->matchState.hashTable + hSize); /* chainTable must follow hashTable */
1127 assert((U32*)cdict->matchState.hashTable3 == (U32*)cdict->matchState.chainTable + chainSize);
1128 memcpy(cctx->blockState.matchState.hashTable, cdict->matchState.hashTable, tableSpace); /* presumes all tables follow each other */
1129 }
1130 /* Zero the hashTable3, since the cdict never fills it */
1131 { size_t const h3Size = (size_t)1 << cctx->blockState.matchState.hashLog3;
1132 assert(cdict->matchState.hashLog3 == 0);
1133 memset(cctx->blockState.matchState.hashTable3, 0, h3Size * sizeof(U32));
1134 }
1135
1136 /* copy dictionary offsets */
1137 {
1138 ZSTD_matchState_t const* srcMatchState = &cdict->matchState;
1139 ZSTD_matchState_t* dstMatchState = &cctx->blockState.matchState;
1140 dstMatchState->window = srcMatchState->window;
1141 dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
1142 dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
1143 dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
1144 }
1145 cctx->dictID = cdict->dictID;
1146
1147 /* copy block state */
1148 memcpy(cctx->blockState.prevCBlock, &cdict->cBlockState, sizeof(cdict->cBlockState));
1149
1150 return 0;
1151 }
1152
1153 /*! ZSTD_copyCCtx_internal() :
1154 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
1155 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
1156 * The "context", in this case, refers to the hash and chain tables,
1157 * entropy tables, and dictionary references.
1158 * `windowLog` value is enforced if != 0, otherwise value is copied from srcCCtx.
1159 * @return : 0, or an error code */
1160 static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
1161 const ZSTD_CCtx* srcCCtx,
1162 ZSTD_frameParameters fParams,
1163 U64 pledgedSrcSize,
1164 ZSTD_buffered_policy_e zbuff)
1165 {
1166 DEBUGLOG(5, "ZSTD_copyCCtx_internal");
1167 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
1168
1169 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
1170 { ZSTD_CCtx_params params = dstCCtx->requestedParams;
1171 /* Copy only compression parameters related to tables. */
1172 params.cParams = srcCCtx->appliedParams.cParams;
1173 params.fParams = fParams;
1174 ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
1175 ZSTDcrp_noMemset, zbuff);
1176 assert(dstCCtx->appliedParams.cParams.windowLog == srcCCtx->appliedParams.cParams.windowLog);
1177 assert(dstCCtx->appliedParams.cParams.strategy == srcCCtx->appliedParams.cParams.strategy);
1178 assert(dstCCtx->appliedParams.cParams.hashLog == srcCCtx->appliedParams.cParams.hashLog);
1179 assert(dstCCtx->appliedParams.cParams.chainLog == srcCCtx->appliedParams.cParams.chainLog);
1180 assert(dstCCtx->blockState.matchState.hashLog3 == srcCCtx->blockState.matchState.hashLog3);
1181 }
1182
1183 /* copy tables */
1184 { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : ((size_t)1 << srcCCtx->appliedParams.cParams.chainLog);
1185 size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
1186 size_t const h3Size = (size_t)1 << srcCCtx->blockState.matchState.hashLog3;
1187 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
1188 assert((U32*)dstCCtx->blockState.matchState.chainTable == (U32*)dstCCtx->blockState.matchState.hashTable + hSize); /* chainTable must follow hashTable */
1189 assert((U32*)dstCCtx->blockState.matchState.hashTable3 == (U32*)dstCCtx->blockState.matchState.chainTable + chainSize);
1190 memcpy(dstCCtx->blockState.matchState.hashTable, srcCCtx->blockState.matchState.hashTable, tableSpace); /* presumes all tables follow each other */
1191 }
1192
1193 /* copy dictionary offsets */
1194 {
1195 ZSTD_matchState_t const* srcMatchState = &srcCCtx->blockState.matchState;
1196 ZSTD_matchState_t* dstMatchState = &dstCCtx->blockState.matchState;
1197 dstMatchState->window = srcMatchState->window;
1198 dstMatchState->nextToUpdate = srcMatchState->nextToUpdate;
1199 dstMatchState->nextToUpdate3= srcMatchState->nextToUpdate3;
1200 dstMatchState->loadedDictEnd= srcMatchState->loadedDictEnd;
1201 }
1202 dstCCtx->dictID = srcCCtx->dictID;
1203
1204 /* copy block state */
1205 memcpy(dstCCtx->blockState.prevCBlock, srcCCtx->blockState.prevCBlock, sizeof(*srcCCtx->blockState.prevCBlock));
1206
1207 return 0;
337 } 1208 }
338 1209
339 /*! ZSTD_copyCCtx() : 1210 /*! ZSTD_copyCCtx() :
340 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`. 1211 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
341 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()). 1212 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
1213 * pledgedSrcSize==0 means "unknown".
342 * @return : 0, or an error code */ 1214 * @return : 0, or an error code */
343 size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize) 1215 size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
344 { 1216 {
345 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong); 1217 ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
346 1218 ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
347 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem)); 1219 ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
348 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, pledgedSrcSize, ZSTDcrp_noMemset); 1220 if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
349 1221 fParams.contentSizeFlag = (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN);
350 /* copy tables */ 1222
351 { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog); 1223 return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx,
352 size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog; 1224 fParams, pledgedSrcSize,
353 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3; 1225 zbuff);
354 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32); 1226 }
355 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace); 1227
356 } 1228
357 1229 #define ZSTD_ROWSIZE 16
358 /* copy dictionary offsets */
359 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
360 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
361 dstCCtx->nextSrc = srcCCtx->nextSrc;
362 dstCCtx->base = srcCCtx->base;
363 dstCCtx->dictBase = srcCCtx->dictBase;
364 dstCCtx->dictLimit = srcCCtx->dictLimit;
365 dstCCtx->lowLimit = srcCCtx->lowLimit;
366 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
367 dstCCtx->dictID = srcCCtx->dictID;
368
369 /* copy entropy tables */
370 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
371 if (srcCCtx->flagStaticTables) {
372 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
373 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
374 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
375 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
376 }
377
378 return 0;
379 }
380
381
382 /*! ZSTD_reduceTable() : 1230 /*! ZSTD_reduceTable() :
383 * reduce table indexes by `reducerValue` */ 1231 * reduce table indexes by `reducerValue`, or squash to zero.
384 static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue) 1232 * PreserveMark preserves "unsorted mark" for btlazy2 strategy.
385 { 1233 * It must be set to a clear 0/1 value, to remove branch during inlining.
386 U32 u; 1234 * Presume table size is a multiple of ZSTD_ROWSIZE
387 for (u=0 ; u < size ; u++) { 1235 * to help auto-vectorization */
388 if (table[u] < reducerValue) table[u] = 0; 1236 FORCE_INLINE_TEMPLATE void
389 else table[u] -= reducerValue; 1237 ZSTD_reduceTable_internal (U32* const table, U32 const size, U32 const reducerValue, int const preserveMark)
390 } 1238 {
1239 int const nbRows = (int)size / ZSTD_ROWSIZE;
1240 int cellNb = 0;
1241 int rowNb;
1242 assert((size & (ZSTD_ROWSIZE-1)) == 0); /* multiple of ZSTD_ROWSIZE */
1243 assert(size < (1U<<31)); /* can be casted to int */
1244 for (rowNb=0 ; rowNb < nbRows ; rowNb++) {
1245 int column;
1246 for (column=0; column<ZSTD_ROWSIZE; column++) {
1247 if (preserveMark) {
1248 U32 const adder = (table[cellNb] == ZSTD_DUBT_UNSORTED_MARK) ? reducerValue : 0;
1249 table[cellNb] += adder;
1250 }
1251 if (table[cellNb] < reducerValue) table[cellNb] = 0;
1252 else table[cellNb] -= reducerValue;
1253 cellNb++;
1254 } }
1255 }
1256
1257 static void ZSTD_reduceTable(U32* const table, U32 const size, U32 const reducerValue)
1258 {
1259 ZSTD_reduceTable_internal(table, size, reducerValue, 0);
1260 }
1261
1262 static void ZSTD_reduceTable_btlazy2(U32* const table, U32 const size, U32 const reducerValue)
1263 {
1264 ZSTD_reduceTable_internal(table, size, reducerValue, 1);
391 } 1265 }
392 1266
393 /*! ZSTD_reduceIndex() : 1267 /*! ZSTD_reduceIndex() :
394 * rescale all indexes to avoid future overflow (indexes are U32) */ 1268 * rescale all indexes to avoid future overflow (indexes are U32) */
395 static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue) 1269 static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
396 { 1270 {
397 { U32 const hSize = 1 << zc->params.cParams.hashLog; 1271 ZSTD_matchState_t* const ms = &zc->blockState.matchState;
398 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); } 1272 { U32 const hSize = (U32)1 << zc->appliedParams.cParams.hashLog;
399 1273 ZSTD_reduceTable(ms->hashTable, hSize, reducerValue);
400 { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog); 1274 }
401 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); } 1275
402 1276 if (zc->appliedParams.cParams.strategy != ZSTD_fast) {
403 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0; 1277 U32 const chainSize = (U32)1 << zc->appliedParams.cParams.chainLog;
404 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); } 1278 if (zc->appliedParams.cParams.strategy == ZSTD_btlazy2)
1279 ZSTD_reduceTable_btlazy2(ms->chainTable, chainSize, reducerValue);
1280 else
1281 ZSTD_reduceTable(ms->chainTable, chainSize, reducerValue);
1282 }
1283
1284 if (ms->hashLog3) {
1285 U32 const h3Size = (U32)1 << ms->hashLog3;
1286 ZSTD_reduceTable(ms->hashTable3, h3Size, reducerValue);
1287 }
405 } 1288 }
406 1289
407 1290
408 /*-******************************************************* 1291 /*-*******************************************************
409 * Block entropic compression 1292 * Block entropic compression
433 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3)); 1316 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
434 break; 1317 break;
435 case 2: /* 2 - 2 - 12 */ 1318 case 2: /* 2 - 2 - 12 */
436 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4))); 1319 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
437 break; 1320 break;
438 default: /*note : should not be necessary : flSize is within {1,2,3} */
439 case 3: /* 2 - 2 - 20 */ 1321 case 3: /* 2 - 2 - 20 */
440 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4))); 1322 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
441 break; 1323 break;
1324 default: /* not necessary : flSize is {1,2,3} */
1325 assert(0);
442 } 1326 }
443 1327
444 memcpy(ostart + flSize, src, srcSize); 1328 memcpy(ostart + flSize, src, srcSize);
445 return srcSize + flSize; 1329 return srcSize + flSize;
446 } 1330 }
458 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3)); 1342 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
459 break; 1343 break;
460 case 2: /* 2 - 2 - 12 */ 1344 case 2: /* 2 - 2 - 12 */
461 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4))); 1345 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
462 break; 1346 break;
463 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
464 case 3: /* 2 - 2 - 20 */ 1347 case 3: /* 2 - 2 - 20 */
465 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4))); 1348 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
466 break; 1349 break;
1350 default: /* not necessary : flSize is {1,2,3} */
1351 assert(0);
467 } 1352 }
468 1353
469 ostart[flSize] = *(const BYTE*)src; 1354 ostart[flSize] = *(const BYTE*)src;
470 return flSize+1; 1355 return flSize+1;
471 } 1356 }
472 1357
473 1358
474 static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; } 1359 static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
475 1360
476 static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc, 1361 static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t const* prevEntropy,
1362 ZSTD_entropyCTables_t* nextEntropy,
1363 ZSTD_strategy strategy, int disableLiteralCompression,
477 void* dst, size_t dstCapacity, 1364 void* dst, size_t dstCapacity,
478 const void* src, size_t srcSize) 1365 const void* src, size_t srcSize,
1366 U32* workspace, const int bmi2)
479 { 1367 {
480 size_t const minGain = ZSTD_minGain(srcSize); 1368 size_t const minGain = ZSTD_minGain(srcSize);
481 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB); 1369 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
482 BYTE* const ostart = (BYTE*)dst; 1370 BYTE* const ostart = (BYTE*)dst;
483 U32 singleStream = srcSize < 256; 1371 U32 singleStream = srcSize < 256;
484 symbolEncodingType_e hType = set_compressed; 1372 symbolEncodingType_e hType = set_compressed;
485 size_t cLitSize; 1373 size_t cLitSize;
486 1374
1375 DEBUGLOG(5,"ZSTD_compressLiterals (disableLiteralCompression=%i)",
1376 disableLiteralCompression);
1377
1378 /* Prepare nextEntropy assuming reusing the existing table */
1379 nextEntropy->hufCTable_repeatMode = prevEntropy->hufCTable_repeatMode;
1380 memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable,
1381 sizeof(prevEntropy->hufCTable));
1382
1383 if (disableLiteralCompression)
1384 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
487 1385
488 /* small ? don't even attempt compression (speed opt) */ 1386 /* small ? don't even attempt compression (speed opt) */
489 # define LITERAL_NOENTROPY 63 1387 # define COMPRESS_LITERALS_SIZE_MIN 63
490 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY; 1388 { size_t const minLitSize = (prevEntropy->hufCTable_repeatMode == HUF_repeat_valid) ? 6 : COMPRESS_LITERALS_SIZE_MIN;
491 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 1389 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
492 } 1390 }
493 1391
494 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */ 1392 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
495 if (zc->flagStaticTables && (lhSize==3)) { 1393 { HUF_repeat repeat = prevEntropy->hufCTable_repeatMode;
496 hType = set_repeat; 1394 int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
497 singleStream = 1; 1395 if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
498 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable); 1396 cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
499 } else { 1397 workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextEntropy->hufCTable, &repeat, preferRepeat, bmi2)
500 cLitSize = singleStream ? HUF_compress1X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters)) 1398 : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
501 : HUF_compress4X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters)); 1399 workspace, HUF_WORKSPACE_SIZE, (HUF_CElt*)nextEntropy->hufCTable, &repeat, preferRepeat, bmi2);
502 } 1400 if (repeat != HUF_repeat_none) {
503 1401 /* reused the existing table */
504 if ((cLitSize==0) | (cLitSize >= srcSize - minGain)) 1402 hType = set_repeat;
1403 }
1404 }
1405
1406 if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
1407 memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, sizeof(prevEntropy->hufCTable));
505 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize); 1408 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
506 if (cLitSize==1) 1409 }
1410 if (cLitSize==1) {
1411 memcpy(nextEntropy->hufCTable, prevEntropy->hufCTable, sizeof(prevEntropy->hufCTable));
507 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize); 1412 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
1413 }
1414
1415 if (hType == set_compressed) {
1416 /* using a newly constructed table */
1417 nextEntropy->hufCTable_repeatMode = HUF_repeat_check;
1418 }
508 1419
509 /* Build header */ 1420 /* Build header */
510 switch(lhSize) 1421 switch(lhSize)
511 { 1422 {
512 case 3: /* 2 - 2 - 10 - 10 */ 1423 case 3: /* 2 - 2 - 10 - 10 */
517 case 4: /* 2 - 2 - 14 - 14 */ 1428 case 4: /* 2 - 2 - 14 - 14 */
518 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18); 1429 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
519 MEM_writeLE32(ostart, lhc); 1430 MEM_writeLE32(ostart, lhc);
520 break; 1431 break;
521 } 1432 }
522 default: /* should not be necessary, lhSize is only {3,4,5} */
523 case 5: /* 2 - 2 - 18 - 18 */ 1433 case 5: /* 2 - 2 - 18 - 18 */
524 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22); 1434 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
525 MEM_writeLE32(ostart, lhc); 1435 MEM_writeLE32(ostart, lhc);
526 ostart[4] = (BYTE)(cLitSize >> 10); 1436 ostart[4] = (BYTE)(cLitSize >> 10);
527 break; 1437 break;
528 } 1438 }
1439 default: /* not possible : lhSize is {3,4,5} */
1440 assert(0);
529 } 1441 }
530 return lhSize+cLitSize; 1442 return lhSize+cLitSize;
531 } 1443 }
532 1444
533 static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
534 8, 9, 10, 11, 12, 13, 14, 15,
535 16, 16, 17, 17, 18, 18, 19, 19,
536 20, 20, 20, 20, 21, 21, 21, 21,
537 22, 22, 22, 22, 22, 22, 22, 22,
538 23, 23, 23, 23, 23, 23, 23, 23,
539 24, 24, 24, 24, 24, 24, 24, 24,
540 24, 24, 24, 24, 24, 24, 24, 24 };
541
542 static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
543 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
544 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
545 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
546 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
547 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
548 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
549 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
550
551 1445
552 void ZSTD_seqToCodes(const seqStore_t* seqStorePtr) 1446 void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
553 { 1447 {
554 BYTE const LL_deltaCode = 19;
555 BYTE const ML_deltaCode = 36;
556 const seqDef* const sequences = seqStorePtr->sequencesStart; 1448 const seqDef* const sequences = seqStorePtr->sequencesStart;
557 BYTE* const llCodeTable = seqStorePtr->llCode; 1449 BYTE* const llCodeTable = seqStorePtr->llCode;
558 BYTE* const ofCodeTable = seqStorePtr->ofCode; 1450 BYTE* const ofCodeTable = seqStorePtr->ofCode;
559 BYTE* const mlCodeTable = seqStorePtr->mlCode; 1451 BYTE* const mlCodeTable = seqStorePtr->mlCode;
560 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); 1452 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
561 U32 u; 1453 U32 u;
562 for (u=0; u<nbSeq; u++) { 1454 for (u=0; u<nbSeq; u++) {
563 U32 const llv = sequences[u].litLength; 1455 U32 const llv = sequences[u].litLength;
564 U32 const mlv = sequences[u].matchLength; 1456 U32 const mlv = sequences[u].matchLength;
565 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv]; 1457 llCodeTable[u] = (BYTE)ZSTD_LLcode(llv);
566 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset); 1458 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
567 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv]; 1459 mlCodeTable[u] = (BYTE)ZSTD_MLcode(mlv);
568 } 1460 }
569 if (seqStorePtr->longLengthID==1) 1461 if (seqStorePtr->longLengthID==1)
570 llCodeTable[seqStorePtr->longLengthPos] = MaxLL; 1462 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
571 if (seqStorePtr->longLengthID==2) 1463 if (seqStorePtr->longLengthID==2)
572 mlCodeTable[seqStorePtr->longLengthPos] = MaxML; 1464 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
573 } 1465 }
574 1466
575 1467 typedef enum {
576 size_t ZSTD_compressSequences(ZSTD_CCtx* zc, 1468 ZSTD_defaultDisallowed = 0,
577 void* dst, size_t dstCapacity, 1469 ZSTD_defaultAllowed = 1
578 size_t srcSize) 1470 } ZSTD_defaultPolicy_e;
579 { 1471
580 const seqStore_t* seqStorePtr = &(zc->seqStore); 1472 MEM_STATIC
1473 symbolEncodingType_e ZSTD_selectEncodingType(
1474 FSE_repeat* repeatMode, size_t const mostFrequent, size_t nbSeq,
1475 U32 defaultNormLog, ZSTD_defaultPolicy_e const isDefaultAllowed)
1476 {
1477 #define MIN_SEQ_FOR_DYNAMIC_FSE 64
1478 #define MAX_SEQ_FOR_STATIC_FSE 1000
1479 ZSTD_STATIC_ASSERT(ZSTD_defaultDisallowed == 0 && ZSTD_defaultAllowed != 0);
1480 if ((mostFrequent == nbSeq) && (!isDefaultAllowed || nbSeq > 2)) {
1481 DEBUGLOG(5, "Selected set_rle");
1482 /* Prefer set_basic over set_rle when there are 2 or less symbols,
1483 * since RLE uses 1 byte, but set_basic uses 5-6 bits per symbol.
1484 * If basic encoding isn't possible, always choose RLE.
1485 */
1486 *repeatMode = FSE_repeat_check;
1487 return set_rle;
1488 }
1489 if ( isDefaultAllowed
1490 && (*repeatMode == FSE_repeat_valid) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
1491 DEBUGLOG(5, "Selected set_repeat");
1492 return set_repeat;
1493 }
1494 if ( isDefaultAllowed
1495 && ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (defaultNormLog-1)))) ) {
1496 DEBUGLOG(5, "Selected set_basic");
1497 /* The format allows default tables to be repeated, but it isn't useful.
1498 * When using simple heuristics to select encoding type, we don't want
1499 * to confuse these tables with dictionaries. When running more careful
1500 * analysis, we don't need to waste time checking both repeating tables
1501 * and default tables.
1502 */
1503 *repeatMode = FSE_repeat_none;
1504 return set_basic;
1505 }
1506 DEBUGLOG(5, "Selected set_compressed");
1507 *repeatMode = FSE_repeat_check;
1508 return set_compressed;
1509 }
1510
1511 MEM_STATIC
1512 size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
1513 FSE_CTable* nextCTable, U32 FSELog, symbolEncodingType_e type,
1514 U32* count, U32 max,
1515 BYTE const* codeTable, size_t nbSeq,
1516 S16 const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
1517 FSE_CTable const* prevCTable, size_t prevCTableSize,
1518 void* workspace, size_t workspaceSize)
1519 {
1520 BYTE* op = (BYTE*)dst;
1521 BYTE const* const oend = op + dstCapacity;
1522
1523 switch (type) {
1524 case set_rle:
1525 *op = codeTable[0];
1526 CHECK_F(FSE_buildCTable_rle(nextCTable, (BYTE)max));
1527 return 1;
1528 case set_repeat:
1529 memcpy(nextCTable, prevCTable, prevCTableSize);
1530 return 0;
1531 case set_basic:
1532 CHECK_F(FSE_buildCTable_wksp(nextCTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize)); /* note : could be pre-calculated */
1533 return 0;
1534 case set_compressed: {
1535 S16 norm[MaxSeq + 1];
1536 size_t nbSeq_1 = nbSeq;
1537 const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
1538 if (count[codeTable[nbSeq-1]] > 1) {
1539 count[codeTable[nbSeq-1]]--;
1540 nbSeq_1--;
1541 }
1542 assert(nbSeq_1 > 1);
1543 CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
1544 { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
1545 if (FSE_isError(NCountSize)) return NCountSize;
1546 CHECK_F(FSE_buildCTable_wksp(nextCTable, norm, max, tableLog, workspace, workspaceSize));
1547 return NCountSize;
1548 }
1549 }
1550 default: return assert(0), ERROR(GENERIC);
1551 }
1552 }
1553
1554 FORCE_INLINE_TEMPLATE size_t
1555 ZSTD_encodeSequences_body(
1556 void* dst, size_t dstCapacity,
1557 FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
1558 FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
1559 FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
1560 seqDef const* sequences, size_t nbSeq, int longOffsets)
1561 {
1562 BIT_CStream_t blockStream;
1563 FSE_CState_t stateMatchLength;
1564 FSE_CState_t stateOffsetBits;
1565 FSE_CState_t stateLitLength;
1566
1567 CHECK_E(BIT_initCStream(&blockStream, dst, dstCapacity), dstSize_tooSmall); /* not enough space remaining */
1568
1569 /* first symbols */
1570 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
1571 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
1572 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
1573 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
1574 if (MEM_32bits()) BIT_flushBits(&blockStream);
1575 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
1576 if (MEM_32bits()) BIT_flushBits(&blockStream);
1577 if (longOffsets) {
1578 U32 const ofBits = ofCodeTable[nbSeq-1];
1579 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1580 if (extraBits) {
1581 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
1582 BIT_flushBits(&blockStream);
1583 }
1584 BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
1585 ofBits - extraBits);
1586 } else {
1587 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
1588 }
1589 BIT_flushBits(&blockStream);
1590
1591 { size_t n;
1592 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
1593 BYTE const llCode = llCodeTable[n];
1594 BYTE const ofCode = ofCodeTable[n];
1595 BYTE const mlCode = mlCodeTable[n];
1596 U32 const llBits = LL_bits[llCode];
1597 U32 const ofBits = ofCode;
1598 U32 const mlBits = ML_bits[mlCode];
1599 DEBUGLOG(6, "encoding: litlen:%2u - matchlen:%2u - offCode:%7u",
1600 sequences[n].litLength,
1601 sequences[n].matchLength + MINMATCH,
1602 sequences[n].offset);
1603 /* 32b*/ /* 64b*/
1604 /* (7)*/ /* (7)*/
1605 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
1606 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
1607 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
1608 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
1609 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
1610 BIT_flushBits(&blockStream); /* (7)*/
1611 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
1612 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
1613 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
1614 if (MEM_32bits() || (ofBits+mlBits+llBits > 56)) BIT_flushBits(&blockStream);
1615 if (longOffsets) {
1616 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1617 if (extraBits) {
1618 BIT_addBits(&blockStream, sequences[n].offset, extraBits);
1619 BIT_flushBits(&blockStream); /* (7)*/
1620 }
1621 BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
1622 ofBits - extraBits); /* 31 */
1623 } else {
1624 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
1625 }
1626 BIT_flushBits(&blockStream); /* (7)*/
1627 } }
1628
1629 DEBUGLOG(6, "ZSTD_encodeSequences: flushing ML state with %u bits", stateMatchLength.stateLog);
1630 FSE_flushCState(&blockStream, &stateMatchLength);
1631 DEBUGLOG(6, "ZSTD_encodeSequences: flushing Off state with %u bits", stateOffsetBits.stateLog);
1632 FSE_flushCState(&blockStream, &stateOffsetBits);
1633 DEBUGLOG(6, "ZSTD_encodeSequences: flushing LL state with %u bits", stateLitLength.stateLog);
1634 FSE_flushCState(&blockStream, &stateLitLength);
1635
1636 { size_t const streamSize = BIT_closeCStream(&blockStream);
1637 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
1638 return streamSize;
1639 }
1640 }
1641
1642 static size_t
1643 ZSTD_encodeSequences_default(
1644 void* dst, size_t dstCapacity,
1645 FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
1646 FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
1647 FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
1648 seqDef const* sequences, size_t nbSeq, int longOffsets)
1649 {
1650 return ZSTD_encodeSequences_body(dst, dstCapacity,
1651 CTable_MatchLength, mlCodeTable,
1652 CTable_OffsetBits, ofCodeTable,
1653 CTable_LitLength, llCodeTable,
1654 sequences, nbSeq, longOffsets);
1655 }
1656
1657
1658 #if DYNAMIC_BMI2
1659
1660 static TARGET_ATTRIBUTE("bmi2") size_t
1661 ZSTD_encodeSequences_bmi2(
1662 void* dst, size_t dstCapacity,
1663 FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
1664 FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
1665 FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
1666 seqDef const* sequences, size_t nbSeq, int longOffsets)
1667 {
1668 return ZSTD_encodeSequences_body(dst, dstCapacity,
1669 CTable_MatchLength, mlCodeTable,
1670 CTable_OffsetBits, ofCodeTable,
1671 CTable_LitLength, llCodeTable,
1672 sequences, nbSeq, longOffsets);
1673 }
1674
1675 #endif
1676
1677 size_t ZSTD_encodeSequences(
1678 void* dst, size_t dstCapacity,
1679 FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
1680 FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
1681 FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
1682 seqDef const* sequences, size_t nbSeq, int longOffsets, int bmi2)
1683 {
1684 #if DYNAMIC_BMI2
1685 if (bmi2) {
1686 return ZSTD_encodeSequences_bmi2(dst, dstCapacity,
1687 CTable_MatchLength, mlCodeTable,
1688 CTable_OffsetBits, ofCodeTable,
1689 CTable_LitLength, llCodeTable,
1690 sequences, nbSeq, longOffsets);
1691 }
1692 #endif
1693 (void)bmi2;
1694 return ZSTD_encodeSequences_default(dst, dstCapacity,
1695 CTable_MatchLength, mlCodeTable,
1696 CTable_OffsetBits, ofCodeTable,
1697 CTable_LitLength, llCodeTable,
1698 sequences, nbSeq, longOffsets);
1699 }
1700
1701 MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
1702 ZSTD_entropyCTables_t const* prevEntropy,
1703 ZSTD_entropyCTables_t* nextEntropy,
1704 ZSTD_CCtx_params const* cctxParams,
1705 void* dst, size_t dstCapacity, U32* workspace,
1706 const int bmi2)
1707 {
1708 const int longOffsets = cctxParams->cParams.windowLog > STREAM_ACCUMULATOR_MIN;
581 U32 count[MaxSeq+1]; 1709 U32 count[MaxSeq+1];
582 S16 norm[MaxSeq+1]; 1710 FSE_CTable* CTable_LitLength = nextEntropy->litlengthCTable;
583 FSE_CTable* CTable_LitLength = zc->litlengthCTable; 1711 FSE_CTable* CTable_OffsetBits = nextEntropy->offcodeCTable;
584 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable; 1712 FSE_CTable* CTable_MatchLength = nextEntropy->matchlengthCTable;
585 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
586 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */ 1713 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
587 const seqDef* const sequences = seqStorePtr->sequencesStart; 1714 const seqDef* const sequences = seqStorePtr->sequencesStart;
588 const BYTE* const ofCodeTable = seqStorePtr->ofCode; 1715 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
589 const BYTE* const llCodeTable = seqStorePtr->llCode; 1716 const BYTE* const llCodeTable = seqStorePtr->llCode;
590 const BYTE* const mlCodeTable = seqStorePtr->mlCode; 1717 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
591 BYTE* const ostart = (BYTE*)dst; 1718 BYTE* const ostart = (BYTE*)dst;
592 BYTE* const oend = ostart + dstCapacity; 1719 BYTE* const oend = ostart + dstCapacity;
593 BYTE* op = ostart; 1720 BYTE* op = ostart;
594 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart; 1721 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
595 BYTE* seqHead; 1722 BYTE* seqHead;
596 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)]; 1723
1724 ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
597 1725
598 /* Compress literals */ 1726 /* Compress literals */
599 { const BYTE* const literals = seqStorePtr->litStart; 1727 { const BYTE* const literals = seqStorePtr->litStart;
600 size_t const litSize = seqStorePtr->lit - literals; 1728 size_t const litSize = seqStorePtr->lit - literals;
601 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize); 1729 size_t const cSize = ZSTD_compressLiterals(
602 if (ZSTD_isError(cSize)) return cSize; 1730 prevEntropy, nextEntropy,
1731 cctxParams->cParams.strategy, cctxParams->disableLiteralCompression,
1732 op, dstCapacity,
1733 literals, litSize,
1734 workspace, bmi2);
1735 if (ZSTD_isError(cSize))
1736 return cSize;
1737 assert(cSize <= dstCapacity);
603 op += cSize; 1738 op += cSize;
604 } 1739 }
605 1740
606 /* Sequences Header */ 1741 /* Sequences Header */
607 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall); 1742 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead*/) return ERROR(dstSize_tooSmall);
608 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq; 1743 if (nbSeq < 0x7F)
609 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2; 1744 *op++ = (BYTE)nbSeq;
610 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3; 1745 else if (nbSeq < LONGNBSEQ)
611 if (nbSeq==0) goto _check_compressibility; 1746 op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
1747 else
1748 op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
1749 if (nbSeq==0) {
1750 memcpy(nextEntropy->litlengthCTable, prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable));
1751 nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
1752 memcpy(nextEntropy->offcodeCTable, prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable));
1753 nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
1754 memcpy(nextEntropy->matchlengthCTable, prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable));
1755 nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
1756 return op - ostart;
1757 }
612 1758
613 /* seqHead : flags for FSE encoding type */ 1759 /* seqHead : flags for FSE encoding type */
614 seqHead = op++; 1760 seqHead = op++;
615 1761
616 #define MIN_SEQ_FOR_DYNAMIC_FSE 64
617 #define MAX_SEQ_FOR_STATIC_FSE 1000
618
619 /* convert length/distances into codes */ 1762 /* convert length/distances into codes */
620 ZSTD_seqToCodes(seqStorePtr); 1763 ZSTD_seqToCodes(seqStorePtr);
621 1764 /* build CTable for Literal Lengths */
622 /* CTable for Literal Lengths */
623 { U32 max = MaxLL; 1765 { U32 max = MaxLL;
624 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->tmpCounters); 1766 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, workspace);
625 if ((mostFrequent == nbSeq) && (nbSeq > 2)) { 1767 DEBUGLOG(5, "Building LL table");
626 *op++ = llCodeTable[0]; 1768 nextEntropy->litlength_repeatMode = prevEntropy->litlength_repeatMode;
627 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max); 1769 LLtype = ZSTD_selectEncodingType(&nextEntropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog, ZSTD_defaultAllowed);
628 LLtype = set_rle; 1770 { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
629 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { 1771 count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
630 LLtype = set_repeat; 1772 prevEntropy->litlengthCTable, sizeof(prevEntropy->litlengthCTable),
631 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) { 1773 workspace, HUF_WORKSPACE_SIZE);
632 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer)); 1774 if (ZSTD_isError(countSize)) return countSize;
633 LLtype = set_basic; 1775 op += countSize;
634 } else {
635 size_t nbSeq_1 = nbSeq;
636 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
637 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
638 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
639 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
640 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
641 op += NCountSize; }
642 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
643 LLtype = set_compressed;
644 } } 1776 } }
645 1777 /* build CTable for Offsets */
646 /* CTable for Offsets */
647 { U32 max = MaxOff; 1778 { U32 max = MaxOff;
648 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->tmpCounters); 1779 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, workspace);
649 if ((mostFrequent == nbSeq) && (nbSeq > 2)) { 1780 /* We can only use the basic table if max <= DefaultMaxOff, otherwise the offsets are too large */
650 *op++ = ofCodeTable[0]; 1781 ZSTD_defaultPolicy_e const defaultPolicy = (max <= DefaultMaxOff) ? ZSTD_defaultAllowed : ZSTD_defaultDisallowed;
651 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max); 1782 DEBUGLOG(5, "Building OF table");
652 Offtype = set_rle; 1783 nextEntropy->offcode_repeatMode = prevEntropy->offcode_repeatMode;
653 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { 1784 Offtype = ZSTD_selectEncodingType(&nextEntropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog, defaultPolicy);
654 Offtype = set_repeat; 1785 { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
655 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) { 1786 count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, DefaultMaxOff,
656 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer)); 1787 prevEntropy->offcodeCTable, sizeof(prevEntropy->offcodeCTable),
657 Offtype = set_basic; 1788 workspace, HUF_WORKSPACE_SIZE);
658 } else { 1789 if (ZSTD_isError(countSize)) return countSize;
659 size_t nbSeq_1 = nbSeq; 1790 op += countSize;
660 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
661 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
662 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
663 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
664 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
665 op += NCountSize; }
666 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
667 Offtype = set_compressed;
668 } } 1791 } }
669 1792 /* build CTable for MatchLengths */
670 /* CTable for MatchLengths */
671 { U32 max = MaxML; 1793 { U32 max = MaxML;
672 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->tmpCounters); 1794 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, workspace);
673 if ((mostFrequent == nbSeq) && (nbSeq > 2)) { 1795 DEBUGLOG(5, "Building ML table");
674 *op++ = *mlCodeTable; 1796 nextEntropy->matchlength_repeatMode = prevEntropy->matchlength_repeatMode;
675 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max); 1797 MLtype = ZSTD_selectEncodingType(&nextEntropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog, ZSTD_defaultAllowed);
676 MLtype = set_rle; 1798 { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
677 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) { 1799 count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
678 MLtype = set_repeat; 1800 prevEntropy->matchlengthCTable, sizeof(prevEntropy->matchlengthCTable),
679 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) { 1801 workspace, HUF_WORKSPACE_SIZE);
680 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer)); 1802 if (ZSTD_isError(countSize)) return countSize;
681 MLtype = set_basic; 1803 op += countSize;
682 } else {
683 size_t nbSeq_1 = nbSeq;
684 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
685 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
686 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
687 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
688 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
689 op += NCountSize; }
690 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
691 MLtype = set_compressed;
692 } } 1804 } }
693 1805
694 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2)); 1806 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
695 zc->flagStaticTables = 0; 1807
696 1808 { size_t const bitstreamSize = ZSTD_encodeSequences(
697 /* Encoding Sequences */ 1809 op, oend - op,
698 { BIT_CStream_t blockStream; 1810 CTable_MatchLength, mlCodeTable,
699 FSE_CState_t stateMatchLength; 1811 CTable_OffsetBits, ofCodeTable,
700 FSE_CState_t stateOffsetBits; 1812 CTable_LitLength, llCodeTable,
701 FSE_CState_t stateLitLength; 1813 sequences, nbSeq,
702 1814 longOffsets, bmi2);
703 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */ 1815 if (ZSTD_isError(bitstreamSize)) return bitstreamSize;
704 1816 op += bitstreamSize;
705 /* first symbols */ 1817 }
706 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]); 1818
707 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]); 1819 return op - ostart;
708 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]); 1820 }
709 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]); 1821
710 if (MEM_32bits()) BIT_flushBits(&blockStream); 1822 MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
711 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]); 1823 ZSTD_entropyCTables_t const* prevEntropy,
712 if (MEM_32bits()) BIT_flushBits(&blockStream); 1824 ZSTD_entropyCTables_t* nextEntropy,
713 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]); 1825 ZSTD_CCtx_params const* cctxParams,
714 BIT_flushBits(&blockStream); 1826 void* dst, size_t dstCapacity,
715 1827 size_t srcSize, U32* workspace, int bmi2)
716 { size_t n; 1828 {
717 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */ 1829 size_t const cSize = ZSTD_compressSequences_internal(
718 BYTE const llCode = llCodeTable[n]; 1830 seqStorePtr, prevEntropy, nextEntropy, cctxParams, dst, dstCapacity,
719 BYTE const ofCode = ofCodeTable[n]; 1831 workspace, bmi2);
720 BYTE const mlCode = mlCodeTable[n]; 1832 /* When srcSize <= dstCapacity, there is enough space to write a raw uncompressed block.
721 U32 const llBits = LL_bits[llCode]; 1833 * Since we ran out of space, block must be not compressible, so fall back to raw uncompressed block.
722 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/ 1834 */
723 U32 const mlBits = ML_bits[mlCode]; 1835 if ((cSize == ERROR(dstSize_tooSmall)) & (srcSize <= dstCapacity))
724 /* (7)*/ /* (7)*/ 1836 return 0; /* block not compressed */
725 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */ 1837 if (ZSTD_isError(cSize)) return cSize;
726 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */ 1838
727 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/ 1839 /* Check compressibility */
728 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */ 1840 { size_t const maxCSize = srcSize - ZSTD_minGain(srcSize); /* note : fixed formula, maybe should depend on compression level, or strategy */
729 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog))) 1841 if (cSize >= maxCSize) return 0; /* block not compressed */
730 BIT_flushBits(&blockStream); /* (7)*/ 1842 }
731 BIT_addBits(&blockStream, sequences[n].litLength, llBits); 1843
732 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream); 1844 /* We check that dictionaries have offset codes available for the first
733 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits); 1845 * block. After the first block, the offcode table might not have large
734 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/ 1846 * enough codes to represent the offsets in the data.
735 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */ 1847 */
736 BIT_flushBits(&blockStream); /* (7)*/ 1848 if (nextEntropy->offcode_repeatMode == FSE_repeat_valid)
737 } } 1849 nextEntropy->offcode_repeatMode = FSE_repeat_check;
738 1850
739 FSE_flushCState(&blockStream, &stateMatchLength); 1851 return cSize;
740 FSE_flushCState(&blockStream, &stateOffsetBits); 1852 }
741 FSE_flushCState(&blockStream, &stateLitLength); 1853
742 1854 /* ZSTD_selectBlockCompressor() :
743 { size_t const streamSize = BIT_closeCStream(&blockStream); 1855 * Not static, but internal use only (used by long distance matcher)
744 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */ 1856 * assumption : strat is a valid strategy */
745 op += streamSize; 1857 ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
1858 {
1859 static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
1860 { ZSTD_compressBlock_fast /* default for 0 */,
1861 ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy,
1862 ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2,
1863 ZSTD_compressBlock_btopt, ZSTD_compressBlock_btultra },
1864 { ZSTD_compressBlock_fast_extDict /* default for 0 */,
1865 ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict,
1866 ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict,
1867 ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict }
1868 };
1869 ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
1870
1871 assert((U32)strat >= (U32)ZSTD_fast);
1872 assert((U32)strat <= (U32)ZSTD_btultra);
1873 return blockCompressor[extDict!=0][(U32)strat];
1874 }
1875
1876 static void ZSTD_storeLastLiterals(seqStore_t* seqStorePtr,
1877 const BYTE* anchor, size_t lastLLSize)
1878 {
1879 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1880 seqStorePtr->lit += lastLLSize;
1881 }
1882
1883 static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
1884 {
1885 ssPtr->lit = ssPtr->litStart;
1886 ssPtr->sequences = ssPtr->sequencesStart;
1887 ssPtr->longLengthID = 0;
1888 }
1889
1890 static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc,
1891 void* dst, size_t dstCapacity,
1892 const void* src, size_t srcSize)
1893 {
1894 ZSTD_matchState_t* const ms = &zc->blockState.matchState;
1895 DEBUGLOG(5, "ZSTD_compressBlock_internal (dstCapacity=%u, dictLimit=%u, nextToUpdate=%u)",
1896 (U32)dstCapacity, ms->window.dictLimit, ms->nextToUpdate);
1897 if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) {
1898 ZSTD_ldm_skipSequences(&zc->externSeqStore, srcSize, zc->appliedParams.cParams.searchLength);
1899 return 0; /* don't even attempt compression below a certain srcSize */
1900 }
1901 ZSTD_resetSeqStore(&(zc->seqStore));
1902
1903 /* limited update after a very long match */
1904 { const BYTE* const base = ms->window.base;
1905 const BYTE* const istart = (const BYTE*)src;
1906 const U32 current = (U32)(istart-base);
1907 if (current > ms->nextToUpdate + 384)
1908 ms->nextToUpdate = current - MIN(192, (U32)(current - ms->nextToUpdate - 384));
1909 }
1910
1911 /* select and store sequences */
1912 { U32 const extDict = ZSTD_window_hasExtDict(ms->window);
1913 size_t lastLLSize;
1914 { int i;
1915 for (i = 0; i < ZSTD_REP_NUM; ++i)
1916 zc->blockState.nextCBlock->rep[i] = zc->blockState.prevCBlock->rep[i];
1917 }
1918 if (zc->externSeqStore.pos < zc->externSeqStore.size) {
1919 assert(!zc->appliedParams.ldmParams.enableLdm);
1920 /* Updates ldmSeqStore.pos */
1921 lastLLSize =
1922 ZSTD_ldm_blockCompress(&zc->externSeqStore,
1923 ms, &zc->seqStore,
1924 zc->blockState.nextCBlock->rep,
1925 &zc->appliedParams.cParams,
1926 src, srcSize, extDict);
1927 assert(zc->externSeqStore.pos <= zc->externSeqStore.size);
1928 } else if (zc->appliedParams.ldmParams.enableLdm) {
1929 rawSeqStore_t ldmSeqStore = {NULL, 0, 0, 0};
1930
1931 ldmSeqStore.seq = zc->ldmSequences;
1932 ldmSeqStore.capacity = zc->maxNbLdmSequences;
1933 /* Updates ldmSeqStore.size */
1934 CHECK_F(ZSTD_ldm_generateSequences(&zc->ldmState, &ldmSeqStore,
1935 &zc->appliedParams.ldmParams,
1936 src, srcSize));
1937 /* Updates ldmSeqStore.pos */
1938 lastLLSize =
1939 ZSTD_ldm_blockCompress(&ldmSeqStore,
1940 ms, &zc->seqStore,
1941 zc->blockState.nextCBlock->rep,
1942 &zc->appliedParams.cParams,
1943 src, srcSize, extDict);
1944 assert(ldmSeqStore.pos == ldmSeqStore.size);
1945 } else { /* not long range mode */
1946 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, extDict);
1947 lastLLSize = blockCompressor(ms, &zc->seqStore, zc->blockState.nextCBlock->rep, &zc->appliedParams.cParams, src, srcSize);
1948 }
1949 { const BYTE* const lastLiterals = (const BYTE*)src + srcSize - lastLLSize;
1950 ZSTD_storeLastLiterals(&zc->seqStore, lastLiterals, lastLLSize);
746 } } 1951 } }
747 1952
748 /* check compressibility */ 1953 /* encode sequences and literals */
749 _check_compressibility: 1954 { size_t const cSize = ZSTD_compressSequences(&zc->seqStore,
750 { size_t const minGain = ZSTD_minGain(srcSize); 1955 &zc->blockState.prevCBlock->entropy, &zc->blockState.nextCBlock->entropy,
751 size_t const maxCSize = srcSize - minGain; 1956 &zc->appliedParams,
752 if ((size_t)(op-ostart) >= maxCSize) return 0; } 1957 dst, dstCapacity,
753 1958 srcSize, zc->entropyWorkspace, zc->bmi2);
754 /* confirm repcodes */ 1959 if (ZSTD_isError(cSize) || cSize == 0) return cSize;
755 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; } 1960 /* confirm repcodes and entropy tables */
756 1961 { ZSTD_compressedBlockState_t* const tmp = zc->blockState.prevCBlock;
757 return op - ostart; 1962 zc->blockState.prevCBlock = zc->blockState.nextCBlock;
758 } 1963 zc->blockState.nextCBlock = tmp;
759
760
761 #if 0 /* for debug */
762 # define STORESEQ_DEBUG
763 #include <stdio.h> /* fprintf */
764 U32 g_startDebug = 0;
765 const BYTE* g_start = NULL;
766 #endif
767
768 /*! ZSTD_storeSeq() :
769 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
770 `offsetCode` : distance to match, or 0 == repCode.
771 `matchCode` : matchLength - MINMATCH
772 */
773 MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)
774 {
775 #ifdef STORESEQ_DEBUG
776 if (g_startDebug) {
777 const U32 pos = (U32)((const BYTE*)literals - g_start);
778 if (g_start==NULL) g_start = (const BYTE*)literals;
779 if ((pos > 1895000) && (pos < 1895300))
780 fprintf(stderr, "Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
781 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
782 }
783 #endif
784 /* copy Literals */
785 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
786 seqStorePtr->lit += litLength;
787
788 /* literal Length */
789 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
790 seqStorePtr->sequences[0].litLength = (U16)litLength;
791
792 /* match offset */
793 seqStorePtr->sequences[0].offset = offsetCode + 1;
794
795 /* match Length */
796 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
797 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
798
799 seqStorePtr->sequences++;
800 }
801
802
803 /*-*************************************
804 * Match length counter
805 ***************************************/
806 static unsigned ZSTD_NbCommonBytes (register size_t val)
807 {
808 if (MEM_isLittleEndian()) {
809 if (MEM_64bits()) {
810 # if defined(_MSC_VER) && defined(_WIN64)
811 unsigned long r = 0;
812 _BitScanForward64( &r, (U64)val );
813 return (unsigned)(r>>3);
814 # elif defined(__GNUC__) && (__GNUC__ >= 3)
815 return (__builtin_ctzll((U64)val) >> 3);
816 # else
817 static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
818 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
819 # endif
820 } else { /* 32 bits */
821 # if defined(_MSC_VER)
822 unsigned long r=0;
823 _BitScanForward( &r, (U32)val );
824 return (unsigned)(r>>3);
825 # elif defined(__GNUC__) && (__GNUC__ >= 3)
826 return (__builtin_ctz((U32)val) >> 3);
827 # else
828 static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
829 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
830 # endif
831 } 1964 }
832 } else { /* Big Endian CPU */ 1965 return cSize;
833 if (MEM_64bits()) { 1966 }
834 # if defined(_MSC_VER) && defined(_WIN64) 1967 }
835 unsigned long r = 0; 1968
836 _BitScanReverse64( &r, val ); 1969
837 return (unsigned)(r>>3); 1970 /*! ZSTD_compress_frameChunk() :
838 # elif defined(__GNUC__) && (__GNUC__ >= 3)
839 return (__builtin_clzll(val) >> 3);
840 # else
841 unsigned r;
842 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
843 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
844 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
845 r += (!val);
846 return r;
847 # endif
848 } else { /* 32 bits */
849 # if defined(_MSC_VER)
850 unsigned long r = 0;
851 _BitScanReverse( &r, (unsigned long)val );
852 return (unsigned)(r>>3);
853 # elif defined(__GNUC__) && (__GNUC__ >= 3)
854 return (__builtin_clz((U32)val) >> 3);
855 # else
856 unsigned r;
857 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
858 r += (!val);
859 return r;
860 # endif
861 } }
862 }
863
864
865 static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
866 {
867 const BYTE* const pStart = pIn;
868 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
869
870 while (pIn < pInLoopLimit) {
871 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
872 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
873 pIn += ZSTD_NbCommonBytes(diff);
874 return (size_t)(pIn - pStart);
875 }
876 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
877 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
878 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
879 return (size_t)(pIn - pStart);
880 }
881
882 /** ZSTD_count_2segments() :
883 * can count match length with `ip` & `match` in 2 different segments.
884 * convention : on reaching mEnd, match count continue starting from iStart
885 */
886 static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
887 {
888 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
889 size_t const matchLength = ZSTD_count(ip, match, vEnd);
890 if (match + matchLength != mEnd) return matchLength;
891 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
892 }
893
894
895 /*-*************************************
896 * Hashes
897 ***************************************/
898 static const U32 prime3bytes = 506832829U;
899 static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
900 MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
901
902 static const U32 prime4bytes = 2654435761U;
903 static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
904 static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
905
906 static const U64 prime5bytes = 889523592379ULL;
907 static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
908 static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
909
910 static const U64 prime6bytes = 227718039650203ULL;
911 static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
912 static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
913
914 static const U64 prime7bytes = 58295818150454627ULL;
915 static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
916 static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
917
918 static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
919 static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
920 static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
921
922 static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
923 {
924 switch(mls)
925 {
926 default:
927 case 4: return ZSTD_hash4Ptr(p, hBits);
928 case 5: return ZSTD_hash5Ptr(p, hBits);
929 case 6: return ZSTD_hash6Ptr(p, hBits);
930 case 7: return ZSTD_hash7Ptr(p, hBits);
931 case 8: return ZSTD_hash8Ptr(p, hBits);
932 }
933 }
934
935
936 /*-*************************************
937 * Fast Scan
938 ***************************************/
939 static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
940 {
941 U32* const hashTable = zc->hashTable;
942 U32 const hBits = zc->params.cParams.hashLog;
943 const BYTE* const base = zc->base;
944 const BYTE* ip = base + zc->nextToUpdate;
945 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
946 const size_t fastHashFillStep = 3;
947
948 while(ip <= iend) {
949 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
950 ip += fastHashFillStep;
951 }
952 }
953
954
955 FORCE_INLINE
956 void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
957 const void* src, size_t srcSize,
958 const U32 mls)
959 {
960 U32* const hashTable = cctx->hashTable;
961 U32 const hBits = cctx->params.cParams.hashLog;
962 seqStore_t* seqStorePtr = &(cctx->seqStore);
963 const BYTE* const base = cctx->base;
964 const BYTE* const istart = (const BYTE*)src;
965 const BYTE* ip = istart;
966 const BYTE* anchor = istart;
967 const U32 lowestIndex = cctx->dictLimit;
968 const BYTE* const lowest = base + lowestIndex;
969 const BYTE* const iend = istart + srcSize;
970 const BYTE* const ilimit = iend - HASH_READ_SIZE;
971 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
972 U32 offsetSaved = 0;
973
974 /* init */
975 ip += (ip==lowest);
976 { U32 const maxRep = (U32)(ip-lowest);
977 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
978 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
979 }
980
981 /* Main Search Loop */
982 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
983 size_t mLength;
984 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
985 U32 const current = (U32)(ip-base);
986 U32 const matchIndex = hashTable[h];
987 const BYTE* match = base + matchIndex;
988 hashTable[h] = current; /* update hash table */
989
990 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
991 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
992 ip++;
993 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
994 } else {
995 U32 offset;
996 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
997 ip += ((ip-anchor) >> g_searchStrength) + 1;
998 continue;
999 }
1000 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1001 offset = (U32)(ip-match);
1002 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1003 offset_2 = offset_1;
1004 offset_1 = offset;
1005
1006 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1007 }
1008
1009 /* match found */
1010 ip += mLength;
1011 anchor = ip;
1012
1013 if (ip <= ilimit) {
1014 /* Fill Table */
1015 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; /* here because current+2 could be > iend-8 */
1016 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1017 /* check immediate repcode */
1018 while ( (ip <= ilimit)
1019 && ( (offset_2>0)
1020 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1021 /* store sequence */
1022 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
1023 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
1024 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
1025 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1026 ip += rLength;
1027 anchor = ip;
1028 continue; /* faster when present ... (?) */
1029 } } }
1030
1031 /* save reps for next block */
1032 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1033 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
1034
1035 /* Last Literals */
1036 { size_t const lastLLSize = iend - anchor;
1037 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1038 seqStorePtr->lit += lastLLSize;
1039 }
1040 }
1041
1042
1043 static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
1044 const void* src, size_t srcSize)
1045 {
1046 const U32 mls = ctx->params.cParams.searchLength;
1047 switch(mls)
1048 {
1049 default:
1050 case 4 :
1051 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
1052 case 5 :
1053 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
1054 case 6 :
1055 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
1056 case 7 :
1057 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
1058 }
1059 }
1060
1061
1062 static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
1063 const void* src, size_t srcSize,
1064 const U32 mls)
1065 {
1066 U32* hashTable = ctx->hashTable;
1067 const U32 hBits = ctx->params.cParams.hashLog;
1068 seqStore_t* seqStorePtr = &(ctx->seqStore);
1069 const BYTE* const base = ctx->base;
1070 const BYTE* const dictBase = ctx->dictBase;
1071 const BYTE* const istart = (const BYTE*)src;
1072 const BYTE* ip = istart;
1073 const BYTE* anchor = istart;
1074 const U32 lowestIndex = ctx->lowLimit;
1075 const BYTE* const dictStart = dictBase + lowestIndex;
1076 const U32 dictLimit = ctx->dictLimit;
1077 const BYTE* const lowPrefixPtr = base + dictLimit;
1078 const BYTE* const dictEnd = dictBase + dictLimit;
1079 const BYTE* const iend = istart + srcSize;
1080 const BYTE* const ilimit = iend - 8;
1081 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1082
1083 /* Search Loop */
1084 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1085 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
1086 const U32 matchIndex = hashTable[h];
1087 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1088 const BYTE* match = matchBase + matchIndex;
1089 const U32 current = (U32)(ip-base);
1090 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1091 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1092 const BYTE* repMatch = repBase + repIndex;
1093 size_t mLength;
1094 hashTable[h] = current; /* update hash table */
1095
1096 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1097 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1098 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1099 mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
1100 ip++;
1101 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1102 } else {
1103 if ( (matchIndex < lowestIndex) ||
1104 (MEM_read32(match) != MEM_read32(ip)) ) {
1105 ip += ((ip-anchor) >> g_searchStrength) + 1;
1106 continue;
1107 }
1108 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1109 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1110 U32 offset;
1111 mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
1112 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1113 offset = current - matchIndex;
1114 offset_2 = offset_1;
1115 offset_1 = offset;
1116 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1117 } }
1118
1119 /* found a match : store it */
1120 ip += mLength;
1121 anchor = ip;
1122
1123 if (ip <= ilimit) {
1124 /* Fill Table */
1125 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
1126 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1127 /* check immediate repcode */
1128 while (ip <= ilimit) {
1129 U32 const current2 = (U32)(ip-base);
1130 U32 const repIndex2 = current2 - offset_2;
1131 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1132 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1133 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1134 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1135 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1136 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1137 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1138 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
1139 ip += repLength2;
1140 anchor = ip;
1141 continue;
1142 }
1143 break;
1144 } } }
1145
1146 /* save reps for next block */
1147 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
1148
1149 /* Last Literals */
1150 { size_t const lastLLSize = iend - anchor;
1151 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1152 seqStorePtr->lit += lastLLSize;
1153 }
1154 }
1155
1156
1157 static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
1158 const void* src, size_t srcSize)
1159 {
1160 U32 const mls = ctx->params.cParams.searchLength;
1161 switch(mls)
1162 {
1163 default:
1164 case 4 :
1165 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
1166 case 5 :
1167 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
1168 case 6 :
1169 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
1170 case 7 :
1171 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
1172 }
1173 }
1174
1175
1176 /*-*************************************
1177 * Double Fast
1178 ***************************************/
1179 static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1180 {
1181 U32* const hashLarge = cctx->hashTable;
1182 U32 const hBitsL = cctx->params.cParams.hashLog;
1183 U32* const hashSmall = cctx->chainTable;
1184 U32 const hBitsS = cctx->params.cParams.chainLog;
1185 const BYTE* const base = cctx->base;
1186 const BYTE* ip = base + cctx->nextToUpdate;
1187 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
1188 const size_t fastHashFillStep = 3;
1189
1190 while(ip <= iend) {
1191 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1192 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1193 ip += fastHashFillStep;
1194 }
1195 }
1196
1197
1198 FORCE_INLINE
1199 void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1200 const void* src, size_t srcSize,
1201 const U32 mls)
1202 {
1203 U32* const hashLong = cctx->hashTable;
1204 const U32 hBitsL = cctx->params.cParams.hashLog;
1205 U32* const hashSmall = cctx->chainTable;
1206 const U32 hBitsS = cctx->params.cParams.chainLog;
1207 seqStore_t* seqStorePtr = &(cctx->seqStore);
1208 const BYTE* const base = cctx->base;
1209 const BYTE* const istart = (const BYTE*)src;
1210 const BYTE* ip = istart;
1211 const BYTE* anchor = istart;
1212 const U32 lowestIndex = cctx->dictLimit;
1213 const BYTE* const lowest = base + lowestIndex;
1214 const BYTE* const iend = istart + srcSize;
1215 const BYTE* const ilimit = iend - HASH_READ_SIZE;
1216 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1217 U32 offsetSaved = 0;
1218
1219 /* init */
1220 ip += (ip==lowest);
1221 { U32 const maxRep = (U32)(ip-lowest);
1222 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1223 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1224 }
1225
1226 /* Main Search Loop */
1227 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1228 size_t mLength;
1229 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1230 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1231 U32 const current = (U32)(ip-base);
1232 U32 const matchIndexL = hashLong[h2];
1233 U32 const matchIndexS = hashSmall[h];
1234 const BYTE* matchLong = base + matchIndexL;
1235 const BYTE* match = base + matchIndexS;
1236 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1237
1238 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1239 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1240 ip++;
1241 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1242 } else {
1243 U32 offset;
1244 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1245 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
1246 offset = (U32)(ip-matchLong);
1247 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1248 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
1249 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1250 U32 const matchIndex3 = hashLong[h3];
1251 const BYTE* match3 = base + matchIndex3;
1252 hashLong[h3] = current + 1;
1253 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1254 mLength = ZSTD_count(ip+9, match3+8, iend) + 8;
1255 ip++;
1256 offset = (U32)(ip-match3);
1257 while (((ip>anchor) & (match3>lowest)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1258 } else {
1259 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1260 offset = (U32)(ip-match);
1261 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1262 }
1263 } else {
1264 ip += ((ip-anchor) >> g_searchStrength) + 1;
1265 continue;
1266 }
1267
1268 offset_2 = offset_1;
1269 offset_1 = offset;
1270
1271 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1272 }
1273
1274 /* match found */
1275 ip += mLength;
1276 anchor = ip;
1277
1278 if (ip <= ilimit) {
1279 /* Fill Table */
1280 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1281 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1282 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1283 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1284
1285 /* check immediate repcode */
1286 while ( (ip <= ilimit)
1287 && ( (offset_2>0)
1288 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1289 /* store sequence */
1290 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
1291 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
1292 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1293 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1294 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1295 ip += rLength;
1296 anchor = ip;
1297 continue; /* faster when present ... (?) */
1298 } } }
1299
1300 /* save reps for next block */
1301 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1302 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
1303
1304 /* Last Literals */
1305 { size_t const lastLLSize = iend - anchor;
1306 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1307 seqStorePtr->lit += lastLLSize;
1308 }
1309 }
1310
1311
1312 static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1313 {
1314 const U32 mls = ctx->params.cParams.searchLength;
1315 switch(mls)
1316 {
1317 default:
1318 case 4 :
1319 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1320 case 5 :
1321 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1322 case 6 :
1323 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1324 case 7 :
1325 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1326 }
1327 }
1328
1329
1330 static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1331 const void* src, size_t srcSize,
1332 const U32 mls)
1333 {
1334 U32* const hashLong = ctx->hashTable;
1335 U32 const hBitsL = ctx->params.cParams.hashLog;
1336 U32* const hashSmall = ctx->chainTable;
1337 U32 const hBitsS = ctx->params.cParams.chainLog;
1338 seqStore_t* seqStorePtr = &(ctx->seqStore);
1339 const BYTE* const base = ctx->base;
1340 const BYTE* const dictBase = ctx->dictBase;
1341 const BYTE* const istart = (const BYTE*)src;
1342 const BYTE* ip = istart;
1343 const BYTE* anchor = istart;
1344 const U32 lowestIndex = ctx->lowLimit;
1345 const BYTE* const dictStart = dictBase + lowestIndex;
1346 const U32 dictLimit = ctx->dictLimit;
1347 const BYTE* const lowPrefixPtr = base + dictLimit;
1348 const BYTE* const dictEnd = dictBase + dictLimit;
1349 const BYTE* const iend = istart + srcSize;
1350 const BYTE* const ilimit = iend - 8;
1351 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1352
1353 /* Search Loop */
1354 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1355 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1356 const U32 matchIndex = hashSmall[hSmall];
1357 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1358 const BYTE* match = matchBase + matchIndex;
1359
1360 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1361 const U32 matchLongIndex = hashLong[hLong];
1362 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1363 const BYTE* matchLong = matchLongBase + matchLongIndex;
1364
1365 const U32 current = (U32)(ip-base);
1366 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1367 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1368 const BYTE* repMatch = repBase + repIndex;
1369 size_t mLength;
1370 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1371
1372 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1373 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1374 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1375 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1376 ip++;
1377 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1378 } else {
1379 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1380 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1381 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1382 U32 offset;
1383 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1384 offset = current - matchLongIndex;
1385 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1386 offset_2 = offset_1;
1387 offset_1 = offset;
1388 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1389
1390 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
1391 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1392 U32 const matchIndex3 = hashLong[h3];
1393 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1394 const BYTE* match3 = match3Base + matchIndex3;
1395 U32 offset;
1396 hashLong[h3] = current + 1;
1397 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1398 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1399 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1400 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1401 ip++;
1402 offset = current+1 - matchIndex3;
1403 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1404 } else {
1405 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1406 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1407 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1408 offset = current - matchIndex;
1409 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1410 }
1411 offset_2 = offset_1;
1412 offset_1 = offset;
1413 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1414
1415 } else {
1416 ip += ((ip-anchor) >> g_searchStrength) + 1;
1417 continue;
1418 } }
1419
1420 /* found a match : store it */
1421 ip += mLength;
1422 anchor = ip;
1423
1424 if (ip <= ilimit) {
1425 /* Fill Table */
1426 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1427 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
1428 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1429 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1430 /* check immediate repcode */
1431 while (ip <= ilimit) {
1432 U32 const current2 = (U32)(ip-base);
1433 U32 const repIndex2 = current2 - offset_2;
1434 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1435 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1436 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1437 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1438 size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1439 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1440 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1441 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1442 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1443 ip += repLength2;
1444 anchor = ip;
1445 continue;
1446 }
1447 break;
1448 } } }
1449
1450 /* save reps for next block */
1451 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
1452
1453 /* Last Literals */
1454 { size_t const lastLLSize = iend - anchor;
1455 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1456 seqStorePtr->lit += lastLLSize;
1457 }
1458 }
1459
1460
1461 static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1462 const void* src, size_t srcSize)
1463 {
1464 U32 const mls = ctx->params.cParams.searchLength;
1465 switch(mls)
1466 {
1467 default:
1468 case 4 :
1469 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1470 case 5 :
1471 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1472 case 6 :
1473 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1474 case 7 :
1475 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1476 }
1477 }
1478
1479
1480 /*-*************************************
1481 * Binary Tree search
1482 ***************************************/
1483 /** ZSTD_insertBt1() : add one or multiple positions to tree.
1484 * ip : assumed <= iend-8 .
1485 * @return : nb of positions added */
1486 static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1487 U32 extDict)
1488 {
1489 U32* const hashTable = zc->hashTable;
1490 U32 const hashLog = zc->params.cParams.hashLog;
1491 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1492 U32* const bt = zc->chainTable;
1493 U32 const btLog = zc->params.cParams.chainLog - 1;
1494 U32 const btMask = (1 << btLog) - 1;
1495 U32 matchIndex = hashTable[h];
1496 size_t commonLengthSmaller=0, commonLengthLarger=0;
1497 const BYTE* const base = zc->base;
1498 const BYTE* const dictBase = zc->dictBase;
1499 const U32 dictLimit = zc->dictLimit;
1500 const BYTE* const dictEnd = dictBase + dictLimit;
1501 const BYTE* const prefixStart = base + dictLimit;
1502 const BYTE* match;
1503 const U32 current = (U32)(ip-base);
1504 const U32 btLow = btMask >= current ? 0 : current - btMask;
1505 U32* smallerPtr = bt + 2*(current&btMask);
1506 U32* largerPtr = smallerPtr + 1;
1507 U32 dummy32; /* to be nullified at the end */
1508 U32 const windowLow = zc->lowLimit;
1509 U32 matchEndIdx = current+8;
1510 size_t bestLength = 8;
1511 #ifdef ZSTD_C_PREDICT
1512 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1513 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1514 predictedSmall += (predictedSmall>0);
1515 predictedLarge += (predictedLarge>0);
1516 #endif /* ZSTD_C_PREDICT */
1517
1518 hashTable[h] = current; /* Update Hash Table */
1519
1520 while (nbCompares-- && (matchIndex > windowLow)) {
1521 U32* const nextPtr = bt + 2*(matchIndex & btMask);
1522 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1523
1524 #ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
1525 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
1526 if (matchIndex == predictedSmall) {
1527 /* no need to check length, result known */
1528 *smallerPtr = matchIndex;
1529 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1530 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1531 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
1532 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
1533 continue;
1534 }
1535 if (matchIndex == predictedLarge) {
1536 *largerPtr = matchIndex;
1537 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1538 largerPtr = nextPtr;
1539 matchIndex = nextPtr[0];
1540 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
1541 continue;
1542 }
1543 #endif
1544 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
1545 match = base + matchIndex;
1546 if (match[matchLength] == ip[matchLength])
1547 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
1548 } else {
1549 match = dictBase + matchIndex;
1550 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1551 if (matchIndex+matchLength >= dictLimit)
1552 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1553 }
1554
1555 if (matchLength > bestLength) {
1556 bestLength = matchLength;
1557 if (matchLength > matchEndIdx - matchIndex)
1558 matchEndIdx = matchIndex + (U32)matchLength;
1559 }
1560
1561 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1562 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
1563
1564 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
1565 /* match is smaller than current */
1566 *smallerPtr = matchIndex; /* update smaller idx */
1567 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1568 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1569 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1570 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
1571 } else {
1572 /* match is larger than current */
1573 *largerPtr = matchIndex;
1574 commonLengthLarger = matchLength;
1575 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1576 largerPtr = nextPtr;
1577 matchIndex = nextPtr[0];
1578 } }
1579
1580 *smallerPtr = *largerPtr = 0;
1581 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
1582 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1583 return 1;
1584 }
1585
1586
1587 static size_t ZSTD_insertBtAndFindBestMatch (
1588 ZSTD_CCtx* zc,
1589 const BYTE* const ip, const BYTE* const iend,
1590 size_t* offsetPtr,
1591 U32 nbCompares, const U32 mls,
1592 U32 extDict)
1593 {
1594 U32* const hashTable = zc->hashTable;
1595 U32 const hashLog = zc->params.cParams.hashLog;
1596 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1597 U32* const bt = zc->chainTable;
1598 U32 const btLog = zc->params.cParams.chainLog - 1;
1599 U32 const btMask = (1 << btLog) - 1;
1600 U32 matchIndex = hashTable[h];
1601 size_t commonLengthSmaller=0, commonLengthLarger=0;
1602 const BYTE* const base = zc->base;
1603 const BYTE* const dictBase = zc->dictBase;
1604 const U32 dictLimit = zc->dictLimit;
1605 const BYTE* const dictEnd = dictBase + dictLimit;
1606 const BYTE* const prefixStart = base + dictLimit;
1607 const U32 current = (U32)(ip-base);
1608 const U32 btLow = btMask >= current ? 0 : current - btMask;
1609 const U32 windowLow = zc->lowLimit;
1610 U32* smallerPtr = bt + 2*(current&btMask);
1611 U32* largerPtr = bt + 2*(current&btMask) + 1;
1612 U32 matchEndIdx = current+8;
1613 U32 dummy32; /* to be nullified at the end */
1614 size_t bestLength = 0;
1615
1616 hashTable[h] = current; /* Update Hash Table */
1617
1618 while (nbCompares-- && (matchIndex > windowLow)) {
1619 U32* const nextPtr = bt + 2*(matchIndex & btMask);
1620 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1621 const BYTE* match;
1622
1623 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
1624 match = base + matchIndex;
1625 if (match[matchLength] == ip[matchLength])
1626 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
1627 } else {
1628 match = dictBase + matchIndex;
1629 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1630 if (matchIndex+matchLength >= dictLimit)
1631 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1632 }
1633
1634 if (matchLength > bestLength) {
1635 if (matchLength > matchEndIdx - matchIndex)
1636 matchEndIdx = matchIndex + (U32)matchLength;
1637 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
1638 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
1639 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1640 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1641 }
1642
1643 if (match[matchLength] < ip[matchLength]) {
1644 /* match is smaller than current */
1645 *smallerPtr = matchIndex; /* update smaller idx */
1646 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1647 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1648 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1649 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
1650 } else {
1651 /* match is larger than current */
1652 *largerPtr = matchIndex;
1653 commonLengthLarger = matchLength;
1654 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1655 largerPtr = nextPtr;
1656 matchIndex = nextPtr[0];
1657 } }
1658
1659 *smallerPtr = *largerPtr = 0;
1660
1661 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
1662 return bestLength;
1663 }
1664
1665
1666 static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1667 {
1668 const BYTE* const base = zc->base;
1669 const U32 target = (U32)(ip - base);
1670 U32 idx = zc->nextToUpdate;
1671
1672 while(idx < target)
1673 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
1674 }
1675
1676 /** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
1677 static size_t ZSTD_BtFindBestMatch (
1678 ZSTD_CCtx* zc,
1679 const BYTE* const ip, const BYTE* const iLimit,
1680 size_t* offsetPtr,
1681 const U32 maxNbAttempts, const U32 mls)
1682 {
1683 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1684 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
1685 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1686 }
1687
1688
1689 static size_t ZSTD_BtFindBestMatch_selectMLS (
1690 ZSTD_CCtx* zc, /* Index table will be updated */
1691 const BYTE* ip, const BYTE* const iLimit,
1692 size_t* offsetPtr,
1693 const U32 maxNbAttempts, const U32 matchLengthSearch)
1694 {
1695 switch(matchLengthSearch)
1696 {
1697 default :
1698 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1699 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1700 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1701 }
1702 }
1703
1704
1705 static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1706 {
1707 const BYTE* const base = zc->base;
1708 const U32 target = (U32)(ip - base);
1709 U32 idx = zc->nextToUpdate;
1710
1711 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1712 }
1713
1714
1715 /** Tree updater, providing best match */
1716 static size_t ZSTD_BtFindBestMatch_extDict (
1717 ZSTD_CCtx* zc,
1718 const BYTE* const ip, const BYTE* const iLimit,
1719 size_t* offsetPtr,
1720 const U32 maxNbAttempts, const U32 mls)
1721 {
1722 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1723 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
1724 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
1725 }
1726
1727
1728 static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
1729 ZSTD_CCtx* zc, /* Index table will be updated */
1730 const BYTE* ip, const BYTE* const iLimit,
1731 size_t* offsetPtr,
1732 const U32 maxNbAttempts, const U32 matchLengthSearch)
1733 {
1734 switch(matchLengthSearch)
1735 {
1736 default :
1737 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1738 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1739 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1740 }
1741 }
1742
1743
1744
1745 /* *********************************
1746 * Hash Chain
1747 ***********************************/
1748 #define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1749
1750 /* Update chains up to ip (excluded)
1751 Assumption : always within prefix (ie. not within extDict) */
1752 FORCE_INLINE
1753 U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1754 {
1755 U32* const hashTable = zc->hashTable;
1756 const U32 hashLog = zc->params.cParams.hashLog;
1757 U32* const chainTable = zc->chainTable;
1758 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1759 const BYTE* const base = zc->base;
1760 const U32 target = (U32)(ip - base);
1761 U32 idx = zc->nextToUpdate;
1762
1763 while(idx < target) { /* catch up */
1764 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1765 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1766 hashTable[h] = idx;
1767 idx++;
1768 }
1769
1770 zc->nextToUpdate = target;
1771 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1772 }
1773
1774
1775
1776 FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1777 size_t ZSTD_HcFindBestMatch_generic (
1778 ZSTD_CCtx* zc, /* Index table will be updated */
1779 const BYTE* const ip, const BYTE* const iLimit,
1780 size_t* offsetPtr,
1781 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1782 {
1783 U32* const chainTable = zc->chainTable;
1784 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1785 const U32 chainMask = chainSize-1;
1786 const BYTE* const base = zc->base;
1787 const BYTE* const dictBase = zc->dictBase;
1788 const U32 dictLimit = zc->dictLimit;
1789 const BYTE* const prefixStart = base + dictLimit;
1790 const BYTE* const dictEnd = dictBase + dictLimit;
1791 const U32 lowLimit = zc->lowLimit;
1792 const U32 current = (U32)(ip-base);
1793 const U32 minChain = current > chainSize ? current - chainSize : 0;
1794 int nbAttempts=maxNbAttempts;
1795 size_t ml=EQUAL_READ32-1;
1796
1797 /* HC4 match finder */
1798 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1799
1800 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
1801 const BYTE* match;
1802 size_t currentMl=0;
1803 if ((!extDict) || matchIndex >= dictLimit) {
1804 match = base + matchIndex;
1805 if (match[ml] == ip[ml]) /* potentially better */
1806 currentMl = ZSTD_count(ip, match, iLimit);
1807 } else {
1808 match = dictBase + matchIndex;
1809 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1810 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1811 }
1812
1813 /* save best solution */
1814 if (currentMl > ml) { ml = currentMl; *offsetPtr = current - matchIndex + ZSTD_REP_MOVE; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }
1815
1816 if (matchIndex <= minChain) break;
1817 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1818 }
1819
1820 return ml;
1821 }
1822
1823
1824 FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1825 ZSTD_CCtx* zc,
1826 const BYTE* ip, const BYTE* const iLimit,
1827 size_t* offsetPtr,
1828 const U32 maxNbAttempts, const U32 matchLengthSearch)
1829 {
1830 switch(matchLengthSearch)
1831 {
1832 default :
1833 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1834 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1835 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1836 }
1837 }
1838
1839
1840 FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1841 ZSTD_CCtx* zc,
1842 const BYTE* ip, const BYTE* const iLimit,
1843 size_t* offsetPtr,
1844 const U32 maxNbAttempts, const U32 matchLengthSearch)
1845 {
1846 switch(matchLengthSearch)
1847 {
1848 default :
1849 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1850 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1851 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1852 }
1853 }
1854
1855
1856 /* *******************************
1857 * Common parser - lazy strategy
1858 *********************************/
1859 FORCE_INLINE
1860 void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1861 const void* src, size_t srcSize,
1862 const U32 searchMethod, const U32 depth)
1863 {
1864 seqStore_t* seqStorePtr = &(ctx->seqStore);
1865 const BYTE* const istart = (const BYTE*)src;
1866 const BYTE* ip = istart;
1867 const BYTE* anchor = istart;
1868 const BYTE* const iend = istart + srcSize;
1869 const BYTE* const ilimit = iend - 8;
1870 const BYTE* const base = ctx->base + ctx->dictLimit;
1871
1872 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1873 U32 const mls = ctx->params.cParams.searchLength;
1874
1875 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1876 size_t* offsetPtr,
1877 U32 maxNbAttempts, U32 matchLengthSearch);
1878 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
1879 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
1880
1881 /* init */
1882 ip += (ip==base);
1883 ctx->nextToUpdate3 = ctx->nextToUpdate;
1884 { U32 const maxRep = (U32)(ip-base);
1885 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
1886 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
1887 }
1888
1889 /* Match Loop */
1890 while (ip < ilimit) {
1891 size_t matchLength=0;
1892 size_t offset=0;
1893 const BYTE* start=ip+1;
1894
1895 /* check repCode */
1896 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
1897 /* repcode : we take it */
1898 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
1899 if (depth==0) goto _storeSequence;
1900 }
1901
1902 /* first search (depth 0) */
1903 { size_t offsetFound = 99999999;
1904 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1905 if (ml2 > matchLength)
1906 matchLength = ml2, start = ip, offset=offsetFound;
1907 }
1908
1909 if (matchLength < EQUAL_READ32) {
1910 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1911 continue;
1912 }
1913
1914 /* let's try to find a better solution */
1915 if (depth>=1)
1916 while (ip<ilimit) {
1917 ip ++;
1918 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1919 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
1920 int const gain2 = (int)(mlRep * 3);
1921 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
1922 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1923 matchLength = mlRep, offset = 0, start = ip;
1924 }
1925 { size_t offset2=99999999;
1926 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1927 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1928 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
1929 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1930 matchLength = ml2, offset = offset2, start = ip;
1931 continue; /* search a better one */
1932 } }
1933
1934 /* let's find an even better one */
1935 if ((depth==2) && (ip<ilimit)) {
1936 ip ++;
1937 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1938 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
1939 int const gain2 = (int)(ml2 * 4);
1940 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
1941 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1942 matchLength = ml2, offset = 0, start = ip;
1943 }
1944 { size_t offset2=99999999;
1945 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1946 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1947 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
1948 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1949 matchLength = ml2, offset = offset2, start = ip;
1950 continue;
1951 } } }
1952 break; /* nothing found : store previous solution */
1953 }
1954
1955 /* catch up */
1956 if (offset) {
1957 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1958 { start--; matchLength++; }
1959 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
1960 }
1961
1962 /* store sequence */
1963 _storeSequence:
1964 { size_t const litLength = start - anchor;
1965 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
1966 anchor = ip = start + matchLength;
1967 }
1968
1969 /* check immediate repcode */
1970 while ( (ip <= ilimit)
1971 && ((offset_2>0)
1972 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1973 /* store sequence */
1974 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
1975 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
1976 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1977 ip += matchLength;
1978 anchor = ip;
1979 continue; /* faster when present ... (?) */
1980 } }
1981
1982 /* Save reps for next block */
1983 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
1984 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
1985
1986 /* Last Literals */
1987 { size_t const lastLLSize = iend - anchor;
1988 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1989 seqStorePtr->lit += lastLLSize;
1990 }
1991 }
1992
1993
1994 static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1995 {
1996 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
1997 }
1998
1999 static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2000 {
2001 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2002 }
2003
2004 static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2005 {
2006 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2007 }
2008
2009 static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2010 {
2011 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2012 }
2013
2014
2015 FORCE_INLINE
2016 void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2017 const void* src, size_t srcSize,
2018 const U32 searchMethod, const U32 depth)
2019 {
2020 seqStore_t* seqStorePtr = &(ctx->seqStore);
2021 const BYTE* const istart = (const BYTE*)src;
2022 const BYTE* ip = istart;
2023 const BYTE* anchor = istart;
2024 const BYTE* const iend = istart + srcSize;
2025 const BYTE* const ilimit = iend - 8;
2026 const BYTE* const base = ctx->base;
2027 const U32 dictLimit = ctx->dictLimit;
2028 const U32 lowestIndex = ctx->lowLimit;
2029 const BYTE* const prefixStart = base + dictLimit;
2030 const BYTE* const dictBase = ctx->dictBase;
2031 const BYTE* const dictEnd = dictBase + dictLimit;
2032 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2033
2034 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2035 const U32 mls = ctx->params.cParams.searchLength;
2036
2037 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2038 size_t* offsetPtr,
2039 U32 maxNbAttempts, U32 matchLengthSearch);
2040 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2041
2042 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
2043
2044 /* init */
2045 ctx->nextToUpdate3 = ctx->nextToUpdate;
2046 ip += (ip == prefixStart);
2047
2048 /* Match Loop */
2049 while (ip < ilimit) {
2050 size_t matchLength=0;
2051 size_t offset=0;
2052 const BYTE* start=ip+1;
2053 U32 current = (U32)(ip-base);
2054
2055 /* check repCode */
2056 { const U32 repIndex = (U32)(current+1 - offset_1);
2057 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2058 const BYTE* const repMatch = repBase + repIndex;
2059 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
2060 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
2061 /* repcode detected we should take it */
2062 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2063 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2064 if (depth==0) goto _storeSequence;
2065 } }
2066
2067 /* first search (depth 0) */
2068 { size_t offsetFound = 99999999;
2069 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
2070 if (ml2 > matchLength)
2071 matchLength = ml2, start = ip, offset=offsetFound;
2072 }
2073
2074 if (matchLength < EQUAL_READ32) {
2075 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2076 continue;
2077 }
2078
2079 /* let's try to find a better solution */
2080 if (depth>=1)
2081 while (ip<ilimit) {
2082 ip ++;
2083 current++;
2084 /* check repCode */
2085 if (offset) {
2086 const U32 repIndex = (U32)(current - offset_1);
2087 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2088 const BYTE* const repMatch = repBase + repIndex;
2089 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
2090 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2091 /* repcode detected */
2092 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2093 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2094 int const gain2 = (int)(repLength * 3);
2095 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
2096 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2097 matchLength = repLength, offset = 0, start = ip;
2098 } }
2099
2100 /* search match, depth 1 */
2101 { size_t offset2=99999999;
2102 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
2103 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2104 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
2105 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2106 matchLength = ml2, offset = offset2, start = ip;
2107 continue; /* search a better one */
2108 } }
2109
2110 /* let's find an even better one */
2111 if ((depth==2) && (ip<ilimit)) {
2112 ip ++;
2113 current++;
2114 /* check repCode */
2115 if (offset) {
2116 const U32 repIndex = (U32)(current - offset_1);
2117 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2118 const BYTE* const repMatch = repBase + repIndex;
2119 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
2120 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2121 /* repcode detected */
2122 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2123 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2124 int gain2 = (int)(repLength * 4);
2125 int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
2126 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2127 matchLength = repLength, offset = 0, start = ip;
2128 } }
2129
2130 /* search match, depth 2 */
2131 { size_t offset2=99999999;
2132 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
2133 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2134 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
2135 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2136 matchLength = ml2, offset = offset2, start = ip;
2137 continue;
2138 } } }
2139 break; /* nothing found : store previous solution */
2140 }
2141
2142 /* catch up */
2143 if (offset) {
2144 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
2145 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2146 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
2147 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
2148 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
2149 }
2150
2151 /* store sequence */
2152 _storeSequence:
2153 { size_t const litLength = start - anchor;
2154 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
2155 anchor = ip = start + matchLength;
2156 }
2157
2158 /* check immediate repcode */
2159 while (ip <= ilimit) {
2160 const U32 repIndex = (U32)((ip-base) - offset_2);
2161 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2162 const BYTE* const repMatch = repBase + repIndex;
2163 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
2164 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2165 /* repcode detected we should take it */
2166 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2167 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2168 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
2169 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2170 ip += matchLength;
2171 anchor = ip;
2172 continue; /* faster when present ... (?) */
2173 }
2174 break;
2175 } }
2176
2177 /* Save reps for next block */
2178 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
2179
2180 /* Last Literals */
2181 { size_t const lastLLSize = iend - anchor;
2182 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2183 seqStorePtr->lit += lastLLSize;
2184 }
2185 }
2186
2187
2188 void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2189 {
2190 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
2191 }
2192
2193 static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2194 {
2195 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
2196 }
2197
2198 static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2199 {
2200 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
2201 }
2202
2203 static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2204 {
2205 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
2206 }
2207
2208
2209 /* The optimal parser */
2210 #include "zstd_opt.h"
2211
2212 static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2213 {
2214 #ifdef ZSTD_OPT_H_91842398743
2215 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2216 #else
2217 (void)ctx; (void)src; (void)srcSize;
2218 return;
2219 #endif
2220 }
2221
2222 static void ZSTD_compressBlock_btopt2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2223 {
2224 #ifdef ZSTD_OPT_H_91842398743
2225 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
2226 #else
2227 (void)ctx; (void)src; (void)srcSize;
2228 return;
2229 #endif
2230 }
2231
2232 static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2233 {
2234 #ifdef ZSTD_OPT_H_91842398743
2235 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2236 #else
2237 (void)ctx; (void)src; (void)srcSize;
2238 return;
2239 #endif
2240 }
2241
2242 static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2243 {
2244 #ifdef ZSTD_OPT_H_91842398743
2245 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
2246 #else
2247 (void)ctx; (void)src; (void)srcSize;
2248 return;
2249 #endif
2250 }
2251
2252
2253 typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
2254
2255 static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
2256 {
2257 static const ZSTD_blockCompressor blockCompressor[2][8] = {
2258 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2 },
2259 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btopt2_extDict }
2260 };
2261
2262 return blockCompressor[extDict][(U32)strat];
2263 }
2264
2265
2266 static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2267 {
2268 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
2269 const BYTE* const base = zc->base;
2270 const BYTE* const istart = (const BYTE*)src;
2271 const U32 current = (U32)(istart-base);
2272 if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */
2273 ZSTD_resetSeqStore(&(zc->seqStore));
2274 if (current > zc->nextToUpdate + 384)
2275 zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384)); /* update tree not updated after finding very long rep matches */
2276 blockCompressor(zc, src, srcSize);
2277 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
2278 }
2279
2280
2281 /*! ZSTD_compress_generic() :
2282 * Compress a chunk of data into one or multiple blocks. 1971 * Compress a chunk of data into one or multiple blocks.
2283 * All blocks will be terminated, all input will be consumed. 1972 * All blocks will be terminated, all input will be consumed.
2284 * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content. 1973 * Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2285 * Frame is supposed already started (header already produced) 1974 * Frame is supposed already started (header already produced)
2286 * @return : compressed size, or an error code 1975 * @return : compressed size, or an error code
2287 */ 1976 */
2288 static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx, 1977 static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
2289 void* dst, size_t dstCapacity, 1978 void* dst, size_t dstCapacity,
2290 const void* src, size_t srcSize, 1979 const void* src, size_t srcSize,
2291 U32 lastFrameChunk) 1980 U32 lastFrameChunk)
2292 { 1981 {
2293 size_t blockSize = cctx->blockSize; 1982 size_t blockSize = cctx->blockSize;
2294 size_t remaining = srcSize; 1983 size_t remaining = srcSize;
2295 const BYTE* ip = (const BYTE*)src; 1984 const BYTE* ip = (const BYTE*)src;
2296 BYTE* const ostart = (BYTE*)dst; 1985 BYTE* const ostart = (BYTE*)dst;
2297 BYTE* op = ostart; 1986 BYTE* op = ostart;
2298 U32 const maxDist = 1 << cctx->params.cParams.windowLog; 1987 U32 const maxDist = (U32)1 << cctx->appliedParams.cParams.windowLog;
2299 1988 assert(cctx->appliedParams.cParams.windowLog <= 31);
2300 if (cctx->params.fParams.checksumFlag && srcSize) 1989
1990 DEBUGLOG(5, "ZSTD_compress_frameChunk (blockSize=%u)", (U32)blockSize);
1991 if (cctx->appliedParams.fParams.checksumFlag && srcSize)
2301 XXH64_update(&cctx->xxhState, src, srcSize); 1992 XXH64_update(&cctx->xxhState, src, srcSize);
2302 1993
2303 while (remaining) { 1994 while (remaining) {
1995 ZSTD_matchState_t* const ms = &cctx->blockState.matchState;
2304 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining); 1996 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
2305 size_t cSize; 1997
2306 1998 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
2307 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */ 1999 return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
2308 if (remaining < blockSize) blockSize = remaining; 2000 if (remaining < blockSize) blockSize = remaining;
2309 2001
2310 /* preemptive overflow correction */ 2002 if (ZSTD_window_needOverflowCorrection(ms->window, ip + blockSize)) {
2311 if (cctx->lowLimit > (2U<<30)) { 2003 U32 const cycleLog = ZSTD_cycleLog(cctx->appliedParams.cParams.chainLog, cctx->appliedParams.cParams.strategy);
2312 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1; 2004 U32 const correction = ZSTD_window_correctOverflow(&ms->window, cycleLog, maxDist, ip);
2313 U32 const current = (U32)(ip - cctx->base); 2005 ZSTD_STATIC_ASSERT(ZSTD_CHAINLOG_MAX <= 30);
2314 U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog); 2006 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_32 <= 30);
2315 U32 const correction = current - newCurrent; 2007 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX <= 31);
2316 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30); 2008
2317 ZSTD_reduceIndex(cctx, correction); 2009 ZSTD_reduceIndex(cctx, correction);
2318 cctx->base += correction; 2010 if (ms->nextToUpdate < correction) ms->nextToUpdate = 0;
2319 cctx->dictBase += correction; 2011 else ms->nextToUpdate -= correction;
2320 cctx->lowLimit -= correction; 2012 ms->loadedDictEnd = 0;
2321 cctx->dictLimit -= correction;
2322 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2323 else cctx->nextToUpdate -= correction;
2324 } 2013 }
2325 2014 ZSTD_window_enforceMaxDist(&ms->window, ip + blockSize, maxDist, &ms->loadedDictEnd);
2326 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) { 2015 if (ms->nextToUpdate < ms->window.lowLimit) ms->nextToUpdate = ms->window.lowLimit;
2327 /* enforce maxDist */ 2016
2328 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist; 2017 { size_t cSize = ZSTD_compressBlock_internal(cctx,
2329 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit; 2018 op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize,
2330 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit; 2019 ip, blockSize);
2331 } 2020 if (ZSTD_isError(cSize)) return cSize;
2332 2021
2333 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize); 2022 if (cSize == 0) { /* block is not compressible */
2334 if (ZSTD_isError(cSize)) return cSize; 2023 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2335 2024 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2336 if (cSize == 0) { /* block is not compressible */ 2025 MEM_writeLE32(op, cBlockHeader24); /* 4th byte will be overwritten */
2337 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3); 2026 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2338 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall); 2027 cSize = ZSTD_blockHeaderSize + blockSize;
2339 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */ 2028 } else {
2340 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize); 2029 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
2341 cSize = ZSTD_blockHeaderSize+blockSize; 2030 MEM_writeLE24(op, cBlockHeader24);
2342 } else { 2031 cSize += ZSTD_blockHeaderSize;
2343 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3); 2032 }
2344 MEM_writeLE24(op, cBlockHeader24); 2033
2345 cSize += ZSTD_blockHeaderSize; 2034 ip += blockSize;
2346 } 2035 assert(remaining >= blockSize);
2347 2036 remaining -= blockSize;
2348 remaining -= blockSize; 2037 op += cSize;
2349 dstCapacity -= cSize; 2038 assert(dstCapacity >= cSize);
2350 ip += blockSize; 2039 dstCapacity -= cSize;
2351 op += cSize; 2040 DEBUGLOG(5, "ZSTD_compress_frameChunk: adding a block of size %u",
2352 } 2041 (U32)cSize);
2042 } }
2353 2043
2354 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending; 2044 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
2355 return op-ostart; 2045 return op-ostart;
2356 } 2046 }
2357 2047
2358 2048
2359 static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity, 2049 static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
2360 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID) 2050 ZSTD_CCtx_params params, U64 pledgedSrcSize, U32 dictID)
2361 { BYTE* const op = (BYTE*)dst; 2051 { BYTE* const op = (BYTE*)dst;
2362 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */ 2052 U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2053 U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
2363 U32 const checksumFlag = params.fParams.checksumFlag>0; 2054 U32 const checksumFlag = params.fParams.checksumFlag>0;
2364 U32 const windowSize = 1U << params.cParams.windowLog; 2055 U32 const windowSize = (U32)1 << params.cParams.windowLog;
2365 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize > (pledgedSrcSize-1)); 2056 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
2366 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3); 2057 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2367 U32 const fcsCode = params.fParams.contentSizeFlag ? 2058 U32 const fcsCode = params.fParams.contentSizeFlag ?
2368 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */ 2059 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
2369 0;
2370 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) ); 2060 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
2371 size_t pos; 2061 size_t pos=0;
2372 2062
2373 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall); 2063 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
2374 2064 DEBUGLOG(4, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
2375 MEM_writeLE32(dst, ZSTD_MAGICNUMBER); 2065 !params.fParams.noDictIDFlag, dictID, dictIDSizeCode);
2376 op[4] = frameHeaderDecriptionByte; pos=5; 2066
2067 if (params.format == ZSTD_f_zstd1) {
2068 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
2069 pos = 4;
2070 }
2071 op[pos++] = frameHeaderDecriptionByte;
2377 if (!singleSegment) op[pos++] = windowLogByte; 2072 if (!singleSegment) op[pos++] = windowLogByte;
2378 switch(dictIDSizeCode) 2073 switch(dictIDSizeCode)
2379 { 2074 {
2380 default: /* impossible */ 2075 default: assert(0); /* impossible */
2381 case 0 : break; 2076 case 0 : break;
2382 case 1 : op[pos] = (BYTE)(dictID); pos++; break; 2077 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
2383 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break; 2078 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
2384 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break; 2079 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2385 } 2080 }
2386 switch(fcsCode) 2081 switch(fcsCode)
2387 { 2082 {
2388 default: /* impossible */ 2083 default: assert(0); /* impossible */
2389 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break; 2084 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
2390 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break; 2085 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2391 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break; 2086 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
2392 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break; 2087 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
2393 } 2088 }
2394 return pos; 2089 return pos;
2395 } 2090 }
2396 2091
2092 /* ZSTD_writeLastEmptyBlock() :
2093 * output an empty Block with end-of-frame mark to complete a frame
2094 * @return : size of data written into `dst` (== ZSTD_blockHeaderSize (defined in zstd_internal.h))
2095 * or an error code if `dstCapcity` is too small (<ZSTD_blockHeaderSize)
2096 */
2097 size_t ZSTD_writeLastEmptyBlock(void* dst, size_t dstCapacity)
2098 {
2099 if (dstCapacity < ZSTD_blockHeaderSize) return ERROR(dstSize_tooSmall);
2100 { U32 const cBlockHeader24 = 1 /*lastBlock*/ + (((U32)bt_raw)<<1); /* 0 size */
2101 MEM_writeLE24(dst, cBlockHeader24);
2102 return ZSTD_blockHeaderSize;
2103 }
2104 }
2105
2106 size_t ZSTD_referenceExternalSequences(ZSTD_CCtx* cctx, rawSeq* seq, size_t nbSeq)
2107 {
2108 if (cctx->stage != ZSTDcs_init)
2109 return ERROR(stage_wrong);
2110 if (cctx->appliedParams.ldmParams.enableLdm)
2111 return ERROR(parameter_unsupported);
2112 cctx->externSeqStore.seq = seq;
2113 cctx->externSeqStore.size = nbSeq;
2114 cctx->externSeqStore.capacity = nbSeq;
2115 cctx->externSeqStore.pos = 0;
2116 return 0;
2117 }
2118
2397 2119
2398 static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx, 2120 static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
2399 void* dst, size_t dstCapacity, 2121 void* dst, size_t dstCapacity,
2400 const void* src, size_t srcSize, 2122 const void* src, size_t srcSize,
2401 U32 frame, U32 lastFrameChunk) 2123 U32 frame, U32 lastFrameChunk)
2402 { 2124 {
2403 const BYTE* const ip = (const BYTE*) src; 2125 ZSTD_matchState_t* ms = &cctx->blockState.matchState;
2404 size_t fhSize = 0; 2126 size_t fhSize = 0;
2405 2127
2128 DEBUGLOG(5, "ZSTD_compressContinue_internal, stage: %u, srcSize: %u",
2129 cctx->stage, (U32)srcSize);
2406 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */ 2130 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
2407 2131
2408 if (frame && (cctx->stage==ZSTDcs_init)) { 2132 if (frame && (cctx->stage==ZSTDcs_init)) {
2409 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID); 2133 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams,
2134 cctx->pledgedSrcSizePlusOne-1, cctx->dictID);
2410 if (ZSTD_isError(fhSize)) return fhSize; 2135 if (ZSTD_isError(fhSize)) return fhSize;
2411 dstCapacity -= fhSize; 2136 dstCapacity -= fhSize;
2412 dst = (char*)dst + fhSize; 2137 dst = (char*)dst + fhSize;
2413 cctx->stage = ZSTDcs_ongoing; 2138 cctx->stage = ZSTDcs_ongoing;
2414 } 2139 }
2415 2140
2416 /* Check if blocks follow each other */ 2141 if (!srcSize) return fhSize; /* do not generate an empty block if no input */
2417 if (src != cctx->nextSrc) { 2142
2418 /* not contiguous */ 2143 if (!ZSTD_window_update(&ms->window, src, srcSize)) {
2419 ptrdiff_t const delta = cctx->nextSrc - ip; 2144 ms->nextToUpdate = ms->window.dictLimit;
2420 cctx->lowLimit = cctx->dictLimit; 2145 }
2421 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base); 2146 if (cctx->appliedParams.ldmParams.enableLdm)
2422 cctx->dictBase = cctx->base; 2147 ZSTD_window_update(&cctx->ldmState.window, src, srcSize);
2423 cctx->base -= delta; 2148
2424 cctx->nextToUpdate = cctx->dictLimit; 2149 DEBUGLOG(5, "ZSTD_compressContinue_internal (blockSize=%u)", (U32)cctx->blockSize);
2425 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */ 2150 { size_t const cSize = frame ?
2426 } 2151 ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2427
2428 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2429 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2430 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2431 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2432 cctx->lowLimit = lowLimitMax;
2433 }
2434
2435 cctx->nextSrc = ip + srcSize;
2436
2437 if (srcSize) {
2438 size_t const cSize = frame ?
2439 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2440 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize); 2152 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
2441 if (ZSTD_isError(cSize)) return cSize; 2153 if (ZSTD_isError(cSize)) return cSize;
2154 cctx->consumedSrcSize += srcSize;
2155 cctx->producedCSize += (cSize + fhSize);
2156 if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */
2157 if (cctx->consumedSrcSize+1 > cctx->pledgedSrcSizePlusOne) {
2158 DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize >= %u",
2159 (U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize);
2160 return ERROR(srcSize_wrong);
2161 }
2162 }
2442 return cSize + fhSize; 2163 return cSize + fhSize;
2443 } else 2164 }
2444 return fhSize; 2165 }
2445 }
2446
2447 2166
2448 size_t ZSTD_compressContinue (ZSTD_CCtx* cctx, 2167 size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
2449 void* dst, size_t dstCapacity, 2168 void* dst, size_t dstCapacity,
2450 const void* src, size_t srcSize) 2169 const void* src, size_t srcSize)
2451 { 2170 {
2452 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 0); 2171 DEBUGLOG(5, "ZSTD_compressContinue (srcSize=%u)", (U32)srcSize);
2453 } 2172 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
2454 2173 }
2455 2174
2456 size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx) 2175
2457 { 2176 size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
2458 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog); 2177 {
2178 ZSTD_compressionParameters const cParams = cctx->appliedParams.cParams;
2179 assert(!ZSTD_checkCParams(cParams));
2180 return MIN (ZSTD_BLOCKSIZE_MAX, (U32)1 << cParams.windowLog);
2459 } 2181 }
2460 2182
2461 size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize) 2183 size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2462 { 2184 {
2463 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx); 2185 size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
2464 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong); 2186 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
2465 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0, 0); 2187 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
2466 } 2188 }
2467 2189
2468 2190 /*! ZSTD_loadDictionaryContent() :
2469 static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize) 2191 * @return : 0, or an error code
2192 */
2193 static size_t ZSTD_loadDictionaryContent(ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const void* src, size_t srcSize)
2470 { 2194 {
2471 const BYTE* const ip = (const BYTE*) src; 2195 const BYTE* const ip = (const BYTE*) src;
2472 const BYTE* const iend = ip + srcSize; 2196 const BYTE* const iend = ip + srcSize;
2473 2197 ZSTD_compressionParameters const* cParams = &params->cParams;
2474 /* input becomes current prefix */ 2198
2475 zc->lowLimit = zc->dictLimit; 2199 ZSTD_window_update(&ms->window, src, srcSize);
2476 zc->dictLimit = (U32)(zc->nextSrc - zc->base); 2200 ms->loadedDictEnd = params->forceWindow ? 0 : (U32)(iend - ms->window.base);
2477 zc->dictBase = zc->base; 2201
2478 zc->base += ip - zc->nextSrc;
2479 zc->nextToUpdate = zc->dictLimit;
2480 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
2481
2482 zc->nextSrc = iend;
2483 if (srcSize <= HASH_READ_SIZE) return 0; 2202 if (srcSize <= HASH_READ_SIZE) return 0;
2484 2203
2485 switch(zc->params.cParams.strategy) 2204 switch(params->cParams.strategy)
2486 { 2205 {
2487 case ZSTD_fast: 2206 case ZSTD_fast:
2488 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength); 2207 ZSTD_fillHashTable(ms, cParams, iend);
2489 break; 2208 break;
2490
2491 case ZSTD_dfast: 2209 case ZSTD_dfast:
2492 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength); 2210 ZSTD_fillDoubleHashTable(ms, cParams, iend);
2493 break; 2211 break;
2494 2212
2495 case ZSTD_greedy: 2213 case ZSTD_greedy:
2496 case ZSTD_lazy: 2214 case ZSTD_lazy:
2497 case ZSTD_lazy2: 2215 case ZSTD_lazy2:
2498 ZSTD_insertAndFindFirstIndex (zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength); 2216 if (srcSize >= HASH_READ_SIZE)
2217 ZSTD_insertAndFindFirstIndex(ms, cParams, iend-HASH_READ_SIZE);
2499 break; 2218 break;
2500 2219
2501 case ZSTD_btlazy2: 2220 case ZSTD_btlazy2: /* we want the dictionary table fully sorted */
2502 case ZSTD_btopt: 2221 case ZSTD_btopt:
2503 case ZSTD_btopt2: 2222 case ZSTD_btultra:
2504 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength); 2223 if (srcSize >= HASH_READ_SIZE)
2224 ZSTD_updateTree(ms, cParams, iend-HASH_READ_SIZE, iend);
2505 break; 2225 break;
2506 2226
2507 default: 2227 default:
2508 return ERROR(GENERIC); /* strategy doesn't exist; impossible */ 2228 assert(0); /* not possible : not a valid strategy id */
2509 } 2229 }
2510 2230
2511 zc->nextToUpdate = zc->loadedDictEnd; 2231 ms->nextToUpdate = (U32)(iend - ms->window.base);
2512 return 0; 2232 return 0;
2513 } 2233 }
2514 2234
2515 2235
2516 /* Dictionaries that assign zero probability to symbols that show up causes problems 2236 /* Dictionaries that assign zero probability to symbols that show up causes problems
2526 return 0; 2246 return 0;
2527 } 2247 }
2528 2248
2529 2249
2530 /* Dictionary format : 2250 /* Dictionary format :
2531 Magic == ZSTD_DICT_MAGIC (4 bytes) 2251 * See :
2532 HUF_writeCTable(256) 2252 * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
2533 FSE_writeNCount(off) 2253 */
2534 FSE_writeNCount(ml) 2254 /*! ZSTD_loadZstdDictionary() :
2535 FSE_writeNCount(ll) 2255 * @return : dictID, or an error code
2536 RepOffsets 2256 * assumptions : magic number supposed already checked
2537 Dictionary content 2257 * dictSize supposed > 8
2538 */ 2258 */
2539 /*! ZSTD_loadDictEntropyStats() : 2259 static size_t ZSTD_loadZstdDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matchState_t* ms, ZSTD_CCtx_params const* params, const void* dict, size_t dictSize, void* workspace)
2540 @return : size read from dictionary
2541 note : magic number supposed already checked */
2542 static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
2543 { 2260 {
2544 const BYTE* dictPtr = (const BYTE*)dict; 2261 const BYTE* dictPtr = (const BYTE*)dict;
2545 const BYTE* const dictEnd = dictPtr + dictSize; 2262 const BYTE* const dictEnd = dictPtr + dictSize;
2546 short offcodeNCount[MaxOff+1]; 2263 short offcodeNCount[MaxOff+1];
2547 unsigned offcodeMaxValue = MaxOff; 2264 unsigned offcodeMaxValue = MaxOff;
2548 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)]; 2265 size_t dictID;
2549 2266
2550 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dict, dictSize); 2267 ZSTD_STATIC_ASSERT(HUF_WORKSPACE_SIZE >= (1<<MAX(MLFSELog,LLFSELog)));
2268
2269 dictPtr += 4; /* skip magic number */
2270 dictID = params->fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
2271 dictPtr += 4;
2272
2273 { unsigned maxSymbolValue = 255;
2274 size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)bs->entropy.hufCTable, &maxSymbolValue, dictPtr, dictEnd-dictPtr);
2551 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted); 2275 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
2276 if (maxSymbolValue < 255) return ERROR(dictionary_corrupted);
2552 dictPtr += hufHeaderSize; 2277 dictPtr += hufHeaderSize;
2553 } 2278 }
2554 2279
2555 { unsigned offcodeLog; 2280 { unsigned offcodeLog;
2556 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr); 2281 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
2557 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted); 2282 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2558 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted); 2283 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
2559 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */ 2284 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
2560 CHECK_E (FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted); 2285 CHECK_E( FSE_buildCTable_wksp(bs->entropy.offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, workspace, HUF_WORKSPACE_SIZE),
2286 dictionary_corrupted);
2561 dictPtr += offcodeHeaderSize; 2287 dictPtr += offcodeHeaderSize;
2562 } 2288 }
2563 2289
2564 { short matchlengthNCount[MaxML+1]; 2290 { short matchlengthNCount[MaxML+1];
2565 unsigned matchlengthMaxValue = MaxML, matchlengthLog; 2291 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
2566 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr); 2292 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
2567 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted); 2293 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2568 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted); 2294 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
2569 /* Every match length code must have non-zero probability */ 2295 /* Every match length code must have non-zero probability */
2570 CHECK_F (ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML)); 2296 CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
2571 CHECK_E (FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted); 2297 CHECK_E( FSE_buildCTable_wksp(bs->entropy.matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, workspace, HUF_WORKSPACE_SIZE),
2298 dictionary_corrupted);
2572 dictPtr += matchlengthHeaderSize; 2299 dictPtr += matchlengthHeaderSize;
2573 } 2300 }
2574 2301
2575 { short litlengthNCount[MaxLL+1]; 2302 { short litlengthNCount[MaxLL+1];
2576 unsigned litlengthMaxValue = MaxLL, litlengthLog; 2303 unsigned litlengthMaxValue = MaxLL, litlengthLog;
2577 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr); 2304 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
2578 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted); 2305 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2579 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted); 2306 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
2580 /* Every literal length code must have non-zero probability */ 2307 /* Every literal length code must have non-zero probability */
2581 CHECK_F (ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL)); 2308 CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
2582 CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted); 2309 CHECK_E( FSE_buildCTable_wksp(bs->entropy.litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, workspace, HUF_WORKSPACE_SIZE),
2310 dictionary_corrupted);
2583 dictPtr += litlengthHeaderSize; 2311 dictPtr += litlengthHeaderSize;
2584 } 2312 }
2585 2313
2586 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted); 2314 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
2587 cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] == 0 || cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted); 2315 bs->rep[0] = MEM_readLE32(dictPtr+0);
2588 cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] == 0 || cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted); 2316 bs->rep[1] = MEM_readLE32(dictPtr+4);
2589 cctx->rep[2] = MEM_readLE32(dictPtr+8); if (cctx->rep[2] == 0 || cctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted); 2317 bs->rep[2] = MEM_readLE32(dictPtr+8);
2590 dictPtr += 12; 2318 dictPtr += 12;
2591 2319
2592 { U32 offcodeMax = MaxOff; 2320 { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
2593 if ((size_t)(dictEnd - dictPtr) <= ((U32)-1) - 128 KB) { 2321 U32 offcodeMax = MaxOff;
2594 U32 const maxOffset = (U32)(dictEnd - dictPtr) + 128 KB; /* The maximum offset that must be supported */ 2322 if (dictContentSize <= ((U32)-1) - 128 KB) {
2595 /* Calculate minimum offset code required to represent maxOffset */ 2323 U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
2596 offcodeMax = ZSTD_highbit32(maxOffset); 2324 offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
2597 } 2325 }
2598 /* Every possible supported offset <= dictContentSize + 128 KB must be representable */ 2326 /* All offset values <= dictContentSize + 128 KB must be representable */
2599 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff))); 2327 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
2600 } 2328 /* All repCodes must be <= dictContentSize and != 0*/
2601 2329 { U32 u;
2602 cctx->flagStaticTables = 1; 2330 for (u=0; u<3; u++) {
2603 return dictPtr - (const BYTE*)dict; 2331 if (bs->rep[u] == 0) return ERROR(dictionary_corrupted);
2332 if (bs->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
2333 } }
2334
2335 bs->entropy.hufCTable_repeatMode = HUF_repeat_valid;
2336 bs->entropy.offcode_repeatMode = FSE_repeat_valid;
2337 bs->entropy.matchlength_repeatMode = FSE_repeat_valid;
2338 bs->entropy.litlength_repeatMode = FSE_repeat_valid;
2339 CHECK_F(ZSTD_loadDictionaryContent(ms, params, dictPtr, dictContentSize));
2340 return dictID;
2341 }
2604 } 2342 }
2605 2343
2606 /** ZSTD_compress_insertDictionary() : 2344 /** ZSTD_compress_insertDictionary() :
2607 * @return : 0, or an error code */ 2345 * @return : dictID, or an error code */
2608 static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize) 2346 static size_t ZSTD_compress_insertDictionary(ZSTD_compressedBlockState_t* bs, ZSTD_matchState_t* ms,
2609 { 2347 ZSTD_CCtx_params const* params,
2348 const void* dict, size_t dictSize,
2349 ZSTD_dictContentType_e dictContentType,
2350 void* workspace)
2351 {
2352 DEBUGLOG(4, "ZSTD_compress_insertDictionary (dictSize=%u)", (U32)dictSize);
2610 if ((dict==NULL) || (dictSize<=8)) return 0; 2353 if ((dict==NULL) || (dictSize<=8)) return 0;
2611 2354
2612 /* default : dict is pure content */ 2355 ZSTD_reset_compressedBlockState(bs);
2613 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize); 2356
2614 zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4); 2357 /* dict restricted modes */
2615 2358 if (dictContentType == ZSTD_dct_rawContent)
2616 /* known magic number : dict is parsed for entropy stats and content */ 2359 return ZSTD_loadDictionaryContent(ms, params, dict, dictSize);
2617 { size_t const loadError = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8); 2360
2618 size_t const eSize = loadError + 8; 2361 if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
2619 if (ZSTD_isError(loadError)) return loadError; 2362 if (dictContentType == ZSTD_dct_auto) {
2620 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize); 2363 DEBUGLOG(4, "raw content dictionary detected");
2621 } 2364 return ZSTD_loadDictionaryContent(ms, params, dict, dictSize);
2365 }
2366 if (dictContentType == ZSTD_dct_fullDict)
2367 return ERROR(dictionary_wrong);
2368 assert(0); /* impossible */
2369 }
2370
2371 /* dict as full zstd dictionary */
2372 return ZSTD_loadZstdDictionary(bs, ms, params, dict, dictSize, workspace);
2622 } 2373 }
2623 2374
2624 /*! ZSTD_compressBegin_internal() : 2375 /*! ZSTD_compressBegin_internal() :
2625 * @return : 0, or an error code */ 2376 * @return : 0, or an error code */
2626 static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx, 2377 size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
2627 const void* dict, size_t dictSize, 2378 const void* dict, size_t dictSize,
2628 ZSTD_parameters params, U64 pledgedSrcSize) 2379 ZSTD_dictContentType_e dictContentType,
2629 { 2380 const ZSTD_CDict* cdict,
2630 ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue; 2381 ZSTD_CCtx_params params, U64 pledgedSrcSize,
2631 CHECK_F(ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp)); 2382 ZSTD_buffered_policy_e zbuff)
2632 return ZSTD_compress_insertDictionary(cctx, dict, dictSize); 2383 {
2633 } 2384 DEBUGLOG(4, "ZSTD_compressBegin_internal: wlog=%u", params.cParams.windowLog);
2634 2385 /* params are supposed to be fully validated at this point */
2386 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
2387 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
2388
2389 if (cdict && cdict->dictContentSize>0) {
2390 cctx->requestedParams = params;
2391 return ZSTD_resetCCtx_usingCDict(cctx, cdict, params.cParams.windowLog,
2392 params.fParams, pledgedSrcSize, zbuff);
2393 }
2394
2395 CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
2396 ZSTDcrp_continue, zbuff) );
2397 {
2398 size_t const dictID = ZSTD_compress_insertDictionary(
2399 cctx->blockState.prevCBlock, &cctx->blockState.matchState,
2400 &params, dict, dictSize, dictContentType, cctx->entropyWorkspace);
2401 if (ZSTD_isError(dictID)) return dictID;
2402 assert(dictID <= (size_t)(U32)-1);
2403 cctx->dictID = (U32)dictID;
2404 }
2405 return 0;
2406 }
2407
2408 size_t ZSTD_compressBegin_advanced_internal(ZSTD_CCtx* cctx,
2409 const void* dict, size_t dictSize,
2410 ZSTD_dictContentType_e dictContentType,
2411 const ZSTD_CDict* cdict,
2412 ZSTD_CCtx_params params,
2413 unsigned long long pledgedSrcSize)
2414 {
2415 DEBUGLOG(4, "ZSTD_compressBegin_advanced_internal: wlog=%u", params.cParams.windowLog);
2416 /* compression parameters verification and optimization */
2417 CHECK_F( ZSTD_checkCParams(params.cParams) );
2418 return ZSTD_compressBegin_internal(cctx,
2419 dict, dictSize, dictContentType,
2420 cdict,
2421 params, pledgedSrcSize,
2422 ZSTDb_not_buffered);
2423 }
2635 2424
2636 /*! ZSTD_compressBegin_advanced() : 2425 /*! ZSTD_compressBegin_advanced() :
2637 * @return : 0, or an error code */ 2426 * @return : 0, or an error code */
2638 size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx, 2427 size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
2639 const void* dict, size_t dictSize, 2428 const void* dict, size_t dictSize,
2640 ZSTD_parameters params, unsigned long long pledgedSrcSize) 2429 ZSTD_parameters params, unsigned long long pledgedSrcSize)
2641 { 2430 {
2642 /* compression parameters verification and optimization */ 2431 ZSTD_CCtx_params const cctxParams =
2643 CHECK_F(ZSTD_checkCParams(params.cParams)); 2432 ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
2644 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize); 2433 return ZSTD_compressBegin_advanced_internal(cctx,
2645 } 2434 dict, dictSize, ZSTD_dct_auto,
2646 2435 NULL /*cdict*/,
2436 cctxParams, pledgedSrcSize);
2437 }
2647 2438
2648 size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel) 2439 size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
2649 { 2440 {
2650 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); 2441 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN, dictSize);
2651 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0); 2442 ZSTD_CCtx_params const cctxParams =
2652 } 2443 ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
2653 2444 DEBUGLOG(4, "ZSTD_compressBegin_usingDict (dictSize=%u)", (U32)dictSize);
2445 return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, NULL,
2446 cctxParams, ZSTD_CONTENTSIZE_UNKNOWN, ZSTDb_not_buffered);
2447 }
2654 2448
2655 size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel) 2449 size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
2656 { 2450 {
2657 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel); 2451 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
2658 } 2452 }
2665 { 2459 {
2666 BYTE* const ostart = (BYTE*)dst; 2460 BYTE* const ostart = (BYTE*)dst;
2667 BYTE* op = ostart; 2461 BYTE* op = ostart;
2668 size_t fhSize = 0; 2462 size_t fhSize = 0;
2669 2463
2464 DEBUGLOG(4, "ZSTD_writeEpilogue");
2670 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */ 2465 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
2671 2466
2672 /* special case : empty frame */ 2467 /* special case : empty frame */
2673 if (cctx->stage == ZSTDcs_init) { 2468 if (cctx->stage == ZSTDcs_init) {
2674 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0); 2469 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0);
2675 if (ZSTD_isError(fhSize)) return fhSize; 2470 if (ZSTD_isError(fhSize)) return fhSize;
2676 dstCapacity -= fhSize; 2471 dstCapacity -= fhSize;
2677 op += fhSize; 2472 op += fhSize;
2678 cctx->stage = ZSTDcs_ongoing; 2473 cctx->stage = ZSTDcs_ongoing;
2679 } 2474 }
2685 MEM_writeLE32(op, cBlockHeader24); 2480 MEM_writeLE32(op, cBlockHeader24);
2686 op += ZSTD_blockHeaderSize; 2481 op += ZSTD_blockHeaderSize;
2687 dstCapacity -= ZSTD_blockHeaderSize; 2482 dstCapacity -= ZSTD_blockHeaderSize;
2688 } 2483 }
2689 2484
2690 if (cctx->params.fParams.checksumFlag) { 2485 if (cctx->appliedParams.fParams.checksumFlag) {
2691 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState); 2486 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2692 if (dstCapacity<4) return ERROR(dstSize_tooSmall); 2487 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2488 DEBUGLOG(4, "ZSTD_writeEpilogue: write checksum : %08X", checksum);
2693 MEM_writeLE32(op, checksum); 2489 MEM_writeLE32(op, checksum);
2694 op += 4; 2490 op += 4;
2695 } 2491 }
2696 2492
2697 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */ 2493 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
2698 return op-ostart; 2494 return op-ostart;
2699 } 2495 }
2700
2701 2496
2702 size_t ZSTD_compressEnd (ZSTD_CCtx* cctx, 2497 size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2703 void* dst, size_t dstCapacity, 2498 void* dst, size_t dstCapacity,
2704 const void* src, size_t srcSize) 2499 const void* src, size_t srcSize)
2705 { 2500 {
2706 size_t endResult; 2501 size_t endResult;
2707 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 1); 2502 size_t const cSize = ZSTD_compressContinue_internal(cctx,
2503 dst, dstCapacity, src, srcSize,
2504 1 /* frame mode */, 1 /* last chunk */);
2708 if (ZSTD_isError(cSize)) return cSize; 2505 if (ZSTD_isError(cSize)) return cSize;
2709 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize); 2506 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2710 if (ZSTD_isError(endResult)) return endResult; 2507 if (ZSTD_isError(endResult)) return endResult;
2508 if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */
2509 DEBUGLOG(4, "end of frame : controlling src size");
2510 if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) {
2511 DEBUGLOG(4, "error : pledgedSrcSize = %u, while realSrcSize = %u",
2512 (U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize);
2513 return ERROR(srcSize_wrong);
2514 } }
2711 return cSize + endResult; 2515 return cSize + endResult;
2712 } 2516 }
2713 2517
2714 2518
2715 static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx, 2519 static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
2716 void* dst, size_t dstCapacity, 2520 void* dst, size_t dstCapacity,
2717 const void* src, size_t srcSize, 2521 const void* src, size_t srcSize,
2718 const void* dict,size_t dictSize, 2522 const void* dict,size_t dictSize,
2719 ZSTD_parameters params) 2523 ZSTD_parameters params)
2720 { 2524 {
2721 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize)); 2525 ZSTD_CCtx_params const cctxParams =
2722 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize); 2526 ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
2527 DEBUGLOG(4, "ZSTD_compress_internal");
2528 return ZSTD_compress_advanced_internal(cctx,
2529 dst, dstCapacity,
2530 src, srcSize,
2531 dict, dictSize,
2532 cctxParams);
2723 } 2533 }
2724 2534
2725 size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx, 2535 size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2726 void* dst, size_t dstCapacity, 2536 void* dst, size_t dstCapacity,
2727 const void* src, size_t srcSize, 2537 const void* src, size_t srcSize,
2728 const void* dict,size_t dictSize, 2538 const void* dict,size_t dictSize,
2729 ZSTD_parameters params) 2539 ZSTD_parameters params)
2730 { 2540 {
2541 DEBUGLOG(4, "ZSTD_compress_advanced");
2731 CHECK_F(ZSTD_checkCParams(params.cParams)); 2542 CHECK_F(ZSTD_checkCParams(params.cParams));
2732 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params); 2543 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2733 } 2544 }
2734 2545
2735 size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, int compressionLevel) 2546 /* Internal */
2736 { 2547 size_t ZSTD_compress_advanced_internal(
2737 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0); 2548 ZSTD_CCtx* cctx,
2738 params.fParams.contentSizeFlag = 1; 2549 void* dst, size_t dstCapacity,
2739 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params); 2550 const void* src, size_t srcSize,
2740 } 2551 const void* dict,size_t dictSize,
2741 2552 ZSTD_CCtx_params params)
2742 size_t ZSTD_compressCCtx (ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel) 2553 {
2743 { 2554 DEBUGLOG(4, "ZSTD_compress_advanced_internal (srcSize:%u)",
2744 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel); 2555 (U32)srcSize);
2556 CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dct_auto, NULL,
2557 params, srcSize, ZSTDb_not_buffered) );
2558 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
2559 }
2560
2561 size_t ZSTD_compress_usingDict(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
2562 const void* dict, size_t dictSize, int compressionLevel)
2563 {
2564 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, srcSize ? srcSize : 1, dict ? dictSize : 0);
2565 ZSTD_CCtx_params cctxParams = ZSTD_assignParamsToCCtxParams(cctx->requestedParams, params);
2566 assert(params.fParams.contentSizeFlag == 1);
2567 ZSTD_CCtxParam_setParameter(&cctxParams, ZSTD_p_compressLiterals, compressionLevel>=0);
2568 return ZSTD_compress_advanced_internal(cctx, dst, dstCapacity, src, srcSize, dict, dictSize, cctxParams);
2569 }
2570
2571 size_t ZSTD_compressCCtx (ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
2572 {
2573 DEBUGLOG(4, "ZSTD_compressCCtx (srcSize=%u)", (U32)srcSize);
2574 return ZSTD_compress_usingDict(cctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
2745 } 2575 }
2746 2576
2747 size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel) 2577 size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
2748 { 2578 {
2749 size_t result; 2579 size_t result;
2750 ZSTD_CCtx ctxBody; 2580 ZSTD_CCtx ctxBody;
2751 memset(&ctxBody, 0, sizeof(ctxBody)); 2581 memset(&ctxBody, 0, sizeof(ctxBody));
2752 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem)); 2582 ctxBody.customMem = ZSTD_defaultCMem;
2753 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel); 2583 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
2754 ZSTD_free(ctxBody.workSpace, defaultCustomMem); /* can't free ctxBody itself, as it's on stack; free only heap content */ 2584 ZSTD_free(ctxBody.workSpace, ZSTD_defaultCMem); /* can't free ctxBody itself, as it's on stack; free only heap content */
2755 return result; 2585 return result;
2756 } 2586 }
2757 2587
2758 2588
2759 /* ===== Dictionary API ===== */ 2589 /* ===== Dictionary API ===== */
2760 2590
2761 struct ZSTD_CDict_s { 2591 /*! ZSTD_estimateCDictSize_advanced() :
2762 void* dictBuffer; 2592 * Estimate amount of memory that will be needed to create a dictionary with following arguments */
2763 const void* dictContent; 2593 size_t ZSTD_estimateCDictSize_advanced(
2764 size_t dictContentSize; 2594 size_t dictSize, ZSTD_compressionParameters cParams,
2765 ZSTD_CCtx* refContext; 2595 ZSTD_dictLoadMethod_e dictLoadMethod)
2766 }; /* typedef'd tp ZSTD_CDict within "zstd.h" */ 2596 {
2597 DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict));
2598 return sizeof(ZSTD_CDict) + HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0)
2599 + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize);
2600 }
2601
2602 size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
2603 {
2604 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
2605 return ZSTD_estimateCDictSize_advanced(dictSize, cParams, ZSTD_dlm_byCopy);
2606 }
2767 2607
2768 size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict) 2608 size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2769 { 2609 {
2770 if (cdict==NULL) return 0; /* support sizeof on NULL */ 2610 if (cdict==NULL) return 0; /* support sizeof on NULL */
2771 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict); 2611 DEBUGLOG(5, "sizeof(*cdict) : %u", (U32)sizeof(*cdict));
2772 } 2612 return cdict->workspaceSize + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
2773 2613 }
2774 ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference, 2614
2775 ZSTD_parameters params, ZSTD_customMem customMem) 2615 static size_t ZSTD_initCDict_internal(
2776 { 2616 ZSTD_CDict* cdict,
2777 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem; 2617 const void* dictBuffer, size_t dictSize,
2778 if (!customMem.customAlloc || !customMem.customFree) return NULL; 2618 ZSTD_dictLoadMethod_e dictLoadMethod,
2779 2619 ZSTD_dictContentType_e dictContentType,
2780 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem); 2620 ZSTD_compressionParameters cParams)
2781 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem); 2621 {
2782 2622 DEBUGLOG(3, "ZSTD_initCDict_internal, dictContentType %u", (U32)dictContentType);
2783 if (!cdict || !cctx) { 2623 assert(!ZSTD_checkCParams(cParams));
2624 cdict->cParams = cParams;
2625 if ((dictLoadMethod == ZSTD_dlm_byRef) || (!dictBuffer) || (!dictSize)) {
2626 cdict->dictBuffer = NULL;
2627 cdict->dictContent = dictBuffer;
2628 } else {
2629 void* const internalBuffer = ZSTD_malloc(dictSize, cdict->customMem);
2630 cdict->dictBuffer = internalBuffer;
2631 cdict->dictContent = internalBuffer;
2632 if (!internalBuffer) return ERROR(memory_allocation);
2633 memcpy(internalBuffer, dictBuffer, dictSize);
2634 }
2635 cdict->dictContentSize = dictSize;
2636
2637 /* Reset the state to no dictionary */
2638 ZSTD_reset_compressedBlockState(&cdict->cBlockState);
2639 { void* const end = ZSTD_reset_matchState(
2640 &cdict->matchState,
2641 (U32*)cdict->workspace + HUF_WORKSPACE_SIZE_U32,
2642 &cParams, ZSTDcrp_continue, /* forCCtx */ 0);
2643 assert(end == (char*)cdict->workspace + cdict->workspaceSize);
2644 (void)end;
2645 }
2646 /* (Maybe) load the dictionary
2647 * Skips loading the dictionary if it is <= 8 bytes.
2648 */
2649 { ZSTD_CCtx_params params;
2650 memset(&params, 0, sizeof(params));
2651 params.compressionLevel = ZSTD_CLEVEL_DEFAULT;
2652 params.fParams.contentSizeFlag = 1;
2653 params.cParams = cParams;
2654 { size_t const dictID = ZSTD_compress_insertDictionary(
2655 &cdict->cBlockState, &cdict->matchState, &params,
2656 cdict->dictContent, cdict->dictContentSize,
2657 dictContentType, cdict->workspace);
2658 if (ZSTD_isError(dictID)) return dictID;
2659 assert(dictID <= (size_t)(U32)-1);
2660 cdict->dictID = (U32)dictID;
2661 }
2662 }
2663
2664 return 0;
2665 }
2666
2667 ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
2668 ZSTD_dictLoadMethod_e dictLoadMethod,
2669 ZSTD_dictContentType_e dictContentType,
2670 ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
2671 {
2672 DEBUGLOG(3, "ZSTD_createCDict_advanced, mode %u", (U32)dictContentType);
2673 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
2674
2675 { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
2676 size_t const workspaceSize = HUF_WORKSPACE_SIZE + ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
2677 void* const workspace = ZSTD_malloc(workspaceSize, customMem);
2678
2679 if (!cdict || !workspace) {
2784 ZSTD_free(cdict, customMem); 2680 ZSTD_free(cdict, customMem);
2785 ZSTD_free(cctx, customMem); 2681 ZSTD_free(workspace, customMem);
2786 return NULL; 2682 return NULL;
2787 } 2683 }
2788 2684 cdict->customMem = customMem;
2789 if ((byReference) || (!dictBuffer) || (!dictSize)) { 2685 cdict->workspace = workspace;
2790 cdict->dictBuffer = NULL; 2686 cdict->workspaceSize = workspaceSize;
2791 cdict->dictContent = dictBuffer; 2687 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
2792 } else { 2688 dictBuffer, dictSize,
2793 void* const internalBuffer = ZSTD_malloc(dictSize, customMem); 2689 dictLoadMethod, dictContentType,
2794 if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; } 2690 cParams) )) {
2795 memcpy(internalBuffer, dictBuffer, dictSize); 2691 ZSTD_freeCDict(cdict);
2796 cdict->dictBuffer = internalBuffer; 2692 return NULL;
2797 cdict->dictContent = internalBuffer;
2798 } 2693 }
2799 2694
2800 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
2801 if (ZSTD_isError(errorCode)) {
2802 ZSTD_free(cdict->dictBuffer, customMem);
2803 ZSTD_free(cctx, customMem);
2804 ZSTD_free(cdict, customMem);
2805 return NULL;
2806 } }
2807
2808 cdict->refContext = cctx;
2809 cdict->dictContentSize = dictSize;
2810 return cdict; 2695 return cdict;
2811 } 2696 }
2812 } 2697 }
2813 2698
2814 ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel) 2699 ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2815 { 2700 {
2816 ZSTD_customMem const allocator = { NULL, NULL, NULL }; 2701 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
2817 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize); 2702 return ZSTD_createCDict_advanced(dict, dictSize,
2818 params.fParams.contentSizeFlag = 1; 2703 ZSTD_dlm_byCopy, ZSTD_dct_auto,
2819 return ZSTD_createCDict_advanced(dict, dictSize, 0, params, allocator); 2704 cParams, ZSTD_defaultCMem);
2820 } 2705 }
2821 2706
2822 ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel) 2707 ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
2823 { 2708 {
2824 ZSTD_customMem const allocator = { NULL, NULL, NULL }; 2709 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
2825 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize); 2710 return ZSTD_createCDict_advanced(dict, dictSize,
2826 params.fParams.contentSizeFlag = 1; 2711 ZSTD_dlm_byRef, ZSTD_dct_auto,
2827 return ZSTD_createCDict_advanced(dict, dictSize, 1, params, allocator); 2712 cParams, ZSTD_defaultCMem);
2828 } 2713 }
2829 2714
2830 size_t ZSTD_freeCDict(ZSTD_CDict* cdict) 2715 size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2831 { 2716 {
2832 if (cdict==NULL) return 0; /* support free on NULL */ 2717 if (cdict==NULL) return 0; /* support free on NULL */
2833 { ZSTD_customMem const cMem = cdict->refContext->customMem; 2718 { ZSTD_customMem const cMem = cdict->customMem;
2834 ZSTD_freeCCtx(cdict->refContext); 2719 ZSTD_free(cdict->workspace, cMem);
2835 ZSTD_free(cdict->dictBuffer, cMem); 2720 ZSTD_free(cdict->dictBuffer, cMem);
2836 ZSTD_free(cdict, cMem); 2721 ZSTD_free(cdict, cMem);
2837 return 0; 2722 return 0;
2838 } 2723 }
2839 } 2724 }
2840 2725
2841 static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) { 2726 /*! ZSTD_initStaticCDict_advanced() :
2842 return ZSTD_getParamsFromCCtx(cdict->refContext); 2727 * Generate a digested dictionary in provided memory area.
2843 } 2728 * workspace: The memory area to emplace the dictionary into.
2844 2729 * Provided pointer must 8-bytes aligned.
2845 size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize) 2730 * It must outlive dictionary usage.
2846 { 2731 * workspaceSize: Use ZSTD_estimateCDictSize()
2847 if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize)) 2732 * to determine how large workspace must be.
2848 else CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->params, pledgedSrcSize)); 2733 * cParams : use ZSTD_getCParams() to transform a compression level
2849 return 0; 2734 * into its relevants cParams.
2735 * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
2736 * Note : there is no corresponding "free" function.
2737 * Since workspace was allocated externally, it must be freed externally.
2738 */
2739 const ZSTD_CDict* ZSTD_initStaticCDict(
2740 void* workspace, size_t workspaceSize,
2741 const void* dict, size_t dictSize,
2742 ZSTD_dictLoadMethod_e dictLoadMethod,
2743 ZSTD_dictContentType_e dictContentType,
2744 ZSTD_compressionParameters cParams)
2745 {
2746 size_t const matchStateSize = ZSTD_sizeof_matchState(&cParams, /* forCCtx */ 0);
2747 size_t const neededSize = sizeof(ZSTD_CDict) + (dictLoadMethod == ZSTD_dlm_byRef ? 0 : dictSize)
2748 + HUF_WORKSPACE_SIZE + matchStateSize;
2749 ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
2750 void* ptr;
2751 if ((size_t)workspace & 7) return NULL; /* 8-aligned */
2752 DEBUGLOG(4, "(workspaceSize < neededSize) : (%u < %u) => %u",
2753 (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize));
2754 if (workspaceSize < neededSize) return NULL;
2755
2756 if (dictLoadMethod == ZSTD_dlm_byCopy) {
2757 memcpy(cdict+1, dict, dictSize);
2758 dict = cdict+1;
2759 ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize;
2760 } else {
2761 ptr = cdict+1;
2762 }
2763 cdict->workspace = ptr;
2764 cdict->workspaceSize = HUF_WORKSPACE_SIZE + matchStateSize;
2765
2766 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
2767 dict, dictSize,
2768 ZSTD_dlm_byRef, dictContentType,
2769 cParams) ))
2770 return NULL;
2771
2772 return cdict;
2773 }
2774
2775 ZSTD_compressionParameters ZSTD_getCParamsFromCDict(const ZSTD_CDict* cdict)
2776 {
2777 assert(cdict != NULL);
2778 return cdict->cParams;
2779 }
2780
2781 /* ZSTD_compressBegin_usingCDict_advanced() :
2782 * cdict must be != NULL */
2783 size_t ZSTD_compressBegin_usingCDict_advanced(
2784 ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
2785 ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
2786 {
2787 DEBUGLOG(4, "ZSTD_compressBegin_usingCDict_advanced");
2788 if (cdict==NULL) return ERROR(dictionary_wrong);
2789 { ZSTD_CCtx_params params = cctx->requestedParams;
2790 params.cParams = ZSTD_getCParamsFromCDict(cdict);
2791 /* Increase window log to fit the entire dictionary and source if the
2792 * source size is known. Limit the increase to 19, which is the
2793 * window log for compression level 1 with the largest source size.
2794 */
2795 if (pledgedSrcSize != ZSTD_CONTENTSIZE_UNKNOWN) {
2796 U32 const limitedSrcSize = (U32)MIN(pledgedSrcSize, 1U << 19);
2797 U32 const limitedSrcLog = limitedSrcSize > 1 ? ZSTD_highbit32(limitedSrcSize - 1) + 1 : 1;
2798 params.cParams.windowLog = MAX(params.cParams.windowLog, limitedSrcLog);
2799 }
2800 params.fParams = fParams;
2801 return ZSTD_compressBegin_internal(cctx,
2802 NULL, 0, ZSTD_dct_auto,
2803 cdict,
2804 params, pledgedSrcSize,
2805 ZSTDb_not_buffered);
2806 }
2807 }
2808
2809 /* ZSTD_compressBegin_usingCDict() :
2810 * pledgedSrcSize=0 means "unknown"
2811 * if pledgedSrcSize>0, it will enable contentSizeFlag */
2812 size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
2813 {
2814 ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
2815 DEBUGLOG(4, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
2816 return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0);
2817 }
2818
2819 size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
2820 void* dst, size_t dstCapacity,
2821 const void* src, size_t srcSize,
2822 const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
2823 {
2824 CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */
2825 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
2850 } 2826 }
2851 2827
2852 /*! ZSTD_compress_usingCDict() : 2828 /*! ZSTD_compress_usingCDict() :
2853 * Compression using a digested Dictionary. 2829 * Compression using a digested Dictionary.
2854 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times. 2830 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
2855 * Note that compression level is decided during dictionary creation */ 2831 * Note that compression parameters are decided at CDict creation time
2832 * while frame parameters are hardcoded */
2856 size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx, 2833 size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2857 void* dst, size_t dstCapacity, 2834 void* dst, size_t dstCapacity,
2858 const void* src, size_t srcSize, 2835 const void* src, size_t srcSize,
2859 const ZSTD_CDict* cdict) 2836 const ZSTD_CDict* cdict)
2860 { 2837 {
2861 CHECK_F(ZSTD_compressBegin_usingCDict(cctx, cdict, srcSize)); 2838 ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
2862 2839 return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
2863 if (cdict->refContext->params.fParams.contentSizeFlag==1) {
2864 cctx->params.fParams.contentSizeFlag = 1;
2865 cctx->frameContentSize = srcSize;
2866 }
2867
2868 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
2869 } 2840 }
2870 2841
2871 2842
2872 2843
2873 /* ****************************************************************** 2844 /* ******************************************************************
2874 * Streaming 2845 * Streaming
2875 ********************************************************************/ 2846 ********************************************************************/
2876 2847
2877 typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
2878
2879 struct ZSTD_CStream_s {
2880 ZSTD_CCtx* cctx;
2881 ZSTD_CDict* cdictLocal;
2882 const ZSTD_CDict* cdict;
2883 char* inBuff;
2884 size_t inBuffSize;
2885 size_t inToCompress;
2886 size_t inBuffPos;
2887 size_t inBuffTarget;
2888 size_t blockSize;
2889 char* outBuff;
2890 size_t outBuffSize;
2891 size_t outBuffContentSize;
2892 size_t outBuffFlushedSize;
2893 ZSTD_cStreamStage stage;
2894 U32 checksum;
2895 U32 frameEnded;
2896 U64 pledgedSrcSize;
2897 U64 inputProcessed;
2898 ZSTD_parameters params;
2899 ZSTD_customMem customMem;
2900 }; /* typedef'd to ZSTD_CStream within "zstd.h" */
2901
2902 ZSTD_CStream* ZSTD_createCStream(void) 2848 ZSTD_CStream* ZSTD_createCStream(void)
2903 { 2849 {
2904 return ZSTD_createCStream_advanced(defaultCustomMem); 2850 DEBUGLOG(3, "ZSTD_createCStream");
2851 return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
2852 }
2853
2854 ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize)
2855 {
2856 return ZSTD_initStaticCCtx(workspace, workspaceSize);
2905 } 2857 }
2906 2858
2907 ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem) 2859 ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
2908 { 2860 { /* CStream and CCtx are now same object */
2909 ZSTD_CStream* zcs; 2861 return ZSTD_createCCtx_advanced(customMem);
2910
2911 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2912 if (!customMem.customAlloc || !customMem.customFree) return NULL;
2913
2914 zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
2915 if (zcs==NULL) return NULL;
2916 memset(zcs, 0, sizeof(ZSTD_CStream));
2917 memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
2918 zcs->cctx = ZSTD_createCCtx_advanced(customMem);
2919 if (zcs->cctx == NULL) { ZSTD_freeCStream(zcs); return NULL; }
2920 return zcs;
2921 } 2862 }
2922 2863
2923 size_t ZSTD_freeCStream(ZSTD_CStream* zcs) 2864 size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
2924 { 2865 {
2925 if (zcs==NULL) return 0; /* support free on NULL */ 2866 return ZSTD_freeCCtx(zcs); /* same object */
2926 { ZSTD_customMem const cMem = zcs->customMem; 2867 }
2927 ZSTD_freeCCtx(zcs->cctx); 2868
2869
2870
2871 /*====== Initialization ======*/
2872
2873 size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
2874
2875 size_t ZSTD_CStreamOutSize(void)
2876 {
2877 return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
2878 }
2879
2880 static size_t ZSTD_resetCStream_internal(ZSTD_CStream* cctx,
2881 const void* const dict, size_t const dictSize, ZSTD_dictContentType_e const dictContentType,
2882 const ZSTD_CDict* const cdict,
2883 ZSTD_CCtx_params const params, unsigned long long const pledgedSrcSize)
2884 {
2885 DEBUGLOG(4, "ZSTD_resetCStream_internal (disableLiteralCompression=%i)",
2886 params.disableLiteralCompression);
2887 /* params are supposed to be fully validated at this point */
2888 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
2889 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
2890
2891 CHECK_F( ZSTD_compressBegin_internal(cctx,
2892 dict, dictSize, dictContentType,
2893 cdict,
2894 params, pledgedSrcSize,
2895 ZSTDb_buffered) );
2896
2897 cctx->inToCompress = 0;
2898 cctx->inBuffPos = 0;
2899 cctx->inBuffTarget = cctx->blockSize
2900 + (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 */
2901 cctx->outBuffContentSize = cctx->outBuffFlushedSize = 0;
2902 cctx->streamStage = zcss_load;
2903 cctx->frameEnded = 0;
2904 return 0; /* ready to go */
2905 }
2906
2907 /* ZSTD_resetCStream():
2908 * pledgedSrcSize == 0 means "unknown" */
2909 size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
2910 {
2911 ZSTD_CCtx_params params = zcs->requestedParams;
2912 DEBUGLOG(4, "ZSTD_resetCStream: pledgedSrcSize = %u", (U32)pledgedSrcSize);
2913 if (pledgedSrcSize==0) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN;
2914 params.fParams.contentSizeFlag = 1;
2915 params.cParams = ZSTD_getCParamsFromCCtxParams(&params, pledgedSrcSize, 0);
2916 return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize);
2917 }
2918
2919 /*! ZSTD_initCStream_internal() :
2920 * Note : for lib/compress only. Used by zstdmt_compress.c.
2921 * Assumption 1 : params are valid
2922 * Assumption 2 : either dict, or cdict, is defined, not both */
2923 size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
2924 const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
2925 ZSTD_CCtx_params params, unsigned long long pledgedSrcSize)
2926 {
2927 DEBUGLOG(4, "ZSTD_initCStream_internal");
2928 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
2929 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
2930
2931 if (dict && dictSize >= 8) {
2932 DEBUGLOG(4, "loading dictionary of size %u", (U32)dictSize);
2933 if (zcs->staticSize) { /* static CCtx : never uses malloc */
2934 /* incompatible with internal cdict creation */
2935 return ERROR(memory_allocation);
2936 }
2928 ZSTD_freeCDict(zcs->cdictLocal); 2937 ZSTD_freeCDict(zcs->cdictLocal);
2929 ZSTD_free(zcs->inBuff, cMem); 2938 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
2930 ZSTD_free(zcs->outBuff, cMem); 2939 ZSTD_dlm_byCopy, ZSTD_dct_auto,
2931 ZSTD_free(zcs, cMem); 2940 params.cParams, zcs->customMem);
2932 return 0; 2941 zcs->cdict = zcs->cdictLocal;
2933 } 2942 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
2934 } 2943 } else {
2935 2944 if (cdict) {
2936 2945 params.cParams = ZSTD_getCParamsFromCDict(cdict); /* cParams are enforced from cdict; it includes windowLog */
2937 /*====== Initialization ======*/ 2946 }
2938 2947 ZSTD_freeCDict(zcs->cdictLocal);
2939 size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; } 2948 zcs->cdictLocal = NULL;
2940 size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; } 2949 zcs->cdict = cdict;
2941 2950 }
2942 size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize) 2951
2943 { 2952 return ZSTD_resetCStream_internal(zcs, NULL, 0, ZSTD_dct_auto, zcs->cdict, params, pledgedSrcSize);
2944 if (zcs->inBuffSize==0) return ERROR(stage_wrong); /* zcs has not been init at least once => can't reset */ 2953 }
2945 2954
2946 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize)) 2955 /* ZSTD_initCStream_usingCDict_advanced() :
2947 else CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize)); 2956 * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
2948 2957 size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
2949 zcs->inToCompress = 0; 2958 const ZSTD_CDict* cdict,
2950 zcs->inBuffPos = 0; 2959 ZSTD_frameParameters fParams,
2951 zcs->inBuffTarget = zcs->blockSize; 2960 unsigned long long pledgedSrcSize)
2952 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; 2961 {
2953 zcs->stage = zcss_load; 2962 DEBUGLOG(4, "ZSTD_initCStream_usingCDict_advanced");
2954 zcs->frameEnded = 0; 2963 if (!cdict) return ERROR(dictionary_wrong); /* cannot handle NULL cdict (does not know what to do) */
2955 zcs->pledgedSrcSize = pledgedSrcSize; 2964 { ZSTD_CCtx_params params = zcs->requestedParams;
2956 zcs->inputProcessed = 0; 2965 params.cParams = ZSTD_getCParamsFromCDict(cdict);
2957 return 0; /* ready to go */ 2966 params.fParams = fParams;
2958 } 2967 return ZSTD_initCStream_internal(zcs,
2959 2968 NULL, 0, cdict,
2969 params, pledgedSrcSize);
2970 }
2971 }
2972
2973 /* note : cdict must outlive compression session */
2974 size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
2975 {
2976 ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksum */, 0 /* hideDictID */ };
2977 DEBUGLOG(4, "ZSTD_initCStream_usingCDict");
2978 return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, ZSTD_CONTENTSIZE_UNKNOWN); /* note : will check that cdict != NULL */
2979 }
2980
2981
2982 /* ZSTD_initCStream_advanced() :
2983 * pledgedSrcSize must be exact.
2984 * if srcSize is not known at init time, use value ZSTD_CONTENTSIZE_UNKNOWN.
2985 * dict is loaded with default parameters ZSTD_dm_auto and ZSTD_dlm_byCopy. */
2960 size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs, 2986 size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
2961 const void* dict, size_t dictSize, 2987 const void* dict, size_t dictSize,
2962 ZSTD_parameters params, unsigned long long pledgedSrcSize) 2988 ZSTD_parameters params, unsigned long long pledgedSrcSize)
2963 { 2989 {
2964 /* allocate buffers */ 2990 DEBUGLOG(4, "ZSTD_initCStream_advanced: pledgedSrcSize=%u, flag=%u",
2965 { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog; 2991 (U32)pledgedSrcSize, params.fParams.contentSizeFlag);
2966 if (zcs->inBuffSize < neededInBuffSize) { 2992 CHECK_F( ZSTD_checkCParams(params.cParams) );
2967 zcs->inBuffSize = neededInBuffSize; 2993 if ((pledgedSrcSize==0) && (params.fParams.contentSizeFlag==0)) pledgedSrcSize = ZSTD_CONTENTSIZE_UNKNOWN; /* for compatibility with older programs relying on this behavior. Users should now specify ZSTD_CONTENTSIZE_UNKNOWN. This line will be removed in the future. */
2968 ZSTD_free(zcs->inBuff, zcs->customMem); 2994 { ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
2969 zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem); 2995 return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL /*cdict*/, cctxParams, pledgedSrcSize);
2970 if (zcs->inBuff == NULL) return ERROR(memory_allocation); 2996 }
2971 }
2972 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
2973 }
2974 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
2975 zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
2976 ZSTD_free(zcs->outBuff, zcs->customMem);
2977 zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
2978 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
2979 }
2980
2981 if (dict && dictSize >= 8) {
2982 ZSTD_freeCDict(zcs->cdictLocal);
2983 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0, params, zcs->customMem);
2984 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
2985 zcs->cdict = zcs->cdictLocal;
2986 } else zcs->cdict = NULL;
2987
2988 zcs->checksum = params.fParams.checksumFlag > 0;
2989 zcs->params = params;
2990
2991 return ZSTD_resetCStream(zcs, pledgedSrcSize);
2992 }
2993
2994 /* note : cdict must outlive compression session */
2995 size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
2996 {
2997 ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict);
2998 size_t const initError = ZSTD_initCStream_advanced(zcs, NULL, 0, params, 0);
2999 zcs->cdict = cdict;
3000 zcs->cctx->dictID = params.fParams.noDictIDFlag ? 0 : cdict->refContext->dictID;
3001 return initError;
3002 } 2997 }
3003 2998
3004 size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel) 2999 size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3005 { 3000 {
3006 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize); 3001 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
3007 return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0); 3002 ZSTD_CCtx_params const cctxParams =
3008 } 3003 ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
3009 3004 return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, cctxParams, ZSTD_CONTENTSIZE_UNKNOWN);
3010 size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize) 3005 }
3011 { 3006
3012 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0); 3007 size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pss)
3013 if (pledgedSrcSize) params.fParams.contentSizeFlag = 1; 3008 {
3014 return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize); 3009 U64 const pledgedSrcSize = (pss==0) ? ZSTD_CONTENTSIZE_UNKNOWN : pss; /* temporary : 0 interpreted as "unknown" during transition period. Users willing to specify "unknown" **must** use ZSTD_CONTENTSIZE_UNKNOWN. `0` will be interpreted as "empty" in the future */
3010 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
3011 ZSTD_CCtx_params const cctxParams = ZSTD_assignParamsToCCtxParams(zcs->requestedParams, params);
3012 return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, cctxParams, pledgedSrcSize);
3015 } 3013 }
3016 3014
3017 size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel) 3015 size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3018 { 3016 {
3019 return ZSTD_initCStream_usingDict(zcs, NULL, 0, compressionLevel); 3017 DEBUGLOG(4, "ZSTD_initCStream");
3020 } 3018 return ZSTD_initCStream_srcSize(zcs, compressionLevel, ZSTD_CONTENTSIZE_UNKNOWN);
3021
3022 size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
3023 {
3024 if (zcs==NULL) return 0; /* support sizeof on NULL */
3025 return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + ZSTD_sizeof_CDict(zcs->cdictLocal) + zcs->outBuffSize + zcs->inBuffSize;
3026 } 3019 }
3027 3020
3028 /*====== Compression ======*/ 3021 /*====== Compression ======*/
3029 3022
3030 typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e; 3023 MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity,
3031 3024 const void* src, size_t srcSize)
3032 MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
3033 { 3025 {
3034 size_t const length = MIN(dstCapacity, srcSize); 3026 size_t const length = MIN(dstCapacity, srcSize);
3035 memcpy(dst, src, length); 3027 if (length) memcpy(dst, src, length);
3036 return length; 3028 return length;
3037 } 3029 }
3038 3030
3039 static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs, 3031 /** ZSTD_compressStream_generic():
3040 void* dst, size_t* dstCapacityPtr, 3032 * internal function for all *compressStream*() variants and *compress_generic()
3041 const void* src, size_t* srcSizePtr, 3033 * non-static, because can be called from zstdmt_compress.c
3042 ZSTD_flush_e const flush) 3034 * @return : hint size for next input */
3043 { 3035 size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3036 ZSTD_outBuffer* output,
3037 ZSTD_inBuffer* input,
3038 ZSTD_EndDirective const flushMode)
3039 {
3040 const char* const istart = (const char*)input->src;
3041 const char* const iend = istart + input->size;
3042 const char* ip = istart + input->pos;
3043 char* const ostart = (char*)output->dst;
3044 char* const oend = ostart + output->size;
3045 char* op = ostart + output->pos;
3044 U32 someMoreWork = 1; 3046 U32 someMoreWork = 1;
3045 const char* const istart = (const char*)src; 3047
3046 const char* const iend = istart + *srcSizePtr; 3048 /* check expectations */
3047 const char* ip = istart; 3049 DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (U32)flushMode);
3048 char* const ostart = (char*)dst; 3050 assert(zcs->inBuff != NULL);
3049 char* const oend = ostart + *dstCapacityPtr; 3051 assert(zcs->inBuffSize > 0);
3050 char* op = ostart; 3052 assert(zcs->outBuff != NULL);
3053 assert(zcs->outBuffSize > 0);
3054 assert(output->pos <= output->size);
3055 assert(input->pos <= input->size);
3051 3056
3052 while (someMoreWork) { 3057 while (someMoreWork) {
3053 switch(zcs->stage) 3058 switch(zcs->streamStage)
3054 { 3059 {
3055 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */ 3060 case zcss_init:
3061 /* call ZSTD_initCStream() first ! */
3062 return ERROR(init_missing);
3056 3063
3057 case zcss_load: 3064 case zcss_load:
3058 /* complete inBuffer */ 3065 if ( (flushMode == ZSTD_e_end)
3066 && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */
3067 && (zcs->inBuffPos == 0) ) {
3068 /* shortcut to compression pass directly into output buffer */
3069 size_t const cSize = ZSTD_compressEnd(zcs,
3070 op, oend-op, ip, iend-ip);
3071 DEBUGLOG(4, "ZSTD_compressEnd : %u", (U32)cSize);
3072 if (ZSTD_isError(cSize)) return cSize;
3073 ip = iend;
3074 op += cSize;
3075 zcs->frameEnded = 1;
3076 ZSTD_startNewCompression(zcs);
3077 someMoreWork = 0; break;
3078 }
3079 /* complete loading into inBuffer */
3059 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos; 3080 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3060 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip); 3081 size_t const loaded = ZSTD_limitCopy(
3082 zcs->inBuff + zcs->inBuffPos, toLoad,
3083 ip, iend-ip);
3061 zcs->inBuffPos += loaded; 3084 zcs->inBuffPos += loaded;
3062 ip += loaded; 3085 ip += loaded;
3063 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) { 3086 if ( (flushMode == ZSTD_e_continue)
3064 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */ 3087 && (zcs->inBuffPos < zcs->inBuffTarget) ) {
3065 } } 3088 /* not enough input to fill full block : stop here */
3089 someMoreWork = 0; break;
3090 }
3091 if ( (flushMode == ZSTD_e_flush)
3092 && (zcs->inBuffPos == zcs->inToCompress) ) {
3093 /* empty */
3094 someMoreWork = 0; break;
3095 }
3096 }
3066 /* compress current block (note : this stage cannot be stopped in the middle) */ 3097 /* compress current block (note : this stage cannot be stopped in the middle) */
3098 DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
3067 { void* cDst; 3099 { void* cDst;
3068 size_t cSize; 3100 size_t cSize;
3069 size_t const iSize = zcs->inBuffPos - zcs->inToCompress; 3101 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3070 size_t oSize = oend-op; 3102 size_t oSize = oend-op;
3103 unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
3071 if (oSize >= ZSTD_compressBound(iSize)) 3104 if (oSize >= ZSTD_compressBound(iSize))
3072 cDst = op; /* compress directly into output buffer (avoid flush stage) */ 3105 cDst = op; /* compress into output buffer, to skip flush stage */
3073 else 3106 else
3074 cDst = zcs->outBuff, oSize = zcs->outBuffSize; 3107 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
3075 cSize = (flush == zsf_end) ? 3108 cSize = lastBlock ?
3076 ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) : 3109 ZSTD_compressEnd(zcs, cDst, oSize,
3077 ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize); 3110 zcs->inBuff + zcs->inToCompress, iSize) :
3111 ZSTD_compressContinue(zcs, cDst, oSize,
3112 zcs->inBuff + zcs->inToCompress, iSize);
3078 if (ZSTD_isError(cSize)) return cSize; 3113 if (ZSTD_isError(cSize)) return cSize;
3079 if (flush == zsf_end) zcs->frameEnded = 1; 3114 zcs->frameEnded = lastBlock;
3080 /* prepare next block */ 3115 /* prepare next block */
3081 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize; 3116 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3082 if (zcs->inBuffTarget > zcs->inBuffSize) 3117 if (zcs->inBuffTarget > zcs->inBuffSize)
3083 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */ 3118 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
3119 DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
3120 (U32)zcs->inBuffTarget, (U32)zcs->inBuffSize);
3121 if (!lastBlock)
3122 assert(zcs->inBuffTarget <= zcs->inBuffSize);
3084 zcs->inToCompress = zcs->inBuffPos; 3123 zcs->inToCompress = zcs->inBuffPos;
3085 if (cDst == op) { op += cSize; break; } /* no need to flush */ 3124 if (cDst == op) { /* no need to flush */
3125 op += cSize;
3126 if (zcs->frameEnded) {
3127 DEBUGLOG(5, "Frame completed directly in outBuffer");
3128 someMoreWork = 0;
3129 ZSTD_startNewCompression(zcs);
3130 }
3131 break;
3132 }
3086 zcs->outBuffContentSize = cSize; 3133 zcs->outBuffContentSize = cSize;
3087 zcs->outBuffFlushedSize = 0; 3134 zcs->outBuffFlushedSize = 0;
3088 zcs->stage = zcss_flush; /* pass-through to flush stage */ 3135 zcs->streamStage = zcss_flush; /* pass-through to flush stage */
3089 } 3136 }
3090 3137 /* fall-through */
3091 case zcss_flush: 3138 case zcss_flush:
3139 DEBUGLOG(5, "flush stage");
3092 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize; 3140 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3093 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush); 3141 size_t const flushed = ZSTD_limitCopy(op, oend-op,
3142 zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3143 DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u",
3144 (U32)toFlush, (U32)(oend-op), (U32)flushed);
3094 op += flushed; 3145 op += flushed;
3095 zcs->outBuffFlushedSize += flushed; 3146 zcs->outBuffFlushedSize += flushed;
3096 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */ 3147 if (toFlush!=flushed) {
3148 /* flush not fully completed, presumably because dst is too small */
3149 assert(op==oend);
3150 someMoreWork = 0;
3151 break;
3152 }
3097 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0; 3153 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
3098 zcs->stage = zcss_load; 3154 if (zcs->frameEnded) {
3155 DEBUGLOG(5, "Frame completed on flush");
3156 someMoreWork = 0;
3157 ZSTD_startNewCompression(zcs);
3158 break;
3159 }
3160 zcs->streamStage = zcss_load;
3099 break; 3161 break;
3100 } 3162 }
3101 3163
3102 case zcss_final: 3164 default: /* impossible */
3103 someMoreWork = 0; /* do nothing */ 3165 assert(0);
3104 break;
3105
3106 default:
3107 return ERROR(GENERIC); /* impossible */
3108 } 3166 }
3109 } 3167 }
3110 3168
3111 *srcSizePtr = ip - istart; 3169 input->pos = ip - istart;
3112 *dstCapacityPtr = op - ostart; 3170 output->pos = op - ostart;
3113 zcs->inputProcessed += *srcSizePtr;
3114 if (zcs->frameEnded) return 0; 3171 if (zcs->frameEnded) return 0;
3115 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos; 3172 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3116 if (hintInSize==0) hintInSize = zcs->blockSize; 3173 if (hintInSize==0) hintInSize = zcs->blockSize;
3117 return hintInSize; 3174 return hintInSize;
3118 } 3175 }
3119 } 3176 }
3120 3177
3121 size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input) 3178 size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
3122 { 3179 {
3123 size_t sizeRead = input->size - input->pos; 3180 /* check conditions */
3124 size_t sizeWritten = output->size - output->pos; 3181 if (output->pos > output->size) return ERROR(GENERIC);
3125 size_t const result = ZSTD_compressStream_generic(zcs, 3182 if (input->pos > input->size) return ERROR(GENERIC);
3126 (char*)(output->dst) + output->pos, &sizeWritten, 3183
3127 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather); 3184 return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue);
3128 input->pos += sizeRead; 3185 }
3129 output->pos += sizeWritten; 3186
3130 return result; 3187
3188 size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
3189 ZSTD_outBuffer* output,
3190 ZSTD_inBuffer* input,
3191 ZSTD_EndDirective endOp)
3192 {
3193 DEBUGLOG(5, "ZSTD_compress_generic, endOp=%u ", (U32)endOp);
3194 /* check conditions */
3195 if (output->pos > output->size) return ERROR(GENERIC);
3196 if (input->pos > input->size) return ERROR(GENERIC);
3197 assert(cctx!=NULL);
3198
3199 /* transparent initialization stage */
3200 if (cctx->streamStage == zcss_init) {
3201 ZSTD_CCtx_params params = cctx->requestedParams;
3202 ZSTD_prefixDict const prefixDict = cctx->prefixDict;
3203 memset(&cctx->prefixDict, 0, sizeof(cctx->prefixDict)); /* single usage */
3204 assert(prefixDict.dict==NULL || cctx->cdict==NULL); /* only one can be set */
3205 DEBUGLOG(4, "ZSTD_compress_generic : transparent init stage");
3206 if (endOp == ZSTD_e_end) cctx->pledgedSrcSizePlusOne = input->size + 1; /* auto-fix pledgedSrcSize */
3207 params.cParams = ZSTD_getCParamsFromCCtxParams(
3208 &cctx->requestedParams, cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
3209
3210 #ifdef ZSTD_MULTITHREAD
3211 if ((cctx->pledgedSrcSizePlusOne-1) <= ZSTDMT_JOBSIZE_MIN) {
3212 params.nbWorkers = 0; /* do not invoke multi-threading when src size is too small */
3213 }
3214 if (params.nbWorkers > 0) {
3215 /* mt context creation */
3216 if (cctx->mtctx == NULL || (params.nbWorkers != ZSTDMT_getNbWorkers(cctx->mtctx))) {
3217 DEBUGLOG(4, "ZSTD_compress_generic: creating new mtctx for nbWorkers=%u",
3218 params.nbWorkers);
3219 if (cctx->mtctx != NULL)
3220 DEBUGLOG(4, "ZSTD_compress_generic: previous nbWorkers was %u",
3221 ZSTDMT_getNbWorkers(cctx->mtctx));
3222 ZSTDMT_freeCCtx(cctx->mtctx);
3223 cctx->mtctx = ZSTDMT_createCCtx_advanced(params.nbWorkers, cctx->customMem);
3224 if (cctx->mtctx == NULL) return ERROR(memory_allocation);
3225 }
3226 /* mt compression */
3227 DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbWorkers=%u", params.nbWorkers);
3228 CHECK_F( ZSTDMT_initCStream_internal(
3229 cctx->mtctx,
3230 prefixDict.dict, prefixDict.dictSize, ZSTD_dct_rawContent,
3231 cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
3232 cctx->streamStage = zcss_load;
3233 cctx->appliedParams.nbWorkers = params.nbWorkers;
3234 } else
3235 #endif
3236 { CHECK_F( ZSTD_resetCStream_internal(cctx,
3237 prefixDict.dict, prefixDict.dictSize, prefixDict.dictContentType,
3238 cctx->cdict,
3239 params, cctx->pledgedSrcSizePlusOne-1) );
3240 assert(cctx->streamStage == zcss_load);
3241 assert(cctx->appliedParams.nbWorkers == 0);
3242 } }
3243
3244 /* compression stage */
3245 #ifdef ZSTD_MULTITHREAD
3246 if (cctx->appliedParams.nbWorkers > 0) {
3247 if (cctx->cParamsChanged) {
3248 ZSTDMT_updateCParams_whileCompressing(cctx->mtctx, &cctx->requestedParams);
3249 cctx->cParamsChanged = 0;
3250 }
3251 { size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
3252 if ( ZSTD_isError(flushMin)
3253 || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
3254 ZSTD_startNewCompression(cctx);
3255 }
3256 return flushMin;
3257 } }
3258 #endif
3259 CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
3260 DEBUGLOG(5, "completed ZSTD_compress_generic");
3261 return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
3262 }
3263
3264 size_t ZSTD_compress_generic_simpleArgs (
3265 ZSTD_CCtx* cctx,
3266 void* dst, size_t dstCapacity, size_t* dstPos,
3267 const void* src, size_t srcSize, size_t* srcPos,
3268 ZSTD_EndDirective endOp)
3269 {
3270 ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
3271 ZSTD_inBuffer input = { src, srcSize, *srcPos };
3272 /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
3273 size_t const cErr = ZSTD_compress_generic(cctx, &output, &input, endOp);
3274 *dstPos = output.pos;
3275 *srcPos = input.pos;
3276 return cErr;
3131 } 3277 }
3132 3278
3133 3279
3134 /*====== Finalize ======*/ 3280 /*====== Finalize ======*/
3135 3281
3136 /*! ZSTD_flushStream() : 3282 /*! ZSTD_flushStream() :
3137 * @return : amount of data remaining to flush */ 3283 * @return : amount of data remaining to flush */
3138 size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 3284 size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
3139 { 3285 {
3140 size_t srcSize = 0; 3286 ZSTD_inBuffer input = { NULL, 0, 0 };
3141 size_t sizeWritten = output->size - output->pos; 3287 if (output->pos > output->size) return ERROR(GENERIC);
3142 size_t const result = ZSTD_compressStream_generic(zcs, 3288 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_flush) );
3143 (char*)(output->dst) + output->pos, &sizeWritten, 3289 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3144 &srcSize, &srcSize, /* use a valid src address instead of NULL */
3145 zsf_flush);
3146 output->pos += sizeWritten;
3147 if (ZSTD_isError(result)) return result;
3148 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3149 } 3290 }
3150 3291
3151 3292
3152 size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output) 3293 size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
3153 { 3294 {
3154 BYTE* const ostart = (BYTE*)(output->dst) + output->pos; 3295 ZSTD_inBuffer input = { NULL, 0, 0 };
3155 BYTE* const oend = (BYTE*)(output->dst) + output->size; 3296 if (output->pos > output->size) return ERROR(GENERIC);
3156 BYTE* op = ostart; 3297 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_end) );
3157 3298 { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE;
3158 if ((zcs->pledgedSrcSize) && (zcs->inputProcessed != zcs->pledgedSrcSize)) 3299 size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4;
3159 return ERROR(srcSize_wrong); /* pledgedSrcSize not respected */ 3300 size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize + lastBlockSize + checksumSize;
3160 3301 DEBUGLOG(4, "ZSTD_endStream : remaining to flush : %u", (U32)toFlush);
3161 if (zcs->stage != zcss_final) { 3302 return toFlush;
3162 /* flush whatever remains */ 3303 }
3163 size_t srcSize = 0; 3304 }
3164 size_t sizeWritten = output->size - output->pos;
3165 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
3166 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3167 op += sizeWritten;
3168 if (remainingToFlush) {
3169 output->pos += sizeWritten;
3170 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4);
3171 }
3172 /* create epilogue */
3173 zcs->stage = zcss_final;
3174 zcs->outBuffContentSize = !notEnded ? 0 :
3175 ZSTD_compressEnd(zcs->cctx, zcs->outBuff, zcs->outBuffSize, NULL, 0); /* write epilogue, including final empty block, into outBuff */
3176 }
3177
3178 /* flush epilogue */
3179 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3180 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3181 op += flushed;
3182 zcs->outBuffFlushedSize += flushed;
3183 output->pos += op-ostart;
3184 if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */
3185 return toFlush - flushed;
3186 }
3187 }
3188
3189 3305
3190 3306
3191 /*-===== Pre-defined compression levels =====-*/ 3307 /*-===== Pre-defined compression levels =====-*/
3192 3308
3193 #define ZSTD_DEFAULT_CLEVEL 1
3194 #define ZSTD_MAX_CLEVEL 22 3309 #define ZSTD_MAX_CLEVEL 22
3195 int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; } 3310 int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
3196 3311
3197 static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = { 3312 static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
3198 { /* "default" */ 3313 { /* "default" - guarantees a monotonically increasing memory budget */
3199 /* W, C, H, S, L, TL, strat */ 3314 /* W, C, H, S, L, TL, strat */
3200 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */ 3315 { 19, 12, 13, 1, 6, 1, ZSTD_fast }, /* base for negative levels */
3201 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */ 3316 { 19, 13, 14, 1, 7, 1, ZSTD_fast }, /* level 1 */
3202 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */ 3317 { 19, 15, 16, 1, 6, 1, ZSTD_fast }, /* level 2 */
3203 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/ 3318 { 20, 16, 17, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3204 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/ 3319 { 20, 17, 18, 1, 5, 8, ZSTD_dfast }, /* level 4 */
3205 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */ 3320 { 20, 17, 18, 2, 5, 16, ZSTD_greedy }, /* level 5 */
3206 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */ 3321 { 21, 17, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3207 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */ 3322 { 21, 18, 19, 3, 5, 16, ZSTD_lazy }, /* level 7 */
3208 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */ 3323 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
3209 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */ 3324 { 21, 19, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3210 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */ 3325 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3211 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */ 3326 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3212 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */ 3327 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3213 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */ 3328 { 22, 21, 22, 4, 5, 32, ZSTD_btlazy2 }, /* level 13 */
3214 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */ 3329 { 22, 21, 22, 5, 5, 32, ZSTD_btlazy2 }, /* level 14 */
3215 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */ 3330 { 22, 22, 22, 6, 5, 32, ZSTD_btlazy2 }, /* level 15 */
3216 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */ 3331 { 22, 21, 22, 4, 5, 48, ZSTD_btopt }, /* level 16 */
3217 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */ 3332 { 23, 22, 22, 4, 4, 48, ZSTD_btopt }, /* level 17 */
3218 { 23, 23, 22, 6, 5, 32, ZSTD_btopt }, /* level 18 */ 3333 { 23, 22, 22, 5, 3, 64, ZSTD_btopt }, /* level 18 */
3219 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */ 3334 { 23, 23, 22, 7, 3,128, ZSTD_btopt }, /* level 19 */
3220 { 25, 25, 23, 7, 3, 64, ZSTD_btopt2 }, /* level 20 */ 3335 { 25, 25, 23, 7, 3,128, ZSTD_btultra }, /* level 20 */
3221 { 26, 26, 23, 7, 3,256, ZSTD_btopt2 }, /* level 21 */ 3336 { 26, 26, 24, 7, 3,256, ZSTD_btultra }, /* level 21 */
3222 { 27, 27, 25, 9, 3,512, ZSTD_btopt2 }, /* level 22 */ 3337 { 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */
3223 }, 3338 },
3224 { /* for srcSize <= 256 KB */ 3339 { /* for srcSize <= 256 KB */
3225 /* W, C, H, S, L, T, strat */ 3340 /* W, C, H, S, L, T, strat */
3226 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */ 3341 { 18, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
3227 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */ 3342 { 18, 13, 14, 1, 6, 1, ZSTD_fast }, /* level 1 */
3228 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */ 3343 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3229 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */ 3344 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3230 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/ 3345 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3231 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/ 3346 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3232 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/ 3347 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3233 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */ 3348 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3234 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */ 3349 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3235 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */ 3350 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3236 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */ 3351 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3237 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/ 3352 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3238 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/ 3353 { 18, 18, 17, 5, 4, 8, ZSTD_btlazy2 }, /* level 12.*/
3239 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */ 3354 { 18, 19, 17, 7, 4, 8, ZSTD_btlazy2 }, /* level 13 */
3240 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/ 3355 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
3241 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/ 3356 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3242 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/ 3357 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3243 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/ 3358 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
3244 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/ 3359 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3245 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/ 3360 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
3246 { 18, 19, 18, 11, 3,512, ZSTD_btopt2 }, /* level 20.*/ 3361 { 18, 19, 18, 11, 3,512, ZSTD_btultra }, /* level 20.*/
3247 { 18, 19, 18, 12, 3,512, ZSTD_btopt2 }, /* level 21.*/ 3362 { 18, 19, 18, 12, 3,512, ZSTD_btultra }, /* level 21.*/
3248 { 18, 19, 18, 13, 3,512, ZSTD_btopt2 }, /* level 22.*/ 3363 { 18, 19, 18, 13, 3,512, ZSTD_btultra }, /* level 22.*/
3249 }, 3364 },
3250 { /* for srcSize <= 128 KB */ 3365 { /* for srcSize <= 128 KB */
3251 /* W, C, H, S, L, T, strat */ 3366 /* W, C, H, S, L, T, strat */
3252 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */ 3367 { 17, 12, 12, 1, 5, 1, ZSTD_fast }, /* level 0 - not used */
3253 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */ 3368 { 17, 12, 13, 1, 6, 1, ZSTD_fast }, /* level 1 */
3254 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */ 3369 { 17, 13, 16, 1, 5, 1, ZSTD_fast }, /* level 2 */
3255 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */ 3370 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3256 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */ 3371 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3257 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */ 3372 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3258 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */ 3373 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3259 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */ 3374 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3267 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/ 3382 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3268 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/ 3383 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3269 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/ 3384 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3270 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/ 3385 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3271 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/ 3386 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
3272 { 17, 18, 17, 9, 3,256, ZSTD_btopt2 }, /* level 20.*/ 3387 { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/
3273 { 17, 18, 17, 10, 3,256, ZSTD_btopt2 }, /* level 21.*/ 3388 { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/
3274 { 17, 18, 17, 11, 3,512, ZSTD_btopt2 }, /* level 22.*/ 3389 { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/
3275 }, 3390 },
3276 { /* for srcSize <= 16 KB */ 3391 { /* for srcSize <= 16 KB */
3277 /* W, C, H, S, L, T, strat */ 3392 /* W, C, H, S, L, T, strat */
3278 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */ 3393 { 14, 12, 13, 1, 5, 1, ZSTD_fast }, /* base for negative levels */
3279 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */ 3394 { 14, 14, 14, 1, 6, 1, ZSTD_fast }, /* level 1 */
3280 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */ 3395 { 14, 14, 14, 1, 4, 1, ZSTD_fast }, /* level 2 */
3281 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/ 3396 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3282 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/ 3397 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3283 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/ 3398 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3284 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */ 3399 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3285 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */ 3400 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3293 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/ 3408 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3294 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/ 3409 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3295 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/ 3410 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3296 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/ 3411 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3297 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/ 3412 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
3298 { 14, 15, 15, 8, 3,256, ZSTD_btopt2 }, /* level 20.*/ 3413 { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/
3299 { 14, 15, 15, 9, 3,256, ZSTD_btopt2 }, /* level 21.*/ 3414 { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/
3300 { 14, 15, 15, 10, 3,256, ZSTD_btopt2 }, /* level 22.*/ 3415 { 14, 15, 15, 10, 3,256, ZSTD_btultra }, /* level 22.*/
3301 }, 3416 },
3302 }; 3417 };
3303 3418
3304 /*! ZSTD_getCParams() : 3419 /*! ZSTD_getCParams() :
3305 * @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`. 3420 * @return ZSTD_compressionParameters structure for a selected compression level, srcSize and dictSize.
3306 * Size values are optional, provide 0 if not known or unused */ 3421 * Size values are optional, provide 0 if not known or unused */
3307 ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) 3422 ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
3308 { 3423 {
3309 ZSTD_compressionParameters cp; 3424 size_t const addedSize = srcSizeHint ? 0 : 500;
3310 size_t const addedSize = srcSize ? 0 : 500; 3425 U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1;
3311 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
3312 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */ 3426 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
3313 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */ 3427 int row = compressionLevel;
3314 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL; 3428 DEBUGLOG(5, "ZSTD_getCParams (cLevel=%i)", compressionLevel);
3315 cp = ZSTD_defaultCParameters[tableID][compressionLevel]; 3429 if (compressionLevel == 0) row = ZSTD_CLEVEL_DEFAULT; /* 0 == default */
3316 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */ 3430 if (compressionLevel < 0) row = 0; /* entry 0 is baseline for fast mode */
3317 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX; 3431 if (compressionLevel > ZSTD_MAX_CLEVEL) row = ZSTD_MAX_CLEVEL;
3318 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX; 3432 { ZSTD_compressionParameters cp = ZSTD_defaultCParameters[tableID][row];
3319 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX; 3433 if (compressionLevel < 0) cp.targetLength = (unsigned)(-compressionLevel); /* acceleration factor */
3320 } 3434 return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); }
3321 cp = ZSTD_adjustCParams(cp, srcSize, dictSize); 3435
3322 return cp;
3323 } 3436 }
3324 3437
3325 /*! ZSTD_getParams() : 3438 /*! ZSTD_getParams() :
3326 * same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`). 3439 * same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
3327 * All fields of `ZSTD_frameParameters` are set to default (0) */ 3440 * All fields of `ZSTD_frameParameters` are set to default (0) */
3328 ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) { 3441 ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
3329 ZSTD_parameters params; 3442 ZSTD_parameters params;
3330 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize); 3443 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize);
3444 DEBUGLOG(5, "ZSTD_getParams (cLevel=%i)", compressionLevel);
3331 memset(&params, 0, sizeof(params)); 3445 memset(&params, 0, sizeof(params));
3332 params.cParams = cParams; 3446 params.cParams = cParams;
3447 params.fParams.contentSizeFlag = 1;
3333 return params; 3448 return params;
3334 } 3449 }