blob: 178ac970a47c998db1df16608788f4067d7fa260 [file] [log] [blame]
Yann Colletf3eca252015-10-22 15:31:46 +01001/*
2 ZSTD HC - High Compression Mode of Zstandard
3 Copyright (C) 2015, Yann Collet.
4
5 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are
9 met:
10
11 * Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 * Redistributions in binary form must reproduce the above
14 copyright notice, this list of conditions and the following disclaimer
15 in the documentation and/or other materials provided with the
16 distribution.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 You can contact the author at :
31 - Zstd source repository : https://www.zstd.net
32*/
33
34
Yann Collet4b100f42015-10-30 15:49:48 +010035/* *******************************************************
36* Compiler specifics
37*********************************************************/
38#ifdef _MSC_VER /* Visual Studio */
39# define FORCE_INLINE static __forceinline
40# include <intrin.h> /* For Visual 2005 */
41# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
42# pragma warning(disable : 4324) /* disable: C4324: padded structure */
43#else
44# define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
45# ifdef __GNUC__
46# define FORCE_INLINE static inline __attribute__((always_inline))
47# else
48# define FORCE_INLINE static inline
49# endif
50#endif
51
52
Yann Colletf3eca252015-10-22 15:31:46 +010053/* *************************************
54* Includes
55***************************************/
56#include <stdlib.h> /* malloc */
57#include <string.h> /* memset */
Yann Collet083fcc82015-10-25 14:06:35 +010058#include "zstdhc_static.h"
Yann Colletf3eca252015-10-22 15:31:46 +010059#include "zstd_static.h"
Yann Collet3d9cf7a2015-10-29 17:15:14 +010060#include "zstd_internal.h"
Yann Colletf3eca252015-10-22 15:31:46 +010061#include "mem.h"
62
63
64/* *************************************
Yann Colletf3eca252015-10-22 15:31:46 +010065* Local Constants
66***************************************/
67#define MINMATCH 4
Yann Collet53fff6c2015-10-24 13:48:37 +010068#define MAXD_LOG 26
Yann Colletf3eca252015-10-22 15:31:46 +010069
70#define KB *1024
71#define MB *1024*1024
72#define GB *(1ULL << 30)
73
74/* *************************************
75* Local Types
76***************************************/
77#define BLOCKSIZE (128 KB) /* define, for static allocation */
78#define WORKPLACESIZE (BLOCKSIZE*3)
79
80struct ZSTD_HC_CCtx_s
81{
Yann Colletf3eca252015-10-22 15:31:46 +010082 const BYTE* end; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010083 const BYTE* base; /* All regular indexes relative to this position */
84 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010085 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010086 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010087 U32 nextToUpdate; /* index from which to continue dictionary update */
Yann Collet083fcc82015-10-25 14:06:35 +010088 ZSTD_HC_parameters params;
Yann Collet712def92015-10-29 18:41:45 +010089 void* workSpace;
90 size_t workSpaceSize;
91
92 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +010093 U32* hashTable;
94 U32* chainTable;
Yann Colletf3eca252015-10-22 15:31:46 +010095};
96
97
98ZSTD_HC_CCtx* ZSTD_HC_createCCtx(void)
99{
Yann Collet712def92015-10-29 18:41:45 +0100100 return (ZSTD_HC_CCtx*) calloc(1, sizeof(ZSTD_HC_CCtx));
Yann Colletf3eca252015-10-22 15:31:46 +0100101}
102
Yann Collet083fcc82015-10-25 14:06:35 +0100103size_t ZSTD_HC_freeCCtx(ZSTD_HC_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100104{
Yann Collet712def92015-10-29 18:41:45 +0100105 free(cctx->workSpace);
Yann Collet083fcc82015-10-25 14:06:35 +0100106 free(cctx);
107 return 0;
108}
109
Yann Collet59d70632015-11-04 12:05:27 +0100110
111/** ZSTD_HC_validateParams
112 correct params value to remain within authorized range
113 optimize for srcSize if srcSize > 0 */
114void ZSTD_HC_validateParams(ZSTD_HC_parameters* params, size_t srcSize)
115{
116 const U32 chainplus = (params->strategy == ZSTD_HC_btlazy2);
117
118 /* validate params */
119 if (params->windowLog > ZSTD_HC_WINDOWLOG_MAX) params->windowLog = ZSTD_HC_WINDOWLOG_MAX;
120 if (params->windowLog < ZSTD_HC_WINDOWLOG_MIN) params->windowLog = ZSTD_HC_WINDOWLOG_MIN;
121
122 /* correct params, to use less memory */
123 if (srcSize > 0)
124 {
125 U32 srcLog = ZSTD_highbit((U32)srcSize-1) + 1;
126 if (params->windowLog > srcLog) params->windowLog = srcLog;
127 }
128
129 if (params->chainLog > params->windowLog + chainplus) params->chainLog = params->windowLog+chainplus; /* <= ZSTD_HC_CHAINLOG_MAX */
130 if (params->chainLog < ZSTD_HC_CHAINLOG_MIN) params->chainLog = ZSTD_HC_CHAINLOG_MIN;
131 if (params->hashLog > ZSTD_HC_HASHLOG_MAX) params->hashLog = ZSTD_HC_HASHLOG_MAX;
132 if (params->hashLog < ZSTD_HC_HASHLOG_MIN) params->hashLog = ZSTD_HC_HASHLOG_MIN;
133 if (params->searchLog > ZSTD_HC_SEARCHLOG_MAX) params->searchLog = ZSTD_HC_SEARCHLOG_MAX;
134 if (params->searchLog < ZSTD_HC_SEARCHLOG_MIN) params->searchLog = ZSTD_HC_SEARCHLOG_MIN;
135 if (params->searchLength> ZSTD_HC_SEARCHLENGTH_MAX) params->searchLength = ZSTD_HC_SEARCHLENGTH_MAX;
136 if (params->searchLength< ZSTD_HC_SEARCHLENGTH_MIN) params->searchLength = ZSTD_HC_SEARCHLENGTH_MIN;
137 if ((U32)params->strategy>(U32)ZSTD_HC_btlazy2) params->strategy = ZSTD_HC_btlazy2;
138 if ((int)params->strategy<(int)ZSTD_HC_greedy) params->strategy = ZSTD_HC_greedy;
139}
140
141
Yann Collet4114f952015-10-30 06:40:22 +0100142static size_t ZSTD_HC_resetCCtx_advanced (ZSTD_HC_CCtx* zc,
143 ZSTD_HC_parameters params)
Yann Collet083fcc82015-10-25 14:06:35 +0100144{
Yann Collet59d70632015-11-04 12:05:27 +0100145 ZSTD_HC_validateParams(&params, 0);
Yann Collet083fcc82015-10-25 14:06:35 +0100146
Yann Collet2acb5d32015-10-29 16:49:43 +0100147 /* reserve table memory */
Yann Collet083fcc82015-10-25 14:06:35 +0100148 {
Yann Collet712def92015-10-29 18:41:45 +0100149 const size_t tableSpace = ((1 << params.chainLog) + (1 << params.hashLog)) * sizeof(U32);
150 const size_t neededSpace = tableSpace + WORKPLACESIZE;
151 if (zc->workSpaceSize < neededSpace)
Yann Collet2acb5d32015-10-29 16:49:43 +0100152 {
Yann Collet712def92015-10-29 18:41:45 +0100153 free(zc->workSpace);
154 zc->workSpaceSize = neededSpace;
155 zc->workSpace = malloc(neededSpace);
Yann Collet4114f952015-10-30 06:40:22 +0100156 if (zc->workSpace == NULL) return ERROR(memory_allocation);
Yann Collet2acb5d32015-10-29 16:49:43 +0100157 }
Yann Collet712def92015-10-29 18:41:45 +0100158 zc->hashTable = (U32*)zc->workSpace;
Yann Colletec43ba42015-10-30 11:51:26 +0100159 zc->chainTable = zc->hashTable + ((size_t)1 << params.hashLog);
160 zc->seqStore.buffer = (void*) (zc->chainTable + ((size_t)1 << params.chainLog));
Yann Collet712def92015-10-29 18:41:45 +0100161 memset(zc->hashTable, 0, tableSpace );
Yann Collet083fcc82015-10-25 14:06:35 +0100162 }
Yann Collet083fcc82015-10-25 14:06:35 +0100163
Yann Collet2acb5d32015-10-29 16:49:43 +0100164 zc->nextToUpdate = 0;
165 zc->end = NULL;
166 zc->base = NULL;
167 zc->dictBase = NULL;
168 zc->dictLimit = 0;
169 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100170 zc->params = params;
Yann Colletf3eca252015-10-22 15:31:46 +0100171 zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer);
172 zc->seqStore.offCodeStart = (BYTE*) (zc->seqStore.offsetStart + (BLOCKSIZE>>2));
173 zc->seqStore.litStart = zc->seqStore.offCodeStart + (BLOCKSIZE>>2);
174 zc->seqStore.litLengthStart = zc->seqStore.litStart + BLOCKSIZE;
175 zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + (BLOCKSIZE>>2);
176 zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (BLOCKSIZE>>2);
Yann Collet2acb5d32015-10-29 16:49:43 +0100177
Yann Collet4114f952015-10-30 06:40:22 +0100178 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100179}
180
Yann Collet083fcc82015-10-25 14:06:35 +0100181
Yann Colletf3eca252015-10-22 15:31:46 +0100182/* *************************************
Yann Collet4b100f42015-10-30 15:49:48 +0100183* Inline functions and Macros
Yann Colletf3eca252015-10-22 15:31:46 +0100184***************************************/
Yann Collet2acb5d32015-10-29 16:49:43 +0100185
Yann Collet4b100f42015-10-30 15:49:48 +0100186static const U32 prime4bytes = 2654435761U;
187static U32 ZSTD_HC_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
188static size_t ZSTD_HC_hash4Ptr(const void* ptr, U32 h) { return ZSTD_HC_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100189
Yann Collet4b100f42015-10-30 15:49:48 +0100190static const U64 prime5bytes = 889523592379ULL;
191static size_t ZSTD_HC_hash5(U64 u, U32 h) { return (size_t)((u * prime5bytes) << (64-40) >> (64-h)) ; }
192static size_t ZSTD_HC_hash5Ptr(const void* p, U32 h) { return ZSTD_HC_hash5(MEM_read64(p), h); }
193
194static const U64 prime6bytes = 227718039650203ULL;
195static size_t ZSTD_HC_hash6(U64 u, U32 h) { return (size_t)((u * prime6bytes) << (64-48) >> (64-h)) ; }
196static size_t ZSTD_HC_hash6Ptr(const void* p, U32 h) { return ZSTD_HC_hash6(MEM_read64(p), h); }
197
Yann Collet96b9f0b2015-11-04 03:52:54 +0100198static size_t ZSTD_HC_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100199{
200 switch(mls)
201 {
202 default:
Yann Collet96b9f0b2015-11-04 03:52:54 +0100203 case 4: return ZSTD_HC_hash4Ptr(p, hBits);
204 case 5: return ZSTD_HC_hash5Ptr(p, hBits);
205 case 6: return ZSTD_HC_hash6Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100206 }
207}
Yann Collet2acb5d32015-10-29 16:49:43 +0100208
Yann Collet050efba2015-11-03 09:49:30 +0100209#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
Yann Colletf3eca252015-10-22 15:31:46 +0100210
Yann Colletf3eca252015-10-22 15:31:46 +0100211
Yann Colletf3eca252015-10-22 15:31:46 +0100212/* *************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +0100213* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +0100214***************************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +0100215/** ZSTD_HC_insertBt1 : add one ptr to tree
216 @ip : assumed <= iend-8 */
217static void ZSTD_HC_insertBt1(ZSTD_HC_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares)
218{
219 U32* const hashTable = zc->hashTable;
220 const U32 hashLog = zc->params.hashLog;
221 const size_t h = ZSTD_HC_hashPtr(ip, hashLog, mls);
222 U32* const bt = zc->chainTable;
223 const U32 btLog = zc->params.chainLog - 1;
224 const U32 btMask= (1 << btLog) - 1;
225 U32 matchIndex = hashTable[h];
226 size_t commonLengthSmaller=0, commonLengthLarger=0;
227 const BYTE* const base = zc->base;
228 const U32 current = (U32)(ip-base);
229 const U32 btLow = btMask >= current ? 0 : current - btMask;
230 U32* smallerPtr = bt + 2*(current&btMask);
231 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet59d70632015-11-04 12:05:27 +0100232 U32 dummy32; /* to be nullified at the end */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100233 const U32 windowSize = 1 << zc->params.windowLog;
234 const U32 windowLow = windowSize >= current ? 0 : current - windowSize;
235
236 hashTable[h] = (U32)(ip-base); /* Update Hash Table */
237
238 while (nbCompares-- && (matchIndex > windowLow))
239 {
240 U32* nextPtr = bt + 2*(matchIndex & btMask);
241 const BYTE* match = base + matchIndex;
242 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
243
244 matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
245
Yann Collet59d70632015-11-04 12:05:27 +0100246 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
247 break; /* just drop , to guarantee consistency (miss a bit of compression; if someone knows better, please tell) */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100248
249 if (match[matchLength] < ip[matchLength])
Yann Collet59d70632015-11-04 12:05:27 +0100250 {
Yann Collet96b9f0b2015-11-04 03:52:54 +0100251 /* match is smaller than current */
252 *smallerPtr = matchIndex; /* update smaller idx */
253 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Collet59d70632015-11-04 12:05:27 +0100254 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100255 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
256 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet59d70632015-11-04 12:05:27 +0100257 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100258 else
Yann Collet59d70632015-11-04 12:05:27 +0100259 {
Yann Collet96b9f0b2015-11-04 03:52:54 +0100260 /* match is larger than current */
261 *largerPtr = matchIndex;
262 commonLengthLarger = matchLength;
Yann Collet59d70632015-11-04 12:05:27 +0100263 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100264 largerPtr = nextPtr;
265 matchIndex = nextPtr[0];
Yann Collet59d70632015-11-04 12:05:27 +0100266 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100267 }
268
Yann Collet59d70632015-11-04 12:05:27 +0100269 *smallerPtr = *largerPtr = 0;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100270}
271
272
273FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
274size_t ZSTD_HC_insertBtAndFindBestMatch (
275 ZSTD_HC_CCtx* zc,
276 const BYTE* const ip, const BYTE* const iend,
277 size_t* offsetPtr,
278 U32 nbCompares, const U32 mls)
279{
280 U32* const hashTable = zc->hashTable;
281 const U32 hashLog = zc->params.hashLog;
282 const size_t h = ZSTD_HC_hashPtr(ip, hashLog, mls);
283 U32* const bt = zc->chainTable;
284 const U32 btLog = zc->params.chainLog - 1;
285 const U32 btMask= (1 << btLog) - 1;
286 U32 matchIndex = hashTable[h];
287 size_t commonLengthSmaller=0, commonLengthLarger=0;
288 const BYTE* const base = zc->base;
289 const U32 current = (U32)(ip-base);
290 const U32 btLow = btMask >= current ? 0 : current - btMask;
291 const U32 windowSize = 1 << zc->params.windowLog;
292 const U32 windowLow = windowSize >= current ? 0 : current - windowSize;
293 U32* smallerPtr = bt + 2*(current&btMask);
294 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Colletb241e9d2015-11-04 13:57:24 +0100295 size_t bestLength = 0;
Yann Collet59d70632015-11-04 12:05:27 +0100296 U32 dummy32; /* to be nullified at the end */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100297
Yann Collet59d70632015-11-04 12:05:27 +0100298 hashTable[h] = (U32)(ip-base); /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100299
300 while (nbCompares-- && (matchIndex > windowLow))
301 {
302 U32* nextPtr = bt + 2*(matchIndex & btMask);
303 const BYTE* match = base + matchIndex;
304 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
305
306 matchLength += ZSTD_count(ip+matchLength, match+matchLength, iend);
307
308 if (matchLength > bestLength)
309 {
Yann Collete8455f52015-11-04 17:41:20 +0100310 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
Yann Colletb241e9d2015-11-04 13:57:24 +0100311 bestLength = matchLength, *offsetPtr = current - matchIndex;
Yann Collet59d70632015-11-04 12:05:27 +0100312 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
313 break; /* drop, next to null, to guarantee consistency (is there a way to do better ?) */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100314 }
315
316 if (match[matchLength] < ip[matchLength])
Yann Collet59d70632015-11-04 12:05:27 +0100317 {
Yann Collet96b9f0b2015-11-04 03:52:54 +0100318 /* match is smaller than current */
319 *smallerPtr = matchIndex; /* update smaller idx */
320 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Collet59d70632015-11-04 12:05:27 +0100321 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
322 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100323 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet59d70632015-11-04 12:05:27 +0100324 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100325 else
Yann Collet59d70632015-11-04 12:05:27 +0100326 {
Yann Collet96b9f0b2015-11-04 03:52:54 +0100327 /* match is larger than current */
328 *largerPtr = matchIndex;
329 commonLengthLarger = matchLength;
Yann Collet59d70632015-11-04 12:05:27 +0100330 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +0100331 largerPtr = nextPtr;
332 matchIndex = nextPtr[0];
Yann Collet59d70632015-11-04 12:05:27 +0100333 }
Yann Collet96b9f0b2015-11-04 03:52:54 +0100334 }
335
Yann Collet59d70632015-11-04 12:05:27 +0100336 *smallerPtr = *largerPtr = 0;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100337
338 zc->nextToUpdate = current+1; /* current has been inserted */
Yann Collet59d70632015-11-04 12:05:27 +0100339 if (bestLength < MINMATCH) return 0;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100340 return bestLength;
341}
342
343
344static void ZSTD_HC_updateTree(ZSTD_HC_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
345{
346 const BYTE* const base = zc->base;
347 const U32 target = (U32)(ip - base);
348 U32 idx = zc->nextToUpdate;
Yann Collet59d70632015-11-04 12:05:27 +0100349 //size_t dummy;
Yann Collet96b9f0b2015-11-04 03:52:54 +0100350
351 for( ; idx < target ; idx++)
352 ZSTD_HC_insertBt1(zc, base+idx, mls, iend, nbCompares);
353 //ZSTD_HC_insertBtAndFindBestMatch(zc, base+idx, iend, &dummy, nbCompares, mls);
354
355 zc->nextToUpdate = target;
356}
357
358
359/** Tree updater, providing best match */
360FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
361size_t ZSTD_HC_BtFindBestMatch (
362 ZSTD_HC_CCtx* zc,
363 const BYTE* const ip, const BYTE* const iLimit,
364 size_t* offsetPtr,
365 const U32 maxNbAttempts, const U32 mls)
366{
367 ZSTD_HC_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
368 return ZSTD_HC_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls);
369}
370
371
372FORCE_INLINE size_t ZSTD_HC_BtFindBestMatch_selectMLS (
373 ZSTD_HC_CCtx* zc, /* Index table will be updated */
374 const BYTE* ip, const BYTE* const iLimit,
375 size_t* offsetPtr,
376 const U32 maxNbAttempts, const U32 matchLengthSearch)
377{
378 switch(matchLengthSearch)
379 {
380 default :
381 case 4 : return ZSTD_HC_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
382 case 5 : return ZSTD_HC_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
383 case 6 : return ZSTD_HC_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
384 }
385}
386
387
Yann Collet5106a762015-11-05 15:00:24 +0100388/* ***********************
389* Hash Chain
390*************************/
391
392/* Update chains up to ip (excluded) */
393static U32 ZSTD_HC_insertAndFindFirstIndex (ZSTD_HC_CCtx* zc, const BYTE* ip, U32 mls)
394{
395 U32* const hashTable = zc->hashTable;
396 const U32 hashLog = zc->params.hashLog;
397 U32* const chainTable = zc->chainTable;
398 const U32 chainMask = (1 << zc->params.chainLog) - 1;
399 const BYTE* const base = zc->base;
400 const U32 target = (U32)(ip - base);
401 U32 idx = zc->nextToUpdate;
402
403 while(idx < target)
404 {
405 size_t h = ZSTD_HC_hashPtr(base+idx, hashLog, mls);
406 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
407 hashTable[h] = idx;
408 idx++;
409 }
410
411 zc->nextToUpdate = target;
412 return hashTable[ZSTD_HC_hashPtr(ip, hashLog, mls)];
413}
414
415
416FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
417size_t ZSTD_HC_insertAndFindBestMatch (
418 ZSTD_HC_CCtx* zc, /* Index table will be updated */
419 const BYTE* const ip, const BYTE* const iLimit,
420 size_t* offsetPtr,
421 const U32 maxNbAttempts, const U32 matchLengthSearch)
422{
423 U32* const chainTable = zc->chainTable;
424 const U32 chainSize = (1 << zc->params.chainLog);
425 const U32 chainMask = chainSize-1;
426 const BYTE* const base = zc->base;
427 const BYTE* const dictBase = zc->dictBase;
428 const U32 dictLimit = zc->dictLimit;
429 const U32 maxDistance = (1 << zc->params.windowLog);
430 const U32 lowLimit = (zc->lowLimit + maxDistance > (U32)(ip-base)) ? zc->lowLimit : (U32)(ip - base) - (maxDistance - 1);
431 U32 matchIndex;
432 const BYTE* match;
433 int nbAttempts=maxNbAttempts;
434 size_t ml=0;
435
436 /* HC4 match finder */
437 matchIndex = ZSTD_HC_insertAndFindFirstIndex (zc, ip, matchLengthSearch);
438
439 while ((matchIndex>lowLimit) && (nbAttempts))
440 {
441 nbAttempts--;
442 if (matchIndex >= dictLimit)
443 {
444 match = base + matchIndex;
445 if ( (match[ml] == ip[ml])
446 && (MEM_read32(match) == MEM_read32(ip)) ) /* ensures minimum match of 4 */
447 {
448 const size_t mlt = ZSTD_count(ip+MINMATCH, match+MINMATCH, iLimit) + MINMATCH;
449 if (mlt > ml)
450 //if (((int)(4*mlt) - (int)ZSTD_highbit((U32)(ip-match)+1)) > ((int)(4*ml) - (int)ZSTD_highbit((U32)((*offsetPtr)+1))))
451 {
452 ml = mlt; *offsetPtr = ip-match;
453 if (ip+ml >= iLimit) break;
454 }
455 }
456 }
457 else
458 {
459 match = dictBase + matchIndex;
460 if (MEM_read32(match) == MEM_read32(ip))
461 {
462 size_t mlt;
463 const BYTE* vLimit = ip + (dictLimit - matchIndex);
464 if (vLimit > iLimit) vLimit = iLimit;
465 mlt = ZSTD_count(ip+MINMATCH, match+MINMATCH, vLimit) + MINMATCH;
466 if ((ip+mlt == vLimit) && (vLimit < iLimit))
467 mlt += ZSTD_count(ip+mlt, base+dictLimit, iLimit);
468 if (mlt > ml) { ml = mlt; *offsetPtr = (ip-base) - matchIndex; }
469 }
470 }
471
472 if (base + matchIndex <= ip - chainSize) break;
473 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
474 }
475
476 return ml;
477}
478
479
480FORCE_INLINE size_t ZSTD_HC_insertAndFindBestMatch_selectMLS (
481 ZSTD_HC_CCtx* zc, /* Index table will be updated */
482 const BYTE* ip, const BYTE* const iLimit,
483 size_t* offsetPtr,
484 const U32 maxNbAttempts, const U32 matchLengthSearch)
485{
486 switch(matchLengthSearch)
487 {
488 default :
489 case 4 : return ZSTD_HC_insertAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
490 case 5 : return ZSTD_HC_insertAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
491 case 6 : return ZSTD_HC_insertAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
492 }
493}
494
495
Yann Collet90361052015-11-05 15:03:12 +0100496/* common lazy function, to be inlined */
Yann Collet5106a762015-11-05 15:00:24 +0100497FORCE_INLINE
498size_t ZSTD_HC_compressBlock_lazy_generic(ZSTD_HC_CCtx* ctx,
499 void* dst, size_t maxDstSize, const void* src, size_t srcSize,
500 const U32 searchMethod, const U32 deep) /* 0 : hc; 1 : bt */
501{
502 seqStore_t* seqStorePtr = &(ctx->seqStore);
503 const BYTE* const istart = (const BYTE*)src;
504 const BYTE* ip = istart;
505 const BYTE* anchor = istart;
506 const BYTE* const iend = istart + srcSize;
507 const BYTE* const ilimit = iend - 8;
508
509 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
510 const U32 maxSearches = 1 << ctx->params.searchLog;
511 const U32 mls = ctx->params.searchLength;
512
513 typedef size_t (*searchMax_f)(ZSTD_HC_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
514 size_t* offsetPtr,
515 U32 maxNbAttempts, U32 matchLengthSearch);
516 searchMax_f searchMax = searchMethod ? ZSTD_HC_BtFindBestMatch_selectMLS : ZSTD_HC_insertAndFindBestMatch_selectMLS;
517
518 /* init */
519 ZSTD_resetSeqStore(seqStorePtr);
520 if (((ip-ctx->base) - ctx->dictLimit) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
521
522 /* Match Loop */
523 while (ip <= ilimit)
524 {
525 size_t matchLength;
526 size_t offset=999999;
527 const BYTE* start;
528
529 /* try to find a first match */
530 if (MEM_read32(ip) == MEM_read32(ip - offset_2))
531 {
532 /* repcode : we take it*/
533 size_t offtmp = offset_2;
534 size_t litLength = ip - anchor;
535 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
536 offset_2 = offset_1;
537 offset_1 = offtmp;
538 ZSTD_storeSeq(seqStorePtr, litLength, anchor, 0, matchLength);
539 ip += matchLength+MINMATCH;
540 anchor = ip;
541 continue;
542 }
543
544 offset_2 = offset_1;
545 matchLength = searchMax(ctx, ip, iend, &offset, maxSearches, mls);
546 if (!matchLength) { ip++; continue; }
547
548 /* let's try to find a better solution */
549 start = ip;
550
551 while (ip<ilimit)
552 {
553 ip ++;
554 if (MEM_read32(ip) == MEM_read32(ip - offset_1))
555 {
556 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
557 int gain2 = (int)(ml2 * 3);
558 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
559 if (gain2 > gain1)
560 matchLength = ml2, offset = 0, start = ip;
561 }
562 {
563 size_t offset2=999999;
564 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
565 int gain2 = (int)(ml2*(3+deep) - ZSTD_highbit((U32)offset2+1)); /* raw approx */
566 int gain1 = (int)(matchLength*(3+deep) - ZSTD_highbit((U32)offset+1) + (3+deep));
567 if (gain2 > gain1)
568 {
569 matchLength = ml2, offset = offset2, start = ip;
570 continue; /* search a better one */
571 }
572 }
573
574 /* let's find an even better one */
575 if (deep && (ip<ilimit))
576 {
577 ip ++;
578 if (MEM_read32(ip) == MEM_read32(ip - offset_1))
579 {
580 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
581 int gain2 = (int)(ml2 * 4);
582 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
583 if (gain2 > gain1)
584 matchLength = ml2, offset = 0, start = ip;
585 }
586 {
587 size_t offset2=999999;
588 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
589 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
590 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
591 if (gain2 > gain1)
592 {
593 matchLength = ml2, offset = offset2, start = ip;
594 continue;
595 }
596 }
597 }
598 break; /* nothing found : store previous solution */
599 }
600
601 /* store sequence */
602 {
603 size_t litLength = start - anchor;
604 if (offset) offset_1 = offset;
605 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
606 ip = start + matchLength;
607 anchor = ip;
608 }
609
610 }
611
612 /* Last Literals */
613 {
614 size_t lastLLSize = iend - anchor;
615 memcpy(seqStorePtr->lit, anchor, lastLLSize);
616 seqStorePtr->lit += lastLLSize;
617 }
618
619 /* Final compression stage */
620 return ZSTD_compressSequences((BYTE*)dst, maxDstSize,
621 seqStorePtr, srcSize);
622}
623
624size_t ZSTD_HC_compressBlock_btlazy2(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
625{
626 return ZSTD_HC_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 1, 1);
627}
628
Yann Collet47b68902015-11-05 15:14:17 +0100629size_t ZSTD_HC_compressBlock_lazy2(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +0100630{
631 return ZSTD_HC_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 1);
632}
633
634size_t ZSTD_HC_compressBlock_lazy(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
635{
636 return ZSTD_HC_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 0);
637}
638
Yann Collet5106a762015-11-05 15:00:24 +0100639
Yann Colletbe2010e2015-10-31 12:57:14 +0100640size_t ZSTD_HC_compressBlock_greedy(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +0100641{
642 seqStore_t* seqStorePtr = &(ctx->seqStore);
643 const BYTE* const istart = (const BYTE*)src;
Yann Colleted0a7812015-10-23 19:25:06 +0100644 const BYTE* ip = istart;
Yann Colletf3eca252015-10-22 15:31:46 +0100645 const BYTE* anchor = istart;
646 const BYTE* const iend = istart + srcSize;
647 const BYTE* const ilimit = iend - 8;
648
Yann Colleted0a7812015-10-23 19:25:06 +0100649 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet083fcc82015-10-25 14:06:35 +0100650 const U32 maxSearches = 1 << ctx->params.searchLog;
Yann Collet4b100f42015-10-30 15:49:48 +0100651 const U32 mls = ctx->params.searchLength;
Yann Colletf3eca252015-10-22 15:31:46 +0100652
653 /* init */
654 ZSTD_resetSeqStore(seqStorePtr);
Yann Colleted0a7812015-10-23 19:25:06 +0100655 if (((ip-ctx->base) - ctx->dictLimit) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Colletf3eca252015-10-22 15:31:46 +0100656
Yann Colleted0a7812015-10-23 19:25:06 +0100657 /* Match Loop */
Yann Colletf3eca252015-10-22 15:31:46 +0100658 while (ip < ilimit)
659 {
Yann Colleted0a7812015-10-23 19:25:06 +0100660 /* repcode */
661 if (MEM_read32(ip) == MEM_read32(ip - offset_2))
Yann Colletf3eca252015-10-22 15:31:46 +0100662 {
Yann Collet4114f952015-10-30 06:40:22 +0100663 /* store sequence */
Yann Collet342892c2015-10-26 17:44:04 +0100664 size_t matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
Yann Colletf3eca252015-10-22 15:31:46 +0100665 size_t litLength = ip-anchor;
Yann Colleted0a7812015-10-23 19:25:06 +0100666 size_t offset = offset_2;
Yann Colletf3eca252015-10-22 15:31:46 +0100667 offset_2 = offset_1;
Yann Colleted0a7812015-10-23 19:25:06 +0100668 offset_1 = offset;
669 ZSTD_storeSeq(seqStorePtr, litLength, anchor, 0, matchLength);
670 ip += matchLength+MINMATCH;
Yann Colletf3eca252015-10-22 15:31:46 +0100671 anchor = ip;
Yann Colleted0a7812015-10-23 19:25:06 +0100672 continue;
673 }
674
Yann Collet4114f952015-10-30 06:40:22 +0100675 offset_2 = offset_1; /* failed once : necessarily offset_1 now */
676
Yann Collet342892c2015-10-26 17:44:04 +0100677 /* repcode at ip+1 */
678 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))
679 {
680 size_t matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend);
681 size_t litLength = ip+1-anchor;
Yann Collet342892c2015-10-26 17:44:04 +0100682 ZSTD_storeSeq(seqStorePtr, litLength, anchor, 0, matchLength);
683 ip += 1+matchLength+MINMATCH;
684 anchor = ip;
685 continue;
686 }
687
Yann Colleted0a7812015-10-23 19:25:06 +0100688 /* search */
689 {
Yann Collet050efba2015-11-03 09:49:30 +0100690 size_t offset=999999;
691 size_t matchLength = ZSTD_HC_insertAndFindBestMatch_selectMLS(ctx, ip, iend, &offset, maxSearches, mls);
Yann Collet4114f952015-10-30 06:40:22 +0100692 if (!matchLength) { ip++; continue; }
Yann Colleted0a7812015-10-23 19:25:06 +0100693 /* store sequence */
694 {
695 size_t litLength = ip-anchor;
Yann Collet050efba2015-11-03 09:49:30 +0100696 offset_1 = offset;
Yann Collet342892c2015-10-26 17:44:04 +0100697 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset_1, matchLength-MINMATCH);
Yann Colleted0a7812015-10-23 19:25:06 +0100698 ip += matchLength;
699 anchor = ip;
700 }
Yann Colletf3eca252015-10-22 15:31:46 +0100701 }
702 }
703
704 /* Last Literals */
705 {
706 size_t lastLLSize = iend - anchor;
707 memcpy(seqStorePtr->lit, anchor, lastLLSize);
708 seqStorePtr->lit += lastLLSize;
709 }
710
Yann Collet2c6992e2015-10-27 12:18:00 +0100711 /* Final compression stage */
Yann Colletf3eca252015-10-22 15:31:46 +0100712 return ZSTD_compressSequences((BYTE*)dst, maxDstSize,
Yann Colletf3eca252015-10-22 15:31:46 +0100713
Yann Colletbe2010e2015-10-31 12:57:14 +0100714 seqStorePtr, srcSize);
715}
716
717
Yann Collet59d70632015-11-04 12:05:27 +0100718typedef size_t (*ZSTD_HC_blockCompressor) (ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize);
719
720
721static ZSTD_HC_blockCompressor ZSTD_HC_selectBlockCompressor(ZSTD_HC_strategy strat)
722{
723 switch(strat)
724 {
725 default :
726 case ZSTD_HC_greedy:
727 return ZSTD_HC_compressBlock_greedy;
728 case ZSTD_HC_lazy:
729 return ZSTD_HC_compressBlock_lazy;
Yann Collet47b68902015-11-05 15:14:17 +0100730 case ZSTD_HC_lazy2:
731 return ZSTD_HC_compressBlock_lazy2;
Yann Collet59d70632015-11-04 12:05:27 +0100732 case ZSTD_HC_btlazy2:
Yann Collet5106a762015-11-05 15:00:24 +0100733 return ZSTD_HC_compressBlock_btlazy2;
Yann Collet59d70632015-11-04 12:05:27 +0100734 }
735}
736
737
Yann Colletbe2010e2015-10-31 12:57:14 +0100738size_t ZSTD_HC_compressBlock(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
739{
Yann Collet59d70632015-11-04 12:05:27 +0100740 ZSTD_HC_blockCompressor blockCompressor = ZSTD_HC_selectBlockCompressor(ctx->params.strategy);
741 return blockCompressor(ctx, dst, maxDstSize, src, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +0100742}
743
744
Yann Colletf3eca252015-10-22 15:31:46 +0100745static size_t ZSTD_HC_compress_generic (ZSTD_HC_CCtx* ctxPtr,
746 void* dst, size_t maxDstSize,
747 const void* src, size_t srcSize)
748{
Yann Collet3e358272015-11-04 18:19:39 +0100749 size_t blockSize = BLOCKSIZE;
Yann Colletf3eca252015-10-22 15:31:46 +0100750 size_t remaining = srcSize;
751 const BYTE* ip = (const BYTE*)src;
752 BYTE* const ostart = (BYTE*)dst;
753 BYTE* op = ostart;
Yann Collet59d70632015-11-04 12:05:27 +0100754 const ZSTD_HC_blockCompressor blockCompressor = ZSTD_HC_selectBlockCompressor(ctxPtr->params.strategy);
Yann Collet9b11b462015-11-01 12:40:22 +0100755
Yann Collet3e358272015-11-04 18:19:39 +0100756 while (remaining)
Yann Colletf3eca252015-10-22 15:31:46 +0100757 {
Yann Collet3e358272015-11-04 18:19:39 +0100758 size_t cSize;
759
Yann Collet3137d1a2015-11-04 23:36:36 +0100760 if (maxDstSize < 3 + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +0100761
762 if (remaining < blockSize) blockSize = remaining;
763 cSize = blockCompressor(ctxPtr, op+3, maxDstSize-3, ip, blockSize);
764 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100765
766 if (cSize == 0)
767 {
768 cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize); /* block is not compressible */
769 }
770 else
771 {
772 op[0] = (BYTE)(cSize>>16);
773 op[1] = (BYTE)(cSize>>8);
774 op[2] = (BYTE)cSize;
775 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
776 cSize += 3;
777 }
778
779 remaining -= blockSize;
Yann Collet3e358272015-11-04 18:19:39 +0100780 maxDstSize -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100781 ip += blockSize;
782 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100783 }
784
785 return op-ostart;
786}
787
788
Yann Collet2acb5d32015-10-29 16:49:43 +0100789size_t ZSTD_HC_compressContinue (ZSTD_HC_CCtx* ctxPtr,
790 void* dst, size_t dstSize,
791 const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +0100792{
Yann Collet2acb5d32015-10-29 16:49:43 +0100793 const BYTE* const ip = (const BYTE*) src;
Yann Colletf3eca252015-10-22 15:31:46 +0100794
795 /* Check if blocks follow each other */
Yann Collet2acb5d32015-10-29 16:49:43 +0100796 if (ip != ctxPtr->end)
Yann Colletf3eca252015-10-22 15:31:46 +0100797 {
Yann Collet2acb5d32015-10-29 16:49:43 +0100798 if (ctxPtr->end != NULL)
Yann Collet4114f952015-10-30 06:40:22 +0100799 ZSTD_HC_resetCCtx_advanced(ctxPtr, ctxPtr->params); /* just reset, but no need to re-alloc */
Yann Collet2acb5d32015-10-29 16:49:43 +0100800 ctxPtr->base = ip;
Yann Colletf3eca252015-10-22 15:31:46 +0100801 }
802
Yann Collet2acb5d32015-10-29 16:49:43 +0100803 ctxPtr->end = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100804 return ZSTD_HC_compress_generic (ctxPtr, dst, dstSize, src, srcSize);
805}
806
807
Yann Collet083fcc82015-10-25 14:06:35 +0100808size_t ZSTD_HC_compressBegin_advanced(ZSTD_HC_CCtx* ctx,
809 void* dst, size_t maxDstSize,
Yann Collet2acb5d32015-10-29 16:49:43 +0100810 const ZSTD_HC_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +0100811{
Yann Collet4114f952015-10-30 06:40:22 +0100812 size_t errorCode;
Yann Colletf3eca252015-10-22 15:31:46 +0100813 if (maxDstSize < 4) return ERROR(dstSize_tooSmall);
Yann Collet4114f952015-10-30 06:40:22 +0100814 errorCode = ZSTD_HC_resetCCtx_advanced(ctx, params);
815 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet2acb5d32015-10-29 16:49:43 +0100816 MEM_writeLE32(dst, ZSTD_magicNumber); /* Write Header */
Yann Colletf3eca252015-10-22 15:31:46 +0100817 return 4;
818}
819
Yann Collet083fcc82015-10-25 14:06:35 +0100820
Yann Collet2acb5d32015-10-29 16:49:43 +0100821size_t ZSTD_HC_compressBegin(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +0100822{
Yann Collet2acb5d32015-10-29 16:49:43 +0100823 if (compressionLevel<=0) compressionLevel = 1;
Yann Collet786f5b52015-10-26 15:45:58 +0100824 if (compressionLevel > ZSTD_HC_MAX_CLEVEL) compressionLevel = ZSTD_HC_MAX_CLEVEL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100825 return ZSTD_HC_compressBegin_advanced(ctx, dst, maxDstSize, ZSTD_HC_defaultParameters[compressionLevel]);
Yann Collet083fcc82015-10-25 14:06:35 +0100826}
827
828
Yann Collet2acb5d32015-10-29 16:49:43 +0100829size_t ZSTD_HC_compressEnd(ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize)
830{
831 BYTE* op = (BYTE*)dst;
832
833 /* Sanity check */
834 (void)ctx;
835 if (maxDstSize < 3) return ERROR(dstSize_tooSmall);
836
837 /* End of frame */
838 op[0] = (BYTE)(bt_end << 6);
839 op[1] = 0;
840 op[2] = 0;
841
842 return 3;
843}
844
Yann Collet083fcc82015-10-25 14:06:35 +0100845size_t ZSTD_HC_compress_advanced (ZSTD_HC_CCtx* ctx,
846 void* dst, size_t maxDstSize,
847 const void* src, size_t srcSize,
848 ZSTD_HC_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +0100849{
850 BYTE* const ostart = (BYTE*)dst;
851 BYTE* op = ostart;
Yann Collet4114f952015-10-30 06:40:22 +0100852 size_t oSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100853
Yann Collet71bcdb52015-10-29 17:08:03 +0100854 /* correct params, to use less memory */
855 U32 srcLog = ZSTD_highbit((U32)srcSize-1) + 1;
856 if (params.windowLog > srcLog) params.windowLog = srcLog;
857 if (params.chainLog > srcLog) params.chainLog = srcLog;
858
Yann Colletf3eca252015-10-22 15:31:46 +0100859 /* Header */
Yann Collet4114f952015-10-30 06:40:22 +0100860 oSize = ZSTD_HC_compressBegin_advanced(ctx, dst, maxDstSize, params);
Yann Colletf3eca252015-10-22 15:31:46 +0100861 if(ZSTD_isError(oSize)) return oSize;
862 op += oSize;
863 maxDstSize -= oSize;
864
865 /* body (compression) */
Yann Collet3d9cf7a2015-10-29 17:15:14 +0100866 ctx->base = (const BYTE*)src;
Yann Collet3e358272015-11-04 18:19:39 +0100867 oSize = ZSTD_HC_compress_generic (ctx, op, maxDstSize, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +0100868 if(ZSTD_isError(oSize)) return oSize;
869 op += oSize;
870 maxDstSize -= oSize;
871
872 /* Close frame */
Yann Collet2acb5d32015-10-29 16:49:43 +0100873 oSize = ZSTD_HC_compressEnd(ctx, op, maxDstSize);
Yann Colletf3eca252015-10-22 15:31:46 +0100874 if(ZSTD_isError(oSize)) return oSize;
875 op += oSize;
876
877 return (op - ostart);
878}
879
Yann Collet2acb5d32015-10-29 16:49:43 +0100880size_t ZSTD_HC_compressCCtx (ZSTD_HC_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +0100881{
Yann Collet2acb5d32015-10-29 16:49:43 +0100882 if (compressionLevel<=1) return ZSTD_compress(dst, maxDstSize, src, srcSize); /* fast mode */
Yann Collet786f5b52015-10-26 15:45:58 +0100883 if (compressionLevel > ZSTD_HC_MAX_CLEVEL) compressionLevel = ZSTD_HC_MAX_CLEVEL;
Yann Collet083fcc82015-10-25 14:06:35 +0100884 return ZSTD_HC_compress_advanced(ctx, dst, maxDstSize, src, srcSize, ZSTD_HC_defaultParameters[compressionLevel]);
885}
886
Yann Collet2acb5d32015-10-29 16:49:43 +0100887size_t ZSTD_HC_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +0100888{
Yann Collet44fe9912015-10-29 22:02:40 +0100889 size_t result;
Yann Collet712def92015-10-29 18:41:45 +0100890 ZSTD_HC_CCtx ctxBody;
891 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Collet44fe9912015-10-29 22:02:40 +0100892 result = ZSTD_HC_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel);
893 free(ctxBody.workSpace);
894 return result;
Yann Colletf3eca252015-10-22 15:31:46 +0100895}