blob: 7f8385b376563f8c88a1dce64202cada8f9cc8c1 [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];
1373 }
1374 }
1375
1376 *smallerPtr = *largerPtr = 0;
1377
Yann Collet72e84cf2015-12-31 19:08:44 +01001378 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
Yann Collet03526e12015-11-23 15:29:15 +01001379 return bestLength;
1380}
1381
Yann Collet2cc12cb2016-01-01 07:47:58 +01001382
1383/** Tree updater, providing best match */
1384FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1385size_t ZSTD_BtFindBestMatch (
1386 ZSTD_CCtx* zc,
1387 const BYTE* const ip, const BYTE* const iLimit,
1388 size_t* offsetPtr,
1389 const U32 maxNbAttempts, const U32 mls)
1390{
1391 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1392 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
1393 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1394}
1395
1396
1397FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS (
1398 ZSTD_CCtx* zc, /* Index table will be updated */
1399 const BYTE* ip, const BYTE* const iLimit,
1400 size_t* offsetPtr,
1401 const U32 maxNbAttempts, const U32 matchLengthSearch)
1402{
1403 switch(matchLengthSearch)
1404 {
1405 default :
1406 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1407 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1408 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1409 }
1410}
1411
1412
1413static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1414{
1415 const BYTE* const base = zc->base;
1416 const U32 target = (U32)(ip - base);
1417 U32 idx = zc->nextToUpdate;
1418
1419 for( ; idx < target ; )
1420 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1421}
1422
1423
Yann Collet03526e12015-11-23 15:29:15 +01001424/** Tree updater, providing best match */
1425FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1426size_t ZSTD_BtFindBestMatch_extDict (
1427 ZSTD_CCtx* zc,
1428 const BYTE* const ip, const BYTE* const iLimit,
1429 size_t* offsetPtr,
1430 const U32 maxNbAttempts, const U32 mls)
1431{
Yann Colletee3f4512015-12-29 22:26:09 +01001432 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1433 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001434 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001435}
1436
1437
1438FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
1439 ZSTD_CCtx* zc, /* Index table will be updated */
1440 const BYTE* ip, const BYTE* const iLimit,
1441 size_t* offsetPtr,
1442 const U32 maxNbAttempts, const U32 matchLengthSearch)
1443{
1444 switch(matchLengthSearch)
1445 {
1446 default :
1447 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1448 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1449 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1450 }
1451}
1452
1453
Yann Collet5106a762015-11-05 15:00:24 +01001454/* ***********************
1455* Hash Chain
1456*************************/
1457
Yann Collet1f44b3f2015-11-05 17:32:18 +01001458#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1459
Yann Collet6bcdeac2015-11-26 11:43:00 +01001460/* Update chains up to ip (excluded)
Yann Collet06eade52015-11-23 14:23:47 +01001461 Assumption : always within prefix (ie. not within extDict) */
1462static U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
Yann Collet5106a762015-11-05 15:00:24 +01001463{
1464 U32* const hashTable = zc->hashTable;
1465 const U32 hashLog = zc->params.hashLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001466 U32* const chainTable = zc->contentTable;
1467 const U32 chainMask = (1 << zc->params.contentLog) - 1;
Yann Collet5106a762015-11-05 15:00:24 +01001468 const BYTE* const base = zc->base;
1469 const U32 target = (U32)(ip - base);
1470 U32 idx = zc->nextToUpdate;
1471
Yann Colletfb810d62016-01-28 00:18:06 +01001472 while(idx < target) {
Yann Collet5be2dd22015-11-11 13:43:58 +01001473 size_t h = ZSTD_hashPtr(base+idx, hashLog, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001474 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1475 hashTable[h] = idx;
1476 idx++;
1477 }
1478
1479 zc->nextToUpdate = target;
Yann Collet5be2dd22015-11-11 13:43:58 +01001480 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
Yann Collet5106a762015-11-05 15:00:24 +01001481}
1482
1483
1484FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Colletc1e52f02015-11-23 14:37:59 +01001485size_t ZSTD_HcFindBestMatch_generic (
Yann Collet5be2dd22015-11-11 13:43:58 +01001486 ZSTD_CCtx* zc, /* Index table will be updated */
Yann Collet5106a762015-11-05 15:00:24 +01001487 const BYTE* const ip, const BYTE* const iLimit,
1488 size_t* offsetPtr,
Yann Colletc1e52f02015-11-23 14:37:59 +01001489 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
Yann Collet287b7d92015-11-22 13:24:05 +01001490{
Yann Collet1f44b3f2015-11-05 17:32:18 +01001491 U32* const chainTable = zc->contentTable;
1492 const U32 chainSize = (1 << zc->params.contentLog);
Yann Collet5106a762015-11-05 15:00:24 +01001493 const U32 chainMask = chainSize-1;
1494 const BYTE* const base = zc->base;
1495 const BYTE* const dictBase = zc->dictBase;
1496 const U32 dictLimit = zc->dictLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001497 const BYTE* const prefixStart = base + dictLimit;
1498 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001499 const U32 lowLimit = zc->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001500 const U32 current = (U32)(ip-base);
1501 const U32 minChain = current > chainSize ? current - chainSize : 0;
Yann Collet5106a762015-11-05 15:00:24 +01001502 U32 matchIndex;
1503 const BYTE* match;
1504 int nbAttempts=maxNbAttempts;
Yann Collet5054ee02015-11-23 13:34:21 +01001505 size_t ml=MINMATCH-1;
Yann Collet5106a762015-11-05 15:00:24 +01001506
1507 /* HC4 match finder */
Yann Colletc1e52f02015-11-23 14:37:59 +01001508 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001509
Yann Colletfb810d62016-01-28 00:18:06 +01001510 while ((matchIndex>lowLimit) && (nbAttempts)) {
Yann Collet5054ee02015-11-23 13:34:21 +01001511 size_t currentMl=0;
Yann Collet5106a762015-11-05 15:00:24 +01001512 nbAttempts--;
Yann Colletfb810d62016-01-28 00:18:06 +01001513 if ((!extDict) || matchIndex >= dictLimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001514 match = base + matchIndex;
Yann Collet4baee502015-11-09 03:19:33 +01001515 if (match[ml] == ip[ml]) /* potentially better */
Yann Collet5054ee02015-11-23 13:34:21 +01001516 currentMl = ZSTD_count(ip, match, iLimit);
Yann Colletfb810d62016-01-28 00:18:06 +01001517 } else {
Yann Collet5106a762015-11-05 15:00:24 +01001518 match = dictBase + matchIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001519 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1520 currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
Yann Collet5106a762015-11-05 15:00:24 +01001521 }
1522
Yann Collet5054ee02015-11-23 13:34:21 +01001523 /* save best solution */
Yann Collet239cc282015-11-23 16:17:21 +01001524 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 +01001525
Yann Collet9a24e592015-11-22 02:53:43 +01001526 if (matchIndex <= minChain) break;
Yann Collet5106a762015-11-05 15:00:24 +01001527 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1528 }
1529
1530 return ml;
1531}
1532
1533
Yann Colletc1e52f02015-11-23 14:37:59 +01001534FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1535 ZSTD_CCtx* zc,
Yann Collet5106a762015-11-05 15:00:24 +01001536 const BYTE* ip, const BYTE* const iLimit,
1537 size_t* offsetPtr,
1538 const U32 maxNbAttempts, const U32 matchLengthSearch)
1539{
1540 switch(matchLengthSearch)
1541 {
1542 default :
Yann Colletc1e52f02015-11-23 14:37:59 +01001543 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1544 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1545 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1546 }
1547}
1548
1549
1550FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1551 ZSTD_CCtx* zc,
1552 const BYTE* ip, const BYTE* const iLimit,
1553 size_t* offsetPtr,
1554 const U32 maxNbAttempts, const U32 matchLengthSearch)
1555{
1556 switch(matchLengthSearch)
1557 {
1558 default :
1559 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1560 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1561 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001562 }
1563}
1564
1565
Yann Collet287b7d92015-11-22 13:24:05 +01001566/* *******************************
Yann Collet9a24e592015-11-22 02:53:43 +01001567* Common parser - lazy strategy
Yann Collet287b7d92015-11-22 13:24:05 +01001568*********************************/
Yann Collet5106a762015-11-05 15:00:24 +01001569FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001570void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1571 const void* src, size_t srcSize,
Yann Collet007c1c62015-11-22 02:42:28 +01001572 const U32 searchMethod, const U32 depth)
Yann Collet5106a762015-11-05 15:00:24 +01001573{
1574 seqStore_t* seqStorePtr = &(ctx->seqStore);
1575 const BYTE* const istart = (const BYTE*)src;
1576 const BYTE* ip = istart;
1577 const BYTE* anchor = istart;
1578 const BYTE* const iend = istart + srcSize;
1579 const BYTE* const ilimit = iend - 8;
Yann Collete47c4e52015-12-05 09:23:53 +01001580 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet5106a762015-11-05 15:00:24 +01001581
1582 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1583 const U32 maxSearches = 1 << ctx->params.searchLog;
1584 const U32 mls = ctx->params.searchLength;
1585
Yann Collet5be2dd22015-11-11 13:43:58 +01001586 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
Yann Collet5106a762015-11-05 15:00:24 +01001587 size_t* offsetPtr,
1588 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet5be2dd22015-11-11 13:43:58 +01001589 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet5106a762015-11-05 15:00:24 +01001590
1591 /* init */
1592 ZSTD_resetSeqStore(seqStorePtr);
Yann Collete47c4e52015-12-05 09:23:53 +01001593 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet5106a762015-11-05 15:00:24 +01001594
1595 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001596 while (ip < ilimit) {
Yann Collet7a231792015-11-21 15:27:35 +01001597 size_t matchLength=0;
1598 size_t offset=0;
1599 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001600
Yann Collet743402c2015-11-20 12:03:53 +01001601 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001602 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1)) {
Yann Collet743402c2015-11-20 12:03:53 +01001603 /* repcode : we take it */
Yann Collet7a231792015-11-21 15:27:35 +01001604 matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH;
Yann Collet007c1c62015-11-22 02:42:28 +01001605 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001606 }
1607
Yann Colletfc2afcf2015-11-06 15:40:14 +01001608 {
Yann Collet239cc282015-11-23 16:17:21 +01001609 /* first search (depth 0) */
1610 size_t offsetFound = 99999999;
1611 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1612 if (ml2 > matchLength)
1613 matchLength = ml2, start = ip, offset=offsetFound;
1614 }
Yann Collet9a24e592015-11-22 02:53:43 +01001615
Yann Colletfb810d62016-01-28 00:18:06 +01001616 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001617 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1618 continue;
1619 }
Yann Collet5106a762015-11-05 15:00:24 +01001620
1621 /* let's try to find a better solution */
Yann Collet007c1c62015-11-22 02:42:28 +01001622 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001623 while (ip<ilimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001624 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001625 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet007c1c62015-11-22 02:42:28 +01001626 size_t mlRep = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1627 int gain2 = (int)(mlRep * 3);
Yann Collet5106a762015-11-05 15:00:24 +01001628 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet007c1c62015-11-22 02:42:28 +01001629 if ((mlRep >= MINMATCH) && (gain2 > gain1))
1630 matchLength = mlRep, offset = 0, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001631 }
1632 {
1633 size_t offset2=999999;
1634 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet007c1c62015-11-22 02:42:28 +01001635 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1636 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001637 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001638 matchLength = ml2, offset = offset2, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001639 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001640 } }
Yann Collet5106a762015-11-05 15:00:24 +01001641
1642 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001643 if ((depth==2) && (ip<ilimit)) {
Yann Collet5106a762015-11-05 15:00:24 +01001644 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001645 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet5106a762015-11-05 15:00:24 +01001646 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1647 int gain2 = (int)(ml2 * 4);
1648 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet4baee502015-11-09 03:19:33 +01001649 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001650 matchLength = ml2, offset = 0, start = ip;
1651 }
1652 {
1653 size_t offset2=999999;
1654 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet628065c2015-11-06 18:44:54 +01001655 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1656 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001657 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001658 matchLength = ml2, offset = offset2, start = ip;
1659 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001660 } } }
Yann Collet5106a762015-11-05 15:00:24 +01001661 break; /* nothing found : store previous solution */
1662 }
1663
Yann Collet4baee502015-11-09 03:19:33 +01001664 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001665 if (offset) {
Yann Collete47c4e52015-12-05 09:23:53 +01001666 while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */
Yann Collet4baee502015-11-09 03:19:33 +01001667 { start--; matchLength++; }
Yann Collet743402c2015-11-20 12:03:53 +01001668 offset_2 = offset_1; offset_1 = offset;
Yann Collet4baee502015-11-09 03:19:33 +01001669 }
1670
1671 /* store sequence */
Yann Collet7a231792015-11-21 15:27:35 +01001672_storeSequence:
Yann Collet5106a762015-11-05 15:00:24 +01001673 {
1674 size_t litLength = start - anchor;
Yann Collet5106a762015-11-05 15:00:24 +01001675 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
Yann Collet4baee502015-11-09 03:19:33 +01001676 anchor = ip = start + matchLength;
Yann Collet5106a762015-11-05 15:00:24 +01001677 }
1678
Yann Collet743402c2015-11-20 12:03:53 +01001679 /* check immediate repcode */
1680 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001681 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet743402c2015-11-20 12:03:53 +01001682 /* store sequence */
1683 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
1684 offset = offset_2;
1685 offset_2 = offset_1;
1686 offset_1 = offset;
1687 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength);
1688 ip += matchLength+MINMATCH;
1689 anchor = ip;
1690 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001691 } }
Yann Collet5106a762015-11-05 15:00:24 +01001692
1693 /* Last Literals */
1694 {
1695 size_t lastLLSize = iend - anchor;
1696 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1697 seqStorePtr->lit += lastLLSize;
1698 }
Yann Collet5106a762015-11-05 15:00:24 +01001699}
1700
inikepe2bfe242016-01-31 11:25:48 +01001701#include "zstd_opt.c"
1702
1703static void ZSTD_compressBlock_opt_bt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1704{
1705 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1, 2);
1706}
1707
1708static void ZSTD_compressBlock_opt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1709{
1710 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0, 2);
1711}
1712
Yann Collet59d1f792016-01-23 19:28:41 +01001713static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001714{
Yann Colleta1249dc2016-01-25 04:22:03 +01001715 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001716}
1717
Yann Collet59d1f792016-01-23 19:28:41 +01001718static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001719{
Yann Colleta1249dc2016-01-25 04:22:03 +01001720 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001721}
1722
Yann Collet59d1f792016-01-23 19:28:41 +01001723static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001724{
Yann Colleta1249dc2016-01-25 04:22:03 +01001725 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001726}
1727
Yann Collet59d1f792016-01-23 19:28:41 +01001728static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01001729{
Yann Colleta1249dc2016-01-25 04:22:03 +01001730 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
Yann Colletbe2010e2015-10-31 12:57:14 +01001731}
1732
1733
Yann Collet9a24e592015-11-22 02:53:43 +01001734FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001735void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1736 const void* src, size_t srcSize,
Yann Collet9a24e592015-11-22 02:53:43 +01001737 const U32 searchMethod, const U32 depth)
1738{
1739 seqStore_t* seqStorePtr = &(ctx->seqStore);
1740 const BYTE* const istart = (const BYTE*)src;
1741 const BYTE* ip = istart;
1742 const BYTE* anchor = istart;
1743 const BYTE* const iend = istart + srcSize;
1744 const BYTE* const ilimit = iend - 8;
1745 const BYTE* const base = ctx->base;
1746 const U32 dictLimit = ctx->dictLimit;
1747 const BYTE* const prefixStart = base + dictLimit;
1748 const BYTE* const dictBase = ctx->dictBase;
1749 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001750 const BYTE* const dictStart = dictBase + ctx->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001751
1752 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1753 const U32 maxSearches = 1 << ctx->params.searchLog;
1754 const U32 mls = ctx->params.searchLength;
1755
1756 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1757 size_t* offsetPtr,
1758 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet03526e12015-11-23 15:29:15 +01001759 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
Yann Collet9a24e592015-11-22 02:53:43 +01001760
1761 /* init */
1762 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet6c3e2e72015-12-11 10:44:07 +01001763 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Collet9a24e592015-11-22 02:53:43 +01001764
1765 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001766 while (ip < ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001767 size_t matchLength=0;
1768 size_t offset=0;
1769 const BYTE* start=ip+1;
1770 U32 current = (U32)(ip-base);
1771
1772 /* check repCode */
1773 {
1774 const U32 repIndex = (U32)(current+1 - offset_1);
1775 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1776 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001777 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001778 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001779 /* repcode detected we should take it */
1780 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001781 matchLength = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
Yann Collet9a24e592015-11-22 02:53:43 +01001782 if (depth==0) goto _storeSequence;
Yann Colletfb810d62016-01-28 00:18:06 +01001783 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001784
1785 {
Yann Collet239cc282015-11-23 16:17:21 +01001786 /* first search (depth 0) */
1787 size_t offsetFound = 99999999;
1788 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1789 if (ml2 > matchLength)
1790 matchLength = ml2, start = ip, offset=offsetFound;
1791 }
Yann Collet9a24e592015-11-22 02:53:43 +01001792
Yann Colletfb810d62016-01-28 00:18:06 +01001793 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001794 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1795 continue;
1796 }
Yann Collet9a24e592015-11-22 02:53:43 +01001797
1798 /* let's try to find a better solution */
1799 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001800 while (ip<ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001801 ip ++;
1802 current++;
1803 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001804 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001805 const U32 repIndex = (U32)(current - offset_1);
1806 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1807 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001808 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001809 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001810 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001811 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001812 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1813 int gain2 = (int)(repLength * 3);
1814 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1815 if ((repLength >= MINMATCH) && (gain2 > gain1))
1816 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001817 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001818
1819 /* search match, depth 1 */
1820 {
1821 size_t offset2=999999;
1822 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1823 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1824 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001825 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001826 matchLength = ml2, offset = offset2, start = ip;
1827 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001828 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001829
1830 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001831 if ((depth==2) && (ip<ilimit)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001832 ip ++;
1833 current++;
1834 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001835 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001836 const U32 repIndex = (U32)(current - offset_1);
1837 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1838 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001839 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001840 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001841 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001842 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001843 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1844 int gain2 = (int)(repLength * 4);
1845 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1846 if ((repLength >= MINMATCH) && (gain2 > gain1))
1847 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001848 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001849
1850 /* search match, depth 2 */
1851 {
1852 size_t offset2=999999;
1853 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1854 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1855 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001856 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001857 matchLength = ml2, offset = offset2, start = ip;
1858 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001859 } } }
Yann Collet9a24e592015-11-22 02:53:43 +01001860 break; /* nothing found : store previous solution */
1861 }
1862
1863 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001864 if (offset) {
Yann Colletc3652152015-11-24 14:06:07 +01001865 U32 matchIndex = (U32)((start-base) - offset);
1866 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1867 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
1868 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet9a24e592015-11-22 02:53:43 +01001869 offset_2 = offset_1; offset_1 = offset;
1870 }
1871
1872 /* store sequence */
1873_storeSequence:
1874 {
1875 size_t litLength = start - anchor;
1876 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1877 anchor = ip = start + matchLength;
1878 }
1879
1880 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001881 while (ip <= ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001882 const U32 repIndex = (U32)((ip-base) - offset_2);
1883 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1884 const BYTE* const repMatch = repBase + repIndex;
Yann Collet239cc282015-11-23 16:17:21 +01001885 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001886 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001887 /* repcode detected we should take it */
1888 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001889 matchLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1890 offset = offset_2; offset_2 = offset_1; offset_1 = offset; /* swap offset history */
Yann Collet9a24e592015-11-22 02:53:43 +01001891 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1892 ip += matchLength;
1893 anchor = ip;
1894 continue; /* faster when present ... (?) */
1895 }
1896 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001897 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001898
1899 /* Last Literals */
1900 {
1901 size_t lastLLSize = iend - anchor;
1902 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1903 seqStorePtr->lit += lastLLSize;
1904 }
Yann Collet9a24e592015-11-22 02:53:43 +01001905}
1906
Yann Collet59d1f792016-01-23 19:28:41 +01001907void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01001908{
Yann Colleta1249dc2016-01-25 04:22:03 +01001909 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01001910}
1911
Yann Collet59d1f792016-01-23 19:28:41 +01001912static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01001913{
Yann Colleta1249dc2016-01-25 04:22:03 +01001914 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01001915}
Yann Collet9a24e592015-11-22 02:53:43 +01001916
Yann Collet59d1f792016-01-23 19:28:41 +01001917static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01001918{
Yann Colleta1249dc2016-01-25 04:22:03 +01001919 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01001920}
1921
Yann Collet59d1f792016-01-23 19:28:41 +01001922static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01001923{
Yann Colleta1249dc2016-01-25 04:22:03 +01001924 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001925}
1926
inikepe2bfe242016-01-31 11:25:48 +01001927static void ZSTD_compressBlock_opt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1928{
inikepbe77f332016-02-09 23:00:41 +01001929 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0, 2);
inikepe2bfe242016-01-31 11:25:48 +01001930}
1931
1932static void ZSTD_compressBlock_opt_bt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1933{
inikepbe77f332016-02-09 23:00:41 +01001934 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1, 2);
inikepe2bfe242016-01-31 11:25:48 +01001935}
1936
Yann Collet7a231792015-11-21 15:27:35 +01001937
Yann Collet59d1f792016-01-23 19:28:41 +01001938typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01001939
Yann Colletb923f652016-01-26 03:14:20 +01001940static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01001941{
inikepe2bfe242016-01-31 11:25:48 +01001942 static const ZSTD_blockCompressor blockCompressor[2][7] = {
1943 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy,ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_opt, ZSTD_compressBlock_opt_bt },
1944 { 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 +01001945 };
1946
1947 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01001948}
1949
1950
Yann Colletbf42c8e2016-01-09 01:08:23 +01001951static 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 +01001952{
Yann Collet03526e12015-11-23 15:29:15 +01001953 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01001954 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 +01001955 blockCompressor(zc, src, srcSize);
Yann Colletb923f652016-01-26 03:14:20 +01001956 return ZSTD_compressSequences(zc, dst, maxDstSize, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01001957}
1958
1959
Yann Collet2ce49232016-02-02 14:36:49 +01001960static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
Yann Colletf3eca252015-10-22 15:31:46 +01001961 void* dst, size_t maxDstSize,
1962 const void* src, size_t srcSize)
1963{
Yann Collet2ce49232016-02-02 14:36:49 +01001964 size_t blockSize = zc->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001965 size_t remaining = srcSize;
1966 const BYTE* ip = (const BYTE*)src;
1967 BYTE* const ostart = (BYTE*)dst;
1968 BYTE* op = ostart;
Yann Collet2ce49232016-02-02 14:36:49 +01001969 const U32 maxDist = 1 << zc->params.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01001970
Yann Collet2ce49232016-02-02 14:36:49 +01001971 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01001972 size_t cSize;
1973
Yann Collet2ce49232016-02-02 14:36:49 +01001974 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 +01001975 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01001976
Yann Collet2ce49232016-02-02 14:36:49 +01001977 if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */
Yann Collet7a6343f2016-02-02 16:00:50 +01001978 U32 newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist;
1979 if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01001980 if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001981 }
Yann Collet89db5e02015-11-13 11:27:46 +01001982
Yann Collet2ce49232016-02-02 14:36:49 +01001983 cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, maxDstSize-ZSTD_blockHeaderSize, ip, blockSize);
Yann Collet3e358272015-11-04 18:19:39 +01001984 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001985
Yann Collet2ce49232016-02-02 14:36:49 +01001986 if (cSize == 0) { /* block is not compressible */
1987 cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize);
Yann Collet523b5942016-01-09 02:10:40 +01001988 if (ZSTD_isError(cSize)) return cSize;
Yann Collet2ce49232016-02-02 14:36:49 +01001989 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01001990 op[0] = (BYTE)(cSize>>16);
1991 op[1] = (BYTE)(cSize>>8);
1992 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01001993 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01001994 cSize += 3;
1995 }
1996
1997 remaining -= blockSize;
Yann Collet3e358272015-11-04 18:19:39 +01001998 maxDstSize -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001999 ip += blockSize;
2000 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002001 }
2002
2003 return op-ostart;
2004}
2005
2006
Yann Colletbf42c8e2016-01-09 01:08:23 +01002007static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
2008 void* dst, size_t dstSize,
2009 const void* src, size_t srcSize,
2010 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01002011{
Yann Collet2acb5d32015-10-29 16:49:43 +01002012 const BYTE* const ip = (const BYTE*) src;
Yann Colletecd651b2016-01-07 15:35:18 +01002013 size_t hbSize = 0;
2014
Yann Collet2ce49232016-02-02 14:36:49 +01002015 if (frame && (zc->stage==0)) {
Yann Colletecd651b2016-01-07 15:35:18 +01002016 hbSize = zc->hbSize;
2017 if (dstSize <= hbSize) return ERROR(dstSize_tooSmall);
2018 zc->stage = 1;
2019 memcpy(dst, zc->headerBuffer, hbSize);
2020 dstSize -= hbSize;
2021 dst = (char*)dst + hbSize;
2022 }
Yann Colletf3eca252015-10-22 15:31:46 +01002023
Yann Collet417890c2015-12-04 17:16:37 +01002024 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01002025 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002026 /* not contiguous */
2027 size_t delta = zc->nextSrc - ip;
2028 zc->lowLimit = zc->dictLimit;
2029 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2030 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01002031 zc->base -= delta;
2032 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01002033 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002034 }
2035
Yann Collet89db5e02015-11-13 11:27:46 +01002036 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01002037 if (zc->lowLimit > (1<<30)) {
inikepc71568f2016-01-30 12:15:56 +01002038 U32 btplus = (zc->params.strategy == ZSTD_btlazy2) || (zc->params.strategy == ZSTD_opt_bt);
Yann Collet6c3e2e72015-12-11 10:44:07 +01002039 U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1;
2040 U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */
2041 U32 correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002042 ZSTD_reduceIndex(zc, correction);
2043 zc->base += correction;
2044 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002045 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002046 zc->dictLimit -= correction;
2047 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2048 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01002049 }
2050
Yann Colletbf42c8e2016-01-09 01:08:23 +01002051 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01002052 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01002053 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2054 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002055 }
2056
Yann Colletc3652152015-11-24 14:06:07 +01002057 zc->nextSrc = ip + srcSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002058 {
Yann Colletbf42c8e2016-01-09 01:08:23 +01002059 size_t cSize;
2060 if (frame) cSize = ZSTD_compress_generic (zc, dst, dstSize, src, srcSize);
2061 else cSize = ZSTD_compressBlock_internal (zc, dst, dstSize, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002062 if (ZSTD_isError(cSize)) return cSize;
2063 return cSize + hbSize;
2064 }
Yann Colletf3eca252015-10-22 15:31:46 +01002065}
2066
Yann Colletbf42c8e2016-01-09 01:08:23 +01002067
2068size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
2069 void* dst, size_t dstSize,
2070 const void* src, size_t srcSize)
2071{
2072 return ZSTD_compressContinue_internal(zc, dst, dstSize, src, srcSize, 1);
2073}
2074
2075
2076size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
2077{
2078 if (srcSize > BLOCKSIZE) return ERROR(srcSize_wrong);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002079 return ZSTD_compressContinue_internal(zc, dst, maxDstSize, src, srcSize, 0);
2080}
2081
2082
Yann Colletb923f652016-01-26 03:14:20 +01002083static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002084{
2085 const BYTE* const ip = (const BYTE*) src;
2086 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002087
Yann Collet417890c2015-12-04 17:16:37 +01002088 /* input becomes current prefix */
2089 zc->lowLimit = zc->dictLimit;
2090 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2091 zc->dictBase = zc->base;
2092 zc->base += ip - zc->nextSrc;
2093 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002094 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002095
2096 zc->nextSrc = iend;
2097 if (srcSize <= 8) return 0;
2098
2099 switch(zc->params.strategy)
2100 {
2101 case ZSTD_fast:
Yann Collet2ce49232016-02-02 14:36:49 +01002102 ZSTD_fillHashTable (zc, iend, zc->params.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002103 break;
2104
2105 case ZSTD_greedy:
2106 case ZSTD_lazy:
2107 case ZSTD_lazy2:
inikepbe77f332016-02-09 23:00:41 +01002108 case ZSTD_opt:
Yann Collet417890c2015-12-04 17:16:37 +01002109 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength);
2110 break;
2111
2112 case ZSTD_btlazy2:
inikepbe77f332016-02-09 23:00:41 +01002113 case ZSTD_opt_bt:
Yann Collet417890c2015-12-04 17:16:37 +01002114 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength);
2115 break;
2116
2117 default:
2118 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2119 }
2120
Yann Collet2ce49232016-02-02 14:36:49 +01002121 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002122 return 0;
2123}
2124
2125
Yann Colletb923f652016-01-26 03:14:20 +01002126/* Dictionary format :
2127 Magic == ZSTD_DICT_MAGIC (4 bytes)
2128 Huff0 CTable (256 * 4 bytes) => to be changed to read from writeCTable
2129 Dictionary content
2130*/
2131/*! ZSTD_loadDictEntropyStats
2132 @return : size read from dictionary */
2133static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2134{
2135 /* note : magic number already checked */
Yann Colletfb810d62016-01-28 00:18:06 +01002136 size_t offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize, errorCode;
2137 short offcodeNCount[MaxOff+1];
2138 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2139 short matchlengthNCount[MaxML+1];
2140 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2141 short litlengthNCount[MaxLL+1];
2142 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2143
Yann Colletb923f652016-01-26 03:14:20 +01002144 const size_t hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize);
2145 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Colletfb810d62016-01-28 00:18:06 +01002146 zc->flagStaticTables = 1;
2147 dict = (const char*)dict + hufHeaderSize;
2148 dictSize -= hufHeaderSize;
2149
2150 offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
2151 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2152 errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2153 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2154 dict = (const char*)dict + offcodeHeaderSize;
2155 dictSize -= offcodeHeaderSize;
2156
2157 matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
2158 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2159 errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2160 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2161 dict = (const char*)dict + matchlengthHeaderSize;
2162 dictSize -= matchlengthHeaderSize;
2163
2164 litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
2165 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2166 errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2167 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2168
2169 return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
Yann Colletb923f652016-01-26 03:14:20 +01002170}
2171
Yann Colletfb810d62016-01-28 00:18:06 +01002172
Yann Collet1c8e1942016-01-26 16:31:22 +01002173static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002174{
Yann Collet2ce49232016-02-02 14:36:49 +01002175 if (dict && (dictSize>4)) {
Yann Collet7b51a292016-01-26 15:58:49 +01002176 U32 magic = MEM_readLE32(dict);
2177 size_t eSize;
2178 if (magic != ZSTD_DICT_MAGIC)
2179 return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletb923f652016-01-26 03:14:20 +01002180
Yann Collet7b51a292016-01-26 15:58:49 +01002181 eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4, dictSize-4) + 4;
2182 if (ZSTD_isError(eSize)) return eSize;
2183 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
2184 }
Yann Colletecd651b2016-01-07 15:35:18 +01002185 return 0;
2186}
2187
2188
Yann Collet417890c2015-12-04 17:16:37 +01002189/*! ZSTD_compressBegin_advanced
Yann Colletecd651b2016-01-07 15:35:18 +01002190* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002191size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
2192 const void* dict, size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002193 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002194{
Yann Collet4114f952015-10-30 06:40:22 +01002195 size_t errorCode;
Yann Collet88fcd292015-11-25 14:42:45 +01002196
2197 ZSTD_validateParams(&params);
2198
Yann Collet1c8e1942016-01-26 16:31:22 +01002199 errorCode = ZSTD_resetCCtx_advanced(zc, params);
Yann Collet4114f952015-10-30 06:40:22 +01002200 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet89db5e02015-11-13 11:27:46 +01002201
Yann Collet1c8e1942016-01-26 16:31:22 +01002202 MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */
2203 ((BYTE*)zc->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN);
2204 zc->hbSize = ZSTD_frameHeaderSize_min;
2205 zc->stage = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002206
Yann Collet1c8e1942016-01-26 16:31:22 +01002207 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002208}
2209
2210
Yann Collet1c8e1942016-01-26 16:31:22 +01002211size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002212{
Yann Collet953ce722016-02-04 15:28:14 +01002213 return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, MAX(128 KB, dictSize)));
Yann Collet1c8e1942016-01-26 16:31:22 +01002214}
Yann Collet083fcc82015-10-25 14:06:35 +01002215
Yann Collet1c8e1942016-01-26 16:31:22 +01002216size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002217{
Yann Collet1c8e1942016-01-26 16:31:22 +01002218 return ZSTD_compressBegin_advanced(zc, NULL, 0, ZSTD_getParams(compressionLevel, 0));
Yann Collet083fcc82015-10-25 14:06:35 +01002219}
2220
2221
Yann Collet31683c02015-12-18 01:26:48 +01002222/*! ZSTD_compressEnd
Yann Collet88fcd292015-11-25 14:42:45 +01002223* Write frame epilogue
2224* @return : nb of bytes written into dst (or an error code) */
Yann Colletecd651b2016-01-07 15:35:18 +01002225size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize)
Yann Collet2acb5d32015-10-29 16:49:43 +01002226{
2227 BYTE* op = (BYTE*)dst;
Yann Colletecd651b2016-01-07 15:35:18 +01002228 size_t hbSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002229
Yann Colletecd651b2016-01-07 15:35:18 +01002230 /* empty frame */
Yann Colletfb810d62016-01-28 00:18:06 +01002231 if (zc->stage==0) {
Yann Colletecd651b2016-01-07 15:35:18 +01002232 hbSize = zc->hbSize;
2233 if (maxDstSize <= hbSize) return ERROR(dstSize_tooSmall);
2234 zc->stage = 1;
2235 memcpy(dst, zc->headerBuffer, hbSize);
2236 maxDstSize -= hbSize;
2237 op += hbSize;
2238 }
2239
2240 /* frame epilogue */
Yann Collet2acb5d32015-10-29 16:49:43 +01002241 if (maxDstSize < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002242 op[0] = (BYTE)(bt_end << 6);
2243 op[1] = 0;
2244 op[2] = 0;
2245
Yann Colletecd651b2016-01-07 15:35:18 +01002246 return 3+hbSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002247}
2248
Yann Colletfd416f12016-01-30 03:14:15 +01002249
2250size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
2251 void* dst, size_t maxDstSize,
2252 const void* src, size_t srcSize)
2253{
2254 size_t outSize;
2255 size_t errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2256 if (ZSTD_isError(errorCode)) return errorCode;
2257 errorCode = ZSTD_compressContinue(cctx, dst, maxDstSize, src, srcSize);
2258 if (ZSTD_isError(errorCode)) return errorCode;
2259 outSize = errorCode;
2260 errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, maxDstSize-outSize);
2261 if (ZSTD_isError(errorCode)) return errorCode;
2262 outSize += errorCode;
2263 return outSize;
2264}
2265
2266
Yann Collet5be2dd22015-11-11 13:43:58 +01002267size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
Yann Collet88fcd292015-11-25 14:42:45 +01002268 void* dst, size_t maxDstSize,
2269 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002270 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002271 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002272{
2273 BYTE* const ostart = (BYTE*)dst;
2274 BYTE* op = ostart;
Yann Collet4114f952015-10-30 06:40:22 +01002275 size_t oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002276
Yann Collet1c8e1942016-01-26 16:31:22 +01002277 /* Init */
2278 oSize = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params);
Yann Colletf3eca252015-10-22 15:31:46 +01002279 if(ZSTD_isError(oSize)) return oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002280
2281 /* body (compression) */
Yann Collet31683c02015-12-18 01:26:48 +01002282 oSize = ZSTD_compressContinue (ctx, op, maxDstSize, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002283 if(ZSTD_isError(oSize)) return oSize;
2284 op += oSize;
2285 maxDstSize -= oSize;
2286
2287 /* Close frame */
Yann Collet5be2dd22015-11-11 13:43:58 +01002288 oSize = ZSTD_compressEnd(ctx, op, maxDstSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002289 if(ZSTD_isError(oSize)) return oSize;
2290 op += oSize;
2291
2292 return (op - ostart);
2293}
2294
Yann Collet31683c02015-12-18 01:26:48 +01002295size_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)
2296{
Yann Collet2ce49232016-02-02 14:36:49 +01002297 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet31683c02015-12-18 01:26:48 +01002298}
2299
Yann Collet5be2dd22015-11-11 13:43:58 +01002300size_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 +01002301{
Yann Collet31683c02015-12-18 01:26:48 +01002302 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet083fcc82015-10-25 14:06:35 +01002303}
2304
Yann Collet5be2dd22015-11-11 13:43:58 +01002305size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002306{
Yann Collet44fe9912015-10-29 22:02:40 +01002307 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002308 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002309 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Collet5be2dd22015-11-11 13:43:58 +01002310 result = ZSTD_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel);
Yann Colletecd651b2016-01-07 15:35:18 +01002311 free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002312 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002313}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002314
Yann Colletfd416f12016-01-30 03:14:15 +01002315
Yann Collet70e8c382016-02-10 13:37:52 +01002316/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01002317
Yann Collet70e8c382016-02-10 13:37:52 +01002318#define ZSTD_MAX_CLEVEL 25
Yann Collet7d968c72016-02-03 02:11:32 +01002319unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2320
Yann Colletfd416f12016-01-30 03:14:15 +01002321static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = {
2322{ /* "default" */
inikepf2fee4c2016-02-05 19:45:25 +01002323 /* SL, W, C, H, S, L, strat */
2324 { 0, 0, 18, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */
2325 { 0, 0, 19, 13, 14, 1, 7, ZSTD_fast }, /* level 1 */
2326 { 0, 0, 19, 15, 16, 1, 6, ZSTD_fast }, /* level 2 */
2327 { 0, 0, 20, 18, 20, 1, 6, ZSTD_fast }, /* level 3 */
2328 { 0, 0, 21, 19, 21, 1, 6, ZSTD_fast }, /* level 4 */
2329 { 0, 0, 20, 14, 18, 3, 5, ZSTD_greedy }, /* level 5 */
2330 { 0, 0, 20, 18, 19, 3, 5, ZSTD_greedy }, /* level 6 */
2331 { 0, 0, 21, 17, 20, 3, 5, ZSTD_lazy }, /* level 7 */
2332 { 0, 0, 21, 19, 20, 3, 5, ZSTD_lazy }, /* level 8 */
2333 { 0, 0, 21, 20, 20, 3, 5, ZSTD_lazy2 }, /* level 9 */
2334 { 0, 0, 21, 19, 21, 4, 5, ZSTD_lazy2 }, /* level 10 */
2335 { 0, 0, 22, 20, 22, 4, 5, ZSTD_lazy2 }, /* level 11 */ // 42498419
2336 { 0, 0, 22, 20, 22, 5, 5, ZSTD_lazy2 }, /* level 12 */
2337 { 0, 0, 22, 21, 22, 5, 5, ZSTD_lazy2 }, /* level 13 */
2338 { 0, 0, 22, 22, 23, 5, 5, ZSTD_lazy2 }, /* level 14 */
2339 { 0, 0, 23, 23, 23, 5, 5, ZSTD_lazy2 }, /* level 15 */
2340 { 0, 0, 23, 21, 22, 5, 5, ZSTD_btlazy2 }, /* level 16 */ // 42113689
2341 { 0, 0, 23, 24, 23, 4, 5, ZSTD_btlazy2 }, /* level 17 */
2342 { 0, 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */
2343 { 0, 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */
2344 { 0, 0, 26, 27, 25, 9, 5, ZSTD_btlazy2 }, /* level 20 */
2345 { 0, 0, 22, 20, 22, 4, 4, ZSTD_lazy2 }, /* level 21 = 11 + L=4 */ // 41902762 lazy1=42087013 norep1=42911693
2346 { 0, 0, 23, 21, 22, 5, 4, ZSTD_btlazy2 }, /* level 22 = 16 + L=4 */ // 41233150 btlazy1=41560211 norep1=42322286
2347 { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt }, /* level 23 */
Yann Collet70e8c382016-02-10 13:37:52 +01002348 { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 24 = 16 + btopt */
2349 { 0, 64, 26, 27, 25, 10, 4, ZSTD_opt_bt }, /* level 25 = 20 + btopt */
Yann Colletfd416f12016-01-30 03:14:15 +01002350},
2351{ /* for srcSize <= 256 KB */
inikepf2fee4c2016-02-05 19:45:25 +01002352 /* SL, W, C, H, S, L, strat */
2353 { 0, 0, 18, 13, 14, 1, 7, ZSTD_fast }, /* level 0 - never used */
2354 { 0, 0, 18, 14, 15, 1, 6, ZSTD_fast }, /* level 1 */
2355 { 0, 0, 18, 14, 15, 1, 5, ZSTD_fast }, /* level 2 */
2356 { 0, 0, 18, 12, 15, 3, 4, ZSTD_greedy }, /* level 3 */
2357 { 0, 0, 18, 13, 15, 4, 4, ZSTD_greedy }, /* level 4 */
2358 { 0, 0, 18, 14, 15, 5, 4, ZSTD_greedy }, /* level 5 */
2359 { 0, 0, 18, 13, 15, 4, 4, ZSTD_lazy }, /* level 6 */
2360 { 0, 0, 18, 14, 16, 5, 4, ZSTD_lazy }, /* level 7 */
2361 { 0, 0, 18, 15, 16, 6, 4, ZSTD_lazy }, /* level 8 */
2362 { 0, 0, 18, 15, 15, 7, 4, ZSTD_lazy }, /* level 9 */
2363 { 0, 0, 18, 16, 16, 7, 4, ZSTD_lazy }, /* level 10 */
2364 { 0, 0, 18, 16, 16, 8, 4, ZSTD_lazy }, /* level 11 */
2365 { 0, 0, 18, 17, 16, 8, 4, ZSTD_lazy }, /* level 12 */
2366 { 0, 0, 18, 17, 16, 9, 4, ZSTD_lazy }, /* level 13 */
2367 { 0, 0, 18, 18, 16, 9, 4, ZSTD_lazy }, /* level 14 */
2368 { 0, 0, 18, 17, 17, 9, 4, ZSTD_lazy2 }, /* level 15 */
2369 { 0, 0, 18, 18, 18, 9, 4, ZSTD_lazy2 }, /* level 16 */
2370 { 0, 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level 17 */
2371 { 0, 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level 18 */
2372 { 0, 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level 19 */
2373 { 0, 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level 20 */
2374 { 0, 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level ??? */
2375 { 0, 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level ??? */
2376 { 0, 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level ??? */
2377 { 0, 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level ??? */
Yann Colletfd416f12016-01-30 03:14:15 +01002378},
2379{ /* for srcSize <= 128 KB */
2380 /* W, C, H, S, L, strat */
inikepf2fee4c2016-02-05 19:45:25 +01002381 { 0, 0, 17, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */
2382 { 0, 0, 17, 12, 13, 1, 6, ZSTD_fast }, /* level 1 */
2383 { 0, 0, 17, 14, 16, 1, 5, ZSTD_fast }, /* level 2 */
2384 { 0, 0, 17, 15, 17, 1, 5, ZSTD_fast }, /* level 3 */
2385 { 0, 0, 17, 13, 15, 2, 4, ZSTD_greedy }, /* level 4 */
2386 { 0, 0, 17, 15, 17, 3, 4, ZSTD_greedy }, /* level 5 */
2387 { 0, 0, 17, 14, 17, 3, 4, ZSTD_lazy }, /* level 6 */
2388 { 0, 0, 17, 16, 17, 4, 4, ZSTD_lazy }, /* level 7 */
2389 { 0, 0, 17, 16, 17, 4, 4, ZSTD_lazy2 }, /* level 8 */
2390 { 0, 0, 17, 17, 16, 5, 4, ZSTD_lazy2 }, /* level 9 */
2391 { 0, 0, 17, 17, 16, 6, 4, ZSTD_lazy2 }, /* level 10 */
2392 { 0, 0, 17, 17, 16, 7, 4, ZSTD_lazy2 }, /* level 11 */
2393 { 0, 0, 17, 17, 16, 8, 4, ZSTD_lazy2 }, /* level 12 */
2394 { 0, 0, 17, 18, 16, 4, 4, ZSTD_btlazy2 }, /* level 13 */
2395 { 0, 0, 17, 18, 16, 5, 4, ZSTD_btlazy2 }, /* level 14 */
2396 { 0, 0, 17, 18, 16, 6, 4, ZSTD_btlazy2 }, /* level 15 */
2397 { 0, 0, 17, 18, 16, 7, 4, ZSTD_btlazy2 }, /* level 16 */
2398 { 0, 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level 17 */
2399 { 0, 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level 18 */
2400 { 0, 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level 19 */
2401 { 0, 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level 20 */
2402 { 0, 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level ??? */
2403 { 0, 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level ??? */
2404 { 0, 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level ??? */
2405 { 0, 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level ??? */
Yann Colletfd416f12016-01-30 03:14:15 +01002406},
2407{ /* for srcSize <= 16 KB */
2408 /* W, C, H, S, L, strat */
inikepf2fee4c2016-02-05 19:45:25 +01002409 { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2410 { 0, 0, 14, 14, 14, 1, 4, ZSTD_fast }, /* level 1 */
2411 { 0, 0, 14, 14, 16, 1, 4, ZSTD_fast }, /* level 2 */
2412 { 0, 0, 14, 14, 14, 5, 4, ZSTD_greedy }, /* level 3 */
2413 { 0, 0, 14, 14, 14, 8, 4, ZSTD_greedy }, /* level 4 */
2414 { 0, 0, 14, 11, 14, 6, 4, ZSTD_lazy }, /* level 5 */
2415 { 0, 0, 14, 14, 13, 6, 5, ZSTD_lazy }, /* level 6 */
2416 { 0, 0, 14, 14, 14, 7, 6, ZSTD_lazy }, /* level 7 */
2417 { 0, 0, 14, 14, 14, 8, 4, ZSTD_lazy }, /* level 8 */
2418 { 0, 0, 14, 14, 15, 9, 4, ZSTD_lazy }, /* level 9 */
2419 { 0, 0, 14, 14, 15, 10, 4, ZSTD_lazy }, /* level 10 */
2420 { 0, 0, 14, 15, 15, 6, 4, ZSTD_btlazy2 }, /* level 11 */
2421 { 0, 0, 14, 15, 15, 7, 4, ZSTD_btlazy2 }, /* level 12 */
2422 { 0, 0, 14, 15, 15, 8, 4, ZSTD_btlazy2 }, /* level 13 */
2423 { 0, 0, 14, 15, 15, 9, 4, ZSTD_btlazy2 }, /* level 14 */
2424 { 0, 0, 14, 15, 15, 10, 4, ZSTD_btlazy2 }, /* level 15 */
2425 { 0, 0, 14, 15, 15, 11, 4, ZSTD_btlazy2 }, /* level 16 */
2426 { 0, 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level 17 */
2427 { 0, 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level 18 */
2428 { 0, 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level 19 */
2429 { 0, 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level 20 */
2430 { 0, 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level ??? */
2431 { 0, 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level ??? */
2432 { 0, 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level ??? */
2433 { 0, 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level ??? */
Yann Colletfd416f12016-01-30 03:14:15 +01002434},
2435};
2436
2437/*! ZSTD_getParams
2438* @return ZSTD_parameters structure for a selected compression level and srcSize.
2439* @srcSizeHint value is optional, select 0 if not known */
2440ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint)
2441{
2442 ZSTD_parameters result;
2443 int tableID = ((srcSizeHint-1) <= 256 KB) + ((srcSizeHint-1) <= 128 KB) + ((srcSizeHint-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
2444 if (compressionLevel<=0) compressionLevel = 1;
2445 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
inikep3379c5d2016-02-05 09:21:20 +01002446#if ZSTD_OPT_DEBUG >= 1
2447 tableID=0;
2448#endif
Yann Colletfd416f12016-01-30 03:14:15 +01002449 result = ZSTD_defaultParameters[tableID][compressionLevel];
2450 result.srcSize = srcSizeHint;
2451 return result;
2452}
2453