blob: 6ca31895e4b3e53871758642848a26c1a611bc65 [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);
194 CLAMP(params->sufficientLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
195 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
1046 /* Last Literals */
1047 {
1048 size_t lastLLSize = iend - anchor;
1049 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1050 seqStorePtr->lit += lastLLSize;
1051 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001052}
1053
1054
Yann Collet59d1f792016-01-23 19:28:41 +01001055void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
1056 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001057{
1058 const U32 mls = ctx->params.searchLength;
1059 switch(mls)
1060 {
1061 default:
1062 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001063 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001064 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001065 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001066 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001067 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001068 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001069 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001070 }
1071}
Yann Colletf3eca252015-10-22 15:31:46 +01001072
Yann Colletf3eca252015-10-22 15:31:46 +01001073
Yann Collet93a823c2015-11-13 15:08:43 +01001074//FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001075void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
1076 const void* src, size_t srcSize,
1077 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001078{
1079 U32* hashTable = ctx->hashTable;
1080 const U32 hBits = ctx->params.hashLog;
1081 seqStore_t* seqStorePtr = &(ctx->seqStore);
1082 const BYTE* const base = ctx->base;
1083 const BYTE* const dictBase = ctx->dictBase;
1084 const BYTE* const istart = (const BYTE*)src;
1085 const BYTE* ip = istart;
1086 const BYTE* anchor = istart;
1087 const U32 lowLimit = ctx->lowLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001088 const BYTE* const dictStart = dictBase + lowLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001089 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001090 const BYTE* const lowPrefixPtr = base + dictLimit;
1091 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001092 const BYTE* const iend = istart + srcSize;
1093 const BYTE* const ilimit = iend - 8;
1094
Yann Collet138e89c2015-11-17 14:26:54 +01001095 U32 offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001096
1097
1098 /* init */
1099 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001100 /* skip first position to avoid read overflow during repcode match check */
Yann Colletfb810d62016-01-28 00:18:06 +01001101 hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0);
Yann Collet61e16ce2016-01-31 02:04:15 +01001102 ip += REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001103
1104 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001105 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001106 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001107 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001108 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001109 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001110 const U32 current = (U32)(ip-base);
Yann Collet743402c2015-11-20 12:03:53 +01001111 const U32 repIndex = current + 1 - offset_1;
Yann Collet402fdcf2015-11-20 12:46:08 +01001112 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001113 const BYTE* repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001114 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001115 U32 offset;
Yann Collet89db5e02015-11-13 11:27:46 +01001116 hashTable[h] = current; /* update hash table */
1117
1118 if ( ((repIndex <= dictLimit-4) || (repIndex >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001119 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001120 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001121 mlCode = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repMatchEnd, lowPrefixPtr);
Yann Collet743402c2015-11-20 12:03:53 +01001122 ip++;
Yann Collet402fdcf2015-11-20 12:46:08 +01001123 offset = 0;
Yann Colletfb810d62016-01-28 00:18:06 +01001124 } else {
Yann Collet402fdcf2015-11-20 12:46:08 +01001125 if ( (matchIndex < lowLimit) ||
1126 (MEM_read32(match) != MEM_read32(ip)) )
1127 { ip += ((ip-anchor) >> g_searchStrength) + 1; continue; }
1128 {
1129 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001130 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1131 mlCode = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iend, matchEnd, lowPrefixPtr);
Yann Colletfb810d62016-01-28 00:18:06 +01001132 while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001133 offset = current - matchIndex;
1134 offset_2 = offset_1;
1135 offset_1 = offset;
Yann Colletfb810d62016-01-28 00:18:06 +01001136 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001137
Yann Collet5054ee02015-11-23 13:34:21 +01001138 /* found a match : store it */
1139 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +01001140 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001141 anchor = ip;
1142
Yann Colletfb810d62016-01-28 00:18:06 +01001143 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001144 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001145 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001146 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1147 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001148 while (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001149 U32 current2 = (U32)(ip-base);
1150 const U32 repIndex2 = current2 - offset_2;
1151 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet743402c2015-11-20 12:03:53 +01001152 if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001153 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001154 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1155 size_t repLength2 = ZSTD_count_2segments(ip+MINMATCH, repMatch2+MINMATCH, iend, repEnd2, lowPrefixPtr);
1156 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1157 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2);
1158 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
1159 ip += repLength2+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001160 anchor = ip;
1161 continue;
1162 }
Yann Collet743402c2015-11-20 12:03:53 +01001163 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001164 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001165
1166 /* Last Literals */
1167 {
1168 size_t lastLLSize = iend - anchor;
1169 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1170 seqStorePtr->lit += lastLLSize;
1171 }
Yann Collet89db5e02015-11-13 11:27:46 +01001172}
1173
1174
Yann Collet59d1f792016-01-23 19:28:41 +01001175void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001176 const void* src, size_t srcSize)
1177{
1178 const U32 mls = ctx->params.searchLength;
1179 switch(mls)
1180 {
1181 default:
1182 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001183 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001184 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001185 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001186 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001187 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001188 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001189 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001190 }
1191}
1192
1193
Yann Colletf3eca252015-10-22 15:31:46 +01001194/* *************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001195* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001196***************************************/
Yann Collet70e8c382016-02-10 13:37:52 +01001197/** ZSTD_insertBt1() : add one or multiple positions to tree
1198* ip : assumed <= iend-8
Yann Collet06eade52015-11-23 14:23:47 +01001199* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001200static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1201 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001202{
1203 U32* const hashTable = zc->hashTable;
1204 const U32 hashLog = zc->params.hashLog;
Yann Collet5be2dd22015-11-11 13:43:58 +01001205 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet1f44b3f2015-11-05 17:32:18 +01001206 U32* const bt = zc->contentTable;
1207 const U32 btLog = zc->params.contentLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001208 const U32 btMask= (1 << btLog) - 1;
1209 U32 matchIndex = hashTable[h];
1210 size_t commonLengthSmaller=0, commonLengthLarger=0;
1211 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001212 const BYTE* const dictBase = zc->dictBase;
1213 const U32 dictLimit = zc->dictLimit;
1214 const BYTE* const dictEnd = dictBase + dictLimit;
1215 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001216 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001217 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001218 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001219 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001220 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001221 U32 dummy32; /* to be nullified at the end */
Yann Collet03526e12015-11-23 15:29:15 +01001222 const U32 windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001223 U32 matchEndIdx = current+8;
Yann Collet7beaa052016-01-21 11:57:45 +01001224 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1225 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1226 predictedSmall += (predictedSmall>0);
1227 predictedLarge += (predictedLarge>0);
Yann Colletf48e35c2015-11-07 01:13:31 +01001228
Yann Collet6c3e2e72015-12-11 10:44:07 +01001229 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001230
Yann Colletfb810d62016-01-28 00:18:06 +01001231 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001232 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001233 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1234
Yann Collet70e8c382016-02-10 13:37:52 +01001235 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001236 if (matchIndex == predictedSmall) {
1237 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001238 *smallerPtr = matchIndex;
1239 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1240 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1241 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001242 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001243 continue;
1244 }
Yann Colletfb810d62016-01-28 00:18:06 +01001245 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001246 *largerPtr = matchIndex;
1247 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1248 largerPtr = nextPtr;
1249 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001250 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001251 continue;
1252 }
1253
Yann Colletfb810d62016-01-28 00:18:06 +01001254 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001255 match = base + matchIndex;
1256 if (match[matchLength] == ip[matchLength])
1257 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001258 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001259 match = dictBase + matchIndex;
1260 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1261 if (matchIndex+matchLength >= dictLimit)
1262 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1263 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001264
Yann Colletee3f4512015-12-29 22:26:09 +01001265 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001266 matchEndIdx = matchIndex + (U32)matchLength;
Yann Colletee3f4512015-12-29 22:26:09 +01001267
Yann Collet59d70632015-11-04 12:05:27 +01001268 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001269 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001270
Yann Colletfb810d62016-01-28 00:18:06 +01001271 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001272 /* match is smaller than current */
1273 *smallerPtr = matchIndex; /* update smaller idx */
1274 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001275 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001276 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001277 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001278 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001279 /* match is larger than current */
1280 *largerPtr = matchIndex;
1281 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001282 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001283 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001284 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001285 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001286
Yann Collet59d70632015-11-04 12:05:27 +01001287 *smallerPtr = *largerPtr = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001288 return (matchEndIdx > current + 8) ? matchEndIdx - current - 8 : 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001289}
1290
1291
Yann Colletee3f4512015-12-29 22:26:09 +01001292static 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 +01001293{
1294 const BYTE* const base = zc->base;
1295 const U32 target = (U32)(ip - base);
1296 U32 idx = zc->nextToUpdate;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001297
Yann Colletf48e35c2015-11-07 01:13:31 +01001298 for( ; idx < target ; )
Yann Collet1358f912016-01-01 07:29:39 +01001299 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001300}
1301
Yann Collet96b9f0b2015-11-04 03:52:54 +01001302FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Collet2cc12cb2016-01-01 07:47:58 +01001303size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001304 ZSTD_CCtx* zc,
1305 const BYTE* const ip, const BYTE* const iend,
1306 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001307 U32 nbCompares, const U32 mls,
1308 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001309{
1310 U32* const hashTable = zc->hashTable;
1311 const U32 hashLog = zc->params.hashLog;
1312 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
1313 U32* const bt = zc->contentTable;
1314 const U32 btLog = zc->params.contentLog - 1;
1315 const U32 btMask= (1 << btLog) - 1;
1316 U32 matchIndex = hashTable[h];
1317 size_t commonLengthSmaller=0, commonLengthLarger=0;
1318 const BYTE* const base = zc->base;
1319 const BYTE* const dictBase = zc->dictBase;
1320 const U32 dictLimit = zc->dictLimit;
1321 const BYTE* const dictEnd = dictBase + dictLimit;
1322 const BYTE* const prefixStart = base + dictLimit;
1323 const U32 current = (U32)(ip-base);
1324 const U32 btLow = btMask >= current ? 0 : current - btMask;
1325 const U32 windowLow = zc->lowLimit;
1326 U32* smallerPtr = bt + 2*(current&btMask);
1327 U32* largerPtr = bt + 2*(current&btMask) + 1;
1328 size_t bestLength = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001329 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001330 U32 dummy32; /* to be nullified at the end */
1331
Yann Collet6c3e2e72015-12-11 10:44:07 +01001332 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001333
Yann Colletfb810d62016-01-28 00:18:06 +01001334 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001335 U32* nextPtr = bt + 2*(matchIndex & btMask);
1336 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1337 const BYTE* match;
1338
Yann Colletfb810d62016-01-28 00:18:06 +01001339 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001340 match = base + matchIndex;
1341 if (match[matchLength] == ip[matchLength])
1342 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001343 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001344 match = dictBase + matchIndex;
1345 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001346 if (matchIndex+matchLength >= dictLimit)
1347 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001348 }
1349
Yann Colletfb810d62016-01-28 00:18:06 +01001350 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001351 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001352 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet03526e12015-11-23 15:29:15 +01001353 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
1354 bestLength = matchLength, *offsetPtr = current - matchIndex;
1355 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1356 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1357 }
1358
Yann Colletfb810d62016-01-28 00:18:06 +01001359 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001360 /* match is smaller than current */
1361 *smallerPtr = matchIndex; /* update smaller idx */
1362 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1363 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1364 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1365 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001366 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001367 /* match is larger than current */
1368 *largerPtr = matchIndex;
1369 commonLengthLarger = matchLength;
1370 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1371 largerPtr = nextPtr;
1372 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001373 } }
Yann Collet03526e12015-11-23 15:29:15 +01001374
1375 *smallerPtr = *largerPtr = 0;
1376
Yann Collet72e84cf2015-12-31 19:08:44 +01001377 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
Yann Collet03526e12015-11-23 15:29:15 +01001378 return bestLength;
1379}
1380
Yann Collet2cc12cb2016-01-01 07:47:58 +01001381
1382/** Tree updater, providing best match */
1383FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1384size_t ZSTD_BtFindBestMatch (
1385 ZSTD_CCtx* zc,
1386 const BYTE* const ip, const BYTE* const iLimit,
1387 size_t* offsetPtr,
1388 const U32 maxNbAttempts, const U32 mls)
1389{
1390 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1391 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
1392 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1393}
1394
1395
Yann Collet768c6bc2016-02-10 14:01:49 +01001396static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001397 ZSTD_CCtx* zc, /* Index table will be updated */
1398 const BYTE* ip, const BYTE* const iLimit,
1399 size_t* offsetPtr,
1400 const U32 maxNbAttempts, const U32 matchLengthSearch)
1401{
1402 switch(matchLengthSearch)
1403 {
1404 default :
1405 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1406 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1407 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1408 }
1409}
1410
1411
1412static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1413{
1414 const BYTE* const base = zc->base;
1415 const U32 target = (U32)(ip - base);
1416 U32 idx = zc->nextToUpdate;
1417
1418 for( ; idx < target ; )
1419 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1420}
1421
1422
Yann Collet03526e12015-11-23 15:29:15 +01001423/** Tree updater, providing best match */
1424FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1425size_t ZSTD_BtFindBestMatch_extDict (
1426 ZSTD_CCtx* zc,
1427 const BYTE* const ip, const BYTE* const iLimit,
1428 size_t* offsetPtr,
1429 const U32 maxNbAttempts, const U32 mls)
1430{
Yann Colletee3f4512015-12-29 22:26:09 +01001431 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1432 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001433 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001434}
1435
1436
1437FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
1438 ZSTD_CCtx* zc, /* Index table will be updated */
1439 const BYTE* ip, const BYTE* const iLimit,
1440 size_t* offsetPtr,
1441 const U32 maxNbAttempts, const U32 matchLengthSearch)
1442{
1443 switch(matchLengthSearch)
1444 {
1445 default :
1446 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1447 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1448 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1449 }
1450}
1451
1452
Yann Collet5106a762015-11-05 15:00:24 +01001453/* ***********************
1454* Hash Chain
1455*************************/
1456
Yann Collet1f44b3f2015-11-05 17:32:18 +01001457#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1458
Yann Collet6bcdeac2015-11-26 11:43:00 +01001459/* Update chains up to ip (excluded)
Yann Collet06eade52015-11-23 14:23:47 +01001460 Assumption : always within prefix (ie. not within extDict) */
1461static U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
Yann Collet5106a762015-11-05 15:00:24 +01001462{
1463 U32* const hashTable = zc->hashTable;
1464 const U32 hashLog = zc->params.hashLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001465 U32* const chainTable = zc->contentTable;
1466 const U32 chainMask = (1 << zc->params.contentLog) - 1;
Yann Collet5106a762015-11-05 15:00:24 +01001467 const BYTE* const base = zc->base;
1468 const U32 target = (U32)(ip - base);
1469 U32 idx = zc->nextToUpdate;
1470
Yann Colletfb810d62016-01-28 00:18:06 +01001471 while(idx < target) {
Yann Collet5be2dd22015-11-11 13:43:58 +01001472 size_t h = ZSTD_hashPtr(base+idx, hashLog, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001473 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1474 hashTable[h] = idx;
1475 idx++;
1476 }
1477
1478 zc->nextToUpdate = target;
Yann Collet5be2dd22015-11-11 13:43:58 +01001479 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
Yann Collet5106a762015-11-05 15:00:24 +01001480}
1481
1482
1483FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Colletc1e52f02015-11-23 14:37:59 +01001484size_t ZSTD_HcFindBestMatch_generic (
Yann Collet5be2dd22015-11-11 13:43:58 +01001485 ZSTD_CCtx* zc, /* Index table will be updated */
Yann Collet5106a762015-11-05 15:00:24 +01001486 const BYTE* const ip, const BYTE* const iLimit,
1487 size_t* offsetPtr,
Yann Colletc1e52f02015-11-23 14:37:59 +01001488 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
Yann Collet287b7d92015-11-22 13:24:05 +01001489{
Yann Collet1f44b3f2015-11-05 17:32:18 +01001490 U32* const chainTable = zc->contentTable;
1491 const U32 chainSize = (1 << zc->params.contentLog);
Yann Collet5106a762015-11-05 15:00:24 +01001492 const U32 chainMask = chainSize-1;
1493 const BYTE* const base = zc->base;
1494 const BYTE* const dictBase = zc->dictBase;
1495 const U32 dictLimit = zc->dictLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001496 const BYTE* const prefixStart = base + dictLimit;
1497 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001498 const U32 lowLimit = zc->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001499 const U32 current = (U32)(ip-base);
1500 const U32 minChain = current > chainSize ? current - chainSize : 0;
Yann Collet5106a762015-11-05 15:00:24 +01001501 U32 matchIndex;
1502 const BYTE* match;
1503 int nbAttempts=maxNbAttempts;
Yann Collet5054ee02015-11-23 13:34:21 +01001504 size_t ml=MINMATCH-1;
Yann Collet5106a762015-11-05 15:00:24 +01001505
1506 /* HC4 match finder */
Yann Colletc1e52f02015-11-23 14:37:59 +01001507 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001508
Yann Colletfb810d62016-01-28 00:18:06 +01001509 while ((matchIndex>lowLimit) && (nbAttempts)) {
Yann Collet5054ee02015-11-23 13:34:21 +01001510 size_t currentMl=0;
Yann Collet5106a762015-11-05 15:00:24 +01001511 nbAttempts--;
Yann Colletfb810d62016-01-28 00:18:06 +01001512 if ((!extDict) || matchIndex >= dictLimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001513 match = base + matchIndex;
Yann Collet4baee502015-11-09 03:19:33 +01001514 if (match[ml] == ip[ml]) /* potentially better */
Yann Collet5054ee02015-11-23 13:34:21 +01001515 currentMl = ZSTD_count(ip, match, iLimit);
Yann Colletfb810d62016-01-28 00:18:06 +01001516 } else {
Yann Collet5106a762015-11-05 15:00:24 +01001517 match = dictBase + matchIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001518 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1519 currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
Yann Collet5106a762015-11-05 15:00:24 +01001520 }
1521
Yann Collet5054ee02015-11-23 13:34:21 +01001522 /* save best solution */
Yann Collet239cc282015-11-23 16:17:21 +01001523 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 +01001524
Yann Collet9a24e592015-11-22 02:53:43 +01001525 if (matchIndex <= minChain) break;
Yann Collet5106a762015-11-05 15:00:24 +01001526 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1527 }
1528
1529 return ml;
1530}
1531
1532
Yann Colletc1e52f02015-11-23 14:37:59 +01001533FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1534 ZSTD_CCtx* zc,
Yann Collet5106a762015-11-05 15:00:24 +01001535 const BYTE* ip, const BYTE* const iLimit,
1536 size_t* offsetPtr,
1537 const U32 maxNbAttempts, const U32 matchLengthSearch)
1538{
1539 switch(matchLengthSearch)
1540 {
1541 default :
Yann Colletc1e52f02015-11-23 14:37:59 +01001542 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1543 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1544 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1545 }
1546}
1547
1548
1549FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1550 ZSTD_CCtx* zc,
1551 const BYTE* ip, const BYTE* const iLimit,
1552 size_t* offsetPtr,
1553 const U32 maxNbAttempts, const U32 matchLengthSearch)
1554{
1555 switch(matchLengthSearch)
1556 {
1557 default :
1558 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1559 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1560 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001561 }
1562}
1563
1564
Yann Collet287b7d92015-11-22 13:24:05 +01001565/* *******************************
Yann Collet9a24e592015-11-22 02:53:43 +01001566* Common parser - lazy strategy
Yann Collet287b7d92015-11-22 13:24:05 +01001567*********************************/
Yann Collet5106a762015-11-05 15:00:24 +01001568FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001569void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1570 const void* src, size_t srcSize,
Yann Collet007c1c62015-11-22 02:42:28 +01001571 const U32 searchMethod, const U32 depth)
Yann Collet5106a762015-11-05 15:00:24 +01001572{
1573 seqStore_t* seqStorePtr = &(ctx->seqStore);
1574 const BYTE* const istart = (const BYTE*)src;
1575 const BYTE* ip = istart;
1576 const BYTE* anchor = istart;
1577 const BYTE* const iend = istart + srcSize;
1578 const BYTE* const ilimit = iend - 8;
Yann Collete47c4e52015-12-05 09:23:53 +01001579 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet5106a762015-11-05 15:00:24 +01001580
1581 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1582 const U32 maxSearches = 1 << ctx->params.searchLog;
1583 const U32 mls = ctx->params.searchLength;
1584
Yann Collet5be2dd22015-11-11 13:43:58 +01001585 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
Yann Collet5106a762015-11-05 15:00:24 +01001586 size_t* offsetPtr,
1587 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet5be2dd22015-11-11 13:43:58 +01001588 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet5106a762015-11-05 15:00:24 +01001589
1590 /* init */
1591 ZSTD_resetSeqStore(seqStorePtr);
Yann Collete47c4e52015-12-05 09:23:53 +01001592 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet5106a762015-11-05 15:00:24 +01001593
1594 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001595 while (ip < ilimit) {
Yann Collet7a231792015-11-21 15:27:35 +01001596 size_t matchLength=0;
1597 size_t offset=0;
1598 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001599
Yann Collet743402c2015-11-20 12:03:53 +01001600 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001601 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1)) {
Yann Collet743402c2015-11-20 12:03:53 +01001602 /* repcode : we take it */
Yann Collet7a231792015-11-21 15:27:35 +01001603 matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH;
Yann Collet007c1c62015-11-22 02:42:28 +01001604 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001605 }
1606
Yann Colletfc2afcf2015-11-06 15:40:14 +01001607 {
Yann Collet239cc282015-11-23 16:17:21 +01001608 /* first search (depth 0) */
1609 size_t offsetFound = 99999999;
1610 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1611 if (ml2 > matchLength)
1612 matchLength = ml2, start = ip, offset=offsetFound;
1613 }
Yann Collet9a24e592015-11-22 02:53:43 +01001614
Yann Colletfb810d62016-01-28 00:18:06 +01001615 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001616 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1617 continue;
1618 }
Yann Collet5106a762015-11-05 15:00:24 +01001619
1620 /* let's try to find a better solution */
Yann Collet007c1c62015-11-22 02:42:28 +01001621 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001622 while (ip<ilimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001623 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001624 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet007c1c62015-11-22 02:42:28 +01001625 size_t mlRep = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1626 int gain2 = (int)(mlRep * 3);
Yann Collet5106a762015-11-05 15:00:24 +01001627 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet007c1c62015-11-22 02:42:28 +01001628 if ((mlRep >= MINMATCH) && (gain2 > gain1))
1629 matchLength = mlRep, offset = 0, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001630 }
1631 {
1632 size_t offset2=999999;
1633 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet007c1c62015-11-22 02:42:28 +01001634 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1635 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001636 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001637 matchLength = ml2, offset = offset2, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001638 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001639 } }
Yann Collet5106a762015-11-05 15:00:24 +01001640
1641 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001642 if ((depth==2) && (ip<ilimit)) {
Yann Collet5106a762015-11-05 15:00:24 +01001643 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001644 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet5106a762015-11-05 15:00:24 +01001645 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1646 int gain2 = (int)(ml2 * 4);
1647 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet4baee502015-11-09 03:19:33 +01001648 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001649 matchLength = ml2, offset = 0, start = ip;
1650 }
1651 {
1652 size_t offset2=999999;
1653 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet628065c2015-11-06 18:44:54 +01001654 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1655 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001656 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001657 matchLength = ml2, offset = offset2, start = ip;
1658 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001659 } } }
Yann Collet5106a762015-11-05 15:00:24 +01001660 break; /* nothing found : store previous solution */
1661 }
1662
Yann Collet768c6bc2016-02-10 14:01:49 +01001663 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001664 if (offset) {
Yann Collete47c4e52015-12-05 09:23:53 +01001665 while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */
Yann Collet4baee502015-11-09 03:19:33 +01001666 { start--; matchLength++; }
Yann Collet743402c2015-11-20 12:03:53 +01001667 offset_2 = offset_1; offset_1 = offset;
Yann Collet4baee502015-11-09 03:19:33 +01001668 }
1669
1670 /* store sequence */
Yann Collet7a231792015-11-21 15:27:35 +01001671_storeSequence:
Yann Collet5106a762015-11-05 15:00:24 +01001672 {
1673 size_t litLength = start - anchor;
Yann Collet5106a762015-11-05 15:00:24 +01001674 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
Yann Collet4baee502015-11-09 03:19:33 +01001675 anchor = ip = start + matchLength;
Yann Collet5106a762015-11-05 15:00:24 +01001676 }
1677
Yann Collet743402c2015-11-20 12:03:53 +01001678 /* check immediate repcode */
1679 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001680 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet743402c2015-11-20 12:03:53 +01001681 /* store sequence */
1682 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
1683 offset = offset_2;
1684 offset_2 = offset_1;
1685 offset_1 = offset;
1686 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength);
1687 ip += matchLength+MINMATCH;
1688 anchor = ip;
1689 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001690 } }
Yann Collet5106a762015-11-05 15:00:24 +01001691
1692 /* Last Literals */
1693 {
1694 size_t lastLLSize = iend - anchor;
1695 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1696 seqStorePtr->lit += lastLLSize;
1697 }
Yann Collet5106a762015-11-05 15:00:24 +01001698}
1699
inikepe2bfe242016-01-31 11:25:48 +01001700#include "zstd_opt.c"
1701
1702static void ZSTD_compressBlock_opt_bt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1703{
1704 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1, 2);
1705}
1706
1707static void ZSTD_compressBlock_opt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1708{
1709 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0, 2);
1710}
1711
Yann Collet59d1f792016-01-23 19:28:41 +01001712static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001713{
Yann Colleta1249dc2016-01-25 04:22:03 +01001714 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001715}
1716
Yann Collet59d1f792016-01-23 19:28:41 +01001717static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001718{
Yann Colleta1249dc2016-01-25 04:22:03 +01001719 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001720}
1721
Yann Collet59d1f792016-01-23 19:28:41 +01001722static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001723{
Yann Colleta1249dc2016-01-25 04:22:03 +01001724 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001725}
1726
Yann Collet59d1f792016-01-23 19:28:41 +01001727static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01001728{
Yann Colleta1249dc2016-01-25 04:22:03 +01001729 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
Yann Colletbe2010e2015-10-31 12:57:14 +01001730}
1731
1732
Yann Collet9a24e592015-11-22 02:53:43 +01001733FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001734void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1735 const void* src, size_t srcSize,
Yann Collet9a24e592015-11-22 02:53:43 +01001736 const U32 searchMethod, const U32 depth)
1737{
1738 seqStore_t* seqStorePtr = &(ctx->seqStore);
1739 const BYTE* const istart = (const BYTE*)src;
1740 const BYTE* ip = istart;
1741 const BYTE* anchor = istart;
1742 const BYTE* const iend = istart + srcSize;
1743 const BYTE* const ilimit = iend - 8;
1744 const BYTE* const base = ctx->base;
1745 const U32 dictLimit = ctx->dictLimit;
1746 const BYTE* const prefixStart = base + dictLimit;
1747 const BYTE* const dictBase = ctx->dictBase;
1748 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001749 const BYTE* const dictStart = dictBase + ctx->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001750
1751 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1752 const U32 maxSearches = 1 << ctx->params.searchLog;
1753 const U32 mls = ctx->params.searchLength;
1754
1755 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1756 size_t* offsetPtr,
1757 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet03526e12015-11-23 15:29:15 +01001758 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
Yann Collet9a24e592015-11-22 02:53:43 +01001759
1760 /* init */
1761 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet6c3e2e72015-12-11 10:44:07 +01001762 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Collet9a24e592015-11-22 02:53:43 +01001763
1764 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001765 while (ip < ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001766 size_t matchLength=0;
1767 size_t offset=0;
1768 const BYTE* start=ip+1;
1769 U32 current = (U32)(ip-base);
1770
1771 /* check repCode */
1772 {
1773 const U32 repIndex = (U32)(current+1 - offset_1);
1774 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1775 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001776 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001777 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001778 /* repcode detected we should take it */
1779 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001780 matchLength = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
Yann Collet9a24e592015-11-22 02:53:43 +01001781 if (depth==0) goto _storeSequence;
Yann Colletfb810d62016-01-28 00:18:06 +01001782 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001783
1784 {
Yann Collet239cc282015-11-23 16:17:21 +01001785 /* first search (depth 0) */
1786 size_t offsetFound = 99999999;
1787 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1788 if (ml2 > matchLength)
1789 matchLength = ml2, start = ip, offset=offsetFound;
1790 }
Yann Collet9a24e592015-11-22 02:53:43 +01001791
Yann Colletfb810d62016-01-28 00:18:06 +01001792 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001793 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1794 continue;
1795 }
Yann Collet9a24e592015-11-22 02:53:43 +01001796
1797 /* let's try to find a better solution */
1798 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001799 while (ip<ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001800 ip ++;
1801 current++;
1802 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001803 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001804 const U32 repIndex = (U32)(current - offset_1);
1805 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1806 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001807 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001808 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001809 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001810 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001811 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1812 int gain2 = (int)(repLength * 3);
1813 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1814 if ((repLength >= MINMATCH) && (gain2 > gain1))
1815 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001816 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001817
1818 /* search match, depth 1 */
1819 {
1820 size_t offset2=999999;
1821 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1822 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1823 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001824 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001825 matchLength = ml2, offset = offset2, start = ip;
1826 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001827 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001828
1829 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001830 if ((depth==2) && (ip<ilimit)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001831 ip ++;
1832 current++;
1833 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001834 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001835 const U32 repIndex = (U32)(current - offset_1);
1836 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1837 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001838 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001839 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001840 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001841 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001842 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1843 int gain2 = (int)(repLength * 4);
1844 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1845 if ((repLength >= MINMATCH) && (gain2 > gain1))
1846 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001847 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001848
1849 /* search match, depth 2 */
1850 {
1851 size_t offset2=999999;
1852 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1853 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1854 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001855 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001856 matchLength = ml2, offset = offset2, start = ip;
1857 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001858 } } }
Yann Collet9a24e592015-11-22 02:53:43 +01001859 break; /* nothing found : store previous solution */
1860 }
1861
1862 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001863 if (offset) {
Yann Colletc3652152015-11-24 14:06:07 +01001864 U32 matchIndex = (U32)((start-base) - offset);
1865 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1866 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
1867 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet9a24e592015-11-22 02:53:43 +01001868 offset_2 = offset_1; offset_1 = offset;
1869 }
1870
1871 /* store sequence */
1872_storeSequence:
1873 {
1874 size_t litLength = start - anchor;
1875 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1876 anchor = ip = start + matchLength;
1877 }
1878
1879 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001880 while (ip <= ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001881 const U32 repIndex = (U32)((ip-base) - offset_2);
1882 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1883 const BYTE* const repMatch = repBase + repIndex;
Yann Collet239cc282015-11-23 16:17:21 +01001884 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001885 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001886 /* repcode detected we should take it */
1887 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001888 matchLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1889 offset = offset_2; offset_2 = offset_1; offset_1 = offset; /* swap offset history */
Yann Collet9a24e592015-11-22 02:53:43 +01001890 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1891 ip += matchLength;
1892 anchor = ip;
1893 continue; /* faster when present ... (?) */
1894 }
1895 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001896 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001897
1898 /* Last Literals */
1899 {
1900 size_t lastLLSize = iend - anchor;
1901 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1902 seqStorePtr->lit += lastLLSize;
1903 }
Yann Collet9a24e592015-11-22 02:53:43 +01001904}
1905
Yann Collet59d1f792016-01-23 19:28:41 +01001906void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01001907{
Yann Colleta1249dc2016-01-25 04:22:03 +01001908 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01001909}
1910
Yann Collet59d1f792016-01-23 19:28:41 +01001911static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01001912{
Yann Colleta1249dc2016-01-25 04:22:03 +01001913 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01001914}
Yann Collet9a24e592015-11-22 02:53:43 +01001915
Yann Collet59d1f792016-01-23 19:28:41 +01001916static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01001917{
Yann Colleta1249dc2016-01-25 04:22:03 +01001918 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01001919}
1920
Yann Collet59d1f792016-01-23 19:28:41 +01001921static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01001922{
Yann Colleta1249dc2016-01-25 04:22:03 +01001923 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001924}
1925
inikepe2bfe242016-01-31 11:25:48 +01001926static void ZSTD_compressBlock_opt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1927{
inikepbe77f332016-02-09 23:00:41 +01001928 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0, 2);
inikepe2bfe242016-01-31 11:25:48 +01001929}
1930
1931static void ZSTD_compressBlock_opt_bt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1932{
inikepbe77f332016-02-09 23:00:41 +01001933 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1, 2);
inikepe2bfe242016-01-31 11:25:48 +01001934}
1935
Yann Collet7a231792015-11-21 15:27:35 +01001936
Yann Collet59d1f792016-01-23 19:28:41 +01001937typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01001938
Yann Colletb923f652016-01-26 03:14:20 +01001939static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01001940{
inikepe2bfe242016-01-31 11:25:48 +01001941 static const ZSTD_blockCompressor blockCompressor[2][7] = {
1942 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy,ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_opt, ZSTD_compressBlock_opt_bt },
1943 { 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 +01001944 };
1945
1946 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01001947}
1948
1949
Yann Colletbf42c8e2016-01-09 01:08:23 +01001950static 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 +01001951{
Yann Collet03526e12015-11-23 15:29:15 +01001952 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01001953 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 +01001954 blockCompressor(zc, src, srcSize);
Yann Colletb923f652016-01-26 03:14:20 +01001955 return ZSTD_compressSequences(zc, dst, maxDstSize, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01001956}
1957
1958
Yann Collet2ce49232016-02-02 14:36:49 +01001959static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
Yann Colletf3eca252015-10-22 15:31:46 +01001960 void* dst, size_t maxDstSize,
1961 const void* src, size_t srcSize)
1962{
Yann Collet2ce49232016-02-02 14:36:49 +01001963 size_t blockSize = zc->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001964 size_t remaining = srcSize;
1965 const BYTE* ip = (const BYTE*)src;
1966 BYTE* const ostart = (BYTE*)dst;
1967 BYTE* op = ostart;
Yann Collet2ce49232016-02-02 14:36:49 +01001968 const U32 maxDist = 1 << zc->params.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01001969
Yann Collet2ce49232016-02-02 14:36:49 +01001970 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01001971 size_t cSize;
1972
Yann Collet2ce49232016-02-02 14:36:49 +01001973 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 +01001974 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01001975
Yann Collet2ce49232016-02-02 14:36:49 +01001976 if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */
Yann Collet7a6343f2016-02-02 16:00:50 +01001977 U32 newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist;
1978 if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01001979 if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001980 }
Yann Collet89db5e02015-11-13 11:27:46 +01001981
Yann Collet2ce49232016-02-02 14:36:49 +01001982 cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, maxDstSize-ZSTD_blockHeaderSize, ip, blockSize);
Yann Collet3e358272015-11-04 18:19:39 +01001983 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001984
Yann Collet2ce49232016-02-02 14:36:49 +01001985 if (cSize == 0) { /* block is not compressible */
1986 cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize);
Yann Collet523b5942016-01-09 02:10:40 +01001987 if (ZSTD_isError(cSize)) return cSize;
Yann Collet2ce49232016-02-02 14:36:49 +01001988 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01001989 op[0] = (BYTE)(cSize>>16);
1990 op[1] = (BYTE)(cSize>>8);
1991 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01001992 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01001993 cSize += 3;
1994 }
1995
1996 remaining -= blockSize;
Yann Collet3e358272015-11-04 18:19:39 +01001997 maxDstSize -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001998 ip += blockSize;
1999 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002000 }
2001
2002 return op-ostart;
2003}
2004
2005
Yann Colletbf42c8e2016-01-09 01:08:23 +01002006static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
2007 void* dst, size_t dstSize,
2008 const void* src, size_t srcSize,
2009 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01002010{
Yann Collet2acb5d32015-10-29 16:49:43 +01002011 const BYTE* const ip = (const BYTE*) src;
Yann Colletecd651b2016-01-07 15:35:18 +01002012 size_t hbSize = 0;
2013
Yann Collet2ce49232016-02-02 14:36:49 +01002014 if (frame && (zc->stage==0)) {
Yann Colletecd651b2016-01-07 15:35:18 +01002015 hbSize = zc->hbSize;
2016 if (dstSize <= hbSize) return ERROR(dstSize_tooSmall);
2017 zc->stage = 1;
2018 memcpy(dst, zc->headerBuffer, hbSize);
2019 dstSize -= hbSize;
2020 dst = (char*)dst + hbSize;
2021 }
Yann Colletf3eca252015-10-22 15:31:46 +01002022
Yann Collet417890c2015-12-04 17:16:37 +01002023 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01002024 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002025 /* not contiguous */
2026 size_t delta = zc->nextSrc - ip;
2027 zc->lowLimit = zc->dictLimit;
2028 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2029 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01002030 zc->base -= delta;
2031 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01002032 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002033 }
2034
Yann Collet89db5e02015-11-13 11:27:46 +01002035 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01002036 if (zc->lowLimit > (1<<30)) {
inikepc71568f2016-01-30 12:15:56 +01002037 U32 btplus = (zc->params.strategy == ZSTD_btlazy2) || (zc->params.strategy == ZSTD_opt_bt);
Yann Collet6c3e2e72015-12-11 10:44:07 +01002038 U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1;
2039 U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */
2040 U32 correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002041 ZSTD_reduceIndex(zc, correction);
2042 zc->base += correction;
2043 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002044 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002045 zc->dictLimit -= correction;
2046 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2047 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01002048 }
2049
Yann Colletbf42c8e2016-01-09 01:08:23 +01002050 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01002051 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01002052 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2053 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002054 }
2055
Yann Colletc3652152015-11-24 14:06:07 +01002056 zc->nextSrc = ip + srcSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002057 {
Yann Colletbf42c8e2016-01-09 01:08:23 +01002058 size_t cSize;
2059 if (frame) cSize = ZSTD_compress_generic (zc, dst, dstSize, src, srcSize);
2060 else cSize = ZSTD_compressBlock_internal (zc, dst, dstSize, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002061 if (ZSTD_isError(cSize)) return cSize;
2062 return cSize + hbSize;
2063 }
Yann Colletf3eca252015-10-22 15:31:46 +01002064}
2065
Yann Colletbf42c8e2016-01-09 01:08:23 +01002066
2067size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
2068 void* dst, size_t dstSize,
2069 const void* src, size_t srcSize)
2070{
2071 return ZSTD_compressContinue_internal(zc, dst, dstSize, src, srcSize, 1);
2072}
2073
2074
2075size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
2076{
2077 if (srcSize > BLOCKSIZE) return ERROR(srcSize_wrong);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002078 return ZSTD_compressContinue_internal(zc, dst, maxDstSize, src, srcSize, 0);
2079}
2080
2081
Yann Colletb923f652016-01-26 03:14:20 +01002082static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002083{
2084 const BYTE* const ip = (const BYTE*) src;
2085 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002086
Yann Collet417890c2015-12-04 17:16:37 +01002087 /* input becomes current prefix */
2088 zc->lowLimit = zc->dictLimit;
2089 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2090 zc->dictBase = zc->base;
2091 zc->base += ip - zc->nextSrc;
2092 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002093 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002094
2095 zc->nextSrc = iend;
2096 if (srcSize <= 8) return 0;
2097
2098 switch(zc->params.strategy)
2099 {
2100 case ZSTD_fast:
Yann Collet2ce49232016-02-02 14:36:49 +01002101 ZSTD_fillHashTable (zc, iend, zc->params.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002102 break;
2103
2104 case ZSTD_greedy:
2105 case ZSTD_lazy:
2106 case ZSTD_lazy2:
inikepbe77f332016-02-09 23:00:41 +01002107 case ZSTD_opt:
Yann Collet417890c2015-12-04 17:16:37 +01002108 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength);
2109 break;
2110
2111 case ZSTD_btlazy2:
inikepbe77f332016-02-09 23:00:41 +01002112 case ZSTD_opt_bt:
Yann Collet417890c2015-12-04 17:16:37 +01002113 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength);
2114 break;
2115
2116 default:
2117 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2118 }
2119
Yann Collet2ce49232016-02-02 14:36:49 +01002120 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002121 return 0;
2122}
2123
2124
Yann Colletb923f652016-01-26 03:14:20 +01002125/* Dictionary format :
2126 Magic == ZSTD_DICT_MAGIC (4 bytes)
2127 Huff0 CTable (256 * 4 bytes) => to be changed to read from writeCTable
2128 Dictionary content
2129*/
2130/*! ZSTD_loadDictEntropyStats
2131 @return : size read from dictionary */
2132static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2133{
2134 /* note : magic number already checked */
Yann Colletfb810d62016-01-28 00:18:06 +01002135 size_t offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize, errorCode;
2136 short offcodeNCount[MaxOff+1];
2137 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2138 short matchlengthNCount[MaxML+1];
2139 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2140 short litlengthNCount[MaxLL+1];
2141 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2142
Yann Colletb923f652016-01-26 03:14:20 +01002143 const size_t hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize);
2144 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Colletfb810d62016-01-28 00:18:06 +01002145 zc->flagStaticTables = 1;
2146 dict = (const char*)dict + hufHeaderSize;
2147 dictSize -= hufHeaderSize;
2148
2149 offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
2150 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2151 errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2152 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2153 dict = (const char*)dict + offcodeHeaderSize;
2154 dictSize -= offcodeHeaderSize;
2155
2156 matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
2157 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2158 errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2159 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2160 dict = (const char*)dict + matchlengthHeaderSize;
2161 dictSize -= matchlengthHeaderSize;
2162
2163 litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
2164 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2165 errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2166 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2167
2168 return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
Yann Colletb923f652016-01-26 03:14:20 +01002169}
2170
Yann Colletfb810d62016-01-28 00:18:06 +01002171
Yann Collet1c8e1942016-01-26 16:31:22 +01002172static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002173{
Yann Collet2ce49232016-02-02 14:36:49 +01002174 if (dict && (dictSize>4)) {
Yann Collet7b51a292016-01-26 15:58:49 +01002175 U32 magic = MEM_readLE32(dict);
2176 size_t eSize;
2177 if (magic != ZSTD_DICT_MAGIC)
2178 return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletb923f652016-01-26 03:14:20 +01002179
Yann Collet7b51a292016-01-26 15:58:49 +01002180 eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4, dictSize-4) + 4;
2181 if (ZSTD_isError(eSize)) return eSize;
2182 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
2183 }
Yann Colletecd651b2016-01-07 15:35:18 +01002184 return 0;
2185}
2186
2187
Yann Collet417890c2015-12-04 17:16:37 +01002188/*! ZSTD_compressBegin_advanced
Yann Colletecd651b2016-01-07 15:35:18 +01002189* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002190size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
2191 const void* dict, size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002192 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002193{
Yann Collet4114f952015-10-30 06:40:22 +01002194 size_t errorCode;
Yann Collet88fcd292015-11-25 14:42:45 +01002195
2196 ZSTD_validateParams(&params);
2197
Yann Collet1c8e1942016-01-26 16:31:22 +01002198 errorCode = ZSTD_resetCCtx_advanced(zc, params);
Yann Collet4114f952015-10-30 06:40:22 +01002199 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet89db5e02015-11-13 11:27:46 +01002200
Yann Collet1c8e1942016-01-26 16:31:22 +01002201 MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */
2202 ((BYTE*)zc->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN);
2203 zc->hbSize = ZSTD_frameHeaderSize_min;
2204 zc->stage = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002205
Yann Collet1c8e1942016-01-26 16:31:22 +01002206 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002207}
2208
2209
Yann Collet1c8e1942016-01-26 16:31:22 +01002210size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002211{
Yann Collet953ce722016-02-04 15:28:14 +01002212 return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, MAX(128 KB, dictSize)));
Yann Collet1c8e1942016-01-26 16:31:22 +01002213}
Yann Collet083fcc82015-10-25 14:06:35 +01002214
Yann Collet1c8e1942016-01-26 16:31:22 +01002215size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002216{
Yann Collet1c8e1942016-01-26 16:31:22 +01002217 return ZSTD_compressBegin_advanced(zc, NULL, 0, ZSTD_getParams(compressionLevel, 0));
Yann Collet083fcc82015-10-25 14:06:35 +01002218}
2219
2220
Yann Collet31683c02015-12-18 01:26:48 +01002221/*! ZSTD_compressEnd
Yann Collet88fcd292015-11-25 14:42:45 +01002222* Write frame epilogue
2223* @return : nb of bytes written into dst (or an error code) */
Yann Colletecd651b2016-01-07 15:35:18 +01002224size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize)
Yann Collet2acb5d32015-10-29 16:49:43 +01002225{
2226 BYTE* op = (BYTE*)dst;
Yann Colletecd651b2016-01-07 15:35:18 +01002227 size_t hbSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002228
Yann Colletecd651b2016-01-07 15:35:18 +01002229 /* empty frame */
Yann Colletfb810d62016-01-28 00:18:06 +01002230 if (zc->stage==0) {
Yann Colletecd651b2016-01-07 15:35:18 +01002231 hbSize = zc->hbSize;
2232 if (maxDstSize <= hbSize) return ERROR(dstSize_tooSmall);
2233 zc->stage = 1;
2234 memcpy(dst, zc->headerBuffer, hbSize);
2235 maxDstSize -= hbSize;
2236 op += hbSize;
2237 }
2238
2239 /* frame epilogue */
Yann Collet2acb5d32015-10-29 16:49:43 +01002240 if (maxDstSize < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002241 op[0] = (BYTE)(bt_end << 6);
2242 op[1] = 0;
2243 op[2] = 0;
2244
Yann Colletecd651b2016-01-07 15:35:18 +01002245 return 3+hbSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002246}
2247
Yann Colletfd416f12016-01-30 03:14:15 +01002248
2249size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
2250 void* dst, size_t maxDstSize,
2251 const void* src, size_t srcSize)
2252{
2253 size_t outSize;
2254 size_t errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2255 if (ZSTD_isError(errorCode)) return errorCode;
2256 errorCode = ZSTD_compressContinue(cctx, dst, maxDstSize, src, srcSize);
2257 if (ZSTD_isError(errorCode)) return errorCode;
2258 outSize = errorCode;
2259 errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, maxDstSize-outSize);
2260 if (ZSTD_isError(errorCode)) return errorCode;
2261 outSize += errorCode;
2262 return outSize;
2263}
2264
2265
Yann Collet5be2dd22015-11-11 13:43:58 +01002266size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
Yann Collet88fcd292015-11-25 14:42:45 +01002267 void* dst, size_t maxDstSize,
2268 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002269 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002270 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002271{
2272 BYTE* const ostart = (BYTE*)dst;
2273 BYTE* op = ostart;
Yann Collet4114f952015-10-30 06:40:22 +01002274 size_t oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002275
Yann Collet1c8e1942016-01-26 16:31:22 +01002276 /* Init */
2277 oSize = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params);
Yann Colletf3eca252015-10-22 15:31:46 +01002278 if(ZSTD_isError(oSize)) return oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002279
2280 /* body (compression) */
Yann Collet31683c02015-12-18 01:26:48 +01002281 oSize = ZSTD_compressContinue (ctx, op, maxDstSize, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002282 if(ZSTD_isError(oSize)) return oSize;
2283 op += oSize;
2284 maxDstSize -= oSize;
2285
2286 /* Close frame */
Yann Collet5be2dd22015-11-11 13:43:58 +01002287 oSize = ZSTD_compressEnd(ctx, op, maxDstSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002288 if(ZSTD_isError(oSize)) return oSize;
2289 op += oSize;
2290
2291 return (op - ostart);
2292}
2293
Yann Collet31683c02015-12-18 01:26:48 +01002294size_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)
2295{
Yann Collet2ce49232016-02-02 14:36:49 +01002296 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet31683c02015-12-18 01:26:48 +01002297}
2298
Yann Collet5be2dd22015-11-11 13:43:58 +01002299size_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 +01002300{
Yann Collet31683c02015-12-18 01:26:48 +01002301 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet083fcc82015-10-25 14:06:35 +01002302}
2303
Yann Collet5be2dd22015-11-11 13:43:58 +01002304size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002305{
Yann Collet44fe9912015-10-29 22:02:40 +01002306 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002307 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002308 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Collet5be2dd22015-11-11 13:43:58 +01002309 result = ZSTD_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel);
Yann Colletecd651b2016-01-07 15:35:18 +01002310 free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002311 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002312}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002313
Yann Colletfd416f12016-01-30 03:14:15 +01002314
Yann Collet70e8c382016-02-10 13:37:52 +01002315/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01002316
Yann Collet70e8c382016-02-10 13:37:52 +01002317#define ZSTD_MAX_CLEVEL 25
Yann Collet7d968c72016-02-03 02:11:32 +01002318unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2319
Yann Colletfd416f12016-01-30 03:14:15 +01002320static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = {
2321{ /* "default" */
inikepf2fee4c2016-02-05 19:45:25 +01002322 /* SL, W, C, H, S, L, strat */
2323 { 0, 0, 18, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */
2324 { 0, 0, 19, 13, 14, 1, 7, ZSTD_fast }, /* level 1 */
2325 { 0, 0, 19, 15, 16, 1, 6, ZSTD_fast }, /* level 2 */
2326 { 0, 0, 20, 18, 20, 1, 6, ZSTD_fast }, /* level 3 */
2327 { 0, 0, 21, 19, 21, 1, 6, ZSTD_fast }, /* level 4 */
2328 { 0, 0, 20, 14, 18, 3, 5, ZSTD_greedy }, /* level 5 */
2329 { 0, 0, 20, 18, 19, 3, 5, ZSTD_greedy }, /* level 6 */
2330 { 0, 0, 21, 17, 20, 3, 5, ZSTD_lazy }, /* level 7 */
2331 { 0, 0, 21, 19, 20, 3, 5, ZSTD_lazy }, /* level 8 */
2332 { 0, 0, 21, 20, 20, 3, 5, ZSTD_lazy2 }, /* level 9 */
2333 { 0, 0, 21, 19, 21, 4, 5, ZSTD_lazy2 }, /* level 10 */
2334 { 0, 0, 22, 20, 22, 4, 5, ZSTD_lazy2 }, /* level 11 */ // 42498419
2335 { 0, 0, 22, 20, 22, 5, 5, ZSTD_lazy2 }, /* level 12 */
2336 { 0, 0, 22, 21, 22, 5, 5, ZSTD_lazy2 }, /* level 13 */
2337 { 0, 0, 22, 22, 23, 5, 5, ZSTD_lazy2 }, /* level 14 */
2338 { 0, 0, 23, 23, 23, 5, 5, ZSTD_lazy2 }, /* level 15 */
2339 { 0, 0, 23, 21, 22, 5, 5, ZSTD_btlazy2 }, /* level 16 */ // 42113689
2340 { 0, 0, 23, 24, 23, 4, 5, ZSTD_btlazy2 }, /* level 17 */
2341 { 0, 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */
2342 { 0, 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */
2343 { 0, 0, 26, 27, 25, 9, 5, ZSTD_btlazy2 }, /* level 20 */
2344 { 0, 0, 22, 20, 22, 4, 4, ZSTD_lazy2 }, /* level 21 = 11 + L=4 */ // 41902762 lazy1=42087013 norep1=42911693
2345 { 0, 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 22 = 16 + L=4 */ // 41233150 btlazy1=41560211 norep1=42322286
2346 { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 23 */
Yann Collet70e8c382016-02-10 13:37:52 +01002347 { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 24 = 16 + btopt */
2348 { 0, 64, 26, 27, 25, 10, 4, ZSTD_opt_bt }, /* level 25 = 20 + btopt */
Yann Colletfd416f12016-01-30 03:14:15 +01002349},
2350{ /* for srcSize <= 256 KB */
inikepf2fee4c2016-02-05 19:45:25 +01002351 /* SL, W, C, H, S, L, strat */
2352 { 0, 0, 18, 13, 14, 1, 7, ZSTD_fast }, /* level 0 - never used */
2353 { 0, 0, 18, 14, 15, 1, 6, ZSTD_fast }, /* level 1 */
2354 { 0, 0, 18, 14, 15, 1, 5, ZSTD_fast }, /* level 2 */
2355 { 0, 0, 18, 12, 15, 3, 4, ZSTD_greedy }, /* level 3 */
2356 { 0, 0, 18, 13, 15, 4, 4, ZSTD_greedy }, /* level 4 */
2357 { 0, 0, 18, 14, 15, 5, 4, ZSTD_greedy }, /* level 5 */
2358 { 0, 0, 18, 13, 15, 4, 4, ZSTD_lazy }, /* level 6 */
2359 { 0, 0, 18, 14, 16, 5, 4, ZSTD_lazy }, /* level 7 */
2360 { 0, 0, 18, 15, 16, 6, 4, ZSTD_lazy }, /* level 8 */
2361 { 0, 0, 18, 15, 15, 7, 4, ZSTD_lazy }, /* level 9 */
2362 { 0, 0, 18, 16, 16, 7, 4, ZSTD_lazy }, /* level 10 */
2363 { 0, 0, 18, 16, 16, 8, 4, ZSTD_lazy }, /* level 11 */
2364 { 0, 0, 18, 17, 16, 8, 4, ZSTD_lazy }, /* level 12 */
2365 { 0, 0, 18, 17, 16, 9, 4, ZSTD_lazy }, /* level 13 */
2366 { 0, 0, 18, 18, 16, 9, 4, ZSTD_lazy }, /* level 14 */
2367 { 0, 0, 18, 17, 17, 9, 4, ZSTD_lazy2 }, /* level 15 */
2368 { 0, 0, 18, 18, 18, 9, 4, ZSTD_lazy2 }, /* level 16 */
2369 { 0, 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level 17 */
2370 { 0, 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level 18 */
2371 { 0, 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level 19 */
2372 { 0, 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level 20 */
2373 { 0, 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level ??? */
2374 { 0, 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level ??? */
2375 { 0, 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level ??? */
2376 { 0, 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level ??? */
Yann Colletfd416f12016-01-30 03:14:15 +01002377},
2378{ /* for srcSize <= 128 KB */
2379 /* W, C, H, S, L, strat */
inikepf2fee4c2016-02-05 19:45:25 +01002380 { 0, 0, 17, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */
2381 { 0, 0, 17, 12, 13, 1, 6, ZSTD_fast }, /* level 1 */
2382 { 0, 0, 17, 14, 16, 1, 5, ZSTD_fast }, /* level 2 */
2383 { 0, 0, 17, 15, 17, 1, 5, ZSTD_fast }, /* level 3 */
2384 { 0, 0, 17, 13, 15, 2, 4, ZSTD_greedy }, /* level 4 */
2385 { 0, 0, 17, 15, 17, 3, 4, ZSTD_greedy }, /* level 5 */
2386 { 0, 0, 17, 14, 17, 3, 4, ZSTD_lazy }, /* level 6 */
2387 { 0, 0, 17, 16, 17, 4, 4, ZSTD_lazy }, /* level 7 */
2388 { 0, 0, 17, 16, 17, 4, 4, ZSTD_lazy2 }, /* level 8 */
2389 { 0, 0, 17, 17, 16, 5, 4, ZSTD_lazy2 }, /* level 9 */
2390 { 0, 0, 17, 17, 16, 6, 4, ZSTD_lazy2 }, /* level 10 */
2391 { 0, 0, 17, 17, 16, 7, 4, ZSTD_lazy2 }, /* level 11 */
2392 { 0, 0, 17, 17, 16, 8, 4, ZSTD_lazy2 }, /* level 12 */
2393 { 0, 0, 17, 18, 16, 4, 4, ZSTD_btlazy2 }, /* level 13 */
2394 { 0, 0, 17, 18, 16, 5, 4, ZSTD_btlazy2 }, /* level 14 */
2395 { 0, 0, 17, 18, 16, 6, 4, ZSTD_btlazy2 }, /* level 15 */
2396 { 0, 0, 17, 18, 16, 7, 4, ZSTD_btlazy2 }, /* level 16 */
2397 { 0, 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level 17 */
2398 { 0, 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level 18 */
2399 { 0, 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level 19 */
2400 { 0, 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level 20 */
2401 { 0, 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level ??? */
2402 { 0, 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level ??? */
2403 { 0, 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level ??? */
2404 { 0, 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level ??? */
Yann Colletfd416f12016-01-30 03:14:15 +01002405},
2406{ /* for srcSize <= 16 KB */
2407 /* W, C, H, S, L, strat */
inikepf2fee4c2016-02-05 19:45:25 +01002408 { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2409 { 0, 0, 14, 14, 14, 1, 4, ZSTD_fast }, /* level 1 */
2410 { 0, 0, 14, 14, 16, 1, 4, ZSTD_fast }, /* level 2 */
2411 { 0, 0, 14, 14, 14, 5, 4, ZSTD_greedy }, /* level 3 */
2412 { 0, 0, 14, 14, 14, 8, 4, ZSTD_greedy }, /* level 4 */
2413 { 0, 0, 14, 11, 14, 6, 4, ZSTD_lazy }, /* level 5 */
2414 { 0, 0, 14, 14, 13, 6, 5, ZSTD_lazy }, /* level 6 */
2415 { 0, 0, 14, 14, 14, 7, 6, ZSTD_lazy }, /* level 7 */
2416 { 0, 0, 14, 14, 14, 8, 4, ZSTD_lazy }, /* level 8 */
2417 { 0, 0, 14, 14, 15, 9, 4, ZSTD_lazy }, /* level 9 */
2418 { 0, 0, 14, 14, 15, 10, 4, ZSTD_lazy }, /* level 10 */
2419 { 0, 0, 14, 15, 15, 6, 4, ZSTD_btlazy2 }, /* level 11 */
2420 { 0, 0, 14, 15, 15, 7, 4, ZSTD_btlazy2 }, /* level 12 */
2421 { 0, 0, 14, 15, 15, 8, 4, ZSTD_btlazy2 }, /* level 13 */
2422 { 0, 0, 14, 15, 15, 9, 4, ZSTD_btlazy2 }, /* level 14 */
2423 { 0, 0, 14, 15, 15, 10, 4, ZSTD_btlazy2 }, /* level 15 */
2424 { 0, 0, 14, 15, 15, 11, 4, ZSTD_btlazy2 }, /* level 16 */
2425 { 0, 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level 17 */
2426 { 0, 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level 18 */
2427 { 0, 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level 19 */
2428 { 0, 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level 20 */
2429 { 0, 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level ??? */
2430 { 0, 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level ??? */
2431 { 0, 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level ??? */
2432 { 0, 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level ??? */
Yann Colletfd416f12016-01-30 03:14:15 +01002433},
2434};
2435
2436/*! ZSTD_getParams
2437* @return ZSTD_parameters structure for a selected compression level and srcSize.
2438* @srcSizeHint value is optional, select 0 if not known */
2439ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint)
2440{
2441 ZSTD_parameters result;
2442 int tableID = ((srcSizeHint-1) <= 256 KB) + ((srcSizeHint-1) <= 128 KB) + ((srcSizeHint-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
2443 if (compressionLevel<=0) compressionLevel = 1;
2444 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
inikep3379c5d2016-02-05 09:21:20 +01002445#if ZSTD_OPT_DEBUG >= 1
2446 tableID=0;
2447#endif
Yann Colletfd416f12016-01-30 03:14:15 +01002448 result = ZSTD_defaultParameters[tableID][compressionLevel];
2449 result.srcSize = srcSizeHint;
2450 return result;
2451}
2452