blob: 399f81169620cb163bceee47e4fbf3a5ca8c8259 [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);
1046 U32* largerPtr = bt + 2*(current&btMask) + 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 Colletf48e35c2015-11-07 01:13:31 +01001050
Yann Collet6c3e2e72015-12-11 10:44:07 +01001051 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001052
1053 while (nbCompares-- && (matchIndex > windowLow))
1054 {
1055 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001056 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1057
Yann Collet1358f912016-01-01 07:29:39 +01001058 if ((!extDict) || (matchIndex+matchLength >= dictLimit))
1059 {
1060 match = base + matchIndex;
1061 if (match[matchLength] == ip[matchLength])
1062 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
1063 }
1064 else
1065 {
1066 match = dictBase + matchIndex;
1067 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1068 if (matchIndex+matchLength >= dictLimit)
1069 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1070 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001071
Yann Colletee3f4512015-12-29 22:26:09 +01001072 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001073 matchEndIdx = matchIndex + (U32)matchLength;
Yann Colletee3f4512015-12-29 22:26:09 +01001074
Yann Collet59d70632015-11-04 12:05:27 +01001075 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001076 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001077
Yann Collet1358f912016-01-01 07:29:39 +01001078 if (match[matchLength] < ip[matchLength]) /* necessarily within correct buffer */
Yann Collet59d70632015-11-04 12:05:27 +01001079 {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001080 /* match is smaller than current */
1081 *smallerPtr = matchIndex; /* update smaller idx */
1082 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001083 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001084 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001085 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet59d70632015-11-04 12:05:27 +01001086 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001087 else
Yann Collet59d70632015-11-04 12:05:27 +01001088 {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001089 /* match is larger than current */
1090 *largerPtr = matchIndex;
1091 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001092 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001093 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001094 matchIndex = nextPtr[0];
Yann Collet59d70632015-11-04 12:05:27 +01001095 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001096 }
1097
Yann Collet59d70632015-11-04 12:05:27 +01001098 *smallerPtr = *largerPtr = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001099 return (matchEndIdx > current + 8) ? matchEndIdx - current - 8 : 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001100}
1101
1102
Yann Colletee3f4512015-12-29 22:26:09 +01001103static 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 +01001104{
1105 const BYTE* const base = zc->base;
1106 const U32 target = (U32)(ip - base);
1107 U32 idx = zc->nextToUpdate;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001108
Yann Colletf48e35c2015-11-07 01:13:31 +01001109 for( ; idx < target ; )
Yann Collet1358f912016-01-01 07:29:39 +01001110 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001111}
1112
Yann Collet96b9f0b2015-11-04 03:52:54 +01001113FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Collet2cc12cb2016-01-01 07:47:58 +01001114size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001115 ZSTD_CCtx* zc,
1116 const BYTE* const ip, const BYTE* const iend,
1117 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001118 U32 nbCompares, const U32 mls,
1119 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001120{
1121 U32* const hashTable = zc->hashTable;
1122 const U32 hashLog = zc->params.hashLog;
1123 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
1124 U32* const bt = zc->contentTable;
1125 const U32 btLog = zc->params.contentLog - 1;
1126 const U32 btMask= (1 << btLog) - 1;
1127 U32 matchIndex = hashTable[h];
1128 size_t commonLengthSmaller=0, commonLengthLarger=0;
1129 const BYTE* const base = zc->base;
1130 const BYTE* const dictBase = zc->dictBase;
1131 const U32 dictLimit = zc->dictLimit;
1132 const BYTE* const dictEnd = dictBase + dictLimit;
1133 const BYTE* const prefixStart = base + dictLimit;
1134 const U32 current = (U32)(ip-base);
1135 const U32 btLow = btMask >= current ? 0 : current - btMask;
1136 const U32 windowLow = zc->lowLimit;
1137 U32* smallerPtr = bt + 2*(current&btMask);
1138 U32* largerPtr = bt + 2*(current&btMask) + 1;
1139 size_t bestLength = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001140 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001141 U32 dummy32; /* to be nullified at the end */
1142
Yann Collet6c3e2e72015-12-11 10:44:07 +01001143 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001144
1145 while (nbCompares-- && (matchIndex > windowLow))
1146 {
1147 U32* nextPtr = bt + 2*(matchIndex & btMask);
1148 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1149 const BYTE* match;
1150
Yann Collet2cc12cb2016-01-01 07:47:58 +01001151 if ((!extDict) || (matchIndex+matchLength >= dictLimit))
Yann Collet03526e12015-11-23 15:29:15 +01001152 {
1153 match = base + matchIndex;
1154 if (match[matchLength] == ip[matchLength])
1155 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
1156 }
1157 else
1158 {
1159 match = dictBase + matchIndex;
1160 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001161 if (matchIndex+matchLength >= dictLimit)
1162 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001163 }
1164
1165 if (matchLength > bestLength)
1166 {
Yann Colletee3f4512015-12-29 22:26:09 +01001167 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001168 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet03526e12015-11-23 15:29:15 +01001169 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
1170 bestLength = matchLength, *offsetPtr = current - matchIndex;
1171 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1172 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1173 }
1174
1175 if (match[matchLength] < ip[matchLength])
1176 {
1177 /* match is smaller than current */
1178 *smallerPtr = matchIndex; /* update smaller idx */
1179 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1180 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1181 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1182 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
1183 }
1184 else
1185 {
1186 /* match is larger than current */
1187 *largerPtr = matchIndex;
1188 commonLengthLarger = matchLength;
1189 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1190 largerPtr = nextPtr;
1191 matchIndex = nextPtr[0];
1192 }
1193 }
1194
1195 *smallerPtr = *largerPtr = 0;
1196
Yann Collet72e84cf2015-12-31 19:08:44 +01001197 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
Yann Collet03526e12015-11-23 15:29:15 +01001198 return bestLength;
1199}
1200
Yann Collet2cc12cb2016-01-01 07:47:58 +01001201
1202/** Tree updater, providing best match */
1203FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1204size_t ZSTD_BtFindBestMatch (
1205 ZSTD_CCtx* zc,
1206 const BYTE* const ip, const BYTE* const iLimit,
1207 size_t* offsetPtr,
1208 const U32 maxNbAttempts, const U32 mls)
1209{
1210 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1211 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
1212 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1213}
1214
1215
1216FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS (
1217 ZSTD_CCtx* zc, /* Index table will be updated */
1218 const BYTE* ip, const BYTE* const iLimit,
1219 size_t* offsetPtr,
1220 const U32 maxNbAttempts, const U32 matchLengthSearch)
1221{
1222 switch(matchLengthSearch)
1223 {
1224 default :
1225 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1226 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1227 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1228 }
1229}
1230
1231
1232static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1233{
1234 const BYTE* const base = zc->base;
1235 const U32 target = (U32)(ip - base);
1236 U32 idx = zc->nextToUpdate;
1237
1238 for( ; idx < target ; )
1239 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1240}
1241
1242
Yann Collet03526e12015-11-23 15:29:15 +01001243/** Tree updater, providing best match */
1244FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1245size_t ZSTD_BtFindBestMatch_extDict (
1246 ZSTD_CCtx* zc,
1247 const BYTE* const ip, const BYTE* const iLimit,
1248 size_t* offsetPtr,
1249 const U32 maxNbAttempts, const U32 mls)
1250{
Yann Colletee3f4512015-12-29 22:26:09 +01001251 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1252 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001253 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001254}
1255
1256
1257FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
1258 ZSTD_CCtx* zc, /* Index table will be updated */
1259 const BYTE* ip, const BYTE* const iLimit,
1260 size_t* offsetPtr,
1261 const U32 maxNbAttempts, const U32 matchLengthSearch)
1262{
1263 switch(matchLengthSearch)
1264 {
1265 default :
1266 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1267 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1268 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1269 }
1270}
1271
1272
Yann Collet5106a762015-11-05 15:00:24 +01001273/* ***********************
1274* Hash Chain
1275*************************/
1276
Yann Collet1f44b3f2015-11-05 17:32:18 +01001277#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1278
Yann Collet6bcdeac2015-11-26 11:43:00 +01001279/* Update chains up to ip (excluded)
Yann Collet06eade52015-11-23 14:23:47 +01001280 Assumption : always within prefix (ie. not within extDict) */
1281static U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
Yann Collet5106a762015-11-05 15:00:24 +01001282{
1283 U32* const hashTable = zc->hashTable;
1284 const U32 hashLog = zc->params.hashLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001285 U32* const chainTable = zc->contentTable;
1286 const U32 chainMask = (1 << zc->params.contentLog) - 1;
Yann Collet5106a762015-11-05 15:00:24 +01001287 const BYTE* const base = zc->base;
1288 const U32 target = (U32)(ip - base);
1289 U32 idx = zc->nextToUpdate;
1290
1291 while(idx < target)
1292 {
Yann Collet5be2dd22015-11-11 13:43:58 +01001293 size_t h = ZSTD_hashPtr(base+idx, hashLog, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001294 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1295 hashTable[h] = idx;
1296 idx++;
1297 }
1298
1299 zc->nextToUpdate = target;
Yann Collet5be2dd22015-11-11 13:43:58 +01001300 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
Yann Collet5106a762015-11-05 15:00:24 +01001301}
1302
1303
1304FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Colletc1e52f02015-11-23 14:37:59 +01001305size_t ZSTD_HcFindBestMatch_generic (
Yann Collet5be2dd22015-11-11 13:43:58 +01001306 ZSTD_CCtx* zc, /* Index table will be updated */
Yann Collet5106a762015-11-05 15:00:24 +01001307 const BYTE* const ip, const BYTE* const iLimit,
1308 size_t* offsetPtr,
Yann Colletc1e52f02015-11-23 14:37:59 +01001309 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
Yann Collet287b7d92015-11-22 13:24:05 +01001310{
Yann Collet1f44b3f2015-11-05 17:32:18 +01001311 U32* const chainTable = zc->contentTable;
1312 const U32 chainSize = (1 << zc->params.contentLog);
Yann Collet5106a762015-11-05 15:00:24 +01001313 const U32 chainMask = chainSize-1;
1314 const BYTE* const base = zc->base;
1315 const BYTE* const dictBase = zc->dictBase;
1316 const U32 dictLimit = zc->dictLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001317 const BYTE* const prefixStart = base + dictLimit;
1318 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001319 const U32 lowLimit = zc->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001320 const U32 current = (U32)(ip-base);
1321 const U32 minChain = current > chainSize ? current - chainSize : 0;
Yann Collet5106a762015-11-05 15:00:24 +01001322 U32 matchIndex;
1323 const BYTE* match;
1324 int nbAttempts=maxNbAttempts;
Yann Collet5054ee02015-11-23 13:34:21 +01001325 size_t ml=MINMATCH-1;
Yann Collet5106a762015-11-05 15:00:24 +01001326
1327 /* HC4 match finder */
Yann Colletc1e52f02015-11-23 14:37:59 +01001328 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001329
1330 while ((matchIndex>lowLimit) && (nbAttempts))
1331 {
Yann Collet5054ee02015-11-23 13:34:21 +01001332 size_t currentMl=0;
Yann Collet5106a762015-11-05 15:00:24 +01001333 nbAttempts--;
Yann Colletc1e52f02015-11-23 14:37:59 +01001334 if ((!extDict) || matchIndex >= dictLimit)
Yann Collet5106a762015-11-05 15:00:24 +01001335 {
1336 match = base + matchIndex;
Yann Collet4baee502015-11-09 03:19:33 +01001337 if (match[ml] == ip[ml]) /* potentially better */
Yann Collet5054ee02015-11-23 13:34:21 +01001338 currentMl = ZSTD_count(ip, match, iLimit);
Yann Collet5106a762015-11-05 15:00:24 +01001339 }
1340 else
1341 {
1342 match = dictBase + matchIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001343 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1344 currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
Yann Collet5106a762015-11-05 15:00:24 +01001345 }
1346
Yann Collet5054ee02015-11-23 13:34:21 +01001347 /* save best solution */
Yann Collet239cc282015-11-23 16:17:21 +01001348 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 +01001349
Yann Collet9a24e592015-11-22 02:53:43 +01001350 if (matchIndex <= minChain) break;
Yann Collet5106a762015-11-05 15:00:24 +01001351 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1352 }
1353
1354 return ml;
1355}
1356
1357
Yann Colletc1e52f02015-11-23 14:37:59 +01001358FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1359 ZSTD_CCtx* zc,
Yann Collet5106a762015-11-05 15:00:24 +01001360 const BYTE* ip, const BYTE* const iLimit,
1361 size_t* offsetPtr,
1362 const U32 maxNbAttempts, const U32 matchLengthSearch)
1363{
1364 switch(matchLengthSearch)
1365 {
1366 default :
Yann Colletc1e52f02015-11-23 14:37:59 +01001367 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1368 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1369 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1370 }
1371}
1372
1373
1374FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1375 ZSTD_CCtx* zc,
1376 const BYTE* ip, const BYTE* const iLimit,
1377 size_t* offsetPtr,
1378 const U32 maxNbAttempts, const U32 matchLengthSearch)
1379{
1380 switch(matchLengthSearch)
1381 {
1382 default :
1383 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1384 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1385 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001386 }
1387}
1388
1389
Yann Collet287b7d92015-11-22 13:24:05 +01001390/* *******************************
Yann Collet9a24e592015-11-22 02:53:43 +01001391* Common parser - lazy strategy
Yann Collet287b7d92015-11-22 13:24:05 +01001392*********************************/
Yann Collet5106a762015-11-05 15:00:24 +01001393FORCE_INLINE
Yann Collet5be2dd22015-11-11 13:43:58 +01001394size_t ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
Yann Colletc95f8992015-11-19 17:28:35 +01001395 void* dst, size_t maxDstSize, const void* src, size_t srcSize,
Yann Collet007c1c62015-11-22 02:42:28 +01001396 const U32 searchMethod, const U32 depth)
Yann Collet5106a762015-11-05 15:00:24 +01001397{
1398 seqStore_t* seqStorePtr = &(ctx->seqStore);
1399 const BYTE* const istart = (const BYTE*)src;
1400 const BYTE* ip = istart;
1401 const BYTE* anchor = istart;
1402 const BYTE* const iend = istart + srcSize;
1403 const BYTE* const ilimit = iend - 8;
Yann Collete47c4e52015-12-05 09:23:53 +01001404 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet5106a762015-11-05 15:00:24 +01001405
1406 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1407 const U32 maxSearches = 1 << ctx->params.searchLog;
1408 const U32 mls = ctx->params.searchLength;
1409
Yann Collet5be2dd22015-11-11 13:43:58 +01001410 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
Yann Collet5106a762015-11-05 15:00:24 +01001411 size_t* offsetPtr,
1412 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet5be2dd22015-11-11 13:43:58 +01001413 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet5106a762015-11-05 15:00:24 +01001414
1415 /* init */
1416 ZSTD_resetSeqStore(seqStorePtr);
Yann Collete47c4e52015-12-05 09:23:53 +01001417 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet5106a762015-11-05 15:00:24 +01001418
1419 /* Match Loop */
Yann Collet7a231792015-11-21 15:27:35 +01001420 while (ip < ilimit)
Yann Collet5106a762015-11-05 15:00:24 +01001421 {
Yann Collet7a231792015-11-21 15:27:35 +01001422 size_t matchLength=0;
1423 size_t offset=0;
1424 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001425
Yann Collet743402c2015-11-20 12:03:53 +01001426 /* check repCode */
Yann Collet7a231792015-11-21 15:27:35 +01001427 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))
Yann Collet5106a762015-11-05 15:00:24 +01001428 {
Yann Collet743402c2015-11-20 12:03:53 +01001429 /* repcode : we take it */
Yann Collet7a231792015-11-21 15:27:35 +01001430 matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH;
Yann Collet007c1c62015-11-22 02:42:28 +01001431 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001432 }
1433
Yann Colletfc2afcf2015-11-06 15:40:14 +01001434 {
Yann Collet239cc282015-11-23 16:17:21 +01001435 /* first search (depth 0) */
1436 size_t offsetFound = 99999999;
1437 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1438 if (ml2 > matchLength)
1439 matchLength = ml2, start = ip, offset=offsetFound;
1440 }
Yann Collet9a24e592015-11-22 02:53:43 +01001441
Yann Collete47c4e52015-12-05 09:23:53 +01001442 if (matchLength < MINMATCH)
Yann Collet239cc282015-11-23 16:17:21 +01001443 {
1444 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1445 continue;
1446 }
Yann Collet5106a762015-11-05 15:00:24 +01001447
1448 /* let's try to find a better solution */
Yann Collet007c1c62015-11-22 02:42:28 +01001449 if (depth>=1)
1450 while (ip<ilimit)
Yann Collet5106a762015-11-05 15:00:24 +01001451 {
1452 ip ++;
Yann Collet7a231792015-11-21 15:27:35 +01001453 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1)))
Yann Collet5106a762015-11-05 15:00:24 +01001454 {
Yann Collet007c1c62015-11-22 02:42:28 +01001455 size_t mlRep = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1456 int gain2 = (int)(mlRep * 3);
Yann Collet5106a762015-11-05 15:00:24 +01001457 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet007c1c62015-11-22 02:42:28 +01001458 if ((mlRep >= MINMATCH) && (gain2 > gain1))
1459 matchLength = mlRep, offset = 0, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001460 }
1461 {
1462 size_t offset2=999999;
1463 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet007c1c62015-11-22 02:42:28 +01001464 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1465 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Collet4baee502015-11-09 03:19:33 +01001466 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001467 {
Yann Collet628065c2015-11-06 18:44:54 +01001468 matchLength = ml2, offset = offset2, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001469 continue; /* search a better one */
1470 }
1471 }
1472
1473 /* let's find an even better one */
Yann Collet007c1c62015-11-22 02:42:28 +01001474 if ((depth==2) && (ip<ilimit))
Yann Collet5106a762015-11-05 15:00:24 +01001475 {
1476 ip ++;
Yann Collet7a231792015-11-21 15:27:35 +01001477 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1)))
Yann Collet5106a762015-11-05 15:00:24 +01001478 {
1479 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1480 int gain2 = (int)(ml2 * 4);
1481 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet4baee502015-11-09 03:19:33 +01001482 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001483 matchLength = ml2, offset = 0, start = ip;
1484 }
1485 {
1486 size_t offset2=999999;
1487 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet628065c2015-11-06 18:44:54 +01001488 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1489 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Collet4baee502015-11-09 03:19:33 +01001490 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001491 {
Yann Collet628065c2015-11-06 18:44:54 +01001492 matchLength = ml2, offset = offset2, start = ip;
1493 continue;
Yann Collet5106a762015-11-05 15:00:24 +01001494 }
1495 }
1496 }
1497 break; /* nothing found : store previous solution */
1498 }
1499
Yann Collet4baee502015-11-09 03:19:33 +01001500 /* catch up */
Yann Collet628065c2015-11-06 18:44:54 +01001501 if (offset)
Yann Collet4baee502015-11-09 03:19:33 +01001502 {
Yann Collete47c4e52015-12-05 09:23:53 +01001503 while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */
Yann Collet4baee502015-11-09 03:19:33 +01001504 { start--; matchLength++; }
Yann Collet743402c2015-11-20 12:03:53 +01001505 offset_2 = offset_1; offset_1 = offset;
Yann Collet4baee502015-11-09 03:19:33 +01001506 }
1507
1508 /* store sequence */
Yann Collet7a231792015-11-21 15:27:35 +01001509_storeSequence:
Yann Collet5106a762015-11-05 15:00:24 +01001510 {
1511 size_t litLength = start - anchor;
Yann Collet5106a762015-11-05 15:00:24 +01001512 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
Yann Collet4baee502015-11-09 03:19:33 +01001513 anchor = ip = start + matchLength;
Yann Collet5106a762015-11-05 15:00:24 +01001514 }
1515
Yann Collet743402c2015-11-20 12:03:53 +01001516 /* check immediate repcode */
1517 while ( (ip <= ilimit)
1518 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) )
1519 {
1520 /* store sequence */
1521 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
1522 offset = offset_2;
1523 offset_2 = offset_1;
1524 offset_1 = offset;
1525 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength);
1526 ip += matchLength+MINMATCH;
1527 anchor = ip;
1528 continue; /* faster when present ... (?) */
1529 }
Yann Collet5106a762015-11-05 15:00:24 +01001530 }
1531
1532 /* Last Literals */
1533 {
1534 size_t lastLLSize = iend - anchor;
1535 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1536 seqStorePtr->lit += lastLLSize;
1537 }
1538
1539 /* Final compression stage */
Yann Collet5054ee02015-11-23 13:34:21 +01001540 return ZSTD_compressSequences(dst, maxDstSize,
Yann Collet5106a762015-11-05 15:00:24 +01001541 seqStorePtr, srcSize);
1542}
1543
Yann Collet5be2dd22015-11-11 13:43:58 +01001544size_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 +01001545{
Yann Collet7a231792015-11-21 15:27:35 +01001546 return ZSTD_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 1, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001547}
1548
Yann Collet5be2dd22015-11-11 13:43:58 +01001549size_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 +01001550{
Yann Collet7a231792015-11-21 15:27:35 +01001551 return ZSTD_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001552}
1553
Yann Collet5be2dd22015-11-11 13:43:58 +01001554size_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 +01001555{
Yann Collet7a231792015-11-21 15:27:35 +01001556 return ZSTD_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001557}
1558
Yann Collet5be2dd22015-11-11 13:43:58 +01001559size_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 +01001560{
Yann Collet7a231792015-11-21 15:27:35 +01001561 return ZSTD_compressBlock_lazy_generic(ctx, dst, maxDstSize, src, srcSize, 0, 0);
Yann Colletbe2010e2015-10-31 12:57:14 +01001562}
1563
1564
Yann Collet9a24e592015-11-22 02:53:43 +01001565FORCE_INLINE
1566size_t ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1567 void* dst, size_t maxDstSize, const void* src, size_t srcSize,
1568 const U32 searchMethod, const U32 depth)
1569{
1570 seqStore_t* seqStorePtr = &(ctx->seqStore);
1571 const BYTE* const istart = (const BYTE*)src;
1572 const BYTE* ip = istart;
1573 const BYTE* anchor = istart;
1574 const BYTE* const iend = istart + srcSize;
1575 const BYTE* const ilimit = iend - 8;
1576 const BYTE* const base = ctx->base;
1577 const U32 dictLimit = ctx->dictLimit;
1578 const BYTE* const prefixStart = base + dictLimit;
1579 const BYTE* const dictBase = ctx->dictBase;
1580 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001581 const BYTE* const dictStart = dictBase + ctx->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001582
1583 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1584 const U32 maxSearches = 1 << ctx->params.searchLog;
1585 const U32 mls = ctx->params.searchLength;
1586
1587 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1588 size_t* offsetPtr,
1589 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet03526e12015-11-23 15:29:15 +01001590 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
Yann Collet9a24e592015-11-22 02:53:43 +01001591
1592 /* init */
1593 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet6c3e2e72015-12-11 10:44:07 +01001594 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Collet9a24e592015-11-22 02:53:43 +01001595
1596 /* Match Loop */
1597 while (ip < ilimit)
1598 {
1599 size_t matchLength=0;
1600 size_t offset=0;
1601 const BYTE* start=ip+1;
1602 U32 current = (U32)(ip-base);
1603
1604 /* check repCode */
1605 {
1606 const U32 repIndex = (U32)(current+1 - offset_1);
1607 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1608 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001609 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletd7233d62015-11-22 14:40:51 +01001610 if (MEM_read32(ip+1) == MEM_read32(repMatch))
Yann Collet9a24e592015-11-22 02:53:43 +01001611 {
1612 /* repcode detected we should take it */
1613 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001614 matchLength = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
Yann Collet9a24e592015-11-22 02:53:43 +01001615 if (depth==0) goto _storeSequence;
1616 }
1617 }
1618
1619 {
Yann Collet239cc282015-11-23 16:17:21 +01001620 /* first search (depth 0) */
1621 size_t offsetFound = 99999999;
1622 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1623 if (ml2 > matchLength)
1624 matchLength = ml2, start = ip, offset=offsetFound;
1625 }
Yann Collet9a24e592015-11-22 02:53:43 +01001626
Yann Collet239cc282015-11-23 16:17:21 +01001627 if (matchLength < MINMATCH)
1628 {
1629 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1630 continue;
1631 }
Yann Collet9a24e592015-11-22 02:53:43 +01001632
1633 /* let's try to find a better solution */
1634 if (depth>=1)
1635 while (ip<ilimit)
1636 {
1637 ip ++;
1638 current++;
1639 /* check repCode */
1640 if (offset)
1641 {
1642 const U32 repIndex = (U32)(current - offset_1);
1643 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1644 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001645 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletd7233d62015-11-22 14:40:51 +01001646 if (MEM_read32(ip) == MEM_read32(repMatch))
Yann Collet9a24e592015-11-22 02:53:43 +01001647 {
1648 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001649 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001650 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1651 int gain2 = (int)(repLength * 3);
1652 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1653 if ((repLength >= MINMATCH) && (gain2 > gain1))
1654 matchLength = repLength, offset = 0, start = ip;
Yann Collet9a24e592015-11-22 02:53:43 +01001655 }
1656 }
1657
1658 /* search match, depth 1 */
1659 {
1660 size_t offset2=999999;
1661 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1662 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1663 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
1664 if ((ml2 >= MINMATCH) && (gain2 > gain1))
1665 {
1666 matchLength = ml2, offset = offset2, start = ip;
1667 continue; /* search a better one */
1668 }
1669 }
1670
1671 /* let's find an even better one */
1672 if ((depth==2) && (ip<ilimit))
1673 {
1674 ip ++;
1675 current++;
1676 /* check repCode */
1677 if (offset)
1678 {
1679 const U32 repIndex = (U32)(current - offset_1);
1680 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1681 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001682 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletd7233d62015-11-22 14:40:51 +01001683 if (MEM_read32(ip) == MEM_read32(repMatch))
Yann Collet9a24e592015-11-22 02:53:43 +01001684 {
1685 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001686 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001687 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1688 int gain2 = (int)(repLength * 4);
1689 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1690 if ((repLength >= MINMATCH) && (gain2 > gain1))
1691 matchLength = repLength, offset = 0, start = ip;
Yann Collet9a24e592015-11-22 02:53:43 +01001692 }
1693 }
1694
1695 /* search match, depth 2 */
1696 {
1697 size_t offset2=999999;
1698 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1699 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1700 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
1701 if ((ml2 >= MINMATCH) && (gain2 > gain1))
1702 {
1703 matchLength = ml2, offset = offset2, start = ip;
1704 continue;
1705 }
1706 }
1707 }
1708 break; /* nothing found : store previous solution */
1709 }
1710
1711 /* catch up */
1712 if (offset)
1713 {
Yann Colletc3652152015-11-24 14:06:07 +01001714 U32 matchIndex = (U32)((start-base) - offset);
1715 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1716 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
1717 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet9a24e592015-11-22 02:53:43 +01001718 offset_2 = offset_1; offset_1 = offset;
1719 }
1720
1721 /* store sequence */
1722_storeSequence:
1723 {
1724 size_t litLength = start - anchor;
1725 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1726 anchor = ip = start + matchLength;
1727 }
1728
1729 /* check immediate repcode */
1730 while (ip <= ilimit)
1731 {
1732 const U32 repIndex = (U32)((ip-base) - offset_2);
1733 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1734 const BYTE* const repMatch = repBase + repIndex;
Yann Collet239cc282015-11-23 16:17:21 +01001735 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletd7233d62015-11-22 14:40:51 +01001736 if (MEM_read32(ip) == MEM_read32(repMatch))
Yann Collet9a24e592015-11-22 02:53:43 +01001737 {
1738 /* repcode detected we should take it */
1739 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001740 matchLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1741 offset = offset_2; offset_2 = offset_1; offset_1 = offset; /* swap offset history */
Yann Collet9a24e592015-11-22 02:53:43 +01001742 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1743 ip += matchLength;
1744 anchor = ip;
1745 continue; /* faster when present ... (?) */
1746 }
1747 break;
1748 }
1749 }
1750
1751 /* Last Literals */
1752 {
1753 size_t lastLLSize = iend - anchor;
1754 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1755 seqStorePtr->lit += lastLLSize;
1756 }
1757
1758 /* Final compression stage */
Yann Collet5054ee02015-11-23 13:34:21 +01001759 return ZSTD_compressSequences(dst, maxDstSize,
Yann Collet9a24e592015-11-22 02:53:43 +01001760 seqStorePtr, srcSize);
1761}
1762
1763size_t ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
1764{
1765 return ZSTD_compressBlock_lazy_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 0, 0);
1766}
1767
Yann Colletb7fc88e2015-11-22 03:12:28 +01001768size_t ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
1769{
1770 return ZSTD_compressBlock_lazy_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 0, 1);
1771}
Yann Collet9a24e592015-11-22 02:53:43 +01001772
Yann Colleta85c77b2015-11-22 12:22:04 +01001773size_t ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
1774{
1775 return ZSTD_compressBlock_lazy_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 0, 2);
1776}
1777
Yann Collet03526e12015-11-23 15:29:15 +01001778static 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 +01001779{
Yann Collet03526e12015-11-23 15:29:15 +01001780 return ZSTD_compressBlock_lazy_extDict_generic(ctx, dst, maxDstSize, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001781}
1782
Yann Collet7a231792015-11-21 15:27:35 +01001783
Yann Collet5be2dd22015-11-11 13:43:58 +01001784typedef 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 +01001785
Yann Collet89db5e02015-11-13 11:27:46 +01001786static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01001787{
Yann Collet7fe531e2015-11-29 02:38:09 +01001788 static const ZSTD_blockCompressor blockCompressor[2][5] = {
1789 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy,ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2 },
1790 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict }
1791 };
1792
1793 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01001794}
1795
1796
Yann Colletbf42c8e2016-01-09 01:08:23 +01001797static 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 +01001798{
Yann Collet03526e12015-11-23 15:29:15 +01001799 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet523b5942016-01-09 02:10:40 +01001800 if (srcSize < MIN_CBLOCK_SIZE+3) return 0; /* don't even attempt compression below a certain srcSize */
Yann Collet03526e12015-11-23 15:29:15 +01001801 return blockCompressor(zc, dst, maxDstSize, src, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01001802}
1803
1804
Yann Collet5be2dd22015-11-11 13:43:58 +01001805static size_t ZSTD_compress_generic (ZSTD_CCtx* ctxPtr,
Yann Colletf3eca252015-10-22 15:31:46 +01001806 void* dst, size_t maxDstSize,
1807 const void* src, size_t srcSize)
1808{
Yann Collet120230b2015-12-02 14:00:45 +01001809 size_t blockSize = ctxPtr->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001810 size_t remaining = srcSize;
1811 const BYTE* ip = (const BYTE*)src;
1812 BYTE* const ostart = (BYTE*)dst;
1813 BYTE* op = ostart;
Yann Collet89db5e02015-11-13 11:27:46 +01001814 const U32 maxDist = 1 << ctxPtr->params.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01001815
Yann Collet3e358272015-11-04 18:19:39 +01001816 while (remaining)
Yann Colletf3eca252015-10-22 15:31:46 +01001817 {
Yann Collet3e358272015-11-04 18:19:39 +01001818 size_t cSize;
1819
Yann Collet3137d1a2015-11-04 23:36:36 +01001820 if (maxDstSize < 3 + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01001821 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01001822
1823 if ((U32)(ip+blockSize - (ctxPtr->base + ctxPtr->lowLimit)) > maxDist)
Yann Colletc3652152015-11-24 14:06:07 +01001824 {
Yann Collet89db5e02015-11-13 11:27:46 +01001825 /* respect windowLog contract */
Yann Colletc3652152015-11-24 14:06:07 +01001826 ctxPtr->lowLimit = (U32)(ip+blockSize - ctxPtr->base) - maxDist;
1827 if (ctxPtr->dictLimit < ctxPtr->lowLimit) ctxPtr->dictLimit = ctxPtr->lowLimit;
1828 }
Yann Collet89db5e02015-11-13 11:27:46 +01001829
Yann Colletbf42c8e2016-01-09 01:08:23 +01001830 cSize = ZSTD_compressBlock_internal(ctxPtr, op+3, maxDstSize-3, ip, blockSize);
Yann Collet3e358272015-11-04 18:19:39 +01001831 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001832
1833 if (cSize == 0)
1834 {
1835 cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize); /* block is not compressible */
Yann Collet523b5942016-01-09 02:10:40 +01001836 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001837 }
1838 else
1839 {
1840 op[0] = (BYTE)(cSize>>16);
1841 op[1] = (BYTE)(cSize>>8);
1842 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01001843 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01001844 cSize += 3;
1845 }
1846
1847 remaining -= blockSize;
Yann Collet3e358272015-11-04 18:19:39 +01001848 maxDstSize -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001849 ip += blockSize;
1850 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001851 }
1852
1853 return op-ostart;
1854}
1855
1856
Yann Colletbf42c8e2016-01-09 01:08:23 +01001857static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
1858 void* dst, size_t dstSize,
1859 const void* src, size_t srcSize,
1860 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01001861{
Yann Collet2acb5d32015-10-29 16:49:43 +01001862 const BYTE* const ip = (const BYTE*) src;
Yann Colletecd651b2016-01-07 15:35:18 +01001863 size_t hbSize = 0;
1864
Yann Colletbf42c8e2016-01-09 01:08:23 +01001865 if (frame && (zc->stage==0))
Yann Colletecd651b2016-01-07 15:35:18 +01001866 {
1867 hbSize = zc->hbSize;
1868 if (dstSize <= hbSize) return ERROR(dstSize_tooSmall);
1869 zc->stage = 1;
1870 memcpy(dst, zc->headerBuffer, hbSize);
1871 dstSize -= hbSize;
1872 dst = (char*)dst + hbSize;
1873 }
Yann Colletf3eca252015-10-22 15:31:46 +01001874
Yann Collet417890c2015-12-04 17:16:37 +01001875 /* Check if blocks follow each other */
1876 if (src != zc->nextSrc)
1877 {
1878 /* not contiguous */
1879 size_t delta = zc->nextSrc - ip;
1880 zc->lowLimit = zc->dictLimit;
1881 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
1882 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01001883 zc->base -= delta;
1884 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01001885 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01001886 }
1887
Yann Collet89db5e02015-11-13 11:27:46 +01001888 /* preemptive overflow correction */
Yann Collet6c3e2e72015-12-11 10:44:07 +01001889 if (zc->lowLimit > (1<<30))
Yann Colletf3eca252015-10-22 15:31:46 +01001890 {
Yann Collet6c3e2e72015-12-11 10:44:07 +01001891 U32 btplus = (zc->params.strategy == ZSTD_btlazy2);
1892 U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1;
1893 U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */
1894 U32 correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001895 ZSTD_reduceIndex(zc, correction);
1896 zc->base += correction;
1897 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001898 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001899 zc->dictLimit -= correction;
1900 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
1901 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01001902 }
1903
Yann Colletbf42c8e2016-01-09 01:08:23 +01001904 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Colletc3652152015-11-24 14:06:07 +01001905 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit))
Yann Collet89db5e02015-11-13 11:27:46 +01001906 {
Yann Colletc3652152015-11-24 14:06:07 +01001907 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
1908 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001909 }
1910
Yann Colletc3652152015-11-24 14:06:07 +01001911 zc->nextSrc = ip + srcSize;
Yann Colletecd651b2016-01-07 15:35:18 +01001912 {
Yann Colletbf42c8e2016-01-09 01:08:23 +01001913 size_t cSize;
1914 if (frame) cSize = ZSTD_compress_generic (zc, dst, dstSize, src, srcSize);
1915 else cSize = ZSTD_compressBlock_internal (zc, dst, dstSize, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01001916 if (ZSTD_isError(cSize)) return cSize;
1917 return cSize + hbSize;
1918 }
Yann Colletf3eca252015-10-22 15:31:46 +01001919}
1920
Yann Colletbf42c8e2016-01-09 01:08:23 +01001921
1922size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
1923 void* dst, size_t dstSize,
1924 const void* src, size_t srcSize)
1925{
1926 return ZSTD_compressContinue_internal(zc, dst, dstSize, src, srcSize, 1);
1927}
1928
1929
1930size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
1931{
1932 if (srcSize > BLOCKSIZE) return ERROR(srcSize_wrong);
Yann Colletbf42c8e2016-01-09 01:08:23 +01001933 return ZSTD_compressContinue_internal(zc, dst, maxDstSize, src, srcSize, 0);
1934}
1935
1936
Yann Collet417890c2015-12-04 17:16:37 +01001937size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* src, size_t srcSize)
1938{
1939 const BYTE* const ip = (const BYTE*) src;
1940 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001941
Yann Collet417890c2015-12-04 17:16:37 +01001942 /* input becomes current prefix */
1943 zc->lowLimit = zc->dictLimit;
1944 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
1945 zc->dictBase = zc->base;
1946 zc->base += ip - zc->nextSrc;
1947 zc->nextToUpdate = zc->dictLimit;
1948
1949 zc->nextSrc = iend;
1950 if (srcSize <= 8) return 0;
1951
1952 switch(zc->params.strategy)
1953 {
1954 case ZSTD_fast:
1955 ZSTD_fillHashTable (zc, iend-8, zc->params.searchLength);
1956 break;
1957
1958 case ZSTD_greedy:
1959 case ZSTD_lazy:
1960 case ZSTD_lazy2:
1961 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength);
1962 break;
1963
1964 case ZSTD_btlazy2:
1965 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength);
Yann Collet48da1642015-12-29 23:40:02 +01001966 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01001967 break;
1968
1969 default:
1970 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
1971 }
1972
1973 return 0;
1974}
1975
1976
Yann Colletecd651b2016-01-07 15:35:18 +01001977/*! ZSTD_duplicateCCtx
1978* Duplicate an existing context @srcCCtx into another one @dstCCtx.
1979* Only works during stage 0 (i.e. before first call to ZSTD_compressContinue())
1980* @return : 0, or an error code */
1981size_t ZSTD_duplicateCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
1982{
Yann Collet6e1c4c62016-01-07 23:07:44 +01001983 const U32 contentLog = (srcCCtx->params.strategy == ZSTD_fast) ? 1 : srcCCtx->params.contentLog;
1984 const size_t tableSpace = ((1 << contentLog) + (1 << srcCCtx->params.hashLog)) * sizeof(U32);
Yann Colletecd651b2016-01-07 15:35:18 +01001985
Yann Collet6e1c4c62016-01-07 23:07:44 +01001986 if (srcCCtx->stage!=0) return ERROR(stage_wrong);
1987
Yann Collet60096272016-01-08 17:27:50 +01001988 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params);
Yann Colletecd651b2016-01-07 15:35:18 +01001989
Yann Collet60096272016-01-08 17:27:50 +01001990 /* copy tables */
1991 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace);
Yann Colletecd651b2016-01-07 15:35:18 +01001992
Yann Collet60096272016-01-08 17:27:50 +01001993 /* copy frame header */
1994 dstCCtx->hbSize = srcCCtx->hbSize;
1995 memcpy(dstCCtx->headerBuffer , srcCCtx->headerBuffer, srcCCtx->hbSize);
1996
1997 /* copy dictionary pointers */
1998 dstCCtx->nextToUpdate= srcCCtx->nextToUpdate;
1999 dstCCtx->nextSrc = srcCCtx->nextSrc;
2000 dstCCtx->base = srcCCtx->base;
2001 dstCCtx->dictBase = srcCCtx->dictBase;
2002 dstCCtx->dictLimit = srcCCtx->dictLimit;
2003 dstCCtx->lowLimit = srcCCtx->lowLimit;
Yann Collet6e1c4c62016-01-07 23:07:44 +01002004
Yann Colletecd651b2016-01-07 15:35:18 +01002005 return 0;
2006}
2007
2008
Yann Collet417890c2015-12-04 17:16:37 +01002009/*! ZSTD_compressBegin_advanced
Yann Colletecd651b2016-01-07 15:35:18 +01002010* @return : 0, or an error code */
Yann Collet5be2dd22015-11-11 13:43:58 +01002011size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* ctx,
Yann Collet88fcd292015-11-25 14:42:45 +01002012 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002013{
Yann Collet4114f952015-10-30 06:40:22 +01002014 size_t errorCode;
Yann Collet88fcd292015-11-25 14:42:45 +01002015
2016 ZSTD_validateParams(&params);
2017
Yann Collet88fcd292015-11-25 14:42:45 +01002018 errorCode = ZSTD_resetCCtx_advanced(ctx, params);
Yann Collet4114f952015-10-30 06:40:22 +01002019 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet89db5e02015-11-13 11:27:46 +01002020
Yann Colletecd651b2016-01-07 15:35:18 +01002021 MEM_writeLE32(ctx->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */
2022 ((BYTE*)ctx->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN);
2023 ctx->hbSize = ZSTD_frameHeaderSize_min;
2024 ctx->stage = 0;
2025
2026 return 0;
Yann Collet88fcd292015-11-25 14:42:45 +01002027}
2028
2029
2030/** ZSTD_getParams
2031* return ZSTD_parameters structure for a selected compression level and srcSize.
2032* srcSizeHint value is optional, select 0 if not known */
2033ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint)
2034{
2035 ZSTD_parameters result;
Yann Colletd6080882015-12-09 09:05:22 +01002036 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 +01002037 if (compressionLevel<=0) compressionLevel = 1;
2038 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
2039 result = ZSTD_defaultParameters[tableID][compressionLevel];
2040 result.srcSize = srcSizeHint;
2041 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002042}
2043
Yann Collet083fcc82015-10-25 14:06:35 +01002044
Yann Colletecd651b2016-01-07 15:35:18 +01002045size_t ZSTD_compressBegin(ZSTD_CCtx* ctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002046{
Yann Colletecd651b2016-01-07 15:35:18 +01002047 return ZSTD_compressBegin_advanced(ctx, ZSTD_getParams(compressionLevel, 0));
Yann Collet083fcc82015-10-25 14:06:35 +01002048}
2049
2050
Yann Collet31683c02015-12-18 01:26:48 +01002051/*! ZSTD_compressEnd
Yann Collet88fcd292015-11-25 14:42:45 +01002052* Write frame epilogue
2053* @return : nb of bytes written into dst (or an error code) */
Yann Colletecd651b2016-01-07 15:35:18 +01002054size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize)
Yann Collet2acb5d32015-10-29 16:49:43 +01002055{
2056 BYTE* op = (BYTE*)dst;
Yann Colletecd651b2016-01-07 15:35:18 +01002057 size_t hbSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002058
Yann Colletecd651b2016-01-07 15:35:18 +01002059 /* empty frame */
2060 if (zc->stage==0)
2061 {
2062 hbSize = zc->hbSize;
2063 if (maxDstSize <= hbSize) return ERROR(dstSize_tooSmall);
2064 zc->stage = 1;
2065 memcpy(dst, zc->headerBuffer, hbSize);
2066 maxDstSize -= hbSize;
2067 op += hbSize;
2068 }
2069
2070 /* frame epilogue */
Yann Collet2acb5d32015-10-29 16:49:43 +01002071 if (maxDstSize < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002072 op[0] = (BYTE)(bt_end << 6);
2073 op[1] = 0;
2074 op[2] = 0;
2075
Yann Colletecd651b2016-01-07 15:35:18 +01002076 return 3+hbSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002077}
2078
Yann Collet5be2dd22015-11-11 13:43:58 +01002079size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
Yann Collet88fcd292015-11-25 14:42:45 +01002080 void* dst, size_t maxDstSize,
2081 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002082 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002083 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002084{
2085 BYTE* const ostart = (BYTE*)dst;
2086 BYTE* op = ostart;
Yann Collet4114f952015-10-30 06:40:22 +01002087 size_t oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002088
2089 /* Header */
Yann Colletecd651b2016-01-07 15:35:18 +01002090 oSize = ZSTD_compressBegin_advanced(ctx, params);
Yann Colletf3eca252015-10-22 15:31:46 +01002091 if(ZSTD_isError(oSize)) return oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002092
Yann Collet31683c02015-12-18 01:26:48 +01002093 /* dictionary */
2094 if (dict)
2095 {
2096 oSize = ZSTD_compress_insertDictionary(ctx, dict, dictSize);
2097 if (ZSTD_isError(oSize)) return oSize;
2098 }
2099
Yann Colletf3eca252015-10-22 15:31:46 +01002100 /* body (compression) */
Yann Collet31683c02015-12-18 01:26:48 +01002101 oSize = ZSTD_compressContinue (ctx, op, maxDstSize, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002102 if(ZSTD_isError(oSize)) return oSize;
2103 op += oSize;
2104 maxDstSize -= oSize;
2105
2106 /* Close frame */
Yann Collet5be2dd22015-11-11 13:43:58 +01002107 oSize = ZSTD_compressEnd(ctx, op, maxDstSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002108 if(ZSTD_isError(oSize)) return oSize;
2109 op += oSize;
2110
2111 return (op - ostart);
2112}
2113
Yann Collet31683c02015-12-18 01:26:48 +01002114size_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)
2115{
2116 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize+dictSize));
2117}
2118
Yann Collet5be2dd22015-11-11 13:43:58 +01002119size_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 +01002120{
Yann Collet31683c02015-12-18 01:26:48 +01002121 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet083fcc82015-10-25 14:06:35 +01002122}
2123
Yann Collet5be2dd22015-11-11 13:43:58 +01002124size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002125{
Yann Collet44fe9912015-10-29 22:02:40 +01002126 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002127 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002128 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Collet5be2dd22015-11-11 13:43:58 +01002129 result = ZSTD_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel);
Yann Colletecd651b2016-01-07 15:35:18 +01002130 free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002131 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002132}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002133