Mercurial > hg
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(¶ms); | |
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(¶ms); | |
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(¶ms.ldmParams, ¶ms.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(¶ms.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, ¶ms.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 = ¶ms->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 ¶ms, 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(¶ms, 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, ¶ms, | |
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(¶ms, 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(¶ms, 0, sizeof(params)); | 3445 memset(¶ms, 0, sizeof(params)); |
3332 params.cParams = cParams; | 3446 params.cParams = cParams; |
3447 params.fParams.contentSizeFlag = 1; | |
3333 return params; | 3448 return params; |
3334 } | 3449 } |