blob: dda6683e6d7d4aa6dfb97d515ad881ad20050530 [file] [log] [blame]
Yann Colletf3eca252015-10-22 15:31:46 +01001/*
2 ZSTD HC - High Compression Mode of Zstandard
Yann Collet863ec402016-01-28 17:56:33 +01003 Copyright (C) 2015-2016, Yann Collet.
Yann Colletf3eca252015-10-22 15:31:46 +01004
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 */
Yann Collet4b100f42015-10-30 15:49:48 +010042#else
Yann Collet4b100f42015-10-30 15:49:48 +010043# ifdef __GNUC__
44# define FORCE_INLINE static inline __attribute__((always_inline))
45# else
46# define FORCE_INLINE static inline
47# endif
48#endif
49
50
Yann Colletf3eca252015-10-22 15:31:46 +010051/* *************************************
Yann Colletae7aa062016-02-03 02:46:46 +010052* Dependencies
Yann Colletf3eca252015-10-22 15:31:46 +010053***************************************/
54#include <stdlib.h> /* malloc */
55#include <string.h> /* memset */
Yann Collet14983e72015-11-11 21:38:21 +010056#include "mem.h"
57#include "fse_static.h"
Yann Colletafe07092016-01-25 04:10:46 +010058#include "huff0_static.h"
Yann Collet3d9cf7a2015-10-29 17:15:14 +010059#include "zstd_internal.h"
Yann Colletf3eca252015-10-22 15:31:46 +010060
61
62/* *************************************
Yann Collet14983e72015-11-11 21:38:21 +010063* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010064***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010065static const U32 g_searchStrength = 8;
Yann Colletf3eca252015-10-22 15:31:46 +010066
Yann Colletf3eca252015-10-22 15:31:46 +010067
68/* *************************************
Yann Collet59d1f792016-01-23 19:28:41 +010069* Helper functions
70***************************************/
Yann Collet59d1f792016-01-23 19:28:41 +010071size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
72
73
74/* *************************************
Yann Collet14983e72015-11-11 21:38:21 +010075* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010076***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010077typedef struct {
78 void* buffer;
79 U32* offsetStart;
80 U32* offset;
81 BYTE* offCodeStart;
82 BYTE* offCode;
83 BYTE* litStart;
84 BYTE* lit;
85 BYTE* litLengthStart;
86 BYTE* litLength;
87 BYTE* matchLengthStart;
88 BYTE* matchLength;
89 BYTE* dumpsStart;
90 BYTE* dumps;
Yann Collet70e8c382016-02-10 13:37:52 +010091 /* opt */
inikep70b05452016-02-03 22:56:55 +010092 U32* matchLengthFreq;
93 U32* litLengthFreq;
94 U32* litFreq;
95 U32* offCodeFreq;
Yann Collet70e8c382016-02-10 13:37:52 +010096 U32 matchLengthSum;
97 U32 litLengthSum;
98 U32 litSum;
99 U32 offCodeSum;
Yann Collet14983e72015-11-11 21:38:21 +0100100} seqStore_t;
101
inikep27e1c6a2016-02-04 11:11:08 +0100102static void ZSTD_resetFreqs(seqStore_t* ssPtr)
Yann Collet14983e72015-11-11 21:38:21 +0100103{
Yann Collet70e8c382016-02-10 13:37:52 +0100104 unsigned u;
105 ssPtr->matchLengthSum = 512; // (1<<MLbits);
106 ssPtr->litLengthSum = 256; // (1<<LLbits);
inikep3bfcfc72016-02-03 18:47:30 +0100107 ssPtr->litSum = (1<<Litbits);
108 ssPtr->offCodeSum = (1<<Offbits);
109
Yann Collet70e8c382016-02-10 13:37:52 +0100110 for (u=0; u<=MaxLit; u++)
111 ssPtr->litFreq[u] = 1;
112 for (u=0; u<=MaxLL; u++)
113 ssPtr->litLengthFreq[u] = 1;
114 for (u=0; u<=MaxML; u++)
115 ssPtr->matchLengthFreq[u] = 1;
116 for (u=0; u<=MaxOff; u++)
117 ssPtr->offCodeFreq[u] = 1;
Yann Collet14983e72015-11-11 21:38:21 +0100118}
119
Yann Collet14983e72015-11-11 21:38:21 +0100120static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
121{
122 ssPtr->offset = ssPtr->offsetStart;
123 ssPtr->lit = ssPtr->litStart;
124 ssPtr->litLength = ssPtr->litLengthStart;
125 ssPtr->matchLength = ssPtr->matchLengthStart;
126 ssPtr->dumps = ssPtr->dumpsStart;
inikep27e1c6a2016-02-04 11:11:08 +0100127
128 ZSTD_resetFreqs(ssPtr);
Yann Collet14983e72015-11-11 21:38:21 +0100129}
130
131
132/* *************************************
133* Context memory management
134***************************************/
Yann Collet5be2dd22015-11-11 13:43:58 +0100135struct ZSTD_CCtx_s
Yann Colletf3eca252015-10-22 15:31:46 +0100136{
Yann Collet89db5e02015-11-13 11:27:46 +0100137 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100138 const BYTE* base; /* All regular indexes relative to this position */
139 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +0100140 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100141 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +0100142 U32 nextToUpdate; /* index from which to continue dictionary update */
Yann Collet2ce49232016-02-02 14:36:49 +0100143 U32 loadedDictEnd;
Yann Colletecd651b2016-01-07 15:35:18 +0100144 U32 stage;
Yann Collet5be2dd22015-11-11 13:43:58 +0100145 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +0100146 void* workSpace;
147 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100148 size_t blockSize;
Yann Colletecd651b2016-01-07 15:35:18 +0100149 size_t hbSize;
Yann Collet60096272016-01-08 17:27:50 +0100150 char headerBuffer[ZSTD_frameHeaderSize_max];
Yann Colletecd651b2016-01-07 15:35:18 +0100151
Yann Collet712def92015-10-29 18:41:45 +0100152 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100153 U32* hashTable;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100154 U32* contentTable;
Yann Colletb923f652016-01-26 03:14:20 +0100155 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +0100156 U32 flagStaticTables;
157 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
158 FSE_CTable matchlengthCTable [FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
159 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Colletf3eca252015-10-22 15:31:46 +0100160};
161
162
Yann Collet5be2dd22015-11-11 13:43:58 +0100163ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100164{
Yann Collet5be2dd22015-11-11 13:43:58 +0100165 return (ZSTD_CCtx*) calloc(1, sizeof(ZSTD_CCtx));
Yann Colletf3eca252015-10-22 15:31:46 +0100166}
167
Yann Collet5be2dd22015-11-11 13:43:58 +0100168size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100169{
Yann Collet712def92015-10-29 18:41:45 +0100170 free(cctx->workSpace);
Yann Collet083fcc82015-10-25 14:06:35 +0100171 free(cctx);
Yann Collet982ffc72016-02-05 02:33:10 +0100172 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100173}
174
Yann Collet59d70632015-11-04 12:05:27 +0100175
Yann Collet14983e72015-11-11 21:38:21 +0100176static unsigned ZSTD_highbit(U32 val);
177
Yann Collet70e8c382016-02-10 13:37:52 +0100178#define CLAMP(val,min,max) { if (val<min) val=min; else if (val>max) val=max; }
179
180/** ZSTD_validateParams()
Yann Collet59d70632015-11-04 12:05:27 +0100181 correct params value to remain within authorized range
182 optimize for srcSize if srcSize > 0 */
Yann Collet88fcd292015-11-25 14:42:45 +0100183void ZSTD_validateParams(ZSTD_parameters* params)
Yann Collet59d70632015-11-04 12:05:27 +0100184{
inikepc71568f2016-01-30 12:15:56 +0100185 const U32 btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_opt_bt);
Yann Collet59d70632015-11-04 12:05:27 +0100186
187 /* validate params */
Yann Collet00fd7a22015-11-28 16:03:22 +0100188 if (MEM_32bits()) if (params->windowLog > 25) params->windowLog = 25; /* 32 bits mode cannot flush > 24 bits */
Yann Collet70e8c382016-02-10 13:37:52 +0100189 CLAMP(params->windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
190 CLAMP(params->contentLog, ZSTD_CONTENTLOG_MIN, ZSTD_CONTENTLOG_MAX);
191 CLAMP(params->hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
192 CLAMP(params->searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
193 CLAMP(params->searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
Yann Colletbd828d92016-02-11 04:38:55 +0100194 CLAMP(params->targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Collet70e8c382016-02-10 13:37:52 +0100195 if ((U32)params->strategy>(U32)ZSTD_opt_bt) params->strategy = ZSTD_opt_bt;
Yann Collet59d70632015-11-04 12:05:27 +0100196
197 /* correct params, to use less memory */
Yann Colletfb810d62016-01-28 00:18:06 +0100198 if ((params->srcSize > 0) && (params->srcSize < (1<<ZSTD_WINDOWLOG_MAX))) {
Yann Collet88fcd292015-11-25 14:42:45 +0100199 U32 srcLog = ZSTD_highbit((U32)(params->srcSize)-1) + 1;
Yann Collet59d70632015-11-04 12:05:27 +0100200 if (params->windowLog > srcLog) params->windowLog = srcLog;
201 }
Yann Collet00fd7a22015-11-28 16:03:22 +0100202 if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet5be2dd22015-11-11 13:43:58 +0100203 if (params->contentLog > params->windowLog+btPlus) params->contentLog = params->windowLog+btPlus; /* <= ZSTD_CONTENTLOG_MAX */
Yann Collet59d70632015-11-04 12:05:27 +0100204}
205
206
Yann Collet5be2dd22015-11-11 13:43:58 +0100207static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Collet88fcd292015-11-25 14:42:45 +0100208 ZSTD_parameters params)
Yann Collet863ec402016-01-28 17:56:33 +0100209{ /* note : params considered validated here */
Yann Collet120230b2015-12-02 14:00:45 +0100210 const size_t blockSize = MIN(BLOCKSIZE, (size_t)1 << params.windowLog);
Yann Collet2acb5d32015-10-29 16:49:43 +0100211 /* reserve table memory */
Yann Collet863ec402016-01-28 17:56:33 +0100212 const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog;
213 const size_t tableSpace = ((1 << contentLog) + (1 << params.hashLog)) * sizeof(U32);
inikep70b05452016-02-03 22:56:55 +0100214 const size_t neededSpace = tableSpace + (256*sizeof(U32)) + (3*blockSize) + ((1<<MLbits) + (1<<LLbits) + (1<<Offbits) + (1<<Litbits))*sizeof(U32);
Yann Collet863ec402016-01-28 17:56:33 +0100215 if (zc->workSpaceSize < neededSpace) {
216 free(zc->workSpace);
217 zc->workSpace = malloc(neededSpace);
218 if (zc->workSpace == NULL) return ERROR(memory_allocation);
219 zc->workSpaceSize = neededSpace;
Yann Collet083fcc82015-10-25 14:06:35 +0100220 }
Yann Collet863ec402016-01-28 17:56:33 +0100221 memset(zc->workSpace, 0, tableSpace ); /* reset only tables */
222 zc->hashTable = (U32*)(zc->workSpace);
223 zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog);
224 zc->seqStore.buffer = zc->contentTable + ((size_t)1 << contentLog);
225 zc->hufTable = (HUF_CElt*)zc->seqStore.buffer;
226 zc->flagStaticTables = 0;
227 zc->seqStore.buffer = (U32*)(zc->seqStore.buffer) + 256;
Yann Collet083fcc82015-10-25 14:06:35 +0100228
Yann Colletf48e35c2015-11-07 01:13:31 +0100229 zc->nextToUpdate = 1;
Yann Collet89db5e02015-11-13 11:27:46 +0100230 zc->nextSrc = NULL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100231 zc->base = NULL;
232 zc->dictBase = NULL;
233 zc->dictLimit = 0;
234 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100235 zc->params = params;
Yann Collet120230b2015-12-02 14:00:45 +0100236 zc->blockSize = blockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100237
238 zc->seqStore.litFreq = (U32*) (zc->seqStore.buffer);
239 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
240 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (1<<LLbits);
241 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (1<<MLbits);
242
243 zc->seqStore.offsetStart = zc->seqStore.offCodeFreq + (1<<Offbits);
Yann Collet120230b2015-12-02 14:00:45 +0100244 zc->seqStore.offCodeStart = (BYTE*) (zc->seqStore.offsetStart + (blockSize>>2));
245 zc->seqStore.litStart = zc->seqStore.offCodeStart + (blockSize>>2);
246 zc->seqStore.litLengthStart = zc->seqStore.litStart + blockSize;
247 zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + (blockSize>>2);
248 zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (blockSize>>2);
Yann Collet70e8c382016-02-10 13:37:52 +0100249 // zc->seqStore.XXX = zc->seqStore.dumpsStart + (blockSize>>4);
inikep3bfcfc72016-02-03 18:47:30 +0100250
Yann Colletecd651b2016-01-07 15:35:18 +0100251 zc->hbSize = 0;
Yann Collet60096272016-01-08 17:27:50 +0100252 zc->stage = 0;
Yann Collet2ce49232016-02-02 14:36:49 +0100253 zc->loadedDictEnd = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +0100254
Yann Collet4114f952015-10-30 06:40:22 +0100255 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100256}
257
Yann Collet083fcc82015-10-25 14:06:35 +0100258
Yann Collet7b51a292016-01-26 15:58:49 +0100259/*! ZSTD_copyCCtx
260* Duplicate an existing context @srcCCtx into another one @dstCCtx.
261* Only works during stage 0 (i.e. before first call to ZSTD_compressContinue())
262* @return : 0, or an error code */
263size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
264{
265 const U32 contentLog = (srcCCtx->params.strategy == ZSTD_fast) ? 1 : srcCCtx->params.contentLog;
266 const size_t tableSpace = ((1 << contentLog) + (1 << srcCCtx->params.hashLog)) * sizeof(U32);
267
268 if (srcCCtx->stage!=0) return ERROR(stage_wrong);
269
270 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params);
271
272 /* copy tables */
273 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace);
274
275 /* copy frame header */
276 dstCCtx->hbSize = srcCCtx->hbSize;
277 memcpy(dstCCtx->headerBuffer , srcCCtx->headerBuffer, srcCCtx->hbSize);
278
279 /* copy dictionary pointers */
280 dstCCtx->nextToUpdate= srcCCtx->nextToUpdate;
281 dstCCtx->nextSrc = srcCCtx->nextSrc;
282 dstCCtx->base = srcCCtx->base;
283 dstCCtx->dictBase = srcCCtx->dictBase;
284 dstCCtx->dictLimit = srcCCtx->dictLimit;
285 dstCCtx->lowLimit = srcCCtx->lowLimit;
Yann Collet7a6343f2016-02-02 16:00:50 +0100286 dstCCtx->loadedDictEnd = srcCCtx->loadedDictEnd;
Yann Collet7b51a292016-01-26 15:58:49 +0100287
Yann Colletfb810d62016-01-28 00:18:06 +0100288 /* copy entropy tables */
289 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100290 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100291 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100292 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
293 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
294 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
295 }
Yann Collet7b51a292016-01-26 15:58:49 +0100296
297 return 0;
298}
299
300
Yann Collet863ec402016-01-28 17:56:33 +0100301/*! ZSTD_reduceIndex
Yann Collet88fcd292015-11-25 14:42:45 +0100302* rescale indexes to avoid future overflow (indexes are U32) */
Yann Collet89db5e02015-11-13 11:27:46 +0100303static void ZSTD_reduceIndex (ZSTD_CCtx* zc,
304 const U32 reducerValue)
305{
Yann Collet88fcd292015-11-25 14:42:45 +0100306 const U32 contentLog = (zc->params.strategy == ZSTD_fast) ? 1 : zc->params.contentLog;
Yann Collet89db5e02015-11-13 11:27:46 +0100307 const U32 tableSpaceU32 = (1 << contentLog) + (1 << zc->params.hashLog);
308 U32* table32 = zc->hashTable;
309 U32 index;
310
Yann Colletfb810d62016-01-28 00:18:06 +0100311 for (index=0 ; index < tableSpaceU32 ; index++) {
Yann Collet89db5e02015-11-13 11:27:46 +0100312 if (table32[index] < reducerValue) table32[index] = 0;
313 else table32[index] -= reducerValue;
314 }
315}
316
317
Yann Collet863ec402016-01-28 17:56:33 +0100318/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100319* Block entropic compression
320*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100321
Yann Collet59d1f792016-01-23 19:28:41 +0100322/* Block format description
323
324 Block = Literal Section - Sequences Section
325 Prerequisite : size of (compressed) block, maximum size of regenerated data
326
327 1) Literal Section
328
329 1.1) Header : 1-5 bytes
330 flags: 2 bits
331 00 compressed by Huff0
332 01 unused
333 10 is Raw (uncompressed)
334 11 is Rle
335 Note : using 01 => Huff0 with precomputed table ?
336 Note : delta map ? => compressed ?
337
338 1.1.1) Huff0-compressed literal block : 3-5 bytes
Yann Colletafe07092016-01-25 04:10:46 +0100339 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
Yann Collet59d1f792016-01-23 19:28:41 +0100340 srcSize < 1 KB => 3 bytes (2-2-10-10)
Yann Colleta1249dc2016-01-25 04:22:03 +0100341 srcSize < 16KB => 4 bytes (2-2-14-14)
Yann Collet59d1f792016-01-23 19:28:41 +0100342 else => 5 bytes (2-2-18-18)
343 big endian convention
344
345 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
346 size : 5 bits: (IS_RAW<<6) + (0<<4) + size
347 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
348 size&255
349 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
350 size>>8&255
351 size&255
352
353 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
354 size : 5 bits: (IS_RLE<<6) + (0<<4) + size
355 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
356 size&255
357 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
358 size>>8&255
359 size&255
360
Yann Colleta1249dc2016-01-25 04:22:03 +0100361 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
362 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
363 srcSize < 1 KB => 3 bytes (2-2-10-10)
364 srcSize < 16KB => 4 bytes (2-2-14-14)
365 else => 5 bytes (2-2-18-18)
366 big endian convention
367
368 1- CTable available (stored into workspace ?)
Yann Colletb923f652016-01-26 03:14:20 +0100369 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
Yann Colleta1249dc2016-01-25 04:22:03 +0100370
Yann Collet59d1f792016-01-23 19:28:41 +0100371
372 1.2) Literal block content
373
374 1.2.1) Huff0 block, using sizes from header
375 See Huff0 format
376
Yann Colletfb810d62016-01-28 00:18:06 +0100377 1.2.2) Huff0 block, using prepared table
Yann Collet59d1f792016-01-23 19:28:41 +0100378
Yann Colletfb810d62016-01-28 00:18:06 +0100379 1.2.3) Raw content
Yann Collet59d1f792016-01-23 19:28:41 +0100380
Yann Colletfb810d62016-01-28 00:18:06 +0100381 1.2.4) single byte
Yann Collet59d1f792016-01-23 19:28:41 +0100382
383
384 2) Sequences section
Yann Colletfb810d62016-01-28 00:18:06 +0100385
386 - Nb Sequences : 2 bytes, little endian
387 - Control Token : 1 byte (see below)
388 - Dumps Length : 1 or 2 bytes (depending on control token)
389 - Dumps : as stated by dumps length
390 - Literal Lengths FSE table (as needed depending on encoding method)
391 - Offset Codes FSE table (as needed depending on encoding method)
392 - Match Lengths FSE table (as needed depending on encoding method)
393
394 2.1) Control Token
395 8 bits, divided as :
396 0-1 : dumpsLength
397 2-3 : MatchLength, FSE encoding method
398 4-5 : Offset Codes, FSE encoding method
399 6-7 : Literal Lengths, FSE encoding method
400
401 FSE encoding method :
402 FSE_ENCODING_RAW : uncompressed; no header
403 FSE_ENCODING_RLE : single repeated value; header 1 byte
404 FSE_ENCODING_STATIC : use prepared table; no header
405 FSE_ENCODING_DYNAMIC : read NCount
Yann Collet59d1f792016-01-23 19:28:41 +0100406*/
Yann Collet14983e72015-11-11 21:38:21 +0100407
408size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
409{
410 BYTE* const ostart = (BYTE* const)dst;
411
412 if (srcSize + ZSTD_blockHeaderSize > maxDstSize) return ERROR(dstSize_tooSmall);
413 memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
414
415 /* Build header */
416 ostart[0] = (BYTE)(srcSize>>16);
417 ostart[1] = (BYTE)(srcSize>>8);
418 ostart[2] = (BYTE) srcSize;
419 ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
420
421 return ZSTD_blockHeaderSize+srcSize;
422}
423
424
425static size_t ZSTD_noCompressLiterals (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
426{
427 BYTE* const ostart = (BYTE* const)dst;
Yann Collet59d1f792016-01-23 19:28:41 +0100428 const U32 flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100429
Yann Collet59d1f792016-01-23 19:28:41 +0100430 if (srcSize + flSize > maxDstSize) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100431
Yann Collet59d1f792016-01-23 19:28:41 +0100432 switch(flSize)
433 {
434 case 1: /* 2 - 1 - 5 */
435 ostart[0] = (BYTE)((IS_RAW<<6) + (0<<5) + srcSize);
436 break;
437 case 2: /* 2 - 2 - 12 */
438 ostart[0] = (BYTE)((IS_RAW<<6) + (2<<4) + (srcSize >> 8));
439 ostart[1] = (BYTE)srcSize;
440 break;
441 default: /*note : should not be necessary : flSize is within {1,2,3} */
442 case 3: /* 2 - 2 - 20 */
443 ostart[0] = (BYTE)((IS_RAW<<6) + (3<<4) + (srcSize >> 16));
444 ostart[1] = (BYTE)(srcSize>>8);
445 ostart[2] = (BYTE)srcSize;
446 break;
447 }
448
449 memcpy(ostart + flSize, src, srcSize);
450 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100451}
452
453static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
454{
455 BYTE* const ostart = (BYTE* const)dst;
Yann Collet59d1f792016-01-23 19:28:41 +0100456 U32 flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100457
Yann Colletfb810d62016-01-28 00:18:06 +0100458 (void)maxDstSize; /* maxDstSize guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100459
460 switch(flSize)
461 {
462 case 1: /* 2 - 1 - 5 */
463 ostart[0] = (BYTE)((IS_RLE<<6) + (0<<5) + srcSize);
464 break;
465 case 2: /* 2 - 2 - 12 */
466 ostart[0] = (BYTE)((IS_RLE<<6) + (2<<4) + (srcSize >> 8));
467 ostart[1] = (BYTE)srcSize;
468 break;
469 default: /*note : should not be necessary : flSize is necessary within {1,2,3} */
470 case 3: /* 2 - 2 - 20 */
471 ostart[0] = (BYTE)((IS_RLE<<6) + (3<<4) + (srcSize >> 16));
472 ostart[1] = (BYTE)(srcSize>>8);
473 ostart[2] = (BYTE)srcSize;
474 break;
475 }
476
477 ostart[flSize] = *(const BYTE*)src;
478 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100479}
480
Yann Collet59d1f792016-01-23 19:28:41 +0100481
Yann Colletb923f652016-01-26 03:14:20 +0100482size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100483
Yann Colletb923f652016-01-26 03:14:20 +0100484static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
485 void* dst, size_t maxDstSize,
Yann Collet14983e72015-11-11 21:38:21 +0100486 const void* src, size_t srcSize)
487{
488 const size_t minGain = ZSTD_minGain(srcSize);
489 BYTE* const ostart = (BYTE*)dst;
Yann Colletb923f652016-01-26 03:14:20 +0100490 const size_t lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Colletafe07092016-01-25 04:10:46 +0100491 U32 singleStream = srcSize < 256;
Yann Colletb923f652016-01-26 03:14:20 +0100492 U32 hType = IS_HUF;
Yann Collet59d1f792016-01-23 19:28:41 +0100493 size_t clitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100494
Yann Collet35f7de52016-01-31 02:51:03 +0100495 if (maxDstSize < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Collet14983e72015-11-11 21:38:21 +0100496
Yann Colletfb810d62016-01-28 00:18:06 +0100497 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletb923f652016-01-26 03:14:20 +0100498 hType = IS_PCH;
499 singleStream = 1;
500 clitSize = HUF_compress1X_usingCTable(ostart+lhSize, maxDstSize-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100501 } else {
Yann Colletb923f652016-01-26 03:14:20 +0100502 clitSize = singleStream ? HUF_compress1X(ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12)
503 : HUF_compress2 (ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12);
504 }
Yann Collet14983e72015-11-11 21:38:21 +0100505
Yann Collet59d1f792016-01-23 19:28:41 +0100506 if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, maxDstSize, src, srcSize);
507 if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, maxDstSize, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100508
509 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100510 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100511 {
Yann Collet59d1f792016-01-23 19:28:41 +0100512 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletb923f652016-01-26 03:14:20 +0100513 ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100514 ostart[1] = (BYTE)((srcSize<<2) + (clitSize>>8));
515 ostart[2] = (BYTE)(clitSize);
516 break;
517 case 4: /* 2 - 2 - 14 - 14 */
Yann Colletb923f652016-01-26 03:14:20 +0100518 ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100519 ostart[1] = (BYTE)(srcSize>> 2);
520 ostart[2] = (BYTE)((srcSize<<6) + (clitSize>>8));
521 ostart[3] = (BYTE)(clitSize);
522 break;
523 default: /* should not be necessary, lhSize is {3,4,5} */
524 case 5: /* 2 - 2 - 18 - 18 */
Yann Colletb923f652016-01-26 03:14:20 +0100525 ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100526 ostart[1] = (BYTE)(srcSize>>6);
527 ostart[2] = (BYTE)((srcSize<<2) + (clitSize>>16));
528 ostart[3] = (BYTE)(clitSize>>8);
529 ostart[4] = (BYTE)(clitSize);
530 break;
Yann Collet14983e72015-11-11 21:38:21 +0100531 }
532
Yann Collet59d1f792016-01-23 19:28:41 +0100533 return lhSize+clitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100534}
535
536
Yann Colletafe07092016-01-25 04:10:46 +0100537#define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */
Yann Collet14983e72015-11-11 21:38:21 +0100538
Yann Colletb923f652016-01-26 03:14:20 +0100539size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
540 void* dst, size_t maxDstSize,
Yann Collet14983e72015-11-11 21:38:21 +0100541 size_t srcSize)
542{
Yann Colletb923f652016-01-26 03:14:20 +0100543 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100544 U32 count[MaxSeq+1];
545 S16 norm[MaxSeq+1];
546 size_t mostFrequent;
Yann Colletfb810d62016-01-28 00:18:06 +0100547 U32 max;
548 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
549 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
550 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100551 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
552 const BYTE* const op_lit_start = seqStorePtr->litStart;
553 const BYTE* const llTable = seqStorePtr->litLengthStart;
554 const BYTE* const llPtr = seqStorePtr->litLength;
555 const BYTE* const mlTable = seqStorePtr->matchLengthStart;
556 const U32* const offsetTable = seqStorePtr->offsetStart;
557 BYTE* const offCodeTable = seqStorePtr->offCodeStart;
Yann Collet5054ee02015-11-23 13:34:21 +0100558 BYTE* const ostart = (BYTE*)dst;
559 BYTE* op = ostart;
560 BYTE* const oend = ostart + maxDstSize;
Yann Collet14983e72015-11-11 21:38:21 +0100561 const size_t nbSeq = llPtr - llTable;
562 const size_t minGain = ZSTD_minGain(srcSize);
563 const size_t maxCSize = srcSize - minGain;
564 BYTE* seqHead;
565
Yann Collet14983e72015-11-11 21:38:21 +0100566 /* Compress literals */
567 {
568 size_t cSize;
569 size_t litSize = seqStorePtr->lit - op_lit_start;
Yann Colletfb810d62016-01-28 00:18:06 +0100570 const size_t minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
Yann Collet14983e72015-11-11 21:38:21 +0100571
Yann Colletb923f652016-01-26 03:14:20 +0100572 if (litSize <= minLitSize)
Yann Collet14983e72015-11-11 21:38:21 +0100573 cSize = ZSTD_noCompressLiterals(op, maxDstSize, op_lit_start, litSize);
574 else
Yann Colletb923f652016-01-26 03:14:20 +0100575 cSize = ZSTD_compressLiterals(zc, op, maxDstSize, op_lit_start, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100576 if (ZSTD_isError(cSize)) return cSize;
577 op += cSize;
578 }
579
580 /* Sequences Header */
Yann Collet61e16ce2016-01-31 02:04:15 +0100581 if ((oend-op) < MIN_SEQUENCES_SIZE) return ERROR(dstSize_tooSmall);
582 if (nbSeq < 128) *op++ = (BYTE)nbSeq;
583 else {
Yann Collet35f7de52016-01-31 02:51:03 +0100584 op[0] = (BYTE)((nbSeq>>8) + 128); op[1] = (BYTE)nbSeq; op+=2;
Yann Collet61e16ce2016-01-31 02:04:15 +0100585 }
Yann Collete93d6ce2016-01-31 00:58:06 +0100586 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100587
Yann Collet863ec402016-01-28 17:56:33 +0100588 /* dumps : contains rests of large lengths */
Yann Collete93d6ce2016-01-31 00:58:06 +0100589 if ((oend-op) < 3 /* dumps */ + 1 /*seqHead*/)
590 return ERROR(dstSize_tooSmall);
591 seqHead = op;
Yann Collet14983e72015-11-11 21:38:21 +0100592 {
593 size_t dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart;
Yann Colletfb810d62016-01-28 00:18:06 +0100594 if (dumpsLength < 512) {
Yann Collet14983e72015-11-11 21:38:21 +0100595 op[0] = (BYTE)(dumpsLength >> 8);
596 op[1] = (BYTE)(dumpsLength);
597 op += 2;
Yann Colletfb810d62016-01-28 00:18:06 +0100598 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100599 op[0] = 2;
600 op[1] = (BYTE)(dumpsLength>>8);
601 op[2] = (BYTE)(dumpsLength);
602 op += 3;
603 }
604 if ((size_t)(oend-op) < dumpsLength+6) return ERROR(dstSize_tooSmall);
605 memcpy(op, seqStorePtr->dumpsStart, dumpsLength);
606 op += dumpsLength;
607 }
608
Yann Colletfb810d62016-01-28 00:18:06 +0100609#define MIN_SEQ_FOR_DYNAMIC_FSE 64
610#define MAX_SEQ_FOR_STATIC_FSE 1000
611
Yann Collet14983e72015-11-11 21:38:21 +0100612 /* CTable for Literal Lengths */
613 max = MaxLL;
Yann Collete93d6ce2016-01-31 00:58:06 +0100614 mostFrequent = FSE_countFast(count, &max, llTable, nbSeq);
Yann Colletfb810d62016-01-28 00:18:06 +0100615 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collete93d6ce2016-01-31 00:58:06 +0100616 *op++ = llTable[0];
Yann Collet14983e72015-11-11 21:38:21 +0100617 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletfb810d62016-01-28 00:18:06 +0100618 LLtype = FSE_ENCODING_RLE;
619 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
620 LLtype = FSE_ENCODING_STATIC;
621 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LLbits-1)))) {
Yann Collet14983e72015-11-11 21:38:21 +0100622 FSE_buildCTable_raw(CTable_LitLength, LLbits);
Yann Colletfb810d62016-01-28 00:18:06 +0100623 LLtype = FSE_ENCODING_RAW;
624 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100625 size_t NCountSize;
Yann Collete93d6ce2016-01-31 00:58:06 +0100626 size_t nbSeq_1 = nbSeq;
Yann Colletfb810d62016-01-28 00:18:06 +0100627 U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
Yann Collete93d6ce2016-01-31 00:58:06 +0100628 if (count[llTable[nbSeq-1]]>1) { count[llTable[nbSeq-1]]--; nbSeq_1--; }
629 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Collet14983e72015-11-11 21:38:21 +0100630 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
631 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
632 op += NCountSize;
633 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
Yann Colletfb810d62016-01-28 00:18:06 +0100634 LLtype = FSE_ENCODING_DYNAMIC;
Yann Collet14983e72015-11-11 21:38:21 +0100635 }
636
Yann Colletfb810d62016-01-28 00:18:06 +0100637 /* CTable for Offset codes */
638 { /* create Offset codes */
639 size_t i; for (i=0; i<nbSeq; i++) {
Yann Collet14983e72015-11-11 21:38:21 +0100640 offCodeTable[i] = (BYTE)ZSTD_highbit(offsetTable[i]) + 1;
641 if (offsetTable[i]==0) offCodeTable[i]=0;
642 }
Yann Collet14983e72015-11-11 21:38:21 +0100643 }
Yann Colletfb810d62016-01-28 00:18:06 +0100644 max = MaxOff;
645 mostFrequent = FSE_countFast(count, &max, offCodeTable, nbSeq);
646 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collete93d6ce2016-01-31 00:58:06 +0100647 *op++ = offCodeTable[0];
Yann Collet14983e72015-11-11 21:38:21 +0100648 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletfb810d62016-01-28 00:18:06 +0100649 Offtype = FSE_ENCODING_RLE;
650 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
651 Offtype = FSE_ENCODING_STATIC;
652 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (Offbits-1)))) {
Yann Collet14983e72015-11-11 21:38:21 +0100653 FSE_buildCTable_raw(CTable_OffsetBits, Offbits);
Yann Colletfb810d62016-01-28 00:18:06 +0100654 Offtype = FSE_ENCODING_RAW;
655 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100656 size_t NCountSize;
Yann Collete93d6ce2016-01-31 00:58:06 +0100657 size_t nbSeq_1 = nbSeq;
Yann Colletfb810d62016-01-28 00:18:06 +0100658 U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collete93d6ce2016-01-31 00:58:06 +0100659 if (count[offCodeTable[nbSeq-1]]>1) { count[offCodeTable[nbSeq-1]]--; nbSeq_1--; }
660 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Collet14983e72015-11-11 21:38:21 +0100661 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
662 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
663 op += NCountSize;
664 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
Yann Colletfb810d62016-01-28 00:18:06 +0100665 Offtype = FSE_ENCODING_DYNAMIC;
Yann Collet14983e72015-11-11 21:38:21 +0100666 }
667
668 /* CTable for MatchLengths */
669 max = MaxML;
Yann Collete93d6ce2016-01-31 00:58:06 +0100670 mostFrequent = FSE_countFast(count, &max, mlTable, nbSeq);
Yann Colletfb810d62016-01-28 00:18:06 +0100671 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collete93d6ce2016-01-31 00:58:06 +0100672 *op++ = *mlTable;
Yann Collet14983e72015-11-11 21:38:21 +0100673 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletfb810d62016-01-28 00:18:06 +0100674 MLtype = FSE_ENCODING_RLE;
675 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
676 MLtype = FSE_ENCODING_STATIC;
677 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (MLbits-1)))) {
Yann Collet14983e72015-11-11 21:38:21 +0100678 FSE_buildCTable_raw(CTable_MatchLength, MLbits);
Yann Colletfb810d62016-01-28 00:18:06 +0100679 MLtype = FSE_ENCODING_RAW;
680 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100681 size_t NCountSize;
Yann Colletfb810d62016-01-28 00:18:06 +0100682 U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
Yann Collet14983e72015-11-11 21:38:21 +0100683 FSE_normalizeCount(norm, tableLog, count, nbSeq, max);
684 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
685 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
686 op += NCountSize;
687 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
Yann Colletfb810d62016-01-28 00:18:06 +0100688 MLtype = FSE_ENCODING_DYNAMIC;
Yann Collet14983e72015-11-11 21:38:21 +0100689 }
690
691 seqHead[0] += (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100692 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100693
694 /* Encoding Sequences */
695 {
696 size_t streamSize, errorCode;
697 BIT_CStream_t blockStream;
698 FSE_CState_t stateMatchLength;
699 FSE_CState_t stateOffsetBits;
700 FSE_CState_t stateLitLength;
701 int i;
702
703 errorCode = BIT_initCStream(&blockStream, op, oend-op);
704 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100705
Yann Collete93d6ce2016-01-31 00:58:06 +0100706 /* first symbols */
707 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlTable[nbSeq-1]);
708 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, offCodeTable[nbSeq-1]);
709 FSE_initCState2(&stateLitLength, CTable_LitLength, llTable[nbSeq-1]);
710 BIT_addBits(&blockStream, offsetTable[nbSeq-1], offCodeTable[nbSeq-1] ? (offCodeTable[nbSeq-1]-1) : 0);
711 BIT_flushBits(&blockStream);
712
713 for (i=(int)nbSeq-2; i>=0; i--) {
Yann Colletfb810d62016-01-28 00:18:06 +0100714 BYTE mlCode = mlTable[i];
Yann Collet14983e72015-11-11 21:38:21 +0100715 U32 offset = offsetTable[i];
716 BYTE offCode = offCodeTable[i]; /* 32b*/ /* 64b*/
Yann Collete93d6ce2016-01-31 00:58:06 +0100717 U32 nbBits = (offCode-1) + (!offCode);
Yann Collet14983e72015-11-11 21:38:21 +0100718 BYTE litLength = llTable[i]; /* (7)*/ /* (7)*/
Yann Colletfb810d62016-01-28 00:18:06 +0100719 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 17 */ /* 17 */
Yann Collet743402c2015-11-20 12:03:53 +0100720 if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */
Yann Collet14983e72015-11-11 21:38:21 +0100721 FSE_encodeSymbol(&blockStream, &stateLitLength, litLength); /* 26 */ /* 61 */
Yann Collete93d6ce2016-01-31 00:58:06 +0100722 FSE_encodeSymbol(&blockStream, &stateOffsetBits, offCode); /* 16 */ /* 51 */
723 if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */
724 BIT_addBits(&blockStream, offset, nbBits); /* 31 */ /* 42 */ /* 24 bits max in 32-bits mode */
Yann Collet14983e72015-11-11 21:38:21 +0100725 BIT_flushBits(&blockStream); /* 7 */ /* 7 */
726 }
727
728 FSE_flushCState(&blockStream, &stateMatchLength);
729 FSE_flushCState(&blockStream, &stateOffsetBits);
730 FSE_flushCState(&blockStream, &stateLitLength);
731
732 streamSize = BIT_closeCStream(&blockStream);
733 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
734 op += streamSize;
735 }
736
737 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100738_check_compressibility:
Yann Collet5054ee02015-11-23 13:34:21 +0100739 if ((size_t)(op-ostart) >= maxCSize) return 0;
Yann Collet14983e72015-11-11 21:38:21 +0100740
Yann Collet5054ee02015-11-23 13:34:21 +0100741 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100742}
743
744
Yann Collete93d6ce2016-01-31 00:58:06 +0100745/*! ZSTD_storeSeq
746 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t
Yann Collet14983e72015-11-11 21:38:21 +0100747 @offsetCode : distance to match, or 0 == repCode
748 @matchCode : matchLength - MINMATCH
749*/
750MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode)
751{
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100752#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100753 static const BYTE* g_start = NULL;
754 if (g_start==NULL) g_start = literals;
Yann Colletfb810d62016-01-28 00:18:06 +0100755 //if (literals - g_start == 8695)
Yann Collet14983e72015-11-11 21:38:21 +0100756 printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n",
757 (U32)(literals - g_start), (U32)litLength, (U32)matchCode+4, (U32)offsetCode);
758#endif
759
760 /* copy Literals */
761 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
762 seqStorePtr->lit += litLength;
763
764 /* literal Length */
Yann Colletfb810d62016-01-28 00:18:06 +0100765 if (litLength >= MaxLL) {
Yann Collet14983e72015-11-11 21:38:21 +0100766 *(seqStorePtr->litLength++) = MaxLL;
Yann Colletfb810d62016-01-28 00:18:06 +0100767 if (litLength<255 + MaxLL) {
Yann Collet14983e72015-11-11 21:38:21 +0100768 *(seqStorePtr->dumps++) = (BYTE)(litLength - MaxLL);
Yann Colletfb810d62016-01-28 00:18:06 +0100769 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100770 *(seqStorePtr->dumps++) = 255;
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100771 if (litLength < (1<<15)) {
772 MEM_writeLE16(seqStorePtr->dumps, (U16)(litLength<<1));
773 seqStorePtr->dumps += 2;
774 } else {
775 MEM_writeLE32(seqStorePtr->dumps, (U32)((litLength<<1)+1));
776 seqStorePtr->dumps += 3;
777 }
Yann Colletfb810d62016-01-28 00:18:06 +0100778 } }
Yann Collet14983e72015-11-11 21:38:21 +0100779 else *(seqStorePtr->litLength++) = (BYTE)litLength;
780
781 /* match offset */
782 *(seqStorePtr->offset++) = (U32)offsetCode;
783
784 /* match Length */
Yann Colletfb810d62016-01-28 00:18:06 +0100785 if (matchCode >= MaxML) {
Yann Collet14983e72015-11-11 21:38:21 +0100786 *(seqStorePtr->matchLength++) = MaxML;
Yann Colletfb810d62016-01-28 00:18:06 +0100787 if (matchCode < 255+MaxML) {
Yann Collet14983e72015-11-11 21:38:21 +0100788 *(seqStorePtr->dumps++) = (BYTE)(matchCode - MaxML);
Yann Colletfb810d62016-01-28 00:18:06 +0100789 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100790 *(seqStorePtr->dumps++) = 255;
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100791 if (matchCode < (1<<15)) {
792 MEM_writeLE16(seqStorePtr->dumps, (U16)(matchCode<<1));
793 seqStorePtr->dumps += 2;
794 } else {
795 MEM_writeLE32(seqStorePtr->dumps, (U32)((matchCode<<1)+1));
796 seqStorePtr->dumps += 3;
797 }
Yann Colletfb810d62016-01-28 00:18:06 +0100798 } }
Yann Collet14983e72015-11-11 21:38:21 +0100799 else *(seqStorePtr->matchLength++) = (BYTE)matchCode;
800}
801
802
Yann Colletf3eca252015-10-22 15:31:46 +0100803/* *************************************
Yann Collet14983e72015-11-11 21:38:21 +0100804* Match length counter
805***************************************/
806static size_t ZSTD_read_ARCH(const void* p) { size_t r; memcpy(&r, p, sizeof(r)); return r; }
807
808static unsigned ZSTD_highbit(U32 val)
809{
810# if defined(_MSC_VER) /* Visual */
811 unsigned long r=0;
812 _BitScanReverse(&r, val);
813 return (unsigned)r;
814# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
815 return 31 - __builtin_clz(val);
816# else /* Software version */
817 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 };
818 U32 v = val;
819 int r;
820 v |= v >> 1;
821 v |= v >> 2;
822 v |= v >> 4;
823 v |= v >> 8;
824 v |= v >> 16;
825 r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];
826 return r;
827# endif
828}
829
Yann Collet5054ee02015-11-23 13:34:21 +0100830static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100831{
Yann Collet863ec402016-01-28 17:56:33 +0100832 if (MEM_isLittleEndian()) {
833 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100834# if defined(_MSC_VER) && defined(_WIN64)
835 unsigned long r = 0;
836 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100837 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100838# elif defined(__GNUC__) && (__GNUC__ >= 3)
839 return (__builtin_ctzll((U64)val) >> 3);
840# else
841 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 };
842 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
843# endif
Yann Collet863ec402016-01-28 17:56:33 +0100844 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100845# if defined(_MSC_VER)
846 unsigned long r=0;
847 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100848 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100849# elif defined(__GNUC__) && (__GNUC__ >= 3)
850 return (__builtin_ctz((U32)val) >> 3);
851# else
852 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 };
853 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
854# endif
855 }
Yann Collet863ec402016-01-28 17:56:33 +0100856 } else { /* Big Endian CPU */
857 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100858# if defined(_MSC_VER) && defined(_WIN64)
859 unsigned long r = 0;
860 _BitScanReverse64( &r, val );
861 return (unsigned)(r>>3);
862# elif defined(__GNUC__) && (__GNUC__ >= 3)
863 return (__builtin_clzll(val) >> 3);
864# else
865 unsigned r;
866 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
867 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
868 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
869 r += (!val);
870 return r;
871# endif
Yann Collet863ec402016-01-28 17:56:33 +0100872 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100873# if defined(_MSC_VER)
874 unsigned long r = 0;
875 _BitScanReverse( &r, (unsigned long)val );
876 return (unsigned)(r>>3);
877# elif defined(__GNUC__) && (__GNUC__ >= 3)
878 return (__builtin_clz((U32)val) >> 3);
879# else
880 unsigned r;
881 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
882 r += (!val);
883 return r;
884# endif
Yann Collet863ec402016-01-28 17:56:33 +0100885 } }
Yann Collet14983e72015-11-11 21:38:21 +0100886}
887
888
Yann Collet5054ee02015-11-23 13:34:21 +0100889static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100890{
891 const BYTE* const pStart = pIn;
892
Yann Colletfb810d62016-01-28 00:18:06 +0100893 while ((pIn<pInLimit-(sizeof(size_t)-1))) {
Yann Collet14983e72015-11-11 21:38:21 +0100894 size_t diff = ZSTD_read_ARCH(pMatch) ^ ZSTD_read_ARCH(pIn);
895 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
896 pIn += ZSTD_NbCommonBytes(diff);
897 return (size_t)(pIn - pStart);
898 }
899
900 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
901 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
902 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
903 return (size_t)(pIn - pStart);
904}
905
Yann Collet5054ee02015-11-23 13:34:21 +0100906/** ZSTD_count_2segments
907* can count match length with ip & match in potentially 2 different segments.
908* convention : on reaching mEnd, match count continue starting from iStart
909*/
910static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
911{
912 size_t matchLength;
913 const BYTE* vEnd = ip + (mEnd - match);
914 if (vEnd > iEnd) vEnd = iEnd;
915 matchLength = ZSTD_count(ip, match, vEnd);
916 if (match + matchLength == mEnd)
917 matchLength += ZSTD_count(ip+matchLength, iStart, iEnd);
918 return matchLength;
919}
920
Yann Collet14983e72015-11-11 21:38:21 +0100921
Yann Collet863ec402016-01-28 17:56:33 +0100922/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100923* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100924***************************************/
Yann Collet4b100f42015-10-30 15:49:48 +0100925static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100926static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100927static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100928
Yann Collet4b100f42015-10-30 15:49:48 +0100929static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100930static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100931static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100932
933static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100934static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100935static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100936
Yann Collet14983e72015-11-11 21:38:21 +0100937static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100938static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100939static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100940
Yann Collet5be2dd22015-11-11 13:43:58 +0100941static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100942{
943 switch(mls)
944 {
945 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100946 case 4: return ZSTD_hash4Ptr(p, hBits);
947 case 5: return ZSTD_hash5Ptr(p, hBits);
948 case 6: return ZSTD_hash6Ptr(p, hBits);
949 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100950 }
951}
Yann Collet2acb5d32015-10-29 16:49:43 +0100952
Yann Collet863ec402016-01-28 17:56:33 +0100953
Yann Collet2ce49232016-02-02 14:36:49 +0100954/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +0100955* Fast Scan
956***************************************/
Yann Collet417890c2015-12-04 17:16:37 +0100957#define FILLHASHSTEP 3
958static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
959{
960 U32* const hashTable = zc->hashTable;
961 const U32 hBits = zc->params.hashLog;
962 const BYTE* const base = zc->base;
963 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet2ce49232016-02-02 14:36:49 +0100964 const BYTE* const iend = ((const BYTE*)end) - 8;
Yann Collet417890c2015-12-04 17:16:37 +0100965
Yann Colletfb810d62016-01-28 00:18:06 +0100966 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +0100967 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
968 ip += FILLHASHSTEP;
969 }
970}
971
972
Yann Collet1f44b3f2015-11-05 17:32:18 +0100973FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +0100974void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc,
Yann Collet89db5e02015-11-13 11:27:46 +0100975 const void* src, size_t srcSize,
976 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100977{
Yann Collet417890c2015-12-04 17:16:37 +0100978 U32* const hashTable = zc->hashTable;
Yann Colletc3652152015-11-24 14:06:07 +0100979 const U32 hBits = zc->params.hashLog;
980 seqStore_t* seqStorePtr = &(zc->seqStore);
981 const BYTE* const base = zc->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100982 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100983 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100984 const BYTE* anchor = istart;
Yann Colletd94efbf2015-12-29 14:29:08 +0100985 const U32 lowIndex = zc->dictLimit;
986 const BYTE* const lowest = base + lowIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100987 const BYTE* const iend = istart + srcSize;
988 const BYTE* const ilimit = iend - 8;
989
Yann Collet89db5e02015-11-13 11:27:46 +0100990 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100991
992
993 /* init */
Yann Collet743402c2015-11-20 12:03:53 +0100994 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +0100995 if (ip < lowest+REPCODE_STARTVALUE) ip = lowest+REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100996
997 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +0100998 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Collet5054ee02015-11-23 13:34:21 +0100999 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001000 size_t offset;
Yann Collet5be2dd22015-11-11 13:43:58 +01001001 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Colletd94efbf2015-12-29 14:29:08 +01001002 const U32 matchIndex = hashTable[h];
1003 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001004 const U32 current = (U32)(ip-base);
1005 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001006
Yann Colletfb810d62016-01-28 00:18:06 +01001007 if (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)) { /* note : by construction, offset_1 <= current */
Yann Collet5054ee02015-11-23 13:34:21 +01001008 mlCode = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +01001009 ip++;
1010 offset = 0;
Yann Colletfb810d62016-01-28 00:18:06 +01001011 } else {
Yann Colletd94efbf2015-12-29 14:29:08 +01001012 if ( (matchIndex <= lowIndex) ||
Yann Colletfb810d62016-01-28 00:18:06 +01001013 (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001014 ip += ((ip-anchor) >> g_searchStrength) + 1;
1015 continue;
1016 }
Yann Collet5054ee02015-11-23 13:34:21 +01001017 mlCode = ZSTD_count(ip+MINMATCH, match+MINMATCH, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +01001018 offset = ip-match;
Yann Collet5054ee02015-11-23 13:34:21 +01001019 while ((ip>anchor) && (match>lowest) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001020 offset_2 = offset_1;
1021 offset_1 = offset;
1022 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001023
Yann Collet402fdcf2015-11-20 12:46:08 +01001024 /* match found */
Yann Collet6bcdeac2015-11-26 11:43:00 +01001025 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +01001026 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001027 anchor = ip;
1028
Yann Colletfb810d62016-01-28 00:18:06 +01001029 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001030 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001031 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 +01001032 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1033 /* check immediate repcode */
1034 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001035 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001036 /* store sequence */
Yann Collet06eade52015-11-23 14:23:47 +01001037 size_t rlCode = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +01001038 size_t tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
1039 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Collet06eade52015-11-23 14:23:47 +01001040 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rlCode);
1041 ip += rlCode+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001042 anchor = ip;
1043 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001044 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001045
Yann Collet44886612016-02-11 04:17:50 +01001046 { /* Last Literals */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001047 size_t lastLLSize = iend - anchor;
1048 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1049 seqStorePtr->lit += lastLLSize;
1050 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001051}
1052
1053
Yann Collet59d1f792016-01-23 19:28:41 +01001054void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
1055 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001056{
1057 const U32 mls = ctx->params.searchLength;
1058 switch(mls)
1059 {
1060 default:
1061 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001062 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001063 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001064 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001065 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001066 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001067 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001068 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001069 }
1070}
Yann Colletf3eca252015-10-22 15:31:46 +01001071
Yann Colletf3eca252015-10-22 15:31:46 +01001072
Yann Collet93a823c2015-11-13 15:08:43 +01001073//FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001074void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
1075 const void* src, size_t srcSize,
1076 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001077{
1078 U32* hashTable = ctx->hashTable;
1079 const U32 hBits = ctx->params.hashLog;
1080 seqStore_t* seqStorePtr = &(ctx->seqStore);
1081 const BYTE* const base = ctx->base;
1082 const BYTE* const dictBase = ctx->dictBase;
1083 const BYTE* const istart = (const BYTE*)src;
1084 const BYTE* ip = istart;
1085 const BYTE* anchor = istart;
1086 const U32 lowLimit = ctx->lowLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001087 const BYTE* const dictStart = dictBase + lowLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001088 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001089 const BYTE* const lowPrefixPtr = base + dictLimit;
1090 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001091 const BYTE* const iend = istart + srcSize;
1092 const BYTE* const ilimit = iend - 8;
1093
Yann Collet138e89c2015-11-17 14:26:54 +01001094 U32 offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001095
1096
1097 /* init */
1098 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001099 /* skip first position to avoid read overflow during repcode match check */
Yann Colletfb810d62016-01-28 00:18:06 +01001100 hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0);
Yann Collet61e16ce2016-01-31 02:04:15 +01001101 ip += REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001102
1103 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001104 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001105 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001106 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001107 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001108 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001109 const U32 current = (U32)(ip-base);
Yann Collet743402c2015-11-20 12:03:53 +01001110 const U32 repIndex = current + 1 - offset_1;
Yann Collet402fdcf2015-11-20 12:46:08 +01001111 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001112 const BYTE* repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001113 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001114 U32 offset;
Yann Collet89db5e02015-11-13 11:27:46 +01001115 hashTable[h] = current; /* update hash table */
1116
1117 if ( ((repIndex <= dictLimit-4) || (repIndex >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001118 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001119 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001120 mlCode = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repMatchEnd, lowPrefixPtr);
Yann Collet743402c2015-11-20 12:03:53 +01001121 ip++;
Yann Collet402fdcf2015-11-20 12:46:08 +01001122 offset = 0;
Yann Colletfb810d62016-01-28 00:18:06 +01001123 } else {
Yann Collet402fdcf2015-11-20 12:46:08 +01001124 if ( (matchIndex < lowLimit) ||
1125 (MEM_read32(match) != MEM_read32(ip)) )
1126 { ip += ((ip-anchor) >> g_searchStrength) + 1; continue; }
1127 {
1128 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001129 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1130 mlCode = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iend, matchEnd, lowPrefixPtr);
Yann Colletfb810d62016-01-28 00:18:06 +01001131 while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001132 offset = current - matchIndex;
1133 offset_2 = offset_1;
1134 offset_1 = offset;
Yann Colletfb810d62016-01-28 00:18:06 +01001135 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001136
Yann Collet5054ee02015-11-23 13:34:21 +01001137 /* found a match : store it */
1138 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +01001139 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001140 anchor = ip;
1141
Yann Colletfb810d62016-01-28 00:18:06 +01001142 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001143 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001144 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001145 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1146 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001147 while (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001148 U32 current2 = (U32)(ip-base);
1149 const U32 repIndex2 = current2 - offset_2;
1150 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet743402c2015-11-20 12:03:53 +01001151 if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001152 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001153 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1154 size_t repLength2 = ZSTD_count_2segments(ip+MINMATCH, repMatch2+MINMATCH, iend, repEnd2, lowPrefixPtr);
1155 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1156 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2);
1157 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
1158 ip += repLength2+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001159 anchor = ip;
1160 continue;
1161 }
Yann Collet743402c2015-11-20 12:03:53 +01001162 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001163 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001164
1165 /* Last Literals */
1166 {
1167 size_t lastLLSize = iend - anchor;
1168 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1169 seqStorePtr->lit += lastLLSize;
1170 }
Yann Collet89db5e02015-11-13 11:27:46 +01001171}
1172
1173
Yann Collet59d1f792016-01-23 19:28:41 +01001174void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001175 const void* src, size_t srcSize)
1176{
1177 const U32 mls = ctx->params.searchLength;
1178 switch(mls)
1179 {
1180 default:
1181 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001182 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001183 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001184 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001185 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001186 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001187 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001188 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001189 }
1190}
1191
1192
Yann Colletf3eca252015-10-22 15:31:46 +01001193/* *************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001194* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001195***************************************/
Yann Collet70e8c382016-02-10 13:37:52 +01001196/** ZSTD_insertBt1() : add one or multiple positions to tree
1197* ip : assumed <= iend-8
Yann Collet06eade52015-11-23 14:23:47 +01001198* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001199static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1200 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001201{
1202 U32* const hashTable = zc->hashTable;
1203 const U32 hashLog = zc->params.hashLog;
Yann Collet5be2dd22015-11-11 13:43:58 +01001204 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet1f44b3f2015-11-05 17:32:18 +01001205 U32* const bt = zc->contentTable;
1206 const U32 btLog = zc->params.contentLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001207 const U32 btMask= (1 << btLog) - 1;
1208 U32 matchIndex = hashTable[h];
1209 size_t commonLengthSmaller=0, commonLengthLarger=0;
1210 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001211 const BYTE* const dictBase = zc->dictBase;
1212 const U32 dictLimit = zc->dictLimit;
1213 const BYTE* const dictEnd = dictBase + dictLimit;
1214 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001215 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001216 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001217 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001218 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001219 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001220 U32 dummy32; /* to be nullified at the end */
Yann Collet03526e12015-11-23 15:29:15 +01001221 const U32 windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001222 U32 matchEndIdx = current+8;
Yann Collet7beaa052016-01-21 11:57:45 +01001223 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1224 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1225 predictedSmall += (predictedSmall>0);
1226 predictedLarge += (predictedLarge>0);
Yann Colletf48e35c2015-11-07 01:13:31 +01001227
Yann Collet6c3e2e72015-12-11 10:44:07 +01001228 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001229
Yann Colletfb810d62016-01-28 00:18:06 +01001230 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001231 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001232 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1233
Yann Collet70e8c382016-02-10 13:37:52 +01001234 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001235 if (matchIndex == predictedSmall) {
1236 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001237 *smallerPtr = matchIndex;
1238 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1239 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1240 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001241 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001242 continue;
1243 }
Yann Colletfb810d62016-01-28 00:18:06 +01001244 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001245 *largerPtr = matchIndex;
1246 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1247 largerPtr = nextPtr;
1248 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001249 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001250 continue;
1251 }
1252
Yann Colletfb810d62016-01-28 00:18:06 +01001253 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001254 match = base + matchIndex;
1255 if (match[matchLength] == ip[matchLength])
1256 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001257 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001258 match = dictBase + matchIndex;
1259 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1260 if (matchIndex+matchLength >= dictLimit)
1261 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1262 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001263
Yann Colletee3f4512015-12-29 22:26:09 +01001264 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001265 matchEndIdx = matchIndex + (U32)matchLength;
Yann Colletee3f4512015-12-29 22:26:09 +01001266
Yann Collet59d70632015-11-04 12:05:27 +01001267 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001268 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001269
Yann Colletfb810d62016-01-28 00:18:06 +01001270 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001271 /* match is smaller than current */
1272 *smallerPtr = matchIndex; /* update smaller idx */
1273 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001274 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001275 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001276 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001277 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001278 /* match is larger than current */
1279 *largerPtr = matchIndex;
1280 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001281 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001282 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001283 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001284 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001285
Yann Collet59d70632015-11-04 12:05:27 +01001286 *smallerPtr = *largerPtr = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001287 return (matchEndIdx > current + 8) ? matchEndIdx - current - 8 : 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001288}
1289
1290
Yann Colletee3f4512015-12-29 22:26:09 +01001291static 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 +01001292{
1293 const BYTE* const base = zc->base;
1294 const U32 target = (U32)(ip - base);
1295 U32 idx = zc->nextToUpdate;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001296
Yann Colletf48e35c2015-11-07 01:13:31 +01001297 for( ; idx < target ; )
Yann Collet1358f912016-01-01 07:29:39 +01001298 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001299}
1300
Yann Collet96b9f0b2015-11-04 03:52:54 +01001301FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Collet2cc12cb2016-01-01 07:47:58 +01001302size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001303 ZSTD_CCtx* zc,
1304 const BYTE* const ip, const BYTE* const iend,
1305 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001306 U32 nbCompares, const U32 mls,
1307 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001308{
1309 U32* const hashTable = zc->hashTable;
1310 const U32 hashLog = zc->params.hashLog;
1311 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
1312 U32* const bt = zc->contentTable;
1313 const U32 btLog = zc->params.contentLog - 1;
1314 const U32 btMask= (1 << btLog) - 1;
1315 U32 matchIndex = hashTable[h];
1316 size_t commonLengthSmaller=0, commonLengthLarger=0;
1317 const BYTE* const base = zc->base;
1318 const BYTE* const dictBase = zc->dictBase;
1319 const U32 dictLimit = zc->dictLimit;
1320 const BYTE* const dictEnd = dictBase + dictLimit;
1321 const BYTE* const prefixStart = base + dictLimit;
1322 const U32 current = (U32)(ip-base);
1323 const U32 btLow = btMask >= current ? 0 : current - btMask;
1324 const U32 windowLow = zc->lowLimit;
1325 U32* smallerPtr = bt + 2*(current&btMask);
1326 U32* largerPtr = bt + 2*(current&btMask) + 1;
1327 size_t bestLength = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001328 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001329 U32 dummy32; /* to be nullified at the end */
1330
Yann Collet6c3e2e72015-12-11 10:44:07 +01001331 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001332
Yann Colletfb810d62016-01-28 00:18:06 +01001333 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001334 U32* nextPtr = bt + 2*(matchIndex & btMask);
1335 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1336 const BYTE* match;
1337
Yann Colletfb810d62016-01-28 00:18:06 +01001338 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001339 match = base + matchIndex;
1340 if (match[matchLength] == ip[matchLength])
1341 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001342 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001343 match = dictBase + matchIndex;
1344 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001345 if (matchIndex+matchLength >= dictLimit)
1346 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001347 }
1348
Yann Colletfb810d62016-01-28 00:18:06 +01001349 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001350 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001351 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet03526e12015-11-23 15:29:15 +01001352 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
1353 bestLength = matchLength, *offsetPtr = current - matchIndex;
1354 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1355 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1356 }
1357
Yann Colletfb810d62016-01-28 00:18:06 +01001358 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001359 /* match is smaller than current */
1360 *smallerPtr = matchIndex; /* update smaller idx */
1361 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1362 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1363 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1364 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001365 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001366 /* match is larger than current */
1367 *largerPtr = matchIndex;
1368 commonLengthLarger = matchLength;
1369 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1370 largerPtr = nextPtr;
1371 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001372 } }
Yann Collet03526e12015-11-23 15:29:15 +01001373
1374 *smallerPtr = *largerPtr = 0;
1375
Yann Collet72e84cf2015-12-31 19:08:44 +01001376 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
Yann Collet03526e12015-11-23 15:29:15 +01001377 return bestLength;
1378}
1379
Yann Collet2cc12cb2016-01-01 07:47:58 +01001380
1381/** Tree updater, providing best match */
1382FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1383size_t ZSTD_BtFindBestMatch (
1384 ZSTD_CCtx* zc,
1385 const BYTE* const ip, const BYTE* const iLimit,
1386 size_t* offsetPtr,
1387 const U32 maxNbAttempts, const U32 mls)
1388{
1389 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1390 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
1391 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1392}
1393
1394
Yann Collet768c6bc2016-02-10 14:01:49 +01001395static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001396 ZSTD_CCtx* zc, /* Index table will be updated */
1397 const BYTE* ip, const BYTE* const iLimit,
1398 size_t* offsetPtr,
1399 const U32 maxNbAttempts, const U32 matchLengthSearch)
1400{
1401 switch(matchLengthSearch)
1402 {
1403 default :
1404 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1405 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1406 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1407 }
1408}
1409
1410
1411static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1412{
1413 const BYTE* const base = zc->base;
1414 const U32 target = (U32)(ip - base);
1415 U32 idx = zc->nextToUpdate;
1416
1417 for( ; idx < target ; )
1418 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1419}
1420
1421
Yann Collet03526e12015-11-23 15:29:15 +01001422/** Tree updater, providing best match */
1423FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1424size_t ZSTD_BtFindBestMatch_extDict (
1425 ZSTD_CCtx* zc,
1426 const BYTE* const ip, const BYTE* const iLimit,
1427 size_t* offsetPtr,
1428 const U32 maxNbAttempts, const U32 mls)
1429{
Yann Colletee3f4512015-12-29 22:26:09 +01001430 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1431 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001432 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001433}
1434
1435
1436FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
1437 ZSTD_CCtx* zc, /* Index table will be updated */
1438 const BYTE* ip, const BYTE* const iLimit,
1439 size_t* offsetPtr,
1440 const U32 maxNbAttempts, const U32 matchLengthSearch)
1441{
1442 switch(matchLengthSearch)
1443 {
1444 default :
1445 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1446 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1447 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1448 }
1449}
1450
1451
Yann Collet5106a762015-11-05 15:00:24 +01001452/* ***********************
1453* Hash Chain
1454*************************/
1455
Yann Collet1f44b3f2015-11-05 17:32:18 +01001456#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1457
Yann Collet6bcdeac2015-11-26 11:43:00 +01001458/* Update chains up to ip (excluded)
Yann Collet06eade52015-11-23 14:23:47 +01001459 Assumption : always within prefix (ie. not within extDict) */
1460static U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
Yann Collet5106a762015-11-05 15:00:24 +01001461{
1462 U32* const hashTable = zc->hashTable;
1463 const U32 hashLog = zc->params.hashLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001464 U32* const chainTable = zc->contentTable;
1465 const U32 chainMask = (1 << zc->params.contentLog) - 1;
Yann Collet5106a762015-11-05 15:00:24 +01001466 const BYTE* const base = zc->base;
1467 const U32 target = (U32)(ip - base);
1468 U32 idx = zc->nextToUpdate;
1469
Yann Colletfb810d62016-01-28 00:18:06 +01001470 while(idx < target) {
Yann Collet5be2dd22015-11-11 13:43:58 +01001471 size_t h = ZSTD_hashPtr(base+idx, hashLog, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001472 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1473 hashTable[h] = idx;
1474 idx++;
1475 }
1476
1477 zc->nextToUpdate = target;
Yann Collet5be2dd22015-11-11 13:43:58 +01001478 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
Yann Collet5106a762015-11-05 15:00:24 +01001479}
1480
1481
1482FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Colletc1e52f02015-11-23 14:37:59 +01001483size_t ZSTD_HcFindBestMatch_generic (
Yann Collet5be2dd22015-11-11 13:43:58 +01001484 ZSTD_CCtx* zc, /* Index table will be updated */
Yann Collet5106a762015-11-05 15:00:24 +01001485 const BYTE* const ip, const BYTE* const iLimit,
1486 size_t* offsetPtr,
Yann Colletc1e52f02015-11-23 14:37:59 +01001487 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
Yann Collet287b7d92015-11-22 13:24:05 +01001488{
Yann Collet1f44b3f2015-11-05 17:32:18 +01001489 U32* const chainTable = zc->contentTable;
1490 const U32 chainSize = (1 << zc->params.contentLog);
Yann Collet5106a762015-11-05 15:00:24 +01001491 const U32 chainMask = chainSize-1;
1492 const BYTE* const base = zc->base;
1493 const BYTE* const dictBase = zc->dictBase;
1494 const U32 dictLimit = zc->dictLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001495 const BYTE* const prefixStart = base + dictLimit;
1496 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001497 const U32 lowLimit = zc->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001498 const U32 current = (U32)(ip-base);
1499 const U32 minChain = current > chainSize ? current - chainSize : 0;
Yann Collet5106a762015-11-05 15:00:24 +01001500 U32 matchIndex;
1501 const BYTE* match;
1502 int nbAttempts=maxNbAttempts;
Yann Collet5054ee02015-11-23 13:34:21 +01001503 size_t ml=MINMATCH-1;
Yann Collet5106a762015-11-05 15:00:24 +01001504
1505 /* HC4 match finder */
Yann Colletc1e52f02015-11-23 14:37:59 +01001506 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001507
Yann Colletfb810d62016-01-28 00:18:06 +01001508 while ((matchIndex>lowLimit) && (nbAttempts)) {
Yann Collet5054ee02015-11-23 13:34:21 +01001509 size_t currentMl=0;
Yann Collet5106a762015-11-05 15:00:24 +01001510 nbAttempts--;
Yann Colletfb810d62016-01-28 00:18:06 +01001511 if ((!extDict) || matchIndex >= dictLimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001512 match = base + matchIndex;
Yann Collet4baee502015-11-09 03:19:33 +01001513 if (match[ml] == ip[ml]) /* potentially better */
Yann Collet5054ee02015-11-23 13:34:21 +01001514 currentMl = ZSTD_count(ip, match, iLimit);
Yann Colletfb810d62016-01-28 00:18:06 +01001515 } else {
Yann Collet5106a762015-11-05 15:00:24 +01001516 match = dictBase + matchIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001517 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1518 currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
Yann Collet5106a762015-11-05 15:00:24 +01001519 }
1520
Yann Collet5054ee02015-11-23 13:34:21 +01001521 /* save best solution */
Yann Collet239cc282015-11-23 16:17:21 +01001522 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 +01001523
Yann Collet9a24e592015-11-22 02:53:43 +01001524 if (matchIndex <= minChain) break;
Yann Collet5106a762015-11-05 15:00:24 +01001525 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1526 }
1527
1528 return ml;
1529}
1530
1531
Yann Colletc1e52f02015-11-23 14:37:59 +01001532FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1533 ZSTD_CCtx* zc,
Yann Collet5106a762015-11-05 15:00:24 +01001534 const BYTE* ip, const BYTE* const iLimit,
1535 size_t* offsetPtr,
1536 const U32 maxNbAttempts, const U32 matchLengthSearch)
1537{
1538 switch(matchLengthSearch)
1539 {
1540 default :
Yann Colletc1e52f02015-11-23 14:37:59 +01001541 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1542 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1543 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1544 }
1545}
1546
1547
1548FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1549 ZSTD_CCtx* zc,
1550 const BYTE* ip, const BYTE* const iLimit,
1551 size_t* offsetPtr,
1552 const U32 maxNbAttempts, const U32 matchLengthSearch)
1553{
1554 switch(matchLengthSearch)
1555 {
1556 default :
1557 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1558 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1559 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001560 }
1561}
1562
1563
Yann Collet287b7d92015-11-22 13:24:05 +01001564/* *******************************
Yann Collet9a24e592015-11-22 02:53:43 +01001565* Common parser - lazy strategy
Yann Collet287b7d92015-11-22 13:24:05 +01001566*********************************/
Yann Collet5106a762015-11-05 15:00:24 +01001567FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001568void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1569 const void* src, size_t srcSize,
Yann Collet007c1c62015-11-22 02:42:28 +01001570 const U32 searchMethod, const U32 depth)
Yann Collet5106a762015-11-05 15:00:24 +01001571{
1572 seqStore_t* seqStorePtr = &(ctx->seqStore);
1573 const BYTE* const istart = (const BYTE*)src;
1574 const BYTE* ip = istart;
1575 const BYTE* anchor = istart;
1576 const BYTE* const iend = istart + srcSize;
1577 const BYTE* const ilimit = iend - 8;
Yann Collete47c4e52015-12-05 09:23:53 +01001578 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet5106a762015-11-05 15:00:24 +01001579
1580 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1581 const U32 maxSearches = 1 << ctx->params.searchLog;
1582 const U32 mls = ctx->params.searchLength;
1583
Yann Collet5be2dd22015-11-11 13:43:58 +01001584 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
Yann Collet5106a762015-11-05 15:00:24 +01001585 size_t* offsetPtr,
1586 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet5be2dd22015-11-11 13:43:58 +01001587 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet5106a762015-11-05 15:00:24 +01001588
1589 /* init */
1590 ZSTD_resetSeqStore(seqStorePtr);
Yann Collete47c4e52015-12-05 09:23:53 +01001591 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet5106a762015-11-05 15:00:24 +01001592
1593 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001594 while (ip < ilimit) {
Yann Collet7a231792015-11-21 15:27:35 +01001595 size_t matchLength=0;
1596 size_t offset=0;
1597 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001598
Yann Collet743402c2015-11-20 12:03:53 +01001599 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001600 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1)) {
Yann Collet743402c2015-11-20 12:03:53 +01001601 /* repcode : we take it */
Yann Collet7a231792015-11-21 15:27:35 +01001602 matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH;
Yann Collet007c1c62015-11-22 02:42:28 +01001603 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001604 }
1605
Yann Colletfc2afcf2015-11-06 15:40:14 +01001606 {
Yann Collet239cc282015-11-23 16:17:21 +01001607 /* first search (depth 0) */
1608 size_t offsetFound = 99999999;
1609 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1610 if (ml2 > matchLength)
1611 matchLength = ml2, start = ip, offset=offsetFound;
1612 }
Yann Collet9a24e592015-11-22 02:53:43 +01001613
Yann Colletfb810d62016-01-28 00:18:06 +01001614 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001615 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1616 continue;
1617 }
Yann Collet5106a762015-11-05 15:00:24 +01001618
1619 /* let's try to find a better solution */
Yann Collet007c1c62015-11-22 02:42:28 +01001620 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001621 while (ip<ilimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001622 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001623 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet007c1c62015-11-22 02:42:28 +01001624 size_t mlRep = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1625 int gain2 = (int)(mlRep * 3);
Yann Collet5106a762015-11-05 15:00:24 +01001626 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet007c1c62015-11-22 02:42:28 +01001627 if ((mlRep >= MINMATCH) && (gain2 > gain1))
1628 matchLength = mlRep, offset = 0, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001629 }
1630 {
1631 size_t offset2=999999;
1632 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet007c1c62015-11-22 02:42:28 +01001633 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1634 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001635 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001636 matchLength = ml2, offset = offset2, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001637 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001638 } }
Yann Collet5106a762015-11-05 15:00:24 +01001639
1640 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001641 if ((depth==2) && (ip<ilimit)) {
Yann Collet5106a762015-11-05 15:00:24 +01001642 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001643 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet5106a762015-11-05 15:00:24 +01001644 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1645 int gain2 = (int)(ml2 * 4);
1646 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet4baee502015-11-09 03:19:33 +01001647 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001648 matchLength = ml2, offset = 0, start = ip;
1649 }
1650 {
1651 size_t offset2=999999;
1652 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet628065c2015-11-06 18:44:54 +01001653 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1654 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001655 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001656 matchLength = ml2, offset = offset2, start = ip;
1657 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001658 } } }
Yann Collet5106a762015-11-05 15:00:24 +01001659 break; /* nothing found : store previous solution */
1660 }
1661
Yann Collet768c6bc2016-02-10 14:01:49 +01001662 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001663 if (offset) {
Yann Collete47c4e52015-12-05 09:23:53 +01001664 while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */
Yann Collet4baee502015-11-09 03:19:33 +01001665 { start--; matchLength++; }
Yann Collet743402c2015-11-20 12:03:53 +01001666 offset_2 = offset_1; offset_1 = offset;
Yann Collet4baee502015-11-09 03:19:33 +01001667 }
1668
1669 /* store sequence */
Yann Collet7a231792015-11-21 15:27:35 +01001670_storeSequence:
Yann Collet5106a762015-11-05 15:00:24 +01001671 {
1672 size_t litLength = start - anchor;
Yann Collet5106a762015-11-05 15:00:24 +01001673 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
Yann Collet4baee502015-11-09 03:19:33 +01001674 anchor = ip = start + matchLength;
Yann Collet5106a762015-11-05 15:00:24 +01001675 }
1676
Yann Collet743402c2015-11-20 12:03:53 +01001677 /* check immediate repcode */
1678 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001679 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet743402c2015-11-20 12:03:53 +01001680 /* store sequence */
1681 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
1682 offset = offset_2;
1683 offset_2 = offset_1;
1684 offset_1 = offset;
1685 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength);
1686 ip += matchLength+MINMATCH;
1687 anchor = ip;
1688 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001689 } }
Yann Collet5106a762015-11-05 15:00:24 +01001690
1691 /* Last Literals */
1692 {
1693 size_t lastLLSize = iend - anchor;
1694 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1695 seqStorePtr->lit += lastLLSize;
1696 }
Yann Collet5106a762015-11-05 15:00:24 +01001697}
1698
Yann Collet3b63f7f2016-02-10 15:05:12 +01001699#include "zstd_opt.h"
inikepe2bfe242016-01-31 11:25:48 +01001700
1701static void ZSTD_compressBlock_opt_bt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1702{
1703 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1, 2);
1704}
1705
1706static void ZSTD_compressBlock_opt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1707{
1708 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0, 2);
1709}
1710
Yann Collet59d1f792016-01-23 19:28:41 +01001711static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001712{
Yann Colleta1249dc2016-01-25 04:22:03 +01001713 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001714}
1715
Yann Collet59d1f792016-01-23 19:28:41 +01001716static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001717{
Yann Colleta1249dc2016-01-25 04:22:03 +01001718 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001719}
1720
Yann Collet59d1f792016-01-23 19:28:41 +01001721static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001722{
Yann Colleta1249dc2016-01-25 04:22:03 +01001723 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001724}
1725
Yann Collet59d1f792016-01-23 19:28:41 +01001726static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01001727{
Yann Colleta1249dc2016-01-25 04:22:03 +01001728 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
Yann Colletbe2010e2015-10-31 12:57:14 +01001729}
1730
1731
Yann Collet9a24e592015-11-22 02:53:43 +01001732FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001733void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1734 const void* src, size_t srcSize,
Yann Collet9a24e592015-11-22 02:53:43 +01001735 const U32 searchMethod, const U32 depth)
1736{
1737 seqStore_t* seqStorePtr = &(ctx->seqStore);
1738 const BYTE* const istart = (const BYTE*)src;
1739 const BYTE* ip = istart;
1740 const BYTE* anchor = istart;
1741 const BYTE* const iend = istart + srcSize;
1742 const BYTE* const ilimit = iend - 8;
1743 const BYTE* const base = ctx->base;
1744 const U32 dictLimit = ctx->dictLimit;
1745 const BYTE* const prefixStart = base + dictLimit;
1746 const BYTE* const dictBase = ctx->dictBase;
1747 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001748 const BYTE* const dictStart = dictBase + ctx->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001749
1750 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1751 const U32 maxSearches = 1 << ctx->params.searchLog;
1752 const U32 mls = ctx->params.searchLength;
1753
1754 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1755 size_t* offsetPtr,
1756 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet03526e12015-11-23 15:29:15 +01001757 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
Yann Collet9a24e592015-11-22 02:53:43 +01001758
1759 /* init */
1760 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet6c3e2e72015-12-11 10:44:07 +01001761 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Collet9a24e592015-11-22 02:53:43 +01001762
1763 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001764 while (ip < ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001765 size_t matchLength=0;
1766 size_t offset=0;
1767 const BYTE* start=ip+1;
1768 U32 current = (U32)(ip-base);
1769
1770 /* check repCode */
1771 {
1772 const U32 repIndex = (U32)(current+1 - offset_1);
1773 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1774 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001775 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001776 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001777 /* repcode detected we should take it */
1778 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001779 matchLength = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
Yann Collet9a24e592015-11-22 02:53:43 +01001780 if (depth==0) goto _storeSequence;
Yann Colletfb810d62016-01-28 00:18:06 +01001781 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001782
1783 {
Yann Collet239cc282015-11-23 16:17:21 +01001784 /* first search (depth 0) */
1785 size_t offsetFound = 99999999;
1786 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1787 if (ml2 > matchLength)
1788 matchLength = ml2, start = ip, offset=offsetFound;
1789 }
Yann Collet9a24e592015-11-22 02:53:43 +01001790
Yann Colletfb810d62016-01-28 00:18:06 +01001791 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001792 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1793 continue;
1794 }
Yann Collet9a24e592015-11-22 02:53:43 +01001795
1796 /* let's try to find a better solution */
1797 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001798 while (ip<ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001799 ip ++;
1800 current++;
1801 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001802 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001803 const U32 repIndex = (U32)(current - offset_1);
1804 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1805 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001806 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001807 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001808 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001809 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001810 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1811 int gain2 = (int)(repLength * 3);
1812 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1813 if ((repLength >= MINMATCH) && (gain2 > gain1))
1814 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001815 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001816
1817 /* search match, depth 1 */
1818 {
1819 size_t offset2=999999;
1820 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1821 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1822 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001823 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001824 matchLength = ml2, offset = offset2, start = ip;
1825 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001826 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001827
1828 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001829 if ((depth==2) && (ip<ilimit)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001830 ip ++;
1831 current++;
1832 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001833 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001834 const U32 repIndex = (U32)(current - offset_1);
1835 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1836 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001837 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001838 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001839 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001840 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001841 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1842 int gain2 = (int)(repLength * 4);
1843 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1844 if ((repLength >= MINMATCH) && (gain2 > gain1))
1845 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001846 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001847
1848 /* search match, depth 2 */
1849 {
1850 size_t offset2=999999;
1851 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1852 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1853 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001854 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001855 matchLength = ml2, offset = offset2, start = ip;
1856 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001857 } } }
Yann Collet9a24e592015-11-22 02:53:43 +01001858 break; /* nothing found : store previous solution */
1859 }
1860
1861 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001862 if (offset) {
Yann Colletc3652152015-11-24 14:06:07 +01001863 U32 matchIndex = (U32)((start-base) - offset);
1864 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1865 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
1866 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet9a24e592015-11-22 02:53:43 +01001867 offset_2 = offset_1; offset_1 = offset;
1868 }
1869
1870 /* store sequence */
1871_storeSequence:
1872 {
1873 size_t litLength = start - anchor;
1874 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1875 anchor = ip = start + matchLength;
1876 }
1877
1878 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001879 while (ip <= ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001880 const U32 repIndex = (U32)((ip-base) - offset_2);
1881 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1882 const BYTE* const repMatch = repBase + repIndex;
Yann Collet239cc282015-11-23 16:17:21 +01001883 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001884 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001885 /* repcode detected we should take it */
1886 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001887 matchLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1888 offset = offset_2; offset_2 = offset_1; offset_1 = offset; /* swap offset history */
Yann Collet9a24e592015-11-22 02:53:43 +01001889 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1890 ip += matchLength;
1891 anchor = ip;
1892 continue; /* faster when present ... (?) */
1893 }
1894 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001895 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001896
1897 /* Last Literals */
1898 {
1899 size_t lastLLSize = iend - anchor;
1900 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1901 seqStorePtr->lit += lastLLSize;
1902 }
Yann Collet9a24e592015-11-22 02:53:43 +01001903}
1904
Yann Collet59d1f792016-01-23 19:28:41 +01001905void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01001906{
Yann Colleta1249dc2016-01-25 04:22:03 +01001907 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01001908}
1909
Yann Collet59d1f792016-01-23 19:28:41 +01001910static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01001911{
Yann Colleta1249dc2016-01-25 04:22:03 +01001912 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01001913}
Yann Collet9a24e592015-11-22 02:53:43 +01001914
Yann Collet59d1f792016-01-23 19:28:41 +01001915static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01001916{
Yann Colleta1249dc2016-01-25 04:22:03 +01001917 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01001918}
1919
Yann Collet59d1f792016-01-23 19:28:41 +01001920static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01001921{
Yann Colleta1249dc2016-01-25 04:22:03 +01001922 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001923}
1924
inikepe2bfe242016-01-31 11:25:48 +01001925static void ZSTD_compressBlock_opt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1926{
inikepbe77f332016-02-09 23:00:41 +01001927 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0, 2);
inikepe2bfe242016-01-31 11:25:48 +01001928}
1929
1930static void ZSTD_compressBlock_opt_bt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1931{
inikepbe77f332016-02-09 23:00:41 +01001932 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1, 2);
inikepe2bfe242016-01-31 11:25:48 +01001933}
1934
Yann Collet7a231792015-11-21 15:27:35 +01001935
Yann Collet59d1f792016-01-23 19:28:41 +01001936typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01001937
Yann Colletb923f652016-01-26 03:14:20 +01001938static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01001939{
inikepe2bfe242016-01-31 11:25:48 +01001940 static const ZSTD_blockCompressor blockCompressor[2][7] = {
1941 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy,ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_opt, ZSTD_compressBlock_opt_bt },
1942 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_opt_extDict, ZSTD_compressBlock_opt_bt_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01001943 };
1944
1945 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01001946}
1947
1948
Yann Colletbf42c8e2016-01-09 01:08:23 +01001949static 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 +01001950{
Yann Collet03526e12015-11-23 15:29:15 +01001951 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01001952 if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */
Yann Collet59d1f792016-01-23 19:28:41 +01001953 blockCompressor(zc, src, srcSize);
Yann Colletb923f652016-01-26 03:14:20 +01001954 return ZSTD_compressSequences(zc, dst, maxDstSize, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01001955}
1956
1957
Yann Collet2ce49232016-02-02 14:36:49 +01001958static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
Yann Colletf3eca252015-10-22 15:31:46 +01001959 void* dst, size_t maxDstSize,
1960 const void* src, size_t srcSize)
1961{
Yann Collet2ce49232016-02-02 14:36:49 +01001962 size_t blockSize = zc->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001963 size_t remaining = srcSize;
1964 const BYTE* ip = (const BYTE*)src;
1965 BYTE* const ostart = (BYTE*)dst;
1966 BYTE* op = ostart;
Yann Collet2ce49232016-02-02 14:36:49 +01001967 const U32 maxDist = 1 << zc->params.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01001968
Yann Collet2ce49232016-02-02 14:36:49 +01001969 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01001970 size_t cSize;
1971
Yann Collet2ce49232016-02-02 14:36:49 +01001972 if (maxDstSize < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01001973 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01001974
Yann Collet2ce49232016-02-02 14:36:49 +01001975 if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */
Yann Collet7a6343f2016-02-02 16:00:50 +01001976 U32 newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist;
1977 if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01001978 if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001979 }
Yann Collet89db5e02015-11-13 11:27:46 +01001980
Yann Collet2ce49232016-02-02 14:36:49 +01001981 cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, maxDstSize-ZSTD_blockHeaderSize, ip, blockSize);
Yann Collet3e358272015-11-04 18:19:39 +01001982 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001983
Yann Collet2ce49232016-02-02 14:36:49 +01001984 if (cSize == 0) { /* block is not compressible */
1985 cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize);
Yann Collet523b5942016-01-09 02:10:40 +01001986 if (ZSTD_isError(cSize)) return cSize;
Yann Collet2ce49232016-02-02 14:36:49 +01001987 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01001988 op[0] = (BYTE)(cSize>>16);
1989 op[1] = (BYTE)(cSize>>8);
1990 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01001991 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01001992 cSize += 3;
1993 }
1994
1995 remaining -= blockSize;
Yann Collet3e358272015-11-04 18:19:39 +01001996 maxDstSize -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001997 ip += blockSize;
1998 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001999 }
2000
2001 return op-ostart;
2002}
2003
2004
Yann Colletbf42c8e2016-01-09 01:08:23 +01002005static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
2006 void* dst, size_t dstSize,
2007 const void* src, size_t srcSize,
2008 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01002009{
Yann Collet2acb5d32015-10-29 16:49:43 +01002010 const BYTE* const ip = (const BYTE*) src;
Yann Colletecd651b2016-01-07 15:35:18 +01002011 size_t hbSize = 0;
2012
Yann Collet2ce49232016-02-02 14:36:49 +01002013 if (frame && (zc->stage==0)) {
Yann Colletecd651b2016-01-07 15:35:18 +01002014 hbSize = zc->hbSize;
2015 if (dstSize <= hbSize) return ERROR(dstSize_tooSmall);
2016 zc->stage = 1;
2017 memcpy(dst, zc->headerBuffer, hbSize);
2018 dstSize -= hbSize;
2019 dst = (char*)dst + hbSize;
2020 }
Yann Colletf3eca252015-10-22 15:31:46 +01002021
Yann Collet417890c2015-12-04 17:16:37 +01002022 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01002023 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002024 /* not contiguous */
2025 size_t delta = zc->nextSrc - ip;
2026 zc->lowLimit = zc->dictLimit;
2027 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2028 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01002029 zc->base -= delta;
2030 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01002031 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002032 }
2033
Yann Collet89db5e02015-11-13 11:27:46 +01002034 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01002035 if (zc->lowLimit > (1<<30)) {
inikepc71568f2016-01-30 12:15:56 +01002036 U32 btplus = (zc->params.strategy == ZSTD_btlazy2) || (zc->params.strategy == ZSTD_opt_bt);
Yann Collet6c3e2e72015-12-11 10:44:07 +01002037 U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1;
2038 U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */
2039 U32 correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002040 ZSTD_reduceIndex(zc, correction);
2041 zc->base += correction;
2042 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002043 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002044 zc->dictLimit -= correction;
2045 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2046 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01002047 }
2048
Yann Colletbf42c8e2016-01-09 01:08:23 +01002049 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01002050 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01002051 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2052 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002053 }
2054
Yann Colletc3652152015-11-24 14:06:07 +01002055 zc->nextSrc = ip + srcSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002056 {
Yann Colletbf42c8e2016-01-09 01:08:23 +01002057 size_t cSize;
2058 if (frame) cSize = ZSTD_compress_generic (zc, dst, dstSize, src, srcSize);
2059 else cSize = ZSTD_compressBlock_internal (zc, dst, dstSize, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002060 if (ZSTD_isError(cSize)) return cSize;
2061 return cSize + hbSize;
2062 }
Yann Colletf3eca252015-10-22 15:31:46 +01002063}
2064
Yann Colletbf42c8e2016-01-09 01:08:23 +01002065
2066size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
2067 void* dst, size_t dstSize,
2068 const void* src, size_t srcSize)
2069{
2070 return ZSTD_compressContinue_internal(zc, dst, dstSize, src, srcSize, 1);
2071}
2072
2073
2074size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
2075{
2076 if (srcSize > BLOCKSIZE) return ERROR(srcSize_wrong);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002077 return ZSTD_compressContinue_internal(zc, dst, maxDstSize, src, srcSize, 0);
2078}
2079
2080
Yann Colletb923f652016-01-26 03:14:20 +01002081static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002082{
2083 const BYTE* const ip = (const BYTE*) src;
2084 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002085
Yann Collet417890c2015-12-04 17:16:37 +01002086 /* input becomes current prefix */
2087 zc->lowLimit = zc->dictLimit;
2088 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2089 zc->dictBase = zc->base;
2090 zc->base += ip - zc->nextSrc;
2091 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002092 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002093
2094 zc->nextSrc = iend;
2095 if (srcSize <= 8) return 0;
2096
2097 switch(zc->params.strategy)
2098 {
2099 case ZSTD_fast:
Yann Collet2ce49232016-02-02 14:36:49 +01002100 ZSTD_fillHashTable (zc, iend, zc->params.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002101 break;
2102
2103 case ZSTD_greedy:
2104 case ZSTD_lazy:
2105 case ZSTD_lazy2:
inikepbe77f332016-02-09 23:00:41 +01002106 case ZSTD_opt:
Yann Collet417890c2015-12-04 17:16:37 +01002107 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength);
2108 break;
2109
2110 case ZSTD_btlazy2:
inikepbe77f332016-02-09 23:00:41 +01002111 case ZSTD_opt_bt:
Yann Collet417890c2015-12-04 17:16:37 +01002112 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength);
2113 break;
2114
2115 default:
2116 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2117 }
2118
Yann Collet2ce49232016-02-02 14:36:49 +01002119 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002120 return 0;
2121}
2122
2123
Yann Colletb923f652016-01-26 03:14:20 +01002124/* Dictionary format :
2125 Magic == ZSTD_DICT_MAGIC (4 bytes)
2126 Huff0 CTable (256 * 4 bytes) => to be changed to read from writeCTable
2127 Dictionary content
2128*/
2129/*! ZSTD_loadDictEntropyStats
2130 @return : size read from dictionary */
2131static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2132{
2133 /* note : magic number already checked */
Yann Colletfb810d62016-01-28 00:18:06 +01002134 size_t offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize, errorCode;
2135 short offcodeNCount[MaxOff+1];
2136 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2137 short matchlengthNCount[MaxML+1];
2138 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2139 short litlengthNCount[MaxLL+1];
2140 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2141
Yann Colletb923f652016-01-26 03:14:20 +01002142 const size_t hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize);
2143 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Colletfb810d62016-01-28 00:18:06 +01002144 zc->flagStaticTables = 1;
2145 dict = (const char*)dict + hufHeaderSize;
2146 dictSize -= hufHeaderSize;
2147
2148 offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
2149 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2150 errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2151 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2152 dict = (const char*)dict + offcodeHeaderSize;
2153 dictSize -= offcodeHeaderSize;
2154
2155 matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
2156 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2157 errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2158 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2159 dict = (const char*)dict + matchlengthHeaderSize;
2160 dictSize -= matchlengthHeaderSize;
2161
2162 litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
2163 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2164 errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2165 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2166
2167 return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
Yann Colletb923f652016-01-26 03:14:20 +01002168}
2169
Yann Colletfb810d62016-01-28 00:18:06 +01002170
Yann Collet1c8e1942016-01-26 16:31:22 +01002171static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002172{
Yann Collet2ce49232016-02-02 14:36:49 +01002173 if (dict && (dictSize>4)) {
Yann Collet7b51a292016-01-26 15:58:49 +01002174 U32 magic = MEM_readLE32(dict);
2175 size_t eSize;
2176 if (magic != ZSTD_DICT_MAGIC)
2177 return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletb923f652016-01-26 03:14:20 +01002178
Yann Collet7b51a292016-01-26 15:58:49 +01002179 eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4, dictSize-4) + 4;
2180 if (ZSTD_isError(eSize)) return eSize;
2181 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
2182 }
Yann Colletecd651b2016-01-07 15:35:18 +01002183 return 0;
2184}
2185
2186
Yann Collet417890c2015-12-04 17:16:37 +01002187/*! ZSTD_compressBegin_advanced
Yann Colletecd651b2016-01-07 15:35:18 +01002188* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002189size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
2190 const void* dict, size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002191 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002192{
Yann Collet4114f952015-10-30 06:40:22 +01002193 size_t errorCode;
Yann Collet88fcd292015-11-25 14:42:45 +01002194
2195 ZSTD_validateParams(&params);
2196
Yann Collet1c8e1942016-01-26 16:31:22 +01002197 errorCode = ZSTD_resetCCtx_advanced(zc, params);
Yann Collet4114f952015-10-30 06:40:22 +01002198 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet89db5e02015-11-13 11:27:46 +01002199
Yann Collet1c8e1942016-01-26 16:31:22 +01002200 MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */
2201 ((BYTE*)zc->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN);
2202 zc->hbSize = ZSTD_frameHeaderSize_min;
2203 zc->stage = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002204
Yann Collet1c8e1942016-01-26 16:31:22 +01002205 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002206}
2207
2208
Yann Collet1c8e1942016-01-26 16:31:22 +01002209size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002210{
Yann Collet953ce722016-02-04 15:28:14 +01002211 return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, MAX(128 KB, dictSize)));
Yann Collet1c8e1942016-01-26 16:31:22 +01002212}
Yann Collet083fcc82015-10-25 14:06:35 +01002213
Yann Collet1c8e1942016-01-26 16:31:22 +01002214size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002215{
Yann Collet1c8e1942016-01-26 16:31:22 +01002216 return ZSTD_compressBegin_advanced(zc, NULL, 0, ZSTD_getParams(compressionLevel, 0));
Yann Collet083fcc82015-10-25 14:06:35 +01002217}
2218
2219
Yann Collet31683c02015-12-18 01:26:48 +01002220/*! ZSTD_compressEnd
Yann Collet88fcd292015-11-25 14:42:45 +01002221* Write frame epilogue
2222* @return : nb of bytes written into dst (or an error code) */
Yann Colletecd651b2016-01-07 15:35:18 +01002223size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize)
Yann Collet2acb5d32015-10-29 16:49:43 +01002224{
2225 BYTE* op = (BYTE*)dst;
Yann Colletecd651b2016-01-07 15:35:18 +01002226 size_t hbSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002227
Yann Colletecd651b2016-01-07 15:35:18 +01002228 /* empty frame */
Yann Colletfb810d62016-01-28 00:18:06 +01002229 if (zc->stage==0) {
Yann Colletecd651b2016-01-07 15:35:18 +01002230 hbSize = zc->hbSize;
2231 if (maxDstSize <= hbSize) return ERROR(dstSize_tooSmall);
2232 zc->stage = 1;
2233 memcpy(dst, zc->headerBuffer, hbSize);
2234 maxDstSize -= hbSize;
2235 op += hbSize;
2236 }
2237
2238 /* frame epilogue */
Yann Collet2acb5d32015-10-29 16:49:43 +01002239 if (maxDstSize < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002240 op[0] = (BYTE)(bt_end << 6);
2241 op[1] = 0;
2242 op[2] = 0;
2243
Yann Colletecd651b2016-01-07 15:35:18 +01002244 return 3+hbSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002245}
2246
Yann Colletfd416f12016-01-30 03:14:15 +01002247
2248size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
2249 void* dst, size_t maxDstSize,
2250 const void* src, size_t srcSize)
2251{
2252 size_t outSize;
2253 size_t errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2254 if (ZSTD_isError(errorCode)) return errorCode;
2255 errorCode = ZSTD_compressContinue(cctx, dst, maxDstSize, src, srcSize);
2256 if (ZSTD_isError(errorCode)) return errorCode;
2257 outSize = errorCode;
2258 errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, maxDstSize-outSize);
2259 if (ZSTD_isError(errorCode)) return errorCode;
2260 outSize += errorCode;
2261 return outSize;
2262}
2263
2264
Yann Collet5be2dd22015-11-11 13:43:58 +01002265size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
Yann Collet88fcd292015-11-25 14:42:45 +01002266 void* dst, size_t maxDstSize,
2267 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002268 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002269 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002270{
2271 BYTE* const ostart = (BYTE*)dst;
2272 BYTE* op = ostart;
Yann Collet4114f952015-10-30 06:40:22 +01002273 size_t oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002274
Yann Collet1c8e1942016-01-26 16:31:22 +01002275 /* Init */
2276 oSize = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params);
Yann Colletf3eca252015-10-22 15:31:46 +01002277 if(ZSTD_isError(oSize)) return oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002278
2279 /* body (compression) */
Yann Collet31683c02015-12-18 01:26:48 +01002280 oSize = ZSTD_compressContinue (ctx, op, maxDstSize, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002281 if(ZSTD_isError(oSize)) return oSize;
2282 op += oSize;
2283 maxDstSize -= oSize;
2284
2285 /* Close frame */
Yann Collet5be2dd22015-11-11 13:43:58 +01002286 oSize = ZSTD_compressEnd(ctx, op, maxDstSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002287 if(ZSTD_isError(oSize)) return oSize;
2288 op += oSize;
2289
2290 return (op - ostart);
2291}
2292
Yann Collet31683c02015-12-18 01:26:48 +01002293size_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)
2294{
Yann Collet2ce49232016-02-02 14:36:49 +01002295 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet31683c02015-12-18 01:26:48 +01002296}
2297
Yann Collet5be2dd22015-11-11 13:43:58 +01002298size_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 +01002299{
Yann Collet31683c02015-12-18 01:26:48 +01002300 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet083fcc82015-10-25 14:06:35 +01002301}
2302
Yann Collet5be2dd22015-11-11 13:43:58 +01002303size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002304{
Yann Collet44fe9912015-10-29 22:02:40 +01002305 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002306 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002307 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Collet5be2dd22015-11-11 13:43:58 +01002308 result = ZSTD_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel);
Yann Colletecd651b2016-01-07 15:35:18 +01002309 free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002310 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002311}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002312
Yann Colletfd416f12016-01-30 03:14:15 +01002313
Yann Collet70e8c382016-02-10 13:37:52 +01002314/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01002315
Yann Collet70e8c382016-02-10 13:37:52 +01002316#define ZSTD_MAX_CLEVEL 25
Yann Collet7d968c72016-02-03 02:11:32 +01002317unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2318
Yann Colletfd416f12016-01-30 03:14:15 +01002319static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = {
2320{ /* "default" */
inikepf2fee4c2016-02-05 19:45:25 +01002321 /* SL, W, C, H, S, L, strat */
2322 { 0, 0, 18, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */
2323 { 0, 0, 19, 13, 14, 1, 7, ZSTD_fast }, /* level 1 */
2324 { 0, 0, 19, 15, 16, 1, 6, ZSTD_fast }, /* level 2 */
2325 { 0, 0, 20, 18, 20, 1, 6, ZSTD_fast }, /* level 3 */
2326 { 0, 0, 21, 19, 21, 1, 6, ZSTD_fast }, /* level 4 */
2327 { 0, 0, 20, 14, 18, 3, 5, ZSTD_greedy }, /* level 5 */
2328 { 0, 0, 20, 18, 19, 3, 5, ZSTD_greedy }, /* level 6 */
2329 { 0, 0, 21, 17, 20, 3, 5, ZSTD_lazy }, /* level 7 */
2330 { 0, 0, 21, 19, 20, 3, 5, ZSTD_lazy }, /* level 8 */
2331 { 0, 0, 21, 20, 20, 3, 5, ZSTD_lazy2 }, /* level 9 */
2332 { 0, 0, 21, 19, 21, 4, 5, ZSTD_lazy2 }, /* level 10 */
2333 { 0, 0, 22, 20, 22, 4, 5, ZSTD_lazy2 }, /* level 11 */ // 42498419
2334 { 0, 0, 22, 20, 22, 5, 5, ZSTD_lazy2 }, /* level 12 */
2335 { 0, 0, 22, 21, 22, 5, 5, ZSTD_lazy2 }, /* level 13 */
2336 { 0, 0, 22, 22, 23, 5, 5, ZSTD_lazy2 }, /* level 14 */
2337 { 0, 0, 23, 23, 23, 5, 5, ZSTD_lazy2 }, /* level 15 */
2338 { 0, 0, 23, 21, 22, 5, 5, ZSTD_btlazy2 }, /* level 16 */ // 42113689
2339 { 0, 0, 23, 24, 23, 4, 5, ZSTD_btlazy2 }, /* level 17 */
2340 { 0, 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */
2341 { 0, 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */
2342 { 0, 0, 26, 27, 25, 9, 5, ZSTD_btlazy2 }, /* level 20 */
Yann Colletb79a0b32016-02-10 17:07:37 +01002343 { 0, 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 21 = 16 + L=4 */ // 41233150 btlazy1=41560211 norep1=42322286
2344 { 0, 12, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 22 */
inikepf2fee4c2016-02-05 19:45:25 +01002345 { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 23 */
Yann Collet70e8c382016-02-10 13:37:52 +01002346 { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 24 = 16 + btopt */
2347 { 0, 64, 26, 27, 25, 10, 4, ZSTD_opt_bt }, /* level 25 = 20 + btopt */
Yann Colletfd416f12016-01-30 03:14:15 +01002348},
2349{ /* for srcSize <= 256 KB */
inikepf2fee4c2016-02-05 19:45:25 +01002350 /* SL, W, C, H, S, L, strat */
2351 { 0, 0, 18, 13, 14, 1, 7, ZSTD_fast }, /* level 0 - never used */
2352 { 0, 0, 18, 14, 15, 1, 6, ZSTD_fast }, /* level 1 */
2353 { 0, 0, 18, 14, 15, 1, 5, ZSTD_fast }, /* level 2 */
2354 { 0, 0, 18, 12, 15, 3, 4, ZSTD_greedy }, /* level 3 */
2355 { 0, 0, 18, 13, 15, 4, 4, ZSTD_greedy }, /* level 4 */
2356 { 0, 0, 18, 14, 15, 5, 4, ZSTD_greedy }, /* level 5 */
2357 { 0, 0, 18, 13, 15, 4, 4, ZSTD_lazy }, /* level 6 */
2358 { 0, 0, 18, 14, 16, 5, 4, ZSTD_lazy }, /* level 7 */
2359 { 0, 0, 18, 15, 16, 6, 4, ZSTD_lazy }, /* level 8 */
2360 { 0, 0, 18, 15, 15, 7, 4, ZSTD_lazy }, /* level 9 */
2361 { 0, 0, 18, 16, 16, 7, 4, ZSTD_lazy }, /* level 10 */
2362 { 0, 0, 18, 16, 16, 8, 4, ZSTD_lazy }, /* level 11 */
2363 { 0, 0, 18, 17, 16, 8, 4, ZSTD_lazy }, /* level 12 */
2364 { 0, 0, 18, 17, 16, 9, 4, ZSTD_lazy }, /* level 13 */
2365 { 0, 0, 18, 18, 16, 9, 4, ZSTD_lazy }, /* level 14 */
2366 { 0, 0, 18, 17, 17, 9, 4, ZSTD_lazy2 }, /* level 15 */
2367 { 0, 0, 18, 18, 18, 9, 4, ZSTD_lazy2 }, /* level 16 */
2368 { 0, 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level 17 */
2369 { 0, 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level 18 */
2370 { 0, 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level 19 */
2371 { 0, 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level 20 */
2372 { 0, 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level ??? */
2373 { 0, 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level ??? */
2374 { 0, 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level ??? */
2375 { 0, 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level ??? */
Yann Colletfd416f12016-01-30 03:14:15 +01002376},
2377{ /* for srcSize <= 128 KB */
2378 /* W, C, H, S, L, strat */
inikepf2fee4c2016-02-05 19:45:25 +01002379 { 0, 0, 17, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */
2380 { 0, 0, 17, 12, 13, 1, 6, ZSTD_fast }, /* level 1 */
2381 { 0, 0, 17, 14, 16, 1, 5, ZSTD_fast }, /* level 2 */
2382 { 0, 0, 17, 15, 17, 1, 5, ZSTD_fast }, /* level 3 */
2383 { 0, 0, 17, 13, 15, 2, 4, ZSTD_greedy }, /* level 4 */
2384 { 0, 0, 17, 15, 17, 3, 4, ZSTD_greedy }, /* level 5 */
2385 { 0, 0, 17, 14, 17, 3, 4, ZSTD_lazy }, /* level 6 */
2386 { 0, 0, 17, 16, 17, 4, 4, ZSTD_lazy }, /* level 7 */
2387 { 0, 0, 17, 16, 17, 4, 4, ZSTD_lazy2 }, /* level 8 */
2388 { 0, 0, 17, 17, 16, 5, 4, ZSTD_lazy2 }, /* level 9 */
2389 { 0, 0, 17, 17, 16, 6, 4, ZSTD_lazy2 }, /* level 10 */
2390 { 0, 0, 17, 17, 16, 7, 4, ZSTD_lazy2 }, /* level 11 */
2391 { 0, 0, 17, 17, 16, 8, 4, ZSTD_lazy2 }, /* level 12 */
2392 { 0, 0, 17, 18, 16, 4, 4, ZSTD_btlazy2 }, /* level 13 */
2393 { 0, 0, 17, 18, 16, 5, 4, ZSTD_btlazy2 }, /* level 14 */
2394 { 0, 0, 17, 18, 16, 6, 4, ZSTD_btlazy2 }, /* level 15 */
2395 { 0, 0, 17, 18, 16, 7, 4, ZSTD_btlazy2 }, /* level 16 */
2396 { 0, 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level 17 */
2397 { 0, 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level 18 */
2398 { 0, 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level 19 */
2399 { 0, 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level 20 */
2400 { 0, 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level ??? */
2401 { 0, 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level ??? */
2402 { 0, 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level ??? */
2403 { 0, 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level ??? */
Yann Colletfd416f12016-01-30 03:14:15 +01002404},
2405{ /* for srcSize <= 16 KB */
2406 /* W, C, H, S, L, strat */
inikepf2fee4c2016-02-05 19:45:25 +01002407 { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2408 { 0, 0, 14, 14, 14, 1, 4, ZSTD_fast }, /* level 1 */
2409 { 0, 0, 14, 14, 16, 1, 4, ZSTD_fast }, /* level 2 */
2410 { 0, 0, 14, 14, 14, 5, 4, ZSTD_greedy }, /* level 3 */
2411 { 0, 0, 14, 14, 14, 8, 4, ZSTD_greedy }, /* level 4 */
2412 { 0, 0, 14, 11, 14, 6, 4, ZSTD_lazy }, /* level 5 */
2413 { 0, 0, 14, 14, 13, 6, 5, ZSTD_lazy }, /* level 6 */
2414 { 0, 0, 14, 14, 14, 7, 6, ZSTD_lazy }, /* level 7 */
2415 { 0, 0, 14, 14, 14, 8, 4, ZSTD_lazy }, /* level 8 */
2416 { 0, 0, 14, 14, 15, 9, 4, ZSTD_lazy }, /* level 9 */
2417 { 0, 0, 14, 14, 15, 10, 4, ZSTD_lazy }, /* level 10 */
2418 { 0, 0, 14, 15, 15, 6, 4, ZSTD_btlazy2 }, /* level 11 */
2419 { 0, 0, 14, 15, 15, 7, 4, ZSTD_btlazy2 }, /* level 12 */
2420 { 0, 0, 14, 15, 15, 8, 4, ZSTD_btlazy2 }, /* level 13 */
2421 { 0, 0, 14, 15, 15, 9, 4, ZSTD_btlazy2 }, /* level 14 */
2422 { 0, 0, 14, 15, 15, 10, 4, ZSTD_btlazy2 }, /* level 15 */
2423 { 0, 0, 14, 15, 15, 11, 4, ZSTD_btlazy2 }, /* level 16 */
2424 { 0, 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level 17 */
2425 { 0, 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level 18 */
2426 { 0, 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level 19 */
2427 { 0, 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level 20 */
2428 { 0, 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level ??? */
2429 { 0, 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level ??? */
2430 { 0, 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level ??? */
2431 { 0, 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level ??? */
Yann Colletfd416f12016-01-30 03:14:15 +01002432},
2433};
2434
2435/*! ZSTD_getParams
2436* @return ZSTD_parameters structure for a selected compression level and srcSize.
2437* @srcSizeHint value is optional, select 0 if not known */
2438ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint)
2439{
2440 ZSTD_parameters result;
2441 int tableID = ((srcSizeHint-1) <= 256 KB) + ((srcSizeHint-1) <= 128 KB) + ((srcSizeHint-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
2442 if (compressionLevel<=0) compressionLevel = 1;
2443 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
inikep3379c5d2016-02-05 09:21:20 +01002444#if ZSTD_OPT_DEBUG >= 1
2445 tableID=0;
2446#endif
Yann Colletfd416f12016-01-30 03:14:15 +01002447 result = ZSTD_defaultParameters[tableID][compressionLevel];
2448 result.srcSize = srcSizeHint;
2449 return result;
2450}
2451