blob: 8487ec58f95abe7accb30b9c78269a306ba3cf4f [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 Collet14983e72015-11-11 21:38:21 +010058#include "mem.h"
59#include "fse_static.h"
60#include "huff0.h"
Yann Colletf3eca252015-10-22 15:31:46 +010061#include "zstd_static.h"
Yann Collet3d9cf7a2015-10-29 17:15:14 +010062#include "zstd_internal.h"
Yann Colletf3eca252015-10-22 15:31:46 +010063
64
65/* *************************************
Yann Collet14983e72015-11-11 21:38:21 +010066* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010067***************************************/
Yann Colletecd651b2016-01-07 15:35:18 +010068ZSTDLIB_API unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet14983e72015-11-11 21:38:21 +010069static const U32 g_searchStrength = 8;
Yann Colletf3eca252015-10-22 15:31:46 +010070
Yann Colletf3eca252015-10-22 15:31:46 +010071
72/* *************************************
Yann Collet14983e72015-11-11 21:38:21 +010073* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010074***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010075typedef struct {
76 void* buffer;
77 U32* offsetStart;
78 U32* offset;
79 BYTE* offCodeStart;
80 BYTE* offCode;
81 BYTE* litStart;
82 BYTE* lit;
83 BYTE* litLengthStart;
84 BYTE* litLength;
85 BYTE* matchLengthStart;
86 BYTE* matchLength;
87 BYTE* dumpsStart;
88 BYTE* dumps;
89} seqStore_t;
90
91static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
92{
93 ssPtr->offset = ssPtr->offsetStart;
94 ssPtr->lit = ssPtr->litStart;
95 ssPtr->litLength = ssPtr->litLengthStart;
96 ssPtr->matchLength = ssPtr->matchLengthStart;
97 ssPtr->dumps = ssPtr->dumpsStart;
98}
99
100
101/* *************************************
102* Context memory management
103***************************************/
Yann Collet5be2dd22015-11-11 13:43:58 +0100104struct ZSTD_CCtx_s
Yann Colletf3eca252015-10-22 15:31:46 +0100105{
Yann Collet89db5e02015-11-13 11:27:46 +0100106 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100107 const BYTE* base; /* All regular indexes relative to this position */
108 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +0100109 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100110 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +0100111 U32 nextToUpdate; /* index from which to continue dictionary update */
Yann Colletecd651b2016-01-07 15:35:18 +0100112 U32 stage;
Yann Collet5be2dd22015-11-11 13:43:58 +0100113 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +0100114 void* workSpace;
115 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100116 size_t blockSize;
Yann Colletecd651b2016-01-07 15:35:18 +0100117 size_t hbSize;
Yann Collet60096272016-01-08 17:27:50 +0100118 char headerBuffer[ZSTD_frameHeaderSize_max];
Yann Colletecd651b2016-01-07 15:35:18 +0100119
Yann Collet712def92015-10-29 18:41:45 +0100120
121 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100122 U32* hashTable;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100123 U32* contentTable;
Yann Colletf3eca252015-10-22 15:31:46 +0100124};
125
126
Yann Collet5be2dd22015-11-11 13:43:58 +0100127ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100128{
Yann Collet5be2dd22015-11-11 13:43:58 +0100129 return (ZSTD_CCtx*) calloc(1, sizeof(ZSTD_CCtx));
Yann Colletf3eca252015-10-22 15:31:46 +0100130}
131
Yann Collet5be2dd22015-11-11 13:43:58 +0100132size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100133{
Yann Collet712def92015-10-29 18:41:45 +0100134 free(cctx->workSpace);
Yann Collet083fcc82015-10-25 14:06:35 +0100135 free(cctx);
136 return 0;
137}
138
Yann Collet59d70632015-11-04 12:05:27 +0100139
Yann Collet14983e72015-11-11 21:38:21 +0100140static unsigned ZSTD_highbit(U32 val);
141
Yann Collet5be2dd22015-11-11 13:43:58 +0100142/** ZSTD_validateParams
Yann Collet59d70632015-11-04 12:05:27 +0100143 correct params value to remain within authorized range
144 optimize for srcSize if srcSize > 0 */
Yann Collet88fcd292015-11-25 14:42:45 +0100145void ZSTD_validateParams(ZSTD_parameters* params)
Yann Collet59d70632015-11-04 12:05:27 +0100146{
Yann Collet5be2dd22015-11-11 13:43:58 +0100147 const U32 btPlus = (params->strategy == ZSTD_btlazy2);
Yann Collet59d70632015-11-04 12:05:27 +0100148
149 /* validate params */
Yann Collet00fd7a22015-11-28 16:03:22 +0100150 if (MEM_32bits()) if (params->windowLog > 25) params->windowLog = 25; /* 32 bits mode cannot flush > 24 bits */
Yann Collet5be2dd22015-11-11 13:43:58 +0100151 if (params->windowLog > ZSTD_WINDOWLOG_MAX) params->windowLog = ZSTD_WINDOWLOG_MAX;
152 if (params->windowLog < ZSTD_WINDOWLOG_MIN) params->windowLog = ZSTD_WINDOWLOG_MIN;
Yann Collet59d70632015-11-04 12:05:27 +0100153
154 /* correct params, to use less memory */
Yann Collet88fcd292015-11-25 14:42:45 +0100155 if ((params->srcSize > 0) && (params->srcSize < (1<<ZSTD_WINDOWLOG_MAX)))
Yann Collet59d70632015-11-04 12:05:27 +0100156 {
Yann Collet88fcd292015-11-25 14:42:45 +0100157 U32 srcLog = ZSTD_highbit((U32)(params->srcSize)-1) + 1;
Yann Collet59d70632015-11-04 12:05:27 +0100158 if (params->windowLog > srcLog) params->windowLog = srcLog;
159 }
160
Yann Collet00fd7a22015-11-28 16:03:22 +0100161 if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet5be2dd22015-11-11 13:43:58 +0100162 if (params->contentLog > params->windowLog+btPlus) params->contentLog = params->windowLog+btPlus; /* <= ZSTD_CONTENTLOG_MAX */
163 if (params->contentLog < ZSTD_CONTENTLOG_MIN) params->contentLog = ZSTD_CONTENTLOG_MIN;
164 if (params->hashLog > ZSTD_HASHLOG_MAX) params->hashLog = ZSTD_HASHLOG_MAX;
165 if (params->hashLog < ZSTD_HASHLOG_MIN) params->hashLog = ZSTD_HASHLOG_MIN;
166 if (params->searchLog > ZSTD_SEARCHLOG_MAX) params->searchLog = ZSTD_SEARCHLOG_MAX;
167 if (params->searchLog < ZSTD_SEARCHLOG_MIN) params->searchLog = ZSTD_SEARCHLOG_MIN;
168 if (params->searchLength> ZSTD_SEARCHLENGTH_MAX) params->searchLength = ZSTD_SEARCHLENGTH_MAX;
169 if (params->searchLength< ZSTD_SEARCHLENGTH_MIN) params->searchLength = ZSTD_SEARCHLENGTH_MIN;
170 if ((U32)params->strategy>(U32)ZSTD_btlazy2) params->strategy = ZSTD_btlazy2;
Yann Collet59d70632015-11-04 12:05:27 +0100171}
172
173
Yann Collet5be2dd22015-11-11 13:43:58 +0100174static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Collet88fcd292015-11-25 14:42:45 +0100175 ZSTD_parameters params)
Yann Collet083fcc82015-10-25 14:06:35 +0100176{
Yann Collet120230b2015-12-02 14:00:45 +0100177 /* note : params considered validated here */
178 const size_t blockSize = MIN(BLOCKSIZE, (size_t)1 << params.windowLog);
179
Yann Collet2acb5d32015-10-29 16:49:43 +0100180 /* reserve table memory */
Yann Collet083fcc82015-10-25 14:06:35 +0100181 {
Yann Collet743402c2015-11-20 12:03:53 +0100182 const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100183 const size_t tableSpace = ((1 << contentLog) + (1 << params.hashLog)) * sizeof(U32);
Yann Collet120230b2015-12-02 14:00:45 +0100184 const size_t neededSpace = tableSpace + (3*blockSize);
Yann Collet712def92015-10-29 18:41:45 +0100185 if (zc->workSpaceSize < neededSpace)
Yann Collet2acb5d32015-10-29 16:49:43 +0100186 {
Yann Collet712def92015-10-29 18:41:45 +0100187 free(zc->workSpace);
188 zc->workSpaceSize = neededSpace;
189 zc->workSpace = malloc(neededSpace);
Yann Collet4114f952015-10-30 06:40:22 +0100190 if (zc->workSpace == NULL) return ERROR(memory_allocation);
Yann Collet2acb5d32015-10-29 16:49:43 +0100191 }
Yann Collet805a52a2015-11-06 10:52:17 +0100192 memset(zc->workSpace, 0, tableSpace );
193 zc->hashTable = (U32*)(zc->workSpace);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100194 zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog);
195 zc->seqStore.buffer = (void*) (zc->contentTable + ((size_t)1 << contentLog));
Yann Collet083fcc82015-10-25 14:06:35 +0100196 }
Yann Collet083fcc82015-10-25 14:06:35 +0100197
Yann Colletf48e35c2015-11-07 01:13:31 +0100198 zc->nextToUpdate = 1;
Yann Collet89db5e02015-11-13 11:27:46 +0100199 zc->nextSrc = NULL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100200 zc->base = NULL;
201 zc->dictBase = NULL;
202 zc->dictLimit = 0;
203 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100204 zc->params = params;
Yann Collet120230b2015-12-02 14:00:45 +0100205 zc->blockSize = blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100206 zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer);
Yann Collet120230b2015-12-02 14:00:45 +0100207 zc->seqStore.offCodeStart = (BYTE*) (zc->seqStore.offsetStart + (blockSize>>2));
208 zc->seqStore.litStart = zc->seqStore.offCodeStart + (blockSize>>2);
209 zc->seqStore.litLengthStart = zc->seqStore.litStart + blockSize;
210 zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + (blockSize>>2);
211 zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (blockSize>>2);
Yann Colletecd651b2016-01-07 15:35:18 +0100212 zc->hbSize = 0;
Yann Collet60096272016-01-08 17:27:50 +0100213 zc->stage = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +0100214
Yann Collet4114f952015-10-30 06:40:22 +0100215 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100216}
217
Yann Collet083fcc82015-10-25 14:06:35 +0100218
Yann Collet88fcd292015-11-25 14:42:45 +0100219/** ZSTD_reduceIndex
220* rescale indexes to avoid future overflow (indexes are U32) */
Yann Collet89db5e02015-11-13 11:27:46 +0100221static void ZSTD_reduceIndex (ZSTD_CCtx* zc,
222 const U32 reducerValue)
223{
Yann Collet88fcd292015-11-25 14:42:45 +0100224 const U32 contentLog = (zc->params.strategy == ZSTD_fast) ? 1 : zc->params.contentLog;
Yann Collet89db5e02015-11-13 11:27:46 +0100225 const U32 tableSpaceU32 = (1 << contentLog) + (1 << zc->params.hashLog);
226 U32* table32 = zc->hashTable;
227 U32 index;
228
229 for (index=0 ; index < tableSpaceU32 ; index++)
230 {
231 if (table32[index] < reducerValue) table32[index] = 0;
232 else table32[index] -= reducerValue;
233 }
234}
235
236
Yann Collet14983e72015-11-11 21:38:21 +0100237/* *******************************************************
238* Block entropic compression
239*********************************************************/
240size_t ZSTD_compressBound(size_t srcSize) /* maximum compressed size */
241{
242 return FSE_compressBound(srcSize) + 12;
243}
244
245
246size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
247{
248 BYTE* const ostart = (BYTE* const)dst;
249
250 if (srcSize + ZSTD_blockHeaderSize > maxDstSize) return ERROR(dstSize_tooSmall);
251 memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
252
253 /* Build header */
254 ostart[0] = (BYTE)(srcSize>>16);
255 ostart[1] = (BYTE)(srcSize>>8);
256 ostart[2] = (BYTE) srcSize;
257 ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
258
259 return ZSTD_blockHeaderSize+srcSize;
260}
261
262
263static size_t ZSTD_noCompressLiterals (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
264{
265 BYTE* const ostart = (BYTE* const)dst;
266
267 if (srcSize + 3 > maxDstSize) return ERROR(dstSize_tooSmall);
268
269 MEM_writeLE32(dst, ((U32)srcSize << 2) | IS_RAW);
270 memcpy(ostart + 3, src, srcSize);
271 return srcSize + 3;
272}
273
274static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
275{
276 BYTE* const ostart = (BYTE* const)dst;
277
278 (void)maxDstSize;
279 MEM_writeLE32(dst, ((U32)srcSize << 2) | IS_RLE); /* note : maxDstSize > litHeaderSize > 4 */
280 ostart[3] = *(const BYTE*)src;
281 return 4;
282}
283
284size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 1; }
285
286static size_t ZSTD_compressLiterals (void* dst, size_t maxDstSize,
287 const void* src, size_t srcSize)
288{
289 const size_t minGain = ZSTD_minGain(srcSize);
290 BYTE* const ostart = (BYTE*)dst;
291 size_t hsize;
292 static const size_t litHeaderSize = 5;
293
294 if (maxDstSize < litHeaderSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
295
296 hsize = HUF_compress(ostart+litHeaderSize, maxDstSize-litHeaderSize, src, srcSize);
297
298 if ((hsize==0) || (hsize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, maxDstSize, src, srcSize);
299 if (hsize==1) return ZSTD_compressRleLiteralsBlock(dst, maxDstSize, src, srcSize);
300
301 /* Build header */
302 {
303 ostart[0] = (BYTE)(srcSize << 2); /* is a block, is compressed */
304 ostart[1] = (BYTE)(srcSize >> 6);
305 ostart[2] = (BYTE)(srcSize >>14);
306 ostart[2] += (BYTE)(hsize << 5);
307 ostart[3] = (BYTE)(hsize >> 3);
308 ostart[4] = (BYTE)(hsize >>11);
309 }
310
311 return hsize+litHeaderSize;
312}
313
314
315#define LITERAL_NOENTROPY 63 /* cheap heuristic */
316
Yann Collet5054ee02015-11-23 13:34:21 +0100317size_t ZSTD_compressSequences(void* dst, size_t maxDstSize,
Yann Collet14983e72015-11-11 21:38:21 +0100318 const seqStore_t* seqStorePtr,
319 size_t srcSize)
320{
321 U32 count[MaxSeq+1];
322 S16 norm[MaxSeq+1];
323 size_t mostFrequent;
324 U32 max = 255;
325 U32 tableLog = 11;
326 U32 CTable_LitLength [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL )];
327 U32 CTable_OffsetBits [FSE_CTABLE_SIZE_U32(OffFSELog,MaxOff)];
328 U32 CTable_MatchLength[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML )];
329 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
330 const BYTE* const op_lit_start = seqStorePtr->litStart;
331 const BYTE* const llTable = seqStorePtr->litLengthStart;
332 const BYTE* const llPtr = seqStorePtr->litLength;
333 const BYTE* const mlTable = seqStorePtr->matchLengthStart;
334 const U32* const offsetTable = seqStorePtr->offsetStart;
335 BYTE* const offCodeTable = seqStorePtr->offCodeStart;
Yann Collet5054ee02015-11-23 13:34:21 +0100336 BYTE* const ostart = (BYTE*)dst;
337 BYTE* op = ostart;
338 BYTE* const oend = ostart + maxDstSize;
Yann Collet14983e72015-11-11 21:38:21 +0100339 const size_t nbSeq = llPtr - llTable;
340 const size_t minGain = ZSTD_minGain(srcSize);
341 const size_t maxCSize = srcSize - minGain;
342 BYTE* seqHead;
343
344
345 /* Compress literals */
346 {
347 size_t cSize;
348 size_t litSize = seqStorePtr->lit - op_lit_start;
349
350 if (litSize <= LITERAL_NOENTROPY)
351 cSize = ZSTD_noCompressLiterals(op, maxDstSize, op_lit_start, litSize);
352 else
353 cSize = ZSTD_compressLiterals(op, maxDstSize, op_lit_start, litSize);
354 if (ZSTD_isError(cSize)) return cSize;
355 op += cSize;
356 }
357
358 /* Sequences Header */
359 if ((oend-op) < MIN_SEQUENCES_SIZE)
360 return ERROR(dstSize_tooSmall);
361 MEM_writeLE16(op, (U16)nbSeq); op+=2;
362 seqHead = op;
363
364 /* dumps : contains too large lengths */
365 {
366 size_t dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart;
367 if (dumpsLength < 512)
368 {
369 op[0] = (BYTE)(dumpsLength >> 8);
370 op[1] = (BYTE)(dumpsLength);
371 op += 2;
372 }
373 else
374 {
375 op[0] = 2;
376 op[1] = (BYTE)(dumpsLength>>8);
377 op[2] = (BYTE)(dumpsLength);
378 op += 3;
379 }
380 if ((size_t)(oend-op) < dumpsLength+6) return ERROR(dstSize_tooSmall);
381 memcpy(op, seqStorePtr->dumpsStart, dumpsLength);
382 op += dumpsLength;
383 }
384
385 /* CTable for Literal Lengths */
386 max = MaxLL;
387 mostFrequent = FSE_countFast(count, &max, seqStorePtr->litLengthStart, nbSeq);
388 if ((mostFrequent == nbSeq) && (nbSeq > 2))
389 {
390 *op++ = *(seqStorePtr->litLengthStart);
391 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
392 LLtype = bt_rle;
393 }
394 else if ((nbSeq < 64) || (mostFrequent < (nbSeq >> (LLbits-1))))
395 {
396 FSE_buildCTable_raw(CTable_LitLength, LLbits);
397 LLtype = bt_raw;
398 }
399 else
400 {
401 size_t NCountSize;
402 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
403 FSE_normalizeCount(norm, tableLog, count, nbSeq, max);
404 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
405 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
406 op += NCountSize;
407 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
408 LLtype = bt_compressed;
409 }
410
411 /* CTable for Offsets codes */
412 {
413 /* create Offset codes */
414 size_t i;
415 max = MaxOff;
416 for (i=0; i<nbSeq; i++)
417 {
418 offCodeTable[i] = (BYTE)ZSTD_highbit(offsetTable[i]) + 1;
419 if (offsetTable[i]==0) offCodeTable[i]=0;
420 }
421 mostFrequent = FSE_countFast(count, &max, offCodeTable, nbSeq);
422 }
423 if ((mostFrequent == nbSeq) && (nbSeq > 2))
424 {
425 *op++ = *offCodeTable;
426 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
427 Offtype = bt_rle;
428 }
429 else if ((nbSeq < 64) || (mostFrequent < (nbSeq >> (Offbits-1))))
430 {
431 FSE_buildCTable_raw(CTable_OffsetBits, Offbits);
432 Offtype = bt_raw;
433 }
434 else
435 {
436 size_t NCountSize;
437 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
438 FSE_normalizeCount(norm, tableLog, count, nbSeq, max);
439 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
440 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
441 op += NCountSize;
442 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
443 Offtype = bt_compressed;
444 }
445
446 /* CTable for MatchLengths */
447 max = MaxML;
448 mostFrequent = FSE_countFast(count, &max, seqStorePtr->matchLengthStart, nbSeq);
449 if ((mostFrequent == nbSeq) && (nbSeq > 2))
450 {
451 *op++ = *seqStorePtr->matchLengthStart;
452 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
453 MLtype = bt_rle;
454 }
455 else if ((nbSeq < 64) || (mostFrequent < (nbSeq >> (MLbits-1))))
456 {
457 FSE_buildCTable_raw(CTable_MatchLength, MLbits);
458 MLtype = bt_raw;
459 }
460 else
461 {
462 size_t NCountSize;
463 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
464 FSE_normalizeCount(norm, tableLog, count, nbSeq, max);
465 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
466 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
467 op += NCountSize;
468 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
469 MLtype = bt_compressed;
470 }
471
472 seqHead[0] += (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
473
474 /* Encoding Sequences */
475 {
476 size_t streamSize, errorCode;
477 BIT_CStream_t blockStream;
478 FSE_CState_t stateMatchLength;
479 FSE_CState_t stateOffsetBits;
480 FSE_CState_t stateLitLength;
481 int i;
482
483 errorCode = BIT_initCStream(&blockStream, op, oend-op);
484 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); /* not enough space remaining */
485 FSE_initCState(&stateMatchLength, CTable_MatchLength);
486 FSE_initCState(&stateOffsetBits, CTable_OffsetBits);
487 FSE_initCState(&stateLitLength, CTable_LitLength);
488
489 for (i=(int)nbSeq-1; i>=0; i--)
490 {
491 BYTE matchLength = mlTable[i];
492 U32 offset = offsetTable[i];
493 BYTE offCode = offCodeTable[i]; /* 32b*/ /* 64b*/
494 U32 nbBits = (offCode-1) * (!!offCode);
495 BYTE litLength = llTable[i]; /* (7)*/ /* (7)*/
496 FSE_encodeSymbol(&blockStream, &stateMatchLength, matchLength); /* 17 */ /* 17 */
Yann Collet743402c2015-11-20 12:03:53 +0100497 if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */
Yann Collet417890c2015-12-04 17:16:37 +0100498 BIT_addBits(&blockStream, offset, nbBits); /* 31 */ /* 42 */ /* 24 bits max in 32-bits mode */
Yann Collet743402c2015-11-20 12:03:53 +0100499 if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */
Yann Collet14983e72015-11-11 21:38:21 +0100500 FSE_encodeSymbol(&blockStream, &stateOffsetBits, offCode); /* 16 */ /* 51 */
501 FSE_encodeSymbol(&blockStream, &stateLitLength, litLength); /* 26 */ /* 61 */
502 BIT_flushBits(&blockStream); /* 7 */ /* 7 */
503 }
504
505 FSE_flushCState(&blockStream, &stateMatchLength);
506 FSE_flushCState(&blockStream, &stateOffsetBits);
507 FSE_flushCState(&blockStream, &stateLitLength);
508
509 streamSize = BIT_closeCStream(&blockStream);
510 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
511 op += streamSize;
512 }
513
514 /* check compressibility */
Yann Collet5054ee02015-11-23 13:34:21 +0100515 if ((size_t)(op-ostart) >= maxCSize) return 0;
Yann Collet14983e72015-11-11 21:38:21 +0100516
Yann Collet5054ee02015-11-23 13:34:21 +0100517 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100518}
519
520
521/** ZSTD_storeSeq
522 Store a sequence (literal length, literals, offset code and match length) into seqStore_t
523 @offsetCode : distance to match, or 0 == repCode
524 @matchCode : matchLength - MINMATCH
525*/
526MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode)
527{
528#if 0
529 static const BYTE* g_start = NULL;
530 if (g_start==NULL) g_start = literals;
531 if (literals - g_start == 8695)
532 printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n",
533 (U32)(literals - g_start), (U32)litLength, (U32)matchCode+4, (U32)offsetCode);
534#endif
535
536 /* copy Literals */
537 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
538 seqStorePtr->lit += litLength;
539
540 /* literal Length */
541 if (litLength >= MaxLL)
542 {
543 *(seqStorePtr->litLength++) = MaxLL;
544 if (litLength<255 + MaxLL)
545 *(seqStorePtr->dumps++) = (BYTE)(litLength - MaxLL);
546 else
547 {
548 *(seqStorePtr->dumps++) = 255;
549 MEM_writeLE32(seqStorePtr->dumps, (U32)litLength); seqStorePtr->dumps += 3;
550 }
551 }
552 else *(seqStorePtr->litLength++) = (BYTE)litLength;
553
554 /* match offset */
555 *(seqStorePtr->offset++) = (U32)offsetCode;
556
557 /* match Length */
558 if (matchCode >= MaxML)
559 {
560 *(seqStorePtr->matchLength++) = MaxML;
561 if (matchCode < 255+MaxML)
562 *(seqStorePtr->dumps++) = (BYTE)(matchCode - MaxML);
563 else
564 {
565 *(seqStorePtr->dumps++) = 255;
566 MEM_writeLE32(seqStorePtr->dumps, (U32)matchCode); seqStorePtr->dumps += 3;
567 }
568 }
569 else *(seqStorePtr->matchLength++) = (BYTE)matchCode;
570}
571
572
Yann Colletf3eca252015-10-22 15:31:46 +0100573/* *************************************
Yann Collet14983e72015-11-11 21:38:21 +0100574* Match length counter
575***************************************/
576static size_t ZSTD_read_ARCH(const void* p) { size_t r; memcpy(&r, p, sizeof(r)); return r; }
577
578static unsigned ZSTD_highbit(U32 val)
579{
580# if defined(_MSC_VER) /* Visual */
581 unsigned long r=0;
582 _BitScanReverse(&r, val);
583 return (unsigned)r;
584# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
585 return 31 - __builtin_clz(val);
586# else /* Software version */
587 static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
588 U32 v = val;
589 int r;
590 v |= v >> 1;
591 v |= v >> 2;
592 v |= v >> 4;
593 v |= v >> 8;
594 v |= v >> 16;
595 r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];
596 return r;
597# endif
598}
599
Yann Collet5054ee02015-11-23 13:34:21 +0100600static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100601{
602 if (MEM_isLittleEndian())
603 {
604 if (MEM_64bits())
605 {
606# if defined(_MSC_VER) && defined(_WIN64)
607 unsigned long r = 0;
608 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100609 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100610# elif defined(__GNUC__) && (__GNUC__ >= 3)
611 return (__builtin_ctzll((U64)val) >> 3);
612# else
613 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 };
614 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
615# endif
616 }
617 else /* 32 bits */
618 {
619# if defined(_MSC_VER)
620 unsigned long r=0;
621 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100622 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100623# elif defined(__GNUC__) && (__GNUC__ >= 3)
624 return (__builtin_ctz((U32)val) >> 3);
625# else
626 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 };
627 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
628# endif
629 }
630 }
631 else /* Big Endian CPU */
632 {
Peter Harrisf06e2382015-12-01 14:58:24 -0500633 if (MEM_64bits())
Yann Collet14983e72015-11-11 21:38:21 +0100634 {
635# if defined(_MSC_VER) && defined(_WIN64)
636 unsigned long r = 0;
637 _BitScanReverse64( &r, val );
638 return (unsigned)(r>>3);
639# elif defined(__GNUC__) && (__GNUC__ >= 3)
640 return (__builtin_clzll(val) >> 3);
641# else
642 unsigned r;
643 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
644 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
645 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
646 r += (!val);
647 return r;
648# endif
649 }
650 else /* 32 bits */
651 {
652# if defined(_MSC_VER)
653 unsigned long r = 0;
654 _BitScanReverse( &r, (unsigned long)val );
655 return (unsigned)(r>>3);
656# elif defined(__GNUC__) && (__GNUC__ >= 3)
657 return (__builtin_clz((U32)val) >> 3);
658# else
659 unsigned r;
660 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
661 r += (!val);
662 return r;
663# endif
664 }
665 }
666}
667
668
Yann Collet5054ee02015-11-23 13:34:21 +0100669static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100670{
671 const BYTE* const pStart = pIn;
672
673 while ((pIn<pInLimit-(sizeof(size_t)-1)))
674 {
675 size_t diff = ZSTD_read_ARCH(pMatch) ^ ZSTD_read_ARCH(pIn);
676 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
677 pIn += ZSTD_NbCommonBytes(diff);
678 return (size_t)(pIn - pStart);
679 }
680
681 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
682 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
683 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
684 return (size_t)(pIn - pStart);
685}
686
Yann Collet5054ee02015-11-23 13:34:21 +0100687/** ZSTD_count_2segments
688* can count match length with ip & match in potentially 2 different segments.
689* convention : on reaching mEnd, match count continue starting from iStart
690*/
691static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
692{
693 size_t matchLength;
694 const BYTE* vEnd = ip + (mEnd - match);
695 if (vEnd > iEnd) vEnd = iEnd;
696 matchLength = ZSTD_count(ip, match, vEnd);
697 if (match + matchLength == mEnd)
698 matchLength += ZSTD_count(ip+matchLength, iStart, iEnd);
699 return matchLength;
700}
701
Yann Collet14983e72015-11-11 21:38:21 +0100702
703
704/* *************************************
705* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100706***************************************/
Yann Collet2acb5d32015-10-29 16:49:43 +0100707
Yann Collet4b100f42015-10-30 15:49:48 +0100708static const U32 prime4bytes = 2654435761U;
Yann Collet5be2dd22015-11-11 13:43:58 +0100709static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
710static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100711
Yann Collet4b100f42015-10-30 15:49:48 +0100712static const U64 prime5bytes = 889523592379ULL;
Yann Collet5be2dd22015-11-11 13:43:58 +0100713static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)((u * prime5bytes) << (64-40) >> (64-h)) ; }
714static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_read64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100715
716static const U64 prime6bytes = 227718039650203ULL;
Yann Collet5be2dd22015-11-11 13:43:58 +0100717static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)((u * prime6bytes) << (64-48) >> (64-h)) ; }
718static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_read64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100719
Yann Collet14983e72015-11-11 21:38:21 +0100720static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet5be2dd22015-11-11 13:43:58 +0100721static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)((u * prime7bytes) << (64-56) >> (64-h)) ; }
722static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_read64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100723
Yann Collet5be2dd22015-11-11 13:43:58 +0100724static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100725{
726 switch(mls)
727 {
728 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100729 case 4: return ZSTD_hash4Ptr(p, hBits);
730 case 5: return ZSTD_hash5Ptr(p, hBits);
731 case 6: return ZSTD_hash6Ptr(p, hBits);
732 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100733 }
734}
Yann Collet2acb5d32015-10-29 16:49:43 +0100735
Yann Collet1f44b3f2015-11-05 17:32:18 +0100736/* *************************************
737* Fast Scan
738***************************************/
739
Yann Collet417890c2015-12-04 17:16:37 +0100740#define FILLHASHSTEP 3
741static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
742{
743 U32* const hashTable = zc->hashTable;
744 const U32 hBits = zc->params.hashLog;
745 const BYTE* const base = zc->base;
746 const BYTE* ip = base + zc->nextToUpdate;
747 const BYTE* const iend = (const BYTE*) end;
748
749 while(ip <= iend)
750 {
751 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
752 ip += FILLHASHSTEP;
753 }
754}
755
756
Yann Collet1f44b3f2015-11-05 17:32:18 +0100757FORCE_INLINE
Yann Colletc3652152015-11-24 14:06:07 +0100758size_t ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc,
Yann Collet89db5e02015-11-13 11:27:46 +0100759 void* dst, size_t maxDstSize,
760 const void* src, size_t srcSize,
761 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100762{
Yann Collet417890c2015-12-04 17:16:37 +0100763 U32* const hashTable = zc->hashTable;
Yann Colletc3652152015-11-24 14:06:07 +0100764 const U32 hBits = zc->params.hashLog;
765 seqStore_t* seqStorePtr = &(zc->seqStore);
766 const BYTE* const base = zc->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100767 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100768 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100769 const BYTE* anchor = istart;
Yann Colletd94efbf2015-12-29 14:29:08 +0100770 const U32 lowIndex = zc->dictLimit;
771 const BYTE* const lowest = base + lowIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100772 const BYTE* const iend = istart + srcSize;
773 const BYTE* const ilimit = iend - 8;
774
Yann Collet89db5e02015-11-13 11:27:46 +0100775 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100776
777
778 /* init */
Yann Collet743402c2015-11-20 12:03:53 +0100779 ZSTD_resetSeqStore(seqStorePtr);
Yann Collete47c4e52015-12-05 09:23:53 +0100780 if (ip < lowest+4)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100781 {
Yann Colletd94efbf2015-12-29 14:29:08 +0100782 hashTable[ZSTD_hashPtr(lowest+1, hBits, mls)] = lowIndex+1;
783 hashTable[ZSTD_hashPtr(lowest+2, hBits, mls)] = lowIndex+2;
784 hashTable[ZSTD_hashPtr(lowest+3, hBits, mls)] = lowIndex+3;
Yann Collete47c4e52015-12-05 09:23:53 +0100785 ip = lowest+4;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100786 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100787
788 /* Main Search Loop */
Yann Collet743402c2015-11-20 12:03:53 +0100789 while (ip < ilimit) /* < instead of <=, because repcode check at (ip+1) */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100790 {
Yann Collet5054ee02015-11-23 13:34:21 +0100791 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +0100792 size_t offset;
Yann Collet5be2dd22015-11-11 13:43:58 +0100793 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Colletd94efbf2015-12-29 14:29:08 +0100794 const U32 matchIndex = hashTable[h];
795 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +0100796 const U32 current = (U32)(ip-base);
797 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100798
Yann Colletecd651b2016-01-07 15:35:18 +0100799 if (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)) /* note : by construction, offset_1 <= current */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100800 {
Yann Collet5054ee02015-11-23 13:34:21 +0100801 mlCode = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +0100802 ip++;
803 offset = 0;
804 }
805 else
806 {
Yann Colletd94efbf2015-12-29 14:29:08 +0100807 if ( (matchIndex <= lowIndex) ||
Yann Collet402fdcf2015-11-20 12:46:08 +0100808 (MEM_read32(match) != MEM_read32(ip)) )
809 {
810 ip += ((ip-anchor) >> g_searchStrength) + 1;
811 continue;
812 }
Yann Collet5054ee02015-11-23 13:34:21 +0100813 mlCode = ZSTD_count(ip+MINMATCH, match+MINMATCH, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +0100814 offset = ip-match;
Yann Collet5054ee02015-11-23 13:34:21 +0100815 while ((ip>anchor) && (match>lowest) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +0100816 offset_2 = offset_1;
817 offset_1 = offset;
818 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100819
Yann Collet402fdcf2015-11-20 12:46:08 +0100820 /* match found */
Yann Collet6bcdeac2015-11-26 11:43:00 +0100821 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +0100822 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +0100823 anchor = ip;
824
825 if (ip <= ilimit)
826 {
827 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +0100828 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2; /* here because current+2 could be > iend-8 */
Yann Collet402fdcf2015-11-20 12:46:08 +0100829 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
830 /* check immediate repcode */
831 while ( (ip <= ilimit)
832 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) )
833 {
834 /* store sequence */
Yann Collet06eade52015-11-23 14:23:47 +0100835 size_t rlCode = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +0100836 size_t tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
837 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Collet06eade52015-11-23 14:23:47 +0100838 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rlCode);
839 ip += rlCode+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +0100840 anchor = ip;
841 continue; /* faster when present ... (?) */
842 }
843 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100844 }
845
846 /* Last Literals */
847 {
848 size_t lastLLSize = iend - anchor;
849 memcpy(seqStorePtr->lit, anchor, lastLLSize);
850 seqStorePtr->lit += lastLLSize;
851 }
852
853 /* Finale compression stage */
Yann Collet5054ee02015-11-23 13:34:21 +0100854 return ZSTD_compressSequences(dst, maxDstSize,
Yann Collet1f44b3f2015-11-05 17:32:18 +0100855 seqStorePtr, srcSize);
856}
857
858
Yann Collet5be2dd22015-11-11 13:43:58 +0100859size_t ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet1f44b3f2015-11-05 17:32:18 +0100860 void* dst, size_t maxDstSize,
861 const void* src, size_t srcSize)
862{
863 const U32 mls = ctx->params.searchLength;
864 switch(mls)
865 {
866 default:
867 case 4 :
Yann Collet5be2dd22015-11-11 13:43:58 +0100868 return ZSTD_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 4);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100869 case 5 :
Yann Collet5be2dd22015-11-11 13:43:58 +0100870 return ZSTD_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 5);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100871 case 6 :
Yann Collet5be2dd22015-11-11 13:43:58 +0100872 return ZSTD_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 6);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100873 case 7 :
Yann Collet5be2dd22015-11-11 13:43:58 +0100874 return ZSTD_compressBlock_fast_generic(ctx, dst, maxDstSize, src, srcSize, 7);
Yann Collet1f44b3f2015-11-05 17:32:18 +0100875 }
876}
Yann Colletf3eca252015-10-22 15:31:46 +0100877
Yann Colletf3eca252015-10-22 15:31:46 +0100878
Yann Collet93a823c2015-11-13 15:08:43 +0100879//FORCE_INLINE
Yann Collet89db5e02015-11-13 11:27:46 +0100880size_t ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
881 void* dst, size_t maxDstSize,
882 const void* src, size_t srcSize,
883 const U32 mls)
884{
885 U32* hashTable = ctx->hashTable;
886 const U32 hBits = ctx->params.hashLog;
887 seqStore_t* seqStorePtr = &(ctx->seqStore);
888 const BYTE* const base = ctx->base;
889 const BYTE* const dictBase = ctx->dictBase;
890 const BYTE* const istart = (const BYTE*)src;
891 const BYTE* ip = istart;
892 const BYTE* anchor = istart;
893 const U32 lowLimit = ctx->lowLimit;
Yann Collet5054ee02015-11-23 13:34:21 +0100894 const BYTE* const dictStart = dictBase + lowLimit;
Yann Collet89db5e02015-11-13 11:27:46 +0100895 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +0100896 const BYTE* const lowPrefixPtr = base + dictLimit;
897 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +0100898 const BYTE* const iend = istart + srcSize;
899 const BYTE* const ilimit = iend - 8;
900
Yann Collet138e89c2015-11-17 14:26:54 +0100901 U32 offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +0100902
903
904 /* init */
905 ZSTD_resetSeqStore(seqStorePtr);
906 {
907 /* skip first 4 positions to avoid read overflow during repcode match check */
908 hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0);
909 hashTable[ZSTD_hashPtr(ip+1, hBits, mls)] = (U32)(ip-base+1);
910 hashTable[ZSTD_hashPtr(ip+2, hBits, mls)] = (U32)(ip-base+2);
911 hashTable[ZSTD_hashPtr(ip+3, hBits, mls)] = (U32)(ip-base+3);
912 ip += 4;
913 }
914
915 /* Main Search Loop */
Yann Collet743402c2015-11-20 12:03:53 +0100916 while (ip < ilimit) /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +0100917 {
918 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +0100919 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +0100920 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +0100921 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +0100922 const U32 current = (U32)(ip-base);
Yann Collet743402c2015-11-20 12:03:53 +0100923 const U32 repIndex = current + 1 - offset_1;
Yann Collet402fdcf2015-11-20 12:46:08 +0100924 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +0100925 const BYTE* repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +0100926 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +0100927 U32 offset;
Yann Collet89db5e02015-11-13 11:27:46 +0100928 hashTable[h] = current; /* update hash table */
929
930 if ( ((repIndex <= dictLimit-4) || (repIndex >= dictLimit))
Yann Collet743402c2015-11-20 12:03:53 +0100931 && (MEM_read32(repMatch) == MEM_read32(ip+1)) )
Yann Collet89db5e02015-11-13 11:27:46 +0100932 {
Yann Collet402fdcf2015-11-20 12:46:08 +0100933 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +0100934 mlCode = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repMatchEnd, lowPrefixPtr);
Yann Collet743402c2015-11-20 12:03:53 +0100935 ip++;
Yann Collet402fdcf2015-11-20 12:46:08 +0100936 offset = 0;
937 }
938 else
939 {
940 if ( (matchIndex < lowLimit) ||
941 (MEM_read32(match) != MEM_read32(ip)) )
942 { ip += ((ip-anchor) >> g_searchStrength) + 1; continue; }
943 {
944 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +0100945 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
946 mlCode = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iend, matchEnd, lowPrefixPtr);
947 while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +0100948 offset = current - matchIndex;
949 offset_2 = offset_1;
950 offset_1 = offset;
951 }
952 }
Yann Collet89db5e02015-11-13 11:27:46 +0100953
Yann Collet5054ee02015-11-23 13:34:21 +0100954 /* found a match : store it */
955 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +0100956 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +0100957 anchor = ip;
958
959 if (ip <= ilimit)
960 {
Yann Collet6bcdeac2015-11-26 11:43:00 +0100961 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +0100962 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +0100963 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
964 /* check immediate repcode */
965 while (ip <= ilimit)
966 {
967 U32 current2 = (U32)(ip-base);
968 const U32 repIndex2 = current2 - offset_2;
969 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet743402c2015-11-20 12:03:53 +0100970 if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit))
971 && (MEM_read32(repMatch2) == MEM_read32(ip)) )
Yann Collet402fdcf2015-11-20 12:46:08 +0100972 {
Yann Collet5054ee02015-11-23 13:34:21 +0100973 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
974 size_t repLength2 = ZSTD_count_2segments(ip+MINMATCH, repMatch2+MINMATCH, iend, repEnd2, lowPrefixPtr);
975 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
976 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2);
977 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
978 ip += repLength2+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +0100979 anchor = ip;
980 continue;
981 }
Yann Collet743402c2015-11-20 12:03:53 +0100982 break;
Yann Collet402fdcf2015-11-20 12:46:08 +0100983 }
984 }
Yann Collet89db5e02015-11-13 11:27:46 +0100985 }
986
987 /* Last Literals */
988 {
989 size_t lastLLSize = iend - anchor;
990 memcpy(seqStorePtr->lit, anchor, lastLLSize);
991 seqStorePtr->lit += lastLLSize;
992 }
993
994 /* Finale compression stage */
Yann Collet5054ee02015-11-23 13:34:21 +0100995 return ZSTD_compressSequences(dst, maxDstSize,
Yann Collet89db5e02015-11-13 11:27:46 +0100996 seqStorePtr, srcSize);
997}
998
999
1000size_t ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
1001 void* dst, size_t maxDstSize,
1002 const void* src, size_t srcSize)
1003{
1004 const U32 mls = ctx->params.searchLength;
1005 switch(mls)
1006 {
1007 default:
1008 case 4 :
1009 return ZSTD_compressBlock_fast_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 4);
1010 case 5 :
1011 return ZSTD_compressBlock_fast_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 5);
1012 case 6 :
1013 return ZSTD_compressBlock_fast_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 6);
1014 case 7 :
1015 return ZSTD_compressBlock_fast_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 7);
1016 }
1017}
1018
1019
Yann Colletf3eca252015-10-22 15:31:46 +01001020/* *************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001021* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001022***************************************/
Yann Collet1358f912016-01-01 07:29:39 +01001023/** ZSTD_insertBt1 : add one or multiple positions to tree
Yann Collet6bcdeac2015-11-26 11:43:00 +01001024* @ip : assumed <= iend-8
Yann Collet06eade52015-11-23 14:23:47 +01001025* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001026static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1027 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001028{
1029 U32* const hashTable = zc->hashTable;
1030 const U32 hashLog = zc->params.hashLog;
Yann Collet5be2dd22015-11-11 13:43:58 +01001031 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet1f44b3f2015-11-05 17:32:18 +01001032 U32* const bt = zc->contentTable;
1033 const U32 btLog = zc->params.contentLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001034 const U32 btMask= (1 << btLog) - 1;
1035 U32 matchIndex = hashTable[h];
1036 size_t commonLengthSmaller=0, commonLengthLarger=0;
1037 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001038 const BYTE* const dictBase = zc->dictBase;
1039 const U32 dictLimit = zc->dictLimit;
1040 const BYTE* const dictEnd = dictBase + dictLimit;
1041 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001042 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001043 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001044 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001045 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001046 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001047 U32 dummy32; /* to be nullified at the end */
Yann Collet03526e12015-11-23 15:29:15 +01001048 const U32 windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001049 U32 matchEndIdx = current+8;
Yann Collet7beaa052016-01-21 11:57:45 +01001050 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1051 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1052 predictedSmall += (predictedSmall>0);
1053 predictedLarge += (predictedLarge>0);
Yann Colletf48e35c2015-11-07 01:13:31 +01001054
Yann Collet6c3e2e72015-12-11 10:44:07 +01001055 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001056
1057 while (nbCompares-- && (matchIndex > windowLow))
1058 {
1059 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001060 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001061 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1062
Yann Colleta87278a2016-01-17 00:12:55 +01001063 if (matchIndex == predictedSmall)
1064 { /* no need to check length, result known */
1065 *smallerPtr = matchIndex;
1066 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1067 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1068 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001069 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001070 continue;
1071 }
1072
1073 if (matchIndex == predictedLarge)
1074 {
1075 *largerPtr = matchIndex;
1076 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1077 largerPtr = nextPtr;
1078 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001079 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001080 continue;
1081 }
1082
Yann Collet1358f912016-01-01 07:29:39 +01001083 if ((!extDict) || (matchIndex+matchLength >= dictLimit))
1084 {
1085 match = base + matchIndex;
1086 if (match[matchLength] == ip[matchLength])
1087 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
1088 }
1089 else
1090 {
1091 match = dictBase + matchIndex;
1092 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1093 if (matchIndex+matchLength >= dictLimit)
1094 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1095 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001096
Yann Colletee3f4512015-12-29 22:26:09 +01001097 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001098 matchEndIdx = matchIndex + (U32)matchLength;
Yann Colletee3f4512015-12-29 22:26:09 +01001099
Yann Collet59d70632015-11-04 12:05:27 +01001100 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001101 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001102
Yann Collet1358f912016-01-01 07:29:39 +01001103 if (match[matchLength] < ip[matchLength]) /* necessarily within correct buffer */
Yann Collet59d70632015-11-04 12:05:27 +01001104 {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001105 /* match is smaller than current */
1106 *smallerPtr = matchIndex; /* update smaller idx */
1107 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001108 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001109 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001110 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet59d70632015-11-04 12:05:27 +01001111 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001112 else
Yann Collet59d70632015-11-04 12:05:27 +01001113 {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001114 /* match is larger than current */
1115 *largerPtr = matchIndex;
1116 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001117 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001118 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001119 matchIndex = nextPtr[0];
Yann Collet59d70632015-11-04 12:05:27 +01001120 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001121 }
1122
Yann Collet59d70632015-11-04 12:05:27 +01001123 *smallerPtr = *largerPtr = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001124 return (matchEndIdx > current + 8) ? matchEndIdx - current - 8 : 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001125}
1126
1127
Yann Colletee3f4512015-12-29 22:26:09 +01001128static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001129{
1130 const BYTE* const base = zc->base;
1131 const U32 target = (U32)(ip - base);
1132 U32 idx = zc->nextToUpdate;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001133
Yann Colletf48e35c2015-11-07 01:13:31 +01001134 for( ; idx < target ; )
Yann Collet1358f912016-01-01 07:29:39 +01001135 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001136}
1137
Yann Collet96b9f0b2015-11-04 03:52:54 +01001138FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Collet2cc12cb2016-01-01 07:47:58 +01001139size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001140 ZSTD_CCtx* zc,
1141 const BYTE* const ip, const BYTE* const iend,
1142 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001143 U32 nbCompares, const U32 mls,
1144 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001145{
1146 U32* const hashTable = zc->hashTable;
1147 const U32 hashLog = zc->params.hashLog;
1148 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
1149 U32* const bt = zc->contentTable;
1150 const U32 btLog = zc->params.contentLog - 1;
1151 const U32 btMask= (1 << btLog) - 1;
1152 U32 matchIndex = hashTable[h];
1153 size_t commonLengthSmaller=0, commonLengthLarger=0;
1154 const BYTE* const base = zc->base;
1155 const BYTE* const dictBase = zc->dictBase;
1156 const U32 dictLimit = zc->dictLimit;
1157 const BYTE* const dictEnd = dictBase + dictLimit;
1158 const BYTE* const prefixStart = base + dictLimit;
1159 const U32 current = (U32)(ip-base);
1160 const U32 btLow = btMask >= current ? 0 : current - btMask;
1161 const U32 windowLow = zc->lowLimit;
1162 U32* smallerPtr = bt + 2*(current&btMask);
1163 U32* largerPtr = bt + 2*(current&btMask) + 1;
1164 size_t bestLength = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001165 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001166 U32 dummy32; /* to be nullified at the end */
1167
Yann Collet6c3e2e72015-12-11 10:44:07 +01001168 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001169
1170 while (nbCompares-- && (matchIndex > windowLow))
1171 {
1172 U32* nextPtr = bt + 2*(matchIndex & btMask);
1173 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1174 const BYTE* match;
1175
Yann Collet2cc12cb2016-01-01 07:47:58 +01001176 if ((!extDict) || (matchIndex+matchLength >= dictLimit))
Yann Collet03526e12015-11-23 15:29:15 +01001177 {
1178 match = base + matchIndex;
1179 if (match[matchLength] == ip[matchLength])
1180 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
1181 }
1182 else
1183 {
1184 match = dictBase + matchIndex;
1185 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001186 if (matchIndex+matchLength >= dictLimit)
1187 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001188 }
1189
1190 if (matchLength > bestLength)
1191 {
Yann Colletee3f4512015-12-29 22:26:09 +01001192 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001193 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet03526e12015-11-23 15:29:15 +01001194 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
1195 bestLength = matchLength, *offsetPtr = current - matchIndex;
1196 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1197 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1198 }
1199
1200 if (match[matchLength] < ip[matchLength])
1201 {
1202 /* match is smaller than current */
1203 *smallerPtr = matchIndex; /* update smaller idx */
1204 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1205 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1206 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1207 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
1208 }
1209 else
1210 {
1211 /* match is larger than current */
1212 *largerPtr = matchIndex;
1213 commonLengthLarger = matchLength;
1214 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1215 largerPtr = nextPtr;
1216 matchIndex = nextPtr[0];
1217 }
1218 }
1219
1220 *smallerPtr = *largerPtr = 0;
1221
Yann Collet72e84cf2015-12-31 19:08:44 +01001222 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
Yann Collet03526e12015-11-23 15:29:15 +01001223 return bestLength;
1224}
1225
Yann Collet2cc12cb2016-01-01 07:47:58 +01001226
1227/** Tree updater, providing best match */
1228FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1229size_t ZSTD_BtFindBestMatch (
1230 ZSTD_CCtx* zc,
1231 const BYTE* const ip, const BYTE* const iLimit,
1232 size_t* offsetPtr,
1233 const U32 maxNbAttempts, const U32 mls)
1234{
1235 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1236 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
1237 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1238}
1239
1240
1241FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS (
1242 ZSTD_CCtx* zc, /* Index table will be updated */
1243 const BYTE* ip, const BYTE* const iLimit,
1244 size_t* offsetPtr,
1245 const U32 maxNbAttempts, const U32 matchLengthSearch)
1246{
1247 switch(matchLengthSearch)
1248 {
1249 default :
1250 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1251 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1252 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1253 }
1254}
1255
1256
1257static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1258{
1259 const BYTE* const base = zc->base;
1260 const U32 target = (U32)(ip - base);
1261 U32 idx = zc->nextToUpdate;
1262
1263 for( ; idx < target ; )
1264 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1265}
1266
1267
Yann Collet03526e12015-11-23 15:29:15 +01001268/** Tree updater, providing best match */
1269FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1270size_t ZSTD_BtFindBestMatch_extDict (
1271 ZSTD_CCtx* zc,
1272 const BYTE* const ip, const BYTE* const iLimit,
1273 size_t* offsetPtr,
1274 const U32 maxNbAttempts, const U32 mls)
1275{
Yann Colletee3f4512015-12-29 22:26:09 +01001276 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1277 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001278 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001279}
1280
1281
1282FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
1283 ZSTD_CCtx* zc, /* Index table will be updated */
1284 const BYTE* ip, const BYTE* const iLimit,
1285 size_t* offsetPtr,
1286 const U32 maxNbAttempts, const U32 matchLengthSearch)
1287{
1288 switch(matchLengthSearch)
1289 {
1290 default :
1291 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1292 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1293 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1294 }
1295}
1296
1297
Yann Collet5106a762015-11-05 15:00:24 +01001298/* ***********************
1299* Hash Chain
1300*************************/
1301
Yann Collet1f44b3f2015-11-05 17:32:18 +01001302#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1303
Yann Collet6bcdeac2015-11-26 11:43:00 +01001304/* Update chains up to ip (excluded)
Yann Collet06eade52015-11-23 14:23:47 +01001305 Assumption : always within prefix (ie. not within extDict) */
1306static U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
Yann Collet5106a762015-11-05 15:00:24 +01001307{
1308 U32* const hashTable = zc->hashTable;
1309 const U32 hashLog = zc->params.hashLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001310 U32* const chainTable = zc->contentTable;
1311 const U32 chainMask = (1 << zc->params.contentLog) - 1;
Yann Collet5106a762015-11-05 15:00:24 +01001312 const BYTE* const base = zc->base;
1313 const U32 target = (U32)(ip - base);
1314 U32 idx = zc->nextToUpdate;
1315
1316 while(idx < target)
1317 {
Yann Collet5be2dd22015-11-11 13:43:58 +01001318 size_t h = ZSTD_hashPtr(base+idx, hashLog, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001319 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1320 hashTable[h] = idx;
1321 idx++;
1322 }
1323
1324 zc->nextToUpdate = target;
Yann Collet5be2dd22015-11-11 13:43:58 +01001325 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
Yann Collet5106a762015-11-05 15:00:24 +01001326}
1327
1328
1329FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Colletc1e52f02015-11-23 14:37:59 +01001330size_t ZSTD_HcFindBestMatch_generic (
Yann Collet5be2dd22015-11-11 13:43:58 +01001331 ZSTD_CCtx* zc, /* Index table will be updated */
Yann Collet5106a762015-11-05 15:00:24 +01001332 const BYTE* const ip, const BYTE* const iLimit,
1333 size_t* offsetPtr,
Yann Colletc1e52f02015-11-23 14:37:59 +01001334 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
Yann Collet287b7d92015-11-22 13:24:05 +01001335{
Yann Collet1f44b3f2015-11-05 17:32:18 +01001336 U32* const chainTable = zc->contentTable;
1337 const U32 chainSize = (1 << zc->params.contentLog);
Yann Collet5106a762015-11-05 15:00:24 +01001338 const U32 chainMask = chainSize-1;
1339 const BYTE* const base = zc->base;
1340 const BYTE* const dictBase = zc->dictBase;
1341 const U32 dictLimit = zc->dictLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001342 const BYTE* const prefixStart = base + dictLimit;
1343 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001344 const U32 lowLimit = zc->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001345 const U32 current = (U32)(ip-base);
1346 const U32 minChain = current > chainSize ? current - chainSize : 0;
Yann Collet5106a762015-11-05 15:00:24 +01001347 U32 matchIndex;
1348 const BYTE* match;
1349 int nbAttempts=maxNbAttempts;
Yann Collet5054ee02015-11-23 13:34:21 +01001350 size_t ml=MINMATCH-1;
Yann Collet5106a762015-11-05 15:00:24 +01001351
1352 /* HC4 match finder */
Yann Colletc1e52f02015-11-23 14:37:59 +01001353 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001354
1355 while ((matchIndex>lowLimit) && (nbAttempts))
1356 {
Yann Collet5054ee02015-11-23 13:34:21 +01001357 size_t currentMl=0;
Yann Collet5106a762015-11-05 15:00:24 +01001358 nbAttempts--;
Yann Colletc1e52f02015-11-23 14:37:59 +01001359 if ((!extDict) || matchIndex >= dictLimit)
Yann Collet5106a762015-11-05 15:00:24 +01001360 {
1361 match = base + matchIndex;
Yann Collet4baee502015-11-09 03:19:33 +01001362 if (match[ml] == ip[ml]) /* potentially better */
Yann Collet5054ee02015-11-23 13:34:21 +01001363 currentMl = ZSTD_count(ip, match, iLimit);
Yann Collet5106a762015-11-05 15:00:24 +01001364 }
1365 else
1366 {
1367 match = dictBase + matchIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001368 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1369 currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
Yann Collet5106a762015-11-05 15:00:24 +01001370 }
1371
Yann Collet5054ee02015-11-23 13:34:21 +01001372 /* save best solution */
Yann Collet239cc282015-11-23 16:17:21 +01001373 if (currentMl > ml) { ml = currentMl; *offsetPtr = current - matchIndex; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }
Yann Collet5054ee02015-11-23 13:34:21 +01001374
Yann Collet9a24e592015-11-22 02:53:43 +01001375 if (matchIndex <= minChain) break;
Yann Collet5106a762015-11-05 15:00:24 +01001376 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1377 }
1378
1379 return ml;
1380}
1381
1382
Yann Colletc1e52f02015-11-23 14:37:59 +01001383FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1384 ZSTD_CCtx* zc,
Yann Collet5106a762015-11-05 15:00:24 +01001385 const BYTE* ip, const BYTE* const iLimit,
1386 size_t* offsetPtr,
1387 const U32 maxNbAttempts, const U32 matchLengthSearch)
1388{
1389 switch(matchLengthSearch)
1390 {
1391 default :
Yann Colletc1e52f02015-11-23 14:37:59 +01001392 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1393 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1394 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1395 }
1396}
1397
1398
1399FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1400 ZSTD_CCtx* zc,
1401 const BYTE* ip, const BYTE* const iLimit,
1402 size_t* offsetPtr,
1403 const U32 maxNbAttempts, const U32 matchLengthSearch)
1404{
1405 switch(matchLengthSearch)
1406 {
1407 default :
1408 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1409 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1410 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001411 }
1412}
1413
1414
Yann Collet287b7d92015-11-22 13:24:05 +01001415/* *******************************
Yann Collet9a24e592015-11-22 02:53:43 +01001416* Common parser - lazy strategy
Yann Collet287b7d92015-11-22 13:24:05 +01001417*********************************/
Yann Collet5106a762015-11-05 15:00:24 +01001418FORCE_INLINE
Yann Collet5be2dd22015-11-11 13:43:58 +01001419size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
Yann Colletc95f8992015-11-19 17:28:35 +01001420 void* dst, size_t maxDstSize, const void* src, size_t srcSize,
Yann Collet007c1c62015-11-22 02:42:28 +01001421 const U32 searchMethod, const U32 depth)
Yann Collet5106a762015-11-05 15:00:24 +01001422{
1423 seqStore_t* seqStorePtr = &(ctx->seqStore);
1424 const BYTE* const istart = (const BYTE*)src;
1425 const BYTE* ip = istart;
1426 const BYTE* anchor = istart;
1427 const BYTE* const iend = istart + srcSize;
1428 const BYTE* const ilimit = iend - 8;
Yann Collete47c4e52015-12-05 09:23:53 +01001429 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet5106a762015-11-05 15:00:24 +01001430
1431 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1432 const U32 maxSearches = 1 << ctx->params.searchLog;
1433 const U32 mls = ctx->params.searchLength;
1434
Yann Collet5be2dd22015-11-11 13:43:58 +01001435 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
Yann Collet5106a762015-11-05 15:00:24 +01001436 size_t* offsetPtr,
1437 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet5be2dd22015-11-11 13:43:58 +01001438 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet5106a762015-11-05 15:00:24 +01001439
1440 /* init */
1441 ZSTD_resetSeqStore(seqStorePtr);
Yann Collete47c4e52015-12-05 09:23:53 +01001442 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet5106a762015-11-05 15:00:24 +01001443
1444 /* Match Loop */
Yann Collet7a231792015-11-21 15:27:35 +01001445 while (ip < ilimit)
Yann Collet5106a762015-11-05 15:00:24 +01001446 {
Yann Collet7a231792015-11-21 15:27:35 +01001447 size_t matchLength=0;
1448 size_t offset=0;
1449 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001450
Yann Collet743402c2015-11-20 12:03:53 +01001451 /* check repCode */
Yann Collet7a231792015-11-21 15:27:35 +01001452 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))
Yann Collet5106a762015-11-05 15:00:24 +01001453 {
Yann Collet743402c2015-11-20 12:03:53 +01001454 /* repcode : we take it */
Yann Collet7a231792015-11-21 15:27:35 +01001455 matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH;
Yann Collet007c1c62015-11-22 02:42:28 +01001456 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001457 }
1458
Yann Colletfc2afcf2015-11-06 15:40:14 +01001459 {
Yann Collet239cc282015-11-23 16:17:21 +01001460 /* first search (depth 0) */
1461 size_t offsetFound = 99999999;
1462 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1463 if (ml2 > matchLength)
1464 matchLength = ml2, start = ip, offset=offsetFound;
1465 }
Yann Collet9a24e592015-11-22 02:53:43 +01001466
Yann Collete47c4e52015-12-05 09:23:53 +01001467 if (matchLength < MINMATCH)
Yann Collet239cc282015-11-23 16:17:21 +01001468 {
1469 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1470 continue;
1471 }
Yann Collet5106a762015-11-05 15:00:24 +01001472
1473 /* let's try to find a better solution */
Yann Collet007c1c62015-11-22 02:42:28 +01001474 if (depth>=1)
1475 while (ip<ilimit)
Yann Collet5106a762015-11-05 15:00:24 +01001476 {
1477 ip ++;
Yann Collet7a231792015-11-21 15:27:35 +01001478 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1)))
Yann Collet5106a762015-11-05 15:00:24 +01001479 {
Yann Collet007c1c62015-11-22 02:42:28 +01001480 size_t mlRep = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1481 int gain2 = (int)(mlRep * 3);
Yann Collet5106a762015-11-05 15:00:24 +01001482 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet007c1c62015-11-22 02:42:28 +01001483 if ((mlRep >= MINMATCH) && (gain2 > gain1))
1484 matchLength = mlRep, offset = 0, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001485 }
1486 {
1487 size_t offset2=999999;
1488 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet007c1c62015-11-22 02:42:28 +01001489 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1490 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Collet4baee502015-11-09 03:19:33 +01001491 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001492 {
Yann Collet628065c2015-11-06 18:44:54 +01001493 matchLength = ml2, offset = offset2, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001494 continue; /* search a better one */
1495 }
1496 }
1497
1498 /* let's find an even better one */
Yann Collet007c1c62015-11-22 02:42:28 +01001499 if ((depth==2) && (ip<ilimit))
Yann Collet5106a762015-11-05 15:00:24 +01001500 {
1501 ip ++;
Yann Collet7a231792015-11-21 15:27:35 +01001502 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1)))
Yann Collet5106a762015-11-05 15:00:24 +01001503 {
1504 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1505 int gain2 = (int)(ml2 * 4);
1506 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet4baee502015-11-09 03:19:33 +01001507 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001508 matchLength = ml2, offset = 0, start = ip;
1509 }
1510 {
1511 size_t offset2=999999;
1512 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet628065c2015-11-06 18:44:54 +01001513 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1514 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Collet4baee502015-11-09 03:19:33 +01001515 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001516 {
Yann Collet628065c2015-11-06 18:44:54 +01001517 matchLength = ml2, offset = offset2, start = ip;
1518 continue;
Yann Collet5106a762015-11-05 15:00:24 +01001519 }
1520 }
1521 }
1522 break; /* nothing found : store previous solution */
1523 }
1524
Yann Collet4baee502015-11-09 03:19:33 +01001525 /* catch up */
Yann Collet628065c2015-11-06 18:44:54 +01001526 if (offset)
Yann Collet4baee502015-11-09 03:19:33 +01001527 {
Yann Collete47c4e52015-12-05 09:23:53 +01001528 while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */
Yann Collet4baee502015-11-09 03:19:33 +01001529 { start--; matchLength++; }
Yann Collet743402c2015-11-20 12:03:53 +01001530 offset_2 = offset_1; offset_1 = offset;
Yann Collet4baee502015-11-09 03:19:33 +01001531 }
1532
1533 /* store sequence */
Yann Collet7a231792015-11-21 15:27:35 +01001534_storeSequence:
Yann Collet5106a762015-11-05 15:00:24 +01001535 {
1536 size_t litLength = start - anchor;
Yann Collet5106a762015-11-05 15:00:24 +01001537 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
Yann Collet4baee502015-11-09 03:19:33 +01001538 anchor = ip = start + matchLength;
Yann Collet5106a762015-11-05 15:00:24 +01001539 }
1540
Yann Collet743402c2015-11-20 12:03:53 +01001541 /* check immediate repcode */
1542 while ( (ip <= ilimit)
1543 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) )
1544 {
1545 /* store sequence */
1546 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
1547 offset = offset_2;
1548 offset_2 = offset_1;
1549 offset_1 = offset;
1550 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength);
1551 ip += matchLength+MINMATCH;
1552 anchor = ip;
1553 continue; /* faster when present ... (?) */
1554 }
Yann Collet5106a762015-11-05 15:00:24 +01001555 }
1556
1557 /* Last Literals */
1558 {
1559 size_t lastLLSize = iend - anchor;
1560 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1561 seqStorePtr->lit += lastLLSize;
1562 }
1563
1564 /* Final compression stage */
Yann Collet5054ee02015-11-23 13:34:21 +01001565 return ZSTD_compressSequences(dst, maxDstSize,
Yann Collet5106a762015-11-05 15:00:24 +01001566 seqStorePtr, srcSize);
1567}
1568
Yann Collet5be2dd22015-11-11 13:43:58 +01001569size_t ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001570{
Yann Collet7a231792015-11-21 15:27:35 +01001571 return ZSTD_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 1, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001572}
1573
Yann Collet5be2dd22015-11-11 13:43:58 +01001574size_t ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001575{
Yann Collet7a231792015-11-21 15:27:35 +01001576 return ZSTD_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001577}
1578
Yann Collet5be2dd22015-11-11 13:43:58 +01001579size_t ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001580{
Yann Collet7a231792015-11-21 15:27:35 +01001581 return ZSTD_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001582}
1583
Yann Collet5be2dd22015-11-11 13:43:58 +01001584size_t ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01001585{
Yann Collet7a231792015-11-21 15:27:35 +01001586 return ZSTD_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 0);
Yann Colletbe2010e2015-10-31 12:57:14 +01001587}
1588
1589
Yann Collet9a24e592015-11-22 02:53:43 +01001590FORCE_INLINE
1591size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1592 void* dst, size_t maxDstSize, const void* src, size_t srcSize,
1593 const U32 searchMethod, const U32 depth)
1594{
1595 seqStore_t* seqStorePtr = &(ctx->seqStore);
1596 const BYTE* const istart = (const BYTE*)src;
1597 const BYTE* ip = istart;
1598 const BYTE* anchor = istart;
1599 const BYTE* const iend = istart + srcSize;
1600 const BYTE* const ilimit = iend - 8;
1601 const BYTE* const base = ctx->base;
1602 const U32 dictLimit = ctx->dictLimit;
1603 const BYTE* const prefixStart = base + dictLimit;
1604 const BYTE* const dictBase = ctx->dictBase;
1605 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001606 const BYTE* const dictStart = dictBase + ctx->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001607
1608 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1609 const U32 maxSearches = 1 << ctx->params.searchLog;
1610 const U32 mls = ctx->params.searchLength;
1611
1612 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1613 size_t* offsetPtr,
1614 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet03526e12015-11-23 15:29:15 +01001615 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
Yann Collet9a24e592015-11-22 02:53:43 +01001616
1617 /* init */
1618 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet6c3e2e72015-12-11 10:44:07 +01001619 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Collet9a24e592015-11-22 02:53:43 +01001620
1621 /* Match Loop */
1622 while (ip < ilimit)
1623 {
1624 size_t matchLength=0;
1625 size_t offset=0;
1626 const BYTE* start=ip+1;
1627 U32 current = (U32)(ip-base);
1628
1629 /* check repCode */
1630 {
1631 const U32 repIndex = (U32)(current+1 - offset_1);
1632 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1633 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001634 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletd7233d62015-11-22 14:40:51 +01001635 if (MEM_read32(ip+1) == MEM_read32(repMatch))
Yann Collet9a24e592015-11-22 02:53:43 +01001636 {
1637 /* repcode detected we should take it */
1638 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001639 matchLength = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
Yann Collet9a24e592015-11-22 02:53:43 +01001640 if (depth==0) goto _storeSequence;
1641 }
1642 }
1643
1644 {
Yann Collet239cc282015-11-23 16:17:21 +01001645 /* first search (depth 0) */
1646 size_t offsetFound = 99999999;
1647 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1648 if (ml2 > matchLength)
1649 matchLength = ml2, start = ip, offset=offsetFound;
1650 }
Yann Collet9a24e592015-11-22 02:53:43 +01001651
Yann Collet239cc282015-11-23 16:17:21 +01001652 if (matchLength < MINMATCH)
1653 {
1654 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1655 continue;
1656 }
Yann Collet9a24e592015-11-22 02:53:43 +01001657
1658 /* let's try to find a better solution */
1659 if (depth>=1)
1660 while (ip<ilimit)
1661 {
1662 ip ++;
1663 current++;
1664 /* check repCode */
1665 if (offset)
1666 {
1667 const U32 repIndex = (U32)(current - offset_1);
1668 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1669 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001670 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletd7233d62015-11-22 14:40:51 +01001671 if (MEM_read32(ip) == MEM_read32(repMatch))
Yann Collet9a24e592015-11-22 02:53:43 +01001672 {
1673 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001674 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001675 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1676 int gain2 = (int)(repLength * 3);
1677 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1678 if ((repLength >= MINMATCH) && (gain2 > gain1))
1679 matchLength = repLength, offset = 0, start = ip;
Yann Collet9a24e592015-11-22 02:53:43 +01001680 }
1681 }
1682
1683 /* search match, depth 1 */
1684 {
1685 size_t offset2=999999;
1686 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1687 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1688 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
1689 if ((ml2 >= MINMATCH) && (gain2 > gain1))
1690 {
1691 matchLength = ml2, offset = offset2, start = ip;
1692 continue; /* search a better one */
1693 }
1694 }
1695
1696 /* let's find an even better one */
1697 if ((depth==2) && (ip<ilimit))
1698 {
1699 ip ++;
1700 current++;
1701 /* check repCode */
1702 if (offset)
1703 {
1704 const U32 repIndex = (U32)(current - offset_1);
1705 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1706 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001707 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletd7233d62015-11-22 14:40:51 +01001708 if (MEM_read32(ip) == MEM_read32(repMatch))
Yann Collet9a24e592015-11-22 02:53:43 +01001709 {
1710 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001711 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001712 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1713 int gain2 = (int)(repLength * 4);
1714 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1715 if ((repLength >= MINMATCH) && (gain2 > gain1))
1716 matchLength = repLength, offset = 0, start = ip;
Yann Collet9a24e592015-11-22 02:53:43 +01001717 }
1718 }
1719
1720 /* search match, depth 2 */
1721 {
1722 size_t offset2=999999;
1723 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1724 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1725 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
1726 if ((ml2 >= MINMATCH) && (gain2 > gain1))
1727 {
1728 matchLength = ml2, offset = offset2, start = ip;
1729 continue;
1730 }
1731 }
1732 }
1733 break; /* nothing found : store previous solution */
1734 }
1735
1736 /* catch up */
1737 if (offset)
1738 {
Yann Colletc3652152015-11-24 14:06:07 +01001739 U32 matchIndex = (U32)((start-base) - offset);
1740 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1741 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
1742 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet9a24e592015-11-22 02:53:43 +01001743 offset_2 = offset_1; offset_1 = offset;
1744 }
1745
1746 /* store sequence */
1747_storeSequence:
1748 {
1749 size_t litLength = start - anchor;
1750 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1751 anchor = ip = start + matchLength;
1752 }
1753
1754 /* check immediate repcode */
1755 while (ip <= ilimit)
1756 {
1757 const U32 repIndex = (U32)((ip-base) - offset_2);
1758 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1759 const BYTE* const repMatch = repBase + repIndex;
Yann Collet239cc282015-11-23 16:17:21 +01001760 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletd7233d62015-11-22 14:40:51 +01001761 if (MEM_read32(ip) == MEM_read32(repMatch))
Yann Collet9a24e592015-11-22 02:53:43 +01001762 {
1763 /* repcode detected we should take it */
1764 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001765 matchLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1766 offset = offset_2; offset_2 = offset_1; offset_1 = offset; /* swap offset history */
Yann Collet9a24e592015-11-22 02:53:43 +01001767 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1768 ip += matchLength;
1769 anchor = ip;
1770 continue; /* faster when present ... (?) */
1771 }
1772 break;
1773 }
1774 }
1775
1776 /* Last Literals */
1777 {
1778 size_t lastLLSize = iend - anchor;
1779 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1780 seqStorePtr->lit += lastLLSize;
1781 }
1782
1783 /* Final compression stage */
Yann Collet5054ee02015-11-23 13:34:21 +01001784 return ZSTD_compressSequences(dst, maxDstSize,
Yann Collet9a24e592015-11-22 02:53:43 +01001785 seqStorePtr, srcSize);
1786}
1787
1788size_t ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
1789{
1790 return ZSTD_compressBlock_lazy_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 0, 0);
1791}
1792
Yann Colletb7fc88e2015-11-22 03:12:28 +01001793size_t ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
1794{
1795 return ZSTD_compressBlock_lazy_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 0, 1);
1796}
Yann Collet9a24e592015-11-22 02:53:43 +01001797
Yann Colleta85c77b2015-11-22 12:22:04 +01001798size_t ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
1799{
1800 return ZSTD_compressBlock_lazy_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 0, 2);
1801}
1802
Yann Collet03526e12015-11-23 15:29:15 +01001803static size_t ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01001804{
Yann Collet03526e12015-11-23 15:29:15 +01001805 return ZSTD_compressBlock_lazy_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001806}
1807
Yann Collet7a231792015-11-21 15:27:35 +01001808
Yann Collet5be2dd22015-11-11 13:43:58 +01001809typedef size_t (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01001810
Yann Collet89db5e02015-11-13 11:27:46 +01001811static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01001812{
Yann Collet7fe531e2015-11-29 02:38:09 +01001813 static const ZSTD_blockCompressor blockCompressor[2][5] = {
1814 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy,ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2 },
1815 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict }
1816 };
1817
1818 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01001819}
1820
1821
Yann Colletbf42c8e2016-01-09 01:08:23 +01001822static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
Yann Colletbe2010e2015-10-31 12:57:14 +01001823{
Yann Collet03526e12015-11-23 15:29:15 +01001824 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet523b5942016-01-09 02:10:40 +01001825 if (srcSize < MIN_CBLOCK_SIZE+3) return 0; /* don't even attempt compression below a certain srcSize */
Yann Collet03526e12015-11-23 15:29:15 +01001826 return blockCompressor(zc, dst, maxDstSize, src, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01001827}
1828
1829
Yann Collet5be2dd22015-11-11 13:43:58 +01001830static size_t ZSTD_compress_generic (ZSTD_CCtx* ctxPtr,
Yann Colletf3eca252015-10-22 15:31:46 +01001831 void* dst, size_t maxDstSize,
1832 const void* src, size_t srcSize)
1833{
Yann Collet120230b2015-12-02 14:00:45 +01001834 size_t blockSize = ctxPtr->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001835 size_t remaining = srcSize;
1836 const BYTE* ip = (const BYTE*)src;
1837 BYTE* const ostart = (BYTE*)dst;
1838 BYTE* op = ostart;
Yann Collet89db5e02015-11-13 11:27:46 +01001839 const U32 maxDist = 1 << ctxPtr->params.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01001840
Yann Collet3e358272015-11-04 18:19:39 +01001841 while (remaining)
Yann Colletf3eca252015-10-22 15:31:46 +01001842 {
Yann Collet3e358272015-11-04 18:19:39 +01001843 size_t cSize;
1844
Yann Collet3137d1a2015-11-04 23:36:36 +01001845 if (maxDstSize < 3 + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01001846 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01001847
1848 if ((U32)(ip+blockSize - (ctxPtr->base + ctxPtr->lowLimit)) > maxDist)
Yann Colletc3652152015-11-24 14:06:07 +01001849 {
Yann Collet89db5e02015-11-13 11:27:46 +01001850 /* respect windowLog contract */
Yann Colletc3652152015-11-24 14:06:07 +01001851 ctxPtr->lowLimit = (U32)(ip+blockSize - ctxPtr->base) - maxDist;
1852 if (ctxPtr->dictLimit < ctxPtr->lowLimit) ctxPtr->dictLimit = ctxPtr->lowLimit;
1853 }
Yann Collet89db5e02015-11-13 11:27:46 +01001854
Yann Colletbf42c8e2016-01-09 01:08:23 +01001855 cSize = ZSTD_compressBlock_internal(ctxPtr, op+3, maxDstSize-3, ip, blockSize);
Yann Collet3e358272015-11-04 18:19:39 +01001856 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001857
1858 if (cSize == 0)
1859 {
1860 cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize); /* block is not compressible */
Yann Collet523b5942016-01-09 02:10:40 +01001861 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001862 }
1863 else
1864 {
1865 op[0] = (BYTE)(cSize>>16);
1866 op[1] = (BYTE)(cSize>>8);
1867 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01001868 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01001869 cSize += 3;
1870 }
1871
1872 remaining -= blockSize;
Yann Collet3e358272015-11-04 18:19:39 +01001873 maxDstSize -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001874 ip += blockSize;
1875 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001876 }
1877
1878 return op-ostart;
1879}
1880
1881
Yann Colletbf42c8e2016-01-09 01:08:23 +01001882static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
1883 void* dst, size_t dstSize,
1884 const void* src, size_t srcSize,
1885 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01001886{
Yann Collet2acb5d32015-10-29 16:49:43 +01001887 const BYTE* const ip = (const BYTE*) src;
Yann Colletecd651b2016-01-07 15:35:18 +01001888 size_t hbSize = 0;
1889
Yann Colletbf42c8e2016-01-09 01:08:23 +01001890 if (frame && (zc->stage==0))
Yann Colletecd651b2016-01-07 15:35:18 +01001891 {
1892 hbSize = zc->hbSize;
1893 if (dstSize <= hbSize) return ERROR(dstSize_tooSmall);
1894 zc->stage = 1;
1895 memcpy(dst, zc->headerBuffer, hbSize);
1896 dstSize -= hbSize;
1897 dst = (char*)dst + hbSize;
1898 }
Yann Colletf3eca252015-10-22 15:31:46 +01001899
Yann Collet417890c2015-12-04 17:16:37 +01001900 /* Check if blocks follow each other */
1901 if (src != zc->nextSrc)
1902 {
1903 /* not contiguous */
1904 size_t delta = zc->nextSrc - ip;
1905 zc->lowLimit = zc->dictLimit;
1906 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
1907 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01001908 zc->base -= delta;
1909 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01001910 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01001911 }
1912
Yann Collet89db5e02015-11-13 11:27:46 +01001913 /* preemptive overflow correction */
Yann Collet6c3e2e72015-12-11 10:44:07 +01001914 if (zc->lowLimit > (1<<30))
Yann Colletf3eca252015-10-22 15:31:46 +01001915 {
Yann Collet6c3e2e72015-12-11 10:44:07 +01001916 U32 btplus = (zc->params.strategy == ZSTD_btlazy2);
1917 U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1;
1918 U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */
1919 U32 correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001920 ZSTD_reduceIndex(zc, correction);
1921 zc->base += correction;
1922 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001923 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001924 zc->dictLimit -= correction;
1925 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
1926 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01001927 }
1928
Yann Colletbf42c8e2016-01-09 01:08:23 +01001929 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Colletc3652152015-11-24 14:06:07 +01001930 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit))
Yann Collet89db5e02015-11-13 11:27:46 +01001931 {
Yann Colletc3652152015-11-24 14:06:07 +01001932 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
1933 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001934 }
1935
Yann Colletc3652152015-11-24 14:06:07 +01001936 zc->nextSrc = ip + srcSize;
Yann Colletecd651b2016-01-07 15:35:18 +01001937 {
Yann Colletbf42c8e2016-01-09 01:08:23 +01001938 size_t cSize;
1939 if (frame) cSize = ZSTD_compress_generic (zc, dst, dstSize, src, srcSize);
1940 else cSize = ZSTD_compressBlock_internal (zc, dst, dstSize, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01001941 if (ZSTD_isError(cSize)) return cSize;
1942 return cSize + hbSize;
1943 }
Yann Colletf3eca252015-10-22 15:31:46 +01001944}
1945
Yann Colletbf42c8e2016-01-09 01:08:23 +01001946
1947size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
1948 void* dst, size_t dstSize,
1949 const void* src, size_t srcSize)
1950{
1951 return ZSTD_compressContinue_internal(zc, dst, dstSize, src, srcSize, 1);
1952}
1953
1954
1955size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
1956{
1957 if (srcSize > BLOCKSIZE) return ERROR(srcSize_wrong);
Yann Colletbf42c8e2016-01-09 01:08:23 +01001958 return ZSTD_compressContinue_internal(zc, dst, maxDstSize, src, srcSize, 0);
1959}
1960
1961
Yann Collet417890c2015-12-04 17:16:37 +01001962size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* src, size_t srcSize)
1963{
1964 const BYTE* const ip = (const BYTE*) src;
1965 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001966
Yann Collet417890c2015-12-04 17:16:37 +01001967 /* input becomes current prefix */
1968 zc->lowLimit = zc->dictLimit;
1969 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
1970 zc->dictBase = zc->base;
1971 zc->base += ip - zc->nextSrc;
1972 zc->nextToUpdate = zc->dictLimit;
1973
1974 zc->nextSrc = iend;
1975 if (srcSize <= 8) return 0;
1976
1977 switch(zc->params.strategy)
1978 {
1979 case ZSTD_fast:
1980 ZSTD_fillHashTable (zc, iend-8, zc->params.searchLength);
1981 break;
1982
1983 case ZSTD_greedy:
1984 case ZSTD_lazy:
1985 case ZSTD_lazy2:
1986 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength);
1987 break;
1988
1989 case ZSTD_btlazy2:
1990 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength);
Yann Collet48da1642015-12-29 23:40:02 +01001991 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01001992 break;
1993
1994 default:
1995 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
1996 }
1997
1998 return 0;
1999}
2000
2001
Yann Colletecd651b2016-01-07 15:35:18 +01002002/*! ZSTD_duplicateCCtx
2003* Duplicate an existing context @srcCCtx into another one @dstCCtx.
2004* Only works during stage 0 (i.e. before first call to ZSTD_compressContinue())
2005* @return : 0, or an error code */
2006size_t ZSTD_duplicateCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
2007{
Yann Collet6e1c4c62016-01-07 23:07:44 +01002008 const U32 contentLog = (srcCCtx->params.strategy == ZSTD_fast) ? 1 : srcCCtx->params.contentLog;
2009 const size_t tableSpace = ((1 << contentLog) + (1 << srcCCtx->params.hashLog)) * sizeof(U32);
Yann Colletecd651b2016-01-07 15:35:18 +01002010
Yann Collet6e1c4c62016-01-07 23:07:44 +01002011 if (srcCCtx->stage!=0) return ERROR(stage_wrong);
2012
Yann Collet60096272016-01-08 17:27:50 +01002013 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params);
Yann Colletecd651b2016-01-07 15:35:18 +01002014
Yann Collet60096272016-01-08 17:27:50 +01002015 /* copy tables */
2016 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace);
Yann Colletecd651b2016-01-07 15:35:18 +01002017
Yann Collet60096272016-01-08 17:27:50 +01002018 /* copy frame header */
2019 dstCCtx->hbSize = srcCCtx->hbSize;
2020 memcpy(dstCCtx->headerBuffer , srcCCtx->headerBuffer, srcCCtx->hbSize);
2021
2022 /* copy dictionary pointers */
2023 dstCCtx->nextToUpdate= srcCCtx->nextToUpdate;
2024 dstCCtx->nextSrc = srcCCtx->nextSrc;
2025 dstCCtx->base = srcCCtx->base;
2026 dstCCtx->dictBase = srcCCtx->dictBase;
2027 dstCCtx->dictLimit = srcCCtx->dictLimit;
2028 dstCCtx->lowLimit = srcCCtx->lowLimit;
Yann Collet6e1c4c62016-01-07 23:07:44 +01002029
Yann Colletecd651b2016-01-07 15:35:18 +01002030 return 0;
2031}
2032
2033
Yann Collet417890c2015-12-04 17:16:37 +01002034/*! ZSTD_compressBegin_advanced
Yann Colletecd651b2016-01-07 15:35:18 +01002035* @return : 0, or an error code */
Yann Collet5be2dd22015-11-11 13:43:58 +01002036size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* ctx,
Yann Collet88fcd292015-11-25 14:42:45 +01002037 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002038{
Yann Collet4114f952015-10-30 06:40:22 +01002039 size_t errorCode;
Yann Collet88fcd292015-11-25 14:42:45 +01002040
2041 ZSTD_validateParams(&params);
2042
Yann Collet88fcd292015-11-25 14:42:45 +01002043 errorCode = ZSTD_resetCCtx_advanced(ctx, params);
Yann Collet4114f952015-10-30 06:40:22 +01002044 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet89db5e02015-11-13 11:27:46 +01002045
Yann Colletecd651b2016-01-07 15:35:18 +01002046 MEM_writeLE32(ctx->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */
2047 ((BYTE*)ctx->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN);
2048 ctx->hbSize = ZSTD_frameHeaderSize_min;
2049 ctx->stage = 0;
2050
2051 return 0;
Yann Collet88fcd292015-11-25 14:42:45 +01002052}
2053
2054
2055/** ZSTD_getParams
2056* return ZSTD_parameters structure for a selected compression level and srcSize.
2057* srcSizeHint value is optional, select 0 if not known */
2058ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint)
2059{
2060 ZSTD_parameters result;
Yann Colletd6080882015-12-09 09:05:22 +01002061 int tableID = ((srcSizeHint-1) <= 256 KB) + ((srcSizeHint-1) <= 128 KB) + ((srcSizeHint-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet88fcd292015-11-25 14:42:45 +01002062 if (compressionLevel<=0) compressionLevel = 1;
2063 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
2064 result = ZSTD_defaultParameters[tableID][compressionLevel];
2065 result.srcSize = srcSizeHint;
2066 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002067}
2068
Yann Collet083fcc82015-10-25 14:06:35 +01002069
Yann Colletecd651b2016-01-07 15:35:18 +01002070size_t ZSTD_compressBegin(ZSTD_CCtx* ctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002071{
Yann Colletecd651b2016-01-07 15:35:18 +01002072 return ZSTD_compressBegin_advanced(ctx, ZSTD_getParams(compressionLevel, 0));
Yann Collet083fcc82015-10-25 14:06:35 +01002073}
2074
2075
Yann Collet31683c02015-12-18 01:26:48 +01002076/*! ZSTD_compressEnd
Yann Collet88fcd292015-11-25 14:42:45 +01002077* Write frame epilogue
2078* @return : nb of bytes written into dst (or an error code) */
Yann Colletecd651b2016-01-07 15:35:18 +01002079size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize)
Yann Collet2acb5d32015-10-29 16:49:43 +01002080{
2081 BYTE* op = (BYTE*)dst;
Yann Colletecd651b2016-01-07 15:35:18 +01002082 size_t hbSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002083
Yann Colletecd651b2016-01-07 15:35:18 +01002084 /* empty frame */
2085 if (zc->stage==0)
2086 {
2087 hbSize = zc->hbSize;
2088 if (maxDstSize <= hbSize) return ERROR(dstSize_tooSmall);
2089 zc->stage = 1;
2090 memcpy(dst, zc->headerBuffer, hbSize);
2091 maxDstSize -= hbSize;
2092 op += hbSize;
2093 }
2094
2095 /* frame epilogue */
Yann Collet2acb5d32015-10-29 16:49:43 +01002096 if (maxDstSize < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002097 op[0] = (BYTE)(bt_end << 6);
2098 op[1] = 0;
2099 op[2] = 0;
2100
Yann Colletecd651b2016-01-07 15:35:18 +01002101 return 3+hbSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002102}
2103
Yann Collet5be2dd22015-11-11 13:43:58 +01002104size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
Yann Collet88fcd292015-11-25 14:42:45 +01002105 void* dst, size_t maxDstSize,
2106 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002107 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002108 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002109{
2110 BYTE* const ostart = (BYTE*)dst;
2111 BYTE* op = ostart;
Yann Collet4114f952015-10-30 06:40:22 +01002112 size_t oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002113
2114 /* Header */
Yann Colletecd651b2016-01-07 15:35:18 +01002115 oSize = ZSTD_compressBegin_advanced(ctx, params);
Yann Colletf3eca252015-10-22 15:31:46 +01002116 if(ZSTD_isError(oSize)) return oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002117
Yann Collet31683c02015-12-18 01:26:48 +01002118 /* dictionary */
2119 if (dict)
2120 {
2121 oSize = ZSTD_compress_insertDictionary(ctx, dict, dictSize);
2122 if (ZSTD_isError(oSize)) return oSize;
2123 }
2124
Yann Colletf3eca252015-10-22 15:31:46 +01002125 /* body (compression) */
Yann Collet31683c02015-12-18 01:26:48 +01002126 oSize = ZSTD_compressContinue (ctx, op, maxDstSize, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002127 if(ZSTD_isError(oSize)) return oSize;
2128 op += oSize;
2129 maxDstSize -= oSize;
2130
2131 /* Close frame */
Yann Collet5be2dd22015-11-11 13:43:58 +01002132 oSize = ZSTD_compressEnd(ctx, op, maxDstSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002133 if(ZSTD_isError(oSize)) return oSize;
2134 op += oSize;
2135
2136 return (op - ostart);
2137}
2138
Yann Collet31683c02015-12-18 01:26:48 +01002139size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, const void* dict, size_t dictSize, int compressionLevel)
2140{
2141 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize+dictSize));
2142}
2143
Yann Collet5be2dd22015-11-11 13:43:58 +01002144size_t ZSTD_compressCCtx (ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002145{
Yann Collet31683c02015-12-18 01:26:48 +01002146 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet083fcc82015-10-25 14:06:35 +01002147}
2148
Yann Collet5be2dd22015-11-11 13:43:58 +01002149size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002150{
Yann Collet44fe9912015-10-29 22:02:40 +01002151 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002152 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002153 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Collet5be2dd22015-11-11 13:43:58 +01002154 result = ZSTD_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel);
Yann Colletecd651b2016-01-07 15:35:18 +01002155 free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002156 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002157}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002158