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