blob: 407b3e8dfb9057225a37041a68050b81bed8bf92 [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;
inikep70b05452016-02-03 22:56:55 +010091 U32* matchLengthFreq;
92 U32* litLengthFreq;
93 U32* litFreq;
94 U32* offCodeFreq;
inikep3bfcfc72016-02-03 18:47:30 +010095 U32 matchLengthSum;
96 U32 litLengthSum;
97 U32 litSum;
98 U32 offCodeSum;
Yann Collet14983e72015-11-11 21:38:21 +010099} seqStore_t;
100
inikep27e1c6a2016-02-04 11:11:08 +0100101static void ZSTD_resetFreqs(seqStore_t* ssPtr)
Yann Collet14983e72015-11-11 21:38:21 +0100102{
inikep3bfcfc72016-02-03 18:47:30 +0100103 ssPtr->matchLengthSum = (1<<MLbits);
104 ssPtr->litLengthSum = (1<<LLbits);
105 ssPtr->litSum = (1<<Litbits);
106 ssPtr->offCodeSum = (1<<Offbits);
107
inikep70b05452016-02-03 22:56:55 +0100108 for (int i=0; i<=MaxLit; i++)
109 ssPtr->litFreq[i] = 1;
110 for (int i=0; i<=MaxLL; i++)
111 ssPtr->litLengthFreq[i] = 1;
112 for (int i=0; i<=MaxML; i++)
113 ssPtr->matchLengthFreq[i] = 1;
114 for (int i=0; i<=MaxOff; i++)
115 ssPtr->offCodeFreq[i] = 1;
Yann Collet14983e72015-11-11 21:38:21 +0100116}
117
Yann Collet14983e72015-11-11 21:38:21 +0100118static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
119{
120 ssPtr->offset = ssPtr->offsetStart;
121 ssPtr->lit = ssPtr->litStart;
122 ssPtr->litLength = ssPtr->litLengthStart;
123 ssPtr->matchLength = ssPtr->matchLengthStart;
124 ssPtr->dumps = ssPtr->dumpsStart;
inikep27e1c6a2016-02-04 11:11:08 +0100125
126 ZSTD_resetFreqs(ssPtr);
Yann Collet14983e72015-11-11 21:38:21 +0100127}
128
129
130/* *************************************
131* Context memory management
132***************************************/
Yann Collet5be2dd22015-11-11 13:43:58 +0100133struct ZSTD_CCtx_s
Yann Colletf3eca252015-10-22 15:31:46 +0100134{
Yann Collet89db5e02015-11-13 11:27:46 +0100135 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100136 const BYTE* base; /* All regular indexes relative to this position */
137 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +0100138 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100139 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +0100140 U32 nextToUpdate; /* index from which to continue dictionary update */
Yann Collet2ce49232016-02-02 14:36:49 +0100141 U32 loadedDictEnd;
Yann Colletecd651b2016-01-07 15:35:18 +0100142 U32 stage;
Yann Collet5be2dd22015-11-11 13:43:58 +0100143 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +0100144 void* workSpace;
145 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100146 size_t blockSize;
Yann Colletecd651b2016-01-07 15:35:18 +0100147 size_t hbSize;
Yann Collet60096272016-01-08 17:27:50 +0100148 char headerBuffer[ZSTD_frameHeaderSize_max];
Yann Colletecd651b2016-01-07 15:35:18 +0100149
Yann Collet712def92015-10-29 18:41:45 +0100150 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100151 U32* hashTable;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100152 U32* contentTable;
Yann Colletb923f652016-01-26 03:14:20 +0100153 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +0100154 U32 flagStaticTables;
155 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
156 FSE_CTable matchlengthCTable [FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
157 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Colletf3eca252015-10-22 15:31:46 +0100158};
159
160
Yann Collet5be2dd22015-11-11 13:43:58 +0100161ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100162{
Yann Collet5be2dd22015-11-11 13:43:58 +0100163 return (ZSTD_CCtx*) calloc(1, sizeof(ZSTD_CCtx));
Yann Colletf3eca252015-10-22 15:31:46 +0100164}
165
Yann Collet5be2dd22015-11-11 13:43:58 +0100166size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100167{
Yann Collet712def92015-10-29 18:41:45 +0100168 free(cctx->workSpace);
Yann Collet083fcc82015-10-25 14:06:35 +0100169 free(cctx);
Yann Collet982ffc72016-02-05 02:33:10 +0100170 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100171}
172
Yann Collet59d70632015-11-04 12:05:27 +0100173
Yann Collet14983e72015-11-11 21:38:21 +0100174static unsigned ZSTD_highbit(U32 val);
175
Yann Collet5be2dd22015-11-11 13:43:58 +0100176/** ZSTD_validateParams
Yann Collet59d70632015-11-04 12:05:27 +0100177 correct params value to remain within authorized range
178 optimize for srcSize if srcSize > 0 */
Yann Collet88fcd292015-11-25 14:42:45 +0100179void ZSTD_validateParams(ZSTD_parameters* params)
Yann Collet59d70632015-11-04 12:05:27 +0100180{
inikepc71568f2016-01-30 12:15:56 +0100181 const U32 btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_opt_bt);
Yann Collet59d70632015-11-04 12:05:27 +0100182
183 /* validate params */
Yann Collet00fd7a22015-11-28 16:03:22 +0100184 if (MEM_32bits()) if (params->windowLog > 25) params->windowLog = 25; /* 32 bits mode cannot flush > 24 bits */
Yann Collet5be2dd22015-11-11 13:43:58 +0100185 if (params->windowLog > ZSTD_WINDOWLOG_MAX) params->windowLog = ZSTD_WINDOWLOG_MAX;
186 if (params->windowLog < ZSTD_WINDOWLOG_MIN) params->windowLog = ZSTD_WINDOWLOG_MIN;
Yann Collet59d70632015-11-04 12:05:27 +0100187
188 /* correct params, to use less memory */
Yann Colletfb810d62016-01-28 00:18:06 +0100189 if ((params->srcSize > 0) && (params->srcSize < (1<<ZSTD_WINDOWLOG_MAX))) {
Yann Collet88fcd292015-11-25 14:42:45 +0100190 U32 srcLog = ZSTD_highbit((U32)(params->srcSize)-1) + 1;
Yann Collet59d70632015-11-04 12:05:27 +0100191 if (params->windowLog > srcLog) params->windowLog = srcLog;
192 }
193
Yann Collet00fd7a22015-11-28 16:03:22 +0100194 if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet5be2dd22015-11-11 13:43:58 +0100195 if (params->contentLog > params->windowLog+btPlus) params->contentLog = params->windowLog+btPlus; /* <= ZSTD_CONTENTLOG_MAX */
196 if (params->contentLog < ZSTD_CONTENTLOG_MIN) params->contentLog = ZSTD_CONTENTLOG_MIN;
197 if (params->hashLog > ZSTD_HASHLOG_MAX) params->hashLog = ZSTD_HASHLOG_MAX;
198 if (params->hashLog < ZSTD_HASHLOG_MIN) params->hashLog = ZSTD_HASHLOG_MIN;
199 if (params->searchLog > ZSTD_SEARCHLOG_MAX) params->searchLog = ZSTD_SEARCHLOG_MAX;
200 if (params->searchLog < ZSTD_SEARCHLOG_MIN) params->searchLog = ZSTD_SEARCHLOG_MIN;
201 if (params->searchLength> ZSTD_SEARCHLENGTH_MAX) params->searchLength = ZSTD_SEARCHLENGTH_MAX;
202 if (params->searchLength< ZSTD_SEARCHLENGTH_MIN) params->searchLength = ZSTD_SEARCHLENGTH_MIN;
inikepc71568f2016-01-30 12:15:56 +0100203 if ((U32)params->strategy>(U32)ZSTD_opt_bt) params->strategy = ZSTD_opt_bt;
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 Colletf3eca252015-10-22 15:31:46 +0100237 zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer);
Yann Collet120230b2015-12-02 14:00:45 +0100238 zc->seqStore.offCodeStart = (BYTE*) (zc->seqStore.offsetStart + (blockSize>>2));
239 zc->seqStore.litStart = zc->seqStore.offCodeStart + (blockSize>>2);
240 zc->seqStore.litLengthStart = zc->seqStore.litStart + blockSize;
241 zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + (blockSize>>2);
242 zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (blockSize>>2);
inikepe75621f2016-02-09 21:12:23 +0100243 BYTE* dumpsEnd= zc->seqStore.dumpsStart + (blockSize>>2);
244 zc->seqStore.litFreq = (U32*)(dumpsEnd);
inikep3bfcfc72016-02-03 18:47:30 +0100245 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
246 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (1<<LLbits);
247 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (1<<MLbits);
inikep70b05452016-02-03 22:56:55 +0100248 // zc->seqStore.XXX = zc->seqStore.offCodeFreq + (1<<Offbits)*sizeof(U32);
inikep3bfcfc72016-02-03 18:47:30 +0100249
Yann Colletecd651b2016-01-07 15:35:18 +0100250 zc->hbSize = 0;
Yann Collet60096272016-01-08 17:27:50 +0100251 zc->stage = 0;
Yann Collet2ce49232016-02-02 14:36:49 +0100252 zc->loadedDictEnd = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +0100253
Yann Collet4114f952015-10-30 06:40:22 +0100254 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100255}
256
Yann Collet083fcc82015-10-25 14:06:35 +0100257
Yann Collet7b51a292016-01-26 15:58:49 +0100258/*! ZSTD_copyCCtx
259* Duplicate an existing context @srcCCtx into another one @dstCCtx.
260* Only works during stage 0 (i.e. before first call to ZSTD_compressContinue())
261* @return : 0, or an error code */
262size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
263{
264 const U32 contentLog = (srcCCtx->params.strategy == ZSTD_fast) ? 1 : srcCCtx->params.contentLog;
265 const size_t tableSpace = ((1 << contentLog) + (1 << srcCCtx->params.hashLog)) * sizeof(U32);
266
267 if (srcCCtx->stage!=0) return ERROR(stage_wrong);
268
269 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params);
270
271 /* copy tables */
272 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace);
273
274 /* copy frame header */
275 dstCCtx->hbSize = srcCCtx->hbSize;
276 memcpy(dstCCtx->headerBuffer , srcCCtx->headerBuffer, srcCCtx->hbSize);
277
278 /* copy dictionary pointers */
279 dstCCtx->nextToUpdate= srcCCtx->nextToUpdate;
280 dstCCtx->nextSrc = srcCCtx->nextSrc;
281 dstCCtx->base = srcCCtx->base;
282 dstCCtx->dictBase = srcCCtx->dictBase;
283 dstCCtx->dictLimit = srcCCtx->dictLimit;
284 dstCCtx->lowLimit = srcCCtx->lowLimit;
Yann Collet7a6343f2016-02-02 16:00:50 +0100285 dstCCtx->loadedDictEnd = srcCCtx->loadedDictEnd;
Yann Collet7b51a292016-01-26 15:58:49 +0100286
Yann Colletfb810d62016-01-28 00:18:06 +0100287 /* copy entropy tables */
288 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100289 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100290 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100291 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
292 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
293 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
294 }
Yann Collet7b51a292016-01-26 15:58:49 +0100295
296 return 0;
297}
298
299
Yann Collet863ec402016-01-28 17:56:33 +0100300/*! ZSTD_reduceIndex
Yann Collet88fcd292015-11-25 14:42:45 +0100301* rescale indexes to avoid future overflow (indexes are U32) */
Yann Collet89db5e02015-11-13 11:27:46 +0100302static void ZSTD_reduceIndex (ZSTD_CCtx* zc,
303 const U32 reducerValue)
304{
Yann Collet88fcd292015-11-25 14:42:45 +0100305 const U32 contentLog = (zc->params.strategy == ZSTD_fast) ? 1 : zc->params.contentLog;
Yann Collet89db5e02015-11-13 11:27:46 +0100306 const U32 tableSpaceU32 = (1 << contentLog) + (1 << zc->params.hashLog);
307 U32* table32 = zc->hashTable;
308 U32 index;
309
Yann Colletfb810d62016-01-28 00:18:06 +0100310 for (index=0 ; index < tableSpaceU32 ; index++) {
Yann Collet89db5e02015-11-13 11:27:46 +0100311 if (table32[index] < reducerValue) table32[index] = 0;
312 else table32[index] -= reducerValue;
313 }
314}
315
316
Yann Collet863ec402016-01-28 17:56:33 +0100317/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100318* Block entropic compression
319*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100320
Yann Collet59d1f792016-01-23 19:28:41 +0100321/* Block format description
322
323 Block = Literal Section - Sequences Section
324 Prerequisite : size of (compressed) block, maximum size of regenerated data
325
326 1) Literal Section
327
328 1.1) Header : 1-5 bytes
329 flags: 2 bits
330 00 compressed by Huff0
331 01 unused
332 10 is Raw (uncompressed)
333 11 is Rle
334 Note : using 01 => Huff0 with precomputed table ?
335 Note : delta map ? => compressed ?
336
337 1.1.1) Huff0-compressed literal block : 3-5 bytes
Yann Colletafe07092016-01-25 04:10:46 +0100338 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
Yann Collet59d1f792016-01-23 19:28:41 +0100339 srcSize < 1 KB => 3 bytes (2-2-10-10)
Yann Colleta1249dc2016-01-25 04:22:03 +0100340 srcSize < 16KB => 4 bytes (2-2-14-14)
Yann Collet59d1f792016-01-23 19:28:41 +0100341 else => 5 bytes (2-2-18-18)
342 big endian convention
343
344 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
345 size : 5 bits: (IS_RAW<<6) + (0<<4) + size
346 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
347 size&255
348 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
349 size>>8&255
350 size&255
351
352 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
353 size : 5 bits: (IS_RLE<<6) + (0<<4) + size
354 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
355 size&255
356 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
357 size>>8&255
358 size&255
359
Yann Colleta1249dc2016-01-25 04:22:03 +0100360 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
361 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
362 srcSize < 1 KB => 3 bytes (2-2-10-10)
363 srcSize < 16KB => 4 bytes (2-2-14-14)
364 else => 5 bytes (2-2-18-18)
365 big endian convention
366
367 1- CTable available (stored into workspace ?)
Yann Colletb923f652016-01-26 03:14:20 +0100368 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
Yann Colleta1249dc2016-01-25 04:22:03 +0100369
Yann Collet59d1f792016-01-23 19:28:41 +0100370
371 1.2) Literal block content
372
373 1.2.1) Huff0 block, using sizes from header
374 See Huff0 format
375
Yann Colletfb810d62016-01-28 00:18:06 +0100376 1.2.2) Huff0 block, using prepared table
Yann Collet59d1f792016-01-23 19:28:41 +0100377
Yann Colletfb810d62016-01-28 00:18:06 +0100378 1.2.3) Raw content
Yann Collet59d1f792016-01-23 19:28:41 +0100379
Yann Colletfb810d62016-01-28 00:18:06 +0100380 1.2.4) single byte
Yann Collet59d1f792016-01-23 19:28:41 +0100381
382
383 2) Sequences section
Yann Colletfb810d62016-01-28 00:18:06 +0100384
385 - Nb Sequences : 2 bytes, little endian
386 - Control Token : 1 byte (see below)
387 - Dumps Length : 1 or 2 bytes (depending on control token)
388 - Dumps : as stated by dumps length
389 - Literal Lengths FSE table (as needed depending on encoding method)
390 - Offset Codes FSE table (as needed depending on encoding method)
391 - Match Lengths FSE table (as needed depending on encoding method)
392
393 2.1) Control Token
394 8 bits, divided as :
395 0-1 : dumpsLength
396 2-3 : MatchLength, FSE encoding method
397 4-5 : Offset Codes, FSE encoding method
398 6-7 : Literal Lengths, FSE encoding method
399
400 FSE encoding method :
401 FSE_ENCODING_RAW : uncompressed; no header
402 FSE_ENCODING_RLE : single repeated value; header 1 byte
403 FSE_ENCODING_STATIC : use prepared table; no header
404 FSE_ENCODING_DYNAMIC : read NCount
Yann Collet59d1f792016-01-23 19:28:41 +0100405*/
Yann Collet14983e72015-11-11 21:38:21 +0100406
407size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
408{
409 BYTE* const ostart = (BYTE* const)dst;
410
411 if (srcSize + ZSTD_blockHeaderSize > maxDstSize) return ERROR(dstSize_tooSmall);
412 memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
413
414 /* Build header */
415 ostart[0] = (BYTE)(srcSize>>16);
416 ostart[1] = (BYTE)(srcSize>>8);
417 ostart[2] = (BYTE) srcSize;
418 ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
419
420 return ZSTD_blockHeaderSize+srcSize;
421}
422
423
424static size_t ZSTD_noCompressLiterals (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
425{
426 BYTE* const ostart = (BYTE* const)dst;
Yann Collet59d1f792016-01-23 19:28:41 +0100427 const U32 flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100428
Yann Collet59d1f792016-01-23 19:28:41 +0100429 if (srcSize + flSize > maxDstSize) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100430
Yann Collet59d1f792016-01-23 19:28:41 +0100431 switch(flSize)
432 {
433 case 1: /* 2 - 1 - 5 */
434 ostart[0] = (BYTE)((IS_RAW<<6) + (0<<5) + srcSize);
435 break;
436 case 2: /* 2 - 2 - 12 */
437 ostart[0] = (BYTE)((IS_RAW<<6) + (2<<4) + (srcSize >> 8));
438 ostart[1] = (BYTE)srcSize;
439 break;
440 default: /*note : should not be necessary : flSize is within {1,2,3} */
441 case 3: /* 2 - 2 - 20 */
442 ostart[0] = (BYTE)((IS_RAW<<6) + (3<<4) + (srcSize >> 16));
443 ostart[1] = (BYTE)(srcSize>>8);
444 ostart[2] = (BYTE)srcSize;
445 break;
446 }
447
448 memcpy(ostart + flSize, src, srcSize);
449 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100450}
451
452static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
453{
454 BYTE* const ostart = (BYTE* const)dst;
Yann Collet59d1f792016-01-23 19:28:41 +0100455 U32 flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100456
Yann Colletfb810d62016-01-28 00:18:06 +0100457 (void)maxDstSize; /* maxDstSize guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100458
459 switch(flSize)
460 {
461 case 1: /* 2 - 1 - 5 */
462 ostart[0] = (BYTE)((IS_RLE<<6) + (0<<5) + srcSize);
463 break;
464 case 2: /* 2 - 2 - 12 */
465 ostart[0] = (BYTE)((IS_RLE<<6) + (2<<4) + (srcSize >> 8));
466 ostart[1] = (BYTE)srcSize;
467 break;
468 default: /*note : should not be necessary : flSize is necessary within {1,2,3} */
469 case 3: /* 2 - 2 - 20 */
470 ostart[0] = (BYTE)((IS_RLE<<6) + (3<<4) + (srcSize >> 16));
471 ostart[1] = (BYTE)(srcSize>>8);
472 ostart[2] = (BYTE)srcSize;
473 break;
474 }
475
476 ostart[flSize] = *(const BYTE*)src;
477 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100478}
479
Yann Collet59d1f792016-01-23 19:28:41 +0100480
Yann Colletb923f652016-01-26 03:14:20 +0100481size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100482
Yann Colletb923f652016-01-26 03:14:20 +0100483static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
484 void* dst, size_t maxDstSize,
Yann Collet14983e72015-11-11 21:38:21 +0100485 const void* src, size_t srcSize)
486{
487 const size_t minGain = ZSTD_minGain(srcSize);
488 BYTE* const ostart = (BYTE*)dst;
Yann Colletb923f652016-01-26 03:14:20 +0100489 const size_t lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Colletafe07092016-01-25 04:10:46 +0100490 U32 singleStream = srcSize < 256;
Yann Colletb923f652016-01-26 03:14:20 +0100491 U32 hType = IS_HUF;
Yann Collet59d1f792016-01-23 19:28:41 +0100492 size_t clitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100493
Yann Collet35f7de52016-01-31 02:51:03 +0100494 if (maxDstSize < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Collet14983e72015-11-11 21:38:21 +0100495
Yann Colletfb810d62016-01-28 00:18:06 +0100496 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletb923f652016-01-26 03:14:20 +0100497 hType = IS_PCH;
498 singleStream = 1;
499 clitSize = HUF_compress1X_usingCTable(ostart+lhSize, maxDstSize-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100500 } else {
Yann Colletb923f652016-01-26 03:14:20 +0100501 clitSize = singleStream ? HUF_compress1X(ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12)
502 : HUF_compress2 (ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12);
503 }
Yann Collet14983e72015-11-11 21:38:21 +0100504
Yann Collet59d1f792016-01-23 19:28:41 +0100505 if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, maxDstSize, src, srcSize);
506 if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, maxDstSize, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100507
508 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100509 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100510 {
Yann Collet59d1f792016-01-23 19:28:41 +0100511 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletb923f652016-01-26 03:14:20 +0100512 ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100513 ostart[1] = (BYTE)((srcSize<<2) + (clitSize>>8));
514 ostart[2] = (BYTE)(clitSize);
515 break;
516 case 4: /* 2 - 2 - 14 - 14 */
Yann Colletb923f652016-01-26 03:14:20 +0100517 ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100518 ostart[1] = (BYTE)(srcSize>> 2);
519 ostart[2] = (BYTE)((srcSize<<6) + (clitSize>>8));
520 ostart[3] = (BYTE)(clitSize);
521 break;
522 default: /* should not be necessary, lhSize is {3,4,5} */
523 case 5: /* 2 - 2 - 18 - 18 */
Yann Colletb923f652016-01-26 03:14:20 +0100524 ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100525 ostart[1] = (BYTE)(srcSize>>6);
526 ostart[2] = (BYTE)((srcSize<<2) + (clitSize>>16));
527 ostart[3] = (BYTE)(clitSize>>8);
528 ostart[4] = (BYTE)(clitSize);
529 break;
Yann Collet14983e72015-11-11 21:38:21 +0100530 }
531
Yann Collet59d1f792016-01-23 19:28:41 +0100532 return lhSize+clitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100533}
534
535
Yann Colletafe07092016-01-25 04:10:46 +0100536#define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */
Yann Collet14983e72015-11-11 21:38:21 +0100537
Yann Colletb923f652016-01-26 03:14:20 +0100538size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
539 void* dst, size_t maxDstSize,
Yann Collet14983e72015-11-11 21:38:21 +0100540 size_t srcSize)
541{
Yann Colletb923f652016-01-26 03:14:20 +0100542 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100543 U32 count[MaxSeq+1];
544 S16 norm[MaxSeq+1];
545 size_t mostFrequent;
Yann Colletfb810d62016-01-28 00:18:06 +0100546 U32 max;
547 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
548 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
549 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100550 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
551 const BYTE* const op_lit_start = seqStorePtr->litStart;
552 const BYTE* const llTable = seqStorePtr->litLengthStart;
553 const BYTE* const llPtr = seqStorePtr->litLength;
554 const BYTE* const mlTable = seqStorePtr->matchLengthStart;
555 const U32* const offsetTable = seqStorePtr->offsetStart;
556 BYTE* const offCodeTable = seqStorePtr->offCodeStart;
Yann Collet5054ee02015-11-23 13:34:21 +0100557 BYTE* const ostart = (BYTE*)dst;
558 BYTE* op = ostart;
559 BYTE* const oend = ostart + maxDstSize;
Yann Collet14983e72015-11-11 21:38:21 +0100560 const size_t nbSeq = llPtr - llTable;
561 const size_t minGain = ZSTD_minGain(srcSize);
562 const size_t maxCSize = srcSize - minGain;
563 BYTE* seqHead;
564
565
566 /* 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 Collet5be2dd22015-11-11 13:43:58 +0100931static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_read64(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 Collet5be2dd22015-11-11 13:43:58 +0100935static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_read64(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 Collet5be2dd22015-11-11 13:43:58 +0100939static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_read64(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 Collet1358f912016-01-01 07:29:39 +01001197/** ZSTD_insertBt1 : add one or multiple positions to tree
Yann Collet6bcdeac2015-11-26 11:43:00 +01001198* @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 Colleta87278a2016-01-17 00:12:55 +01001233 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001234 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1235
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 }
1245
Yann Colletfb810d62016-01-28 00:18:06 +01001246 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001247 *largerPtr = matchIndex;
1248 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1249 largerPtr = nextPtr;
1250 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001251 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001252 continue;
1253 }
1254
Yann Colletfb810d62016-01-28 00:18:06 +01001255 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001256 match = base + matchIndex;
1257 if (match[matchLength] == ip[matchLength])
1258 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001259 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001260 match = dictBase + matchIndex;
1261 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1262 if (matchIndex+matchLength >= dictLimit)
1263 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1264 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001265
Yann Colletee3f4512015-12-29 22:26:09 +01001266 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001267 matchEndIdx = matchIndex + (U32)matchLength;
Yann Colletee3f4512015-12-29 22:26:09 +01001268
Yann Collet59d70632015-11-04 12:05:27 +01001269 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001270 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001271
Yann Colletfb810d62016-01-28 00:18:06 +01001272 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001273 /* match is smaller than current */
1274 *smallerPtr = matchIndex; /* update smaller idx */
1275 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001276 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001277 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001278 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001279 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001280 /* match is larger than current */
1281 *largerPtr = matchIndex;
1282 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001283 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001284 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001285 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001286 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001287
Yann Collet59d70632015-11-04 12:05:27 +01001288 *smallerPtr = *largerPtr = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001289 return (matchEndIdx > current + 8) ? matchEndIdx - current - 8 : 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001290}
1291
1292
Yann Colletee3f4512015-12-29 22:26:09 +01001293static 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 +01001294{
1295 const BYTE* const base = zc->base;
1296 const U32 target = (U32)(ip - base);
1297 U32 idx = zc->nextToUpdate;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001298
Yann Colletf48e35c2015-11-07 01:13:31 +01001299 for( ; idx < target ; )
Yann Collet1358f912016-01-01 07:29:39 +01001300 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001301}
1302
Yann Collet96b9f0b2015-11-04 03:52:54 +01001303FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Collet2cc12cb2016-01-01 07:47:58 +01001304size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001305 ZSTD_CCtx* zc,
1306 const BYTE* const ip, const BYTE* const iend,
1307 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001308 U32 nbCompares, const U32 mls,
1309 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001310{
1311 U32* const hashTable = zc->hashTable;
1312 const U32 hashLog = zc->params.hashLog;
1313 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
1314 U32* const bt = zc->contentTable;
1315 const U32 btLog = zc->params.contentLog - 1;
1316 const U32 btMask= (1 << btLog) - 1;
1317 U32 matchIndex = hashTable[h];
1318 size_t commonLengthSmaller=0, commonLengthLarger=0;
1319 const BYTE* const base = zc->base;
1320 const BYTE* const dictBase = zc->dictBase;
1321 const U32 dictLimit = zc->dictLimit;
1322 const BYTE* const dictEnd = dictBase + dictLimit;
1323 const BYTE* const prefixStart = base + dictLimit;
1324 const U32 current = (U32)(ip-base);
1325 const U32 btLow = btMask >= current ? 0 : current - btMask;
1326 const U32 windowLow = zc->lowLimit;
1327 U32* smallerPtr = bt + 2*(current&btMask);
1328 U32* largerPtr = bt + 2*(current&btMask) + 1;
1329 size_t bestLength = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001330 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001331 U32 dummy32; /* to be nullified at the end */
1332
Yann Collet6c3e2e72015-12-11 10:44:07 +01001333 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001334
Yann Colletfb810d62016-01-28 00:18:06 +01001335 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001336 U32* nextPtr = bt + 2*(matchIndex & btMask);
1337 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1338 const BYTE* match;
1339
Yann Colletfb810d62016-01-28 00:18:06 +01001340 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001341 match = base + matchIndex;
1342 if (match[matchLength] == ip[matchLength])
1343 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001344 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001345 match = dictBase + matchIndex;
1346 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001347 if (matchIndex+matchLength >= dictLimit)
1348 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001349 }
1350
Yann Colletfb810d62016-01-28 00:18:06 +01001351 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001352 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001353 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet03526e12015-11-23 15:29:15 +01001354 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
1355 bestLength = matchLength, *offsetPtr = current - matchIndex;
1356 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1357 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1358 }
1359
Yann Colletfb810d62016-01-28 00:18:06 +01001360 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001361 /* match is smaller than current */
1362 *smallerPtr = matchIndex; /* update smaller idx */
1363 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1364 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1365 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1366 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001367 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001368 /* match is larger than current */
1369 *largerPtr = matchIndex;
1370 commonLengthLarger = matchLength;
1371 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1372 largerPtr = nextPtr;
1373 matchIndex = nextPtr[0];
1374 }
1375 }
1376
1377 *smallerPtr = *largerPtr = 0;
1378
Yann Collet72e84cf2015-12-31 19:08:44 +01001379 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
Yann Collet03526e12015-11-23 15:29:15 +01001380 return bestLength;
1381}
1382
Yann Collet2cc12cb2016-01-01 07:47:58 +01001383
1384/** Tree updater, providing best match */
1385FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1386size_t ZSTD_BtFindBestMatch (
1387 ZSTD_CCtx* zc,
1388 const BYTE* const ip, const BYTE* const iLimit,
1389 size_t* offsetPtr,
1390 const U32 maxNbAttempts, const U32 mls)
1391{
1392 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1393 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
1394 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1395}
1396
1397
1398FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS (
1399 ZSTD_CCtx* zc, /* Index table will be updated */
1400 const BYTE* ip, const BYTE* const iLimit,
1401 size_t* offsetPtr,
1402 const U32 maxNbAttempts, const U32 matchLengthSearch)
1403{
1404 switch(matchLengthSearch)
1405 {
1406 default :
1407 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1408 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1409 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1410 }
1411}
1412
1413
1414static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1415{
1416 const BYTE* const base = zc->base;
1417 const U32 target = (U32)(ip - base);
1418 U32 idx = zc->nextToUpdate;
1419
1420 for( ; idx < target ; )
1421 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1422}
1423
1424
Yann Collet03526e12015-11-23 15:29:15 +01001425/** Tree updater, providing best match */
1426FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1427size_t ZSTD_BtFindBestMatch_extDict (
1428 ZSTD_CCtx* zc,
1429 const BYTE* const ip, const BYTE* const iLimit,
1430 size_t* offsetPtr,
1431 const U32 maxNbAttempts, const U32 mls)
1432{
Yann Colletee3f4512015-12-29 22:26:09 +01001433 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1434 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001435 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001436}
1437
1438
1439FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
1440 ZSTD_CCtx* zc, /* Index table will be updated */
1441 const BYTE* ip, const BYTE* const iLimit,
1442 size_t* offsetPtr,
1443 const U32 maxNbAttempts, const U32 matchLengthSearch)
1444{
1445 switch(matchLengthSearch)
1446 {
1447 default :
1448 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1449 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1450 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1451 }
1452}
1453
1454
Yann Collet5106a762015-11-05 15:00:24 +01001455/* ***********************
1456* Hash Chain
1457*************************/
1458
Yann Collet1f44b3f2015-11-05 17:32:18 +01001459#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1460
Yann Collet6bcdeac2015-11-26 11:43:00 +01001461/* Update chains up to ip (excluded)
Yann Collet06eade52015-11-23 14:23:47 +01001462 Assumption : always within prefix (ie. not within extDict) */
1463static U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
Yann Collet5106a762015-11-05 15:00:24 +01001464{
1465 U32* const hashTable = zc->hashTable;
1466 const U32 hashLog = zc->params.hashLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001467 U32* const chainTable = zc->contentTable;
1468 const U32 chainMask = (1 << zc->params.contentLog) - 1;
Yann Collet5106a762015-11-05 15:00:24 +01001469 const BYTE* const base = zc->base;
1470 const U32 target = (U32)(ip - base);
1471 U32 idx = zc->nextToUpdate;
1472
Yann Colletfb810d62016-01-28 00:18:06 +01001473 while(idx < target) {
Yann Collet5be2dd22015-11-11 13:43:58 +01001474 size_t h = ZSTD_hashPtr(base+idx, hashLog, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001475 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1476 hashTable[h] = idx;
1477 idx++;
1478 }
1479
1480 zc->nextToUpdate = target;
Yann Collet5be2dd22015-11-11 13:43:58 +01001481 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
Yann Collet5106a762015-11-05 15:00:24 +01001482}
1483
1484
1485FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Colletc1e52f02015-11-23 14:37:59 +01001486size_t ZSTD_HcFindBestMatch_generic (
Yann Collet5be2dd22015-11-11 13:43:58 +01001487 ZSTD_CCtx* zc, /* Index table will be updated */
Yann Collet5106a762015-11-05 15:00:24 +01001488 const BYTE* const ip, const BYTE* const iLimit,
1489 size_t* offsetPtr,
Yann Colletc1e52f02015-11-23 14:37:59 +01001490 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
Yann Collet287b7d92015-11-22 13:24:05 +01001491{
Yann Collet1f44b3f2015-11-05 17:32:18 +01001492 U32* const chainTable = zc->contentTable;
1493 const U32 chainSize = (1 << zc->params.contentLog);
Yann Collet5106a762015-11-05 15:00:24 +01001494 const U32 chainMask = chainSize-1;
1495 const BYTE* const base = zc->base;
1496 const BYTE* const dictBase = zc->dictBase;
1497 const U32 dictLimit = zc->dictLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001498 const BYTE* const prefixStart = base + dictLimit;
1499 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001500 const U32 lowLimit = zc->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001501 const U32 current = (U32)(ip-base);
1502 const U32 minChain = current > chainSize ? current - chainSize : 0;
Yann Collet5106a762015-11-05 15:00:24 +01001503 U32 matchIndex;
1504 const BYTE* match;
1505 int nbAttempts=maxNbAttempts;
Yann Collet5054ee02015-11-23 13:34:21 +01001506 size_t ml=MINMATCH-1;
Yann Collet5106a762015-11-05 15:00:24 +01001507
1508 /* HC4 match finder */
Yann Colletc1e52f02015-11-23 14:37:59 +01001509 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001510
Yann Colletfb810d62016-01-28 00:18:06 +01001511 while ((matchIndex>lowLimit) && (nbAttempts)) {
Yann Collet5054ee02015-11-23 13:34:21 +01001512 size_t currentMl=0;
Yann Collet5106a762015-11-05 15:00:24 +01001513 nbAttempts--;
Yann Colletfb810d62016-01-28 00:18:06 +01001514 if ((!extDict) || matchIndex >= dictLimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001515 match = base + matchIndex;
Yann Collet4baee502015-11-09 03:19:33 +01001516 if (match[ml] == ip[ml]) /* potentially better */
Yann Collet5054ee02015-11-23 13:34:21 +01001517 currentMl = ZSTD_count(ip, match, iLimit);
Yann Colletfb810d62016-01-28 00:18:06 +01001518 } else {
Yann Collet5106a762015-11-05 15:00:24 +01001519 match = dictBase + matchIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001520 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1521 currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
Yann Collet5106a762015-11-05 15:00:24 +01001522 }
1523
Yann Collet5054ee02015-11-23 13:34:21 +01001524 /* save best solution */
Yann Collet239cc282015-11-23 16:17:21 +01001525 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 +01001526
Yann Collet9a24e592015-11-22 02:53:43 +01001527 if (matchIndex <= minChain) break;
Yann Collet5106a762015-11-05 15:00:24 +01001528 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1529 }
1530
1531 return ml;
1532}
1533
1534
Yann Colletc1e52f02015-11-23 14:37:59 +01001535FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1536 ZSTD_CCtx* zc,
Yann Collet5106a762015-11-05 15:00:24 +01001537 const BYTE* ip, const BYTE* const iLimit,
1538 size_t* offsetPtr,
1539 const U32 maxNbAttempts, const U32 matchLengthSearch)
1540{
1541 switch(matchLengthSearch)
1542 {
1543 default :
Yann Colletc1e52f02015-11-23 14:37:59 +01001544 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1545 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1546 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1547 }
1548}
1549
1550
1551FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1552 ZSTD_CCtx* zc,
1553 const BYTE* ip, const BYTE* const iLimit,
1554 size_t* offsetPtr,
1555 const U32 maxNbAttempts, const U32 matchLengthSearch)
1556{
1557 switch(matchLengthSearch)
1558 {
1559 default :
1560 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1561 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1562 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001563 }
1564}
1565
1566
Yann Collet287b7d92015-11-22 13:24:05 +01001567/* *******************************
Yann Collet9a24e592015-11-22 02:53:43 +01001568* Common parser - lazy strategy
Yann Collet287b7d92015-11-22 13:24:05 +01001569*********************************/
Yann Collet5106a762015-11-05 15:00:24 +01001570FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001571void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1572 const void* src, size_t srcSize,
Yann Collet007c1c62015-11-22 02:42:28 +01001573 const U32 searchMethod, const U32 depth)
Yann Collet5106a762015-11-05 15:00:24 +01001574{
1575 seqStore_t* seqStorePtr = &(ctx->seqStore);
1576 const BYTE* const istart = (const BYTE*)src;
1577 const BYTE* ip = istart;
1578 const BYTE* anchor = istart;
1579 const BYTE* const iend = istart + srcSize;
1580 const BYTE* const ilimit = iend - 8;
Yann Collete47c4e52015-12-05 09:23:53 +01001581 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet5106a762015-11-05 15:00:24 +01001582
1583 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1584 const U32 maxSearches = 1 << ctx->params.searchLog;
1585 const U32 mls = ctx->params.searchLength;
1586
Yann Collet5be2dd22015-11-11 13:43:58 +01001587 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
Yann Collet5106a762015-11-05 15:00:24 +01001588 size_t* offsetPtr,
1589 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet5be2dd22015-11-11 13:43:58 +01001590 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet5106a762015-11-05 15:00:24 +01001591
1592 /* init */
1593 ZSTD_resetSeqStore(seqStorePtr);
Yann Collete47c4e52015-12-05 09:23:53 +01001594 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet5106a762015-11-05 15:00:24 +01001595
1596 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001597 while (ip < ilimit) {
Yann Collet7a231792015-11-21 15:27:35 +01001598 size_t matchLength=0;
1599 size_t offset=0;
1600 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001601
Yann Collet743402c2015-11-20 12:03:53 +01001602 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001603 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1)) {
Yann Collet743402c2015-11-20 12:03:53 +01001604 /* repcode : we take it */
Yann Collet7a231792015-11-21 15:27:35 +01001605 matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH;
Yann Collet007c1c62015-11-22 02:42:28 +01001606 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001607 }
1608
Yann Colletfc2afcf2015-11-06 15:40:14 +01001609 {
Yann Collet239cc282015-11-23 16:17:21 +01001610 /* first search (depth 0) */
1611 size_t offsetFound = 99999999;
1612 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1613 if (ml2 > matchLength)
1614 matchLength = ml2, start = ip, offset=offsetFound;
1615 }
Yann Collet9a24e592015-11-22 02:53:43 +01001616
Yann Colletfb810d62016-01-28 00:18:06 +01001617 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001618 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1619 continue;
1620 }
Yann Collet5106a762015-11-05 15:00:24 +01001621
1622 /* let's try to find a better solution */
Yann Collet007c1c62015-11-22 02:42:28 +01001623 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001624 while (ip<ilimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001625 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001626 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet007c1c62015-11-22 02:42:28 +01001627 size_t mlRep = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1628 int gain2 = (int)(mlRep * 3);
Yann Collet5106a762015-11-05 15:00:24 +01001629 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet007c1c62015-11-22 02:42:28 +01001630 if ((mlRep >= MINMATCH) && (gain2 > gain1))
1631 matchLength = mlRep, offset = 0, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001632 }
1633 {
1634 size_t offset2=999999;
1635 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet007c1c62015-11-22 02:42:28 +01001636 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1637 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001638 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001639 matchLength = ml2, offset = offset2, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001640 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001641 } }
Yann Collet5106a762015-11-05 15:00:24 +01001642
1643 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001644 if ((depth==2) && (ip<ilimit)) {
Yann Collet5106a762015-11-05 15:00:24 +01001645 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001646 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet5106a762015-11-05 15:00:24 +01001647 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1648 int gain2 = (int)(ml2 * 4);
1649 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet4baee502015-11-09 03:19:33 +01001650 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001651 matchLength = ml2, offset = 0, start = ip;
1652 }
1653 {
1654 size_t offset2=999999;
1655 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet628065c2015-11-06 18:44:54 +01001656 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1657 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001658 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001659 matchLength = ml2, offset = offset2, start = ip;
1660 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001661 } } }
Yann Collet5106a762015-11-05 15:00:24 +01001662 break; /* nothing found : store previous solution */
1663 }
1664
Yann Collet4baee502015-11-09 03:19:33 +01001665 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001666 if (offset) {
Yann Collete47c4e52015-12-05 09:23:53 +01001667 while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */
Yann Collet4baee502015-11-09 03:19:33 +01001668 { start--; matchLength++; }
Yann Collet743402c2015-11-20 12:03:53 +01001669 offset_2 = offset_1; offset_1 = offset;
Yann Collet4baee502015-11-09 03:19:33 +01001670 }
1671
1672 /* store sequence */
Yann Collet7a231792015-11-21 15:27:35 +01001673_storeSequence:
Yann Collet5106a762015-11-05 15:00:24 +01001674 {
1675 size_t litLength = start - anchor;
Yann Collet5106a762015-11-05 15:00:24 +01001676 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
Yann Collet4baee502015-11-09 03:19:33 +01001677 anchor = ip = start + matchLength;
Yann Collet5106a762015-11-05 15:00:24 +01001678 }
1679
Yann Collet743402c2015-11-20 12:03:53 +01001680 /* check immediate repcode */
1681 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001682 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet743402c2015-11-20 12:03:53 +01001683 /* store sequence */
1684 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
1685 offset = offset_2;
1686 offset_2 = offset_1;
1687 offset_1 = offset;
1688 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength);
1689 ip += matchLength+MINMATCH;
1690 anchor = ip;
1691 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001692 } }
Yann Collet5106a762015-11-05 15:00:24 +01001693
1694 /* Last Literals */
1695 {
1696 size_t lastLLSize = iend - anchor;
1697 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1698 seqStorePtr->lit += lastLLSize;
1699 }
Yann Collet5106a762015-11-05 15:00:24 +01001700}
1701
inikepe2bfe242016-01-31 11:25:48 +01001702#include "zstd_opt.c"
1703
1704static void ZSTD_compressBlock_opt_bt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1705{
1706 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1, 2);
1707}
1708
1709static void ZSTD_compressBlock_opt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1710{
1711 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0, 2);
1712}
1713
Yann Collet59d1f792016-01-23 19:28:41 +01001714static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001715{
Yann Colleta1249dc2016-01-25 04:22:03 +01001716 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001717}
1718
Yann Collet59d1f792016-01-23 19:28:41 +01001719static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001720{
Yann Colleta1249dc2016-01-25 04:22:03 +01001721 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001722}
1723
Yann Collet59d1f792016-01-23 19:28:41 +01001724static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001725{
Yann Colleta1249dc2016-01-25 04:22:03 +01001726 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001727}
1728
Yann Collet59d1f792016-01-23 19:28:41 +01001729static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01001730{
Yann Colleta1249dc2016-01-25 04:22:03 +01001731 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
Yann Colletbe2010e2015-10-31 12:57:14 +01001732}
1733
1734
Yann Collet9a24e592015-11-22 02:53:43 +01001735FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001736void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1737 const void* src, size_t srcSize,
Yann Collet9a24e592015-11-22 02:53:43 +01001738 const U32 searchMethod, const U32 depth)
1739{
1740 seqStore_t* seqStorePtr = &(ctx->seqStore);
1741 const BYTE* const istart = (const BYTE*)src;
1742 const BYTE* ip = istart;
1743 const BYTE* anchor = istart;
1744 const BYTE* const iend = istart + srcSize;
1745 const BYTE* const ilimit = iend - 8;
1746 const BYTE* const base = ctx->base;
1747 const U32 dictLimit = ctx->dictLimit;
1748 const BYTE* const prefixStart = base + dictLimit;
1749 const BYTE* const dictBase = ctx->dictBase;
1750 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001751 const BYTE* const dictStart = dictBase + ctx->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001752
1753 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1754 const U32 maxSearches = 1 << ctx->params.searchLog;
1755 const U32 mls = ctx->params.searchLength;
1756
1757 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1758 size_t* offsetPtr,
1759 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet03526e12015-11-23 15:29:15 +01001760 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
Yann Collet9a24e592015-11-22 02:53:43 +01001761
1762 /* init */
1763 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet6c3e2e72015-12-11 10:44:07 +01001764 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Collet9a24e592015-11-22 02:53:43 +01001765
1766 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001767 while (ip < ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001768 size_t matchLength=0;
1769 size_t offset=0;
1770 const BYTE* start=ip+1;
1771 U32 current = (U32)(ip-base);
1772
1773 /* check repCode */
1774 {
1775 const U32 repIndex = (U32)(current+1 - offset_1);
1776 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1777 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001778 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001779 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001780 /* repcode detected we should take it */
1781 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001782 matchLength = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
Yann Collet9a24e592015-11-22 02:53:43 +01001783 if (depth==0) goto _storeSequence;
Yann Colletfb810d62016-01-28 00:18:06 +01001784 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001785
1786 {
Yann Collet239cc282015-11-23 16:17:21 +01001787 /* first search (depth 0) */
1788 size_t offsetFound = 99999999;
1789 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1790 if (ml2 > matchLength)
1791 matchLength = ml2, start = ip, offset=offsetFound;
1792 }
Yann Collet9a24e592015-11-22 02:53:43 +01001793
Yann Colletfb810d62016-01-28 00:18:06 +01001794 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001795 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1796 continue;
1797 }
Yann Collet9a24e592015-11-22 02:53:43 +01001798
1799 /* let's try to find a better solution */
1800 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001801 while (ip<ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001802 ip ++;
1803 current++;
1804 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001805 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001806 const U32 repIndex = (U32)(current - offset_1);
1807 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1808 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001809 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001810 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001811 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001812 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001813 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1814 int gain2 = (int)(repLength * 3);
1815 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1816 if ((repLength >= MINMATCH) && (gain2 > gain1))
1817 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001818 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001819
1820 /* search match, depth 1 */
1821 {
1822 size_t offset2=999999;
1823 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1824 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1825 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001826 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001827 matchLength = ml2, offset = offset2, start = ip;
1828 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001829 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001830
1831 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001832 if ((depth==2) && (ip<ilimit)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001833 ip ++;
1834 current++;
1835 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001836 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001837 const U32 repIndex = (U32)(current - offset_1);
1838 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1839 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001840 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001841 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001842 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001843 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001844 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1845 int gain2 = (int)(repLength * 4);
1846 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1847 if ((repLength >= MINMATCH) && (gain2 > gain1))
1848 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001849 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001850
1851 /* search match, depth 2 */
1852 {
1853 size_t offset2=999999;
1854 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1855 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1856 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001857 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001858 matchLength = ml2, offset = offset2, start = ip;
1859 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001860 } } }
Yann Collet9a24e592015-11-22 02:53:43 +01001861 break; /* nothing found : store previous solution */
1862 }
1863
1864 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001865 if (offset) {
Yann Colletc3652152015-11-24 14:06:07 +01001866 U32 matchIndex = (U32)((start-base) - offset);
1867 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1868 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
1869 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet9a24e592015-11-22 02:53:43 +01001870 offset_2 = offset_1; offset_1 = offset;
1871 }
1872
1873 /* store sequence */
1874_storeSequence:
1875 {
1876 size_t litLength = start - anchor;
1877 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1878 anchor = ip = start + matchLength;
1879 }
1880
1881 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001882 while (ip <= ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001883 const U32 repIndex = (U32)((ip-base) - offset_2);
1884 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1885 const BYTE* const repMatch = repBase + repIndex;
Yann Collet239cc282015-11-23 16:17:21 +01001886 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001887 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001888 /* repcode detected we should take it */
1889 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001890 matchLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1891 offset = offset_2; offset_2 = offset_1; offset_1 = offset; /* swap offset history */
Yann Collet9a24e592015-11-22 02:53:43 +01001892 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1893 ip += matchLength;
1894 anchor = ip;
1895 continue; /* faster when present ... (?) */
1896 }
1897 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001898 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001899
1900 /* Last Literals */
1901 {
1902 size_t lastLLSize = iend - anchor;
1903 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1904 seqStorePtr->lit += lastLLSize;
1905 }
Yann Collet9a24e592015-11-22 02:53:43 +01001906}
1907
Yann Collet59d1f792016-01-23 19:28:41 +01001908void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01001909{
Yann Colleta1249dc2016-01-25 04:22:03 +01001910 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01001911}
1912
Yann Collet59d1f792016-01-23 19:28:41 +01001913static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01001914{
Yann Colleta1249dc2016-01-25 04:22:03 +01001915 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01001916}
Yann Collet9a24e592015-11-22 02:53:43 +01001917
Yann Collet59d1f792016-01-23 19:28:41 +01001918static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01001919{
Yann Colleta1249dc2016-01-25 04:22:03 +01001920 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01001921}
1922
Yann Collet59d1f792016-01-23 19:28:41 +01001923static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01001924{
Yann Colleta1249dc2016-01-25 04:22:03 +01001925 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001926}
1927
inikepe2bfe242016-01-31 11:25:48 +01001928static void ZSTD_compressBlock_opt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1929{
inikepbe77f332016-02-09 23:00:41 +01001930 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0, 2);
inikepe2bfe242016-01-31 11:25:48 +01001931}
1932
1933static void ZSTD_compressBlock_opt_bt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1934{
inikepbe77f332016-02-09 23:00:41 +01001935 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1, 2);
inikepe2bfe242016-01-31 11:25:48 +01001936}
1937
Yann Collet7a231792015-11-21 15:27:35 +01001938
Yann Collet59d1f792016-01-23 19:28:41 +01001939typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01001940
Yann Colletb923f652016-01-26 03:14:20 +01001941static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01001942{
inikepe2bfe242016-01-31 11:25:48 +01001943 static const ZSTD_blockCompressor blockCompressor[2][7] = {
1944 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy,ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_opt, ZSTD_compressBlock_opt_bt },
1945 { 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 +01001946 };
1947
1948 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01001949}
1950
1951
Yann Colletbf42c8e2016-01-09 01:08:23 +01001952static 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 +01001953{
Yann Collet03526e12015-11-23 15:29:15 +01001954 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01001955 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 +01001956 blockCompressor(zc, src, srcSize);
Yann Colletb923f652016-01-26 03:14:20 +01001957 return ZSTD_compressSequences(zc, dst, maxDstSize, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01001958}
1959
1960
Yann Collet2ce49232016-02-02 14:36:49 +01001961static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
Yann Colletf3eca252015-10-22 15:31:46 +01001962 void* dst, size_t maxDstSize,
1963 const void* src, size_t srcSize)
1964{
Yann Collet2ce49232016-02-02 14:36:49 +01001965 size_t blockSize = zc->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001966 size_t remaining = srcSize;
1967 const BYTE* ip = (const BYTE*)src;
1968 BYTE* const ostart = (BYTE*)dst;
1969 BYTE* op = ostart;
Yann Collet2ce49232016-02-02 14:36:49 +01001970 const U32 maxDist = 1 << zc->params.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01001971
Yann Collet2ce49232016-02-02 14:36:49 +01001972 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01001973 size_t cSize;
1974
Yann Collet2ce49232016-02-02 14:36:49 +01001975 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 +01001976 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01001977
Yann Collet2ce49232016-02-02 14:36:49 +01001978 if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */
Yann Collet7a6343f2016-02-02 16:00:50 +01001979 U32 newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist;
1980 if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01001981 if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001982 }
Yann Collet89db5e02015-11-13 11:27:46 +01001983
Yann Collet2ce49232016-02-02 14:36:49 +01001984 cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, maxDstSize-ZSTD_blockHeaderSize, ip, blockSize);
Yann Collet3e358272015-11-04 18:19:39 +01001985 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001986
Yann Collet2ce49232016-02-02 14:36:49 +01001987 if (cSize == 0) { /* block is not compressible */
1988 cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize);
Yann Collet523b5942016-01-09 02:10:40 +01001989 if (ZSTD_isError(cSize)) return cSize;
Yann Collet2ce49232016-02-02 14:36:49 +01001990 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01001991 op[0] = (BYTE)(cSize>>16);
1992 op[1] = (BYTE)(cSize>>8);
1993 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01001994 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01001995 cSize += 3;
1996 }
1997
1998 remaining -= blockSize;
Yann Collet3e358272015-11-04 18:19:39 +01001999 maxDstSize -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002000 ip += blockSize;
2001 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002002 }
2003
2004 return op-ostart;
2005}
2006
2007
Yann Colletbf42c8e2016-01-09 01:08:23 +01002008static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
2009 void* dst, size_t dstSize,
2010 const void* src, size_t srcSize,
2011 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01002012{
Yann Collet2acb5d32015-10-29 16:49:43 +01002013 const BYTE* const ip = (const BYTE*) src;
Yann Colletecd651b2016-01-07 15:35:18 +01002014 size_t hbSize = 0;
2015
Yann Collet2ce49232016-02-02 14:36:49 +01002016 if (frame && (zc->stage==0)) {
Yann Colletecd651b2016-01-07 15:35:18 +01002017 hbSize = zc->hbSize;
2018 if (dstSize <= hbSize) return ERROR(dstSize_tooSmall);
2019 zc->stage = 1;
2020 memcpy(dst, zc->headerBuffer, hbSize);
2021 dstSize -= hbSize;
2022 dst = (char*)dst + hbSize;
2023 }
Yann Colletf3eca252015-10-22 15:31:46 +01002024
Yann Collet417890c2015-12-04 17:16:37 +01002025 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01002026 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002027 /* not contiguous */
2028 size_t delta = zc->nextSrc - ip;
2029 zc->lowLimit = zc->dictLimit;
2030 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2031 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01002032 zc->base -= delta;
2033 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01002034 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002035 }
2036
Yann Collet89db5e02015-11-13 11:27:46 +01002037 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01002038 if (zc->lowLimit > (1<<30)) {
inikepc71568f2016-01-30 12:15:56 +01002039 U32 btplus = (zc->params.strategy == ZSTD_btlazy2) || (zc->params.strategy == ZSTD_opt_bt);
Yann Collet6c3e2e72015-12-11 10:44:07 +01002040 U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1;
2041 U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */
2042 U32 correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002043 ZSTD_reduceIndex(zc, correction);
2044 zc->base += correction;
2045 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002046 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002047 zc->dictLimit -= correction;
2048 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2049 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01002050 }
2051
Yann Colletbf42c8e2016-01-09 01:08:23 +01002052 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01002053 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01002054 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2055 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002056 }
2057
Yann Colletc3652152015-11-24 14:06:07 +01002058 zc->nextSrc = ip + srcSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002059 {
Yann Colletbf42c8e2016-01-09 01:08:23 +01002060 size_t cSize;
2061 if (frame) cSize = ZSTD_compress_generic (zc, dst, dstSize, src, srcSize);
2062 else cSize = ZSTD_compressBlock_internal (zc, dst, dstSize, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002063 if (ZSTD_isError(cSize)) return cSize;
2064 return cSize + hbSize;
2065 }
Yann Colletf3eca252015-10-22 15:31:46 +01002066}
2067
Yann Colletbf42c8e2016-01-09 01:08:23 +01002068
2069size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
2070 void* dst, size_t dstSize,
2071 const void* src, size_t srcSize)
2072{
2073 return ZSTD_compressContinue_internal(zc, dst, dstSize, src, srcSize, 1);
2074}
2075
2076
2077size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
2078{
2079 if (srcSize > BLOCKSIZE) return ERROR(srcSize_wrong);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002080 return ZSTD_compressContinue_internal(zc, dst, maxDstSize, src, srcSize, 0);
2081}
2082
2083
Yann Colletb923f652016-01-26 03:14:20 +01002084static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002085{
2086 const BYTE* const ip = (const BYTE*) src;
2087 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002088
Yann Collet417890c2015-12-04 17:16:37 +01002089 /* input becomes current prefix */
2090 zc->lowLimit = zc->dictLimit;
2091 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2092 zc->dictBase = zc->base;
2093 zc->base += ip - zc->nextSrc;
2094 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002095 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002096
2097 zc->nextSrc = iend;
2098 if (srcSize <= 8) return 0;
2099
2100 switch(zc->params.strategy)
2101 {
2102 case ZSTD_fast:
Yann Collet2ce49232016-02-02 14:36:49 +01002103 ZSTD_fillHashTable (zc, iend, zc->params.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002104 break;
2105
2106 case ZSTD_greedy:
2107 case ZSTD_lazy:
2108 case ZSTD_lazy2:
inikepbe77f332016-02-09 23:00:41 +01002109 case ZSTD_opt:
Yann Collet417890c2015-12-04 17:16:37 +01002110 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength);
2111 break;
2112
2113 case ZSTD_btlazy2:
inikepbe77f332016-02-09 23:00:41 +01002114 case ZSTD_opt_bt:
Yann Collet417890c2015-12-04 17:16:37 +01002115 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength);
2116 break;
2117
2118 default:
2119 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2120 }
2121
Yann Collet2ce49232016-02-02 14:36:49 +01002122 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002123 return 0;
2124}
2125
2126
Yann Colletb923f652016-01-26 03:14:20 +01002127/* Dictionary format :
2128 Magic == ZSTD_DICT_MAGIC (4 bytes)
2129 Huff0 CTable (256 * 4 bytes) => to be changed to read from writeCTable
2130 Dictionary content
2131*/
2132/*! ZSTD_loadDictEntropyStats
2133 @return : size read from dictionary */
2134static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2135{
2136 /* note : magic number already checked */
Yann Colletfb810d62016-01-28 00:18:06 +01002137 size_t offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize, errorCode;
2138 short offcodeNCount[MaxOff+1];
2139 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2140 short matchlengthNCount[MaxML+1];
2141 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2142 short litlengthNCount[MaxLL+1];
2143 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2144
Yann Colletb923f652016-01-26 03:14:20 +01002145 const size_t hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize);
2146 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Colletfb810d62016-01-28 00:18:06 +01002147 zc->flagStaticTables = 1;
2148 dict = (const char*)dict + hufHeaderSize;
2149 dictSize -= hufHeaderSize;
2150
2151 offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
2152 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2153 errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2154 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2155 dict = (const char*)dict + offcodeHeaderSize;
2156 dictSize -= offcodeHeaderSize;
2157
2158 matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
2159 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2160 errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2161 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2162 dict = (const char*)dict + matchlengthHeaderSize;
2163 dictSize -= matchlengthHeaderSize;
2164
2165 litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
2166 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2167 errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2168 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2169
2170 return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
Yann Colletb923f652016-01-26 03:14:20 +01002171}
2172
Yann Colletfb810d62016-01-28 00:18:06 +01002173
Yann Collet1c8e1942016-01-26 16:31:22 +01002174static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002175{
Yann Collet2ce49232016-02-02 14:36:49 +01002176 if (dict && (dictSize>4)) {
Yann Collet7b51a292016-01-26 15:58:49 +01002177 U32 magic = MEM_readLE32(dict);
2178 size_t eSize;
2179 if (magic != ZSTD_DICT_MAGIC)
2180 return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletb923f652016-01-26 03:14:20 +01002181
Yann Collet7b51a292016-01-26 15:58:49 +01002182 eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4, dictSize-4) + 4;
2183 if (ZSTD_isError(eSize)) return eSize;
2184 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
2185 }
Yann Colletecd651b2016-01-07 15:35:18 +01002186 return 0;
2187}
2188
2189
Yann Collet417890c2015-12-04 17:16:37 +01002190/*! ZSTD_compressBegin_advanced
Yann Colletecd651b2016-01-07 15:35:18 +01002191* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002192size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
2193 const void* dict, size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002194 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002195{
Yann Collet4114f952015-10-30 06:40:22 +01002196 size_t errorCode;
Yann Collet88fcd292015-11-25 14:42:45 +01002197
2198 ZSTD_validateParams(&params);
2199
Yann Collet1c8e1942016-01-26 16:31:22 +01002200 errorCode = ZSTD_resetCCtx_advanced(zc, params);
Yann Collet4114f952015-10-30 06:40:22 +01002201 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet89db5e02015-11-13 11:27:46 +01002202
Yann Collet1c8e1942016-01-26 16:31:22 +01002203 MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */
2204 ((BYTE*)zc->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN);
2205 zc->hbSize = ZSTD_frameHeaderSize_min;
2206 zc->stage = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002207
Yann Collet1c8e1942016-01-26 16:31:22 +01002208 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002209}
2210
2211
Yann Collet1c8e1942016-01-26 16:31:22 +01002212size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002213{
Yann Collet953ce722016-02-04 15:28:14 +01002214 return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, MAX(128 KB, dictSize)));
Yann Collet1c8e1942016-01-26 16:31:22 +01002215}
Yann Collet083fcc82015-10-25 14:06:35 +01002216
Yann Collet1c8e1942016-01-26 16:31:22 +01002217size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002218{
Yann Collet1c8e1942016-01-26 16:31:22 +01002219 return ZSTD_compressBegin_advanced(zc, NULL, 0, ZSTD_getParams(compressionLevel, 0));
Yann Collet083fcc82015-10-25 14:06:35 +01002220}
2221
2222
Yann Collet31683c02015-12-18 01:26:48 +01002223/*! ZSTD_compressEnd
Yann Collet88fcd292015-11-25 14:42:45 +01002224* Write frame epilogue
2225* @return : nb of bytes written into dst (or an error code) */
Yann Colletecd651b2016-01-07 15:35:18 +01002226size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize)
Yann Collet2acb5d32015-10-29 16:49:43 +01002227{
2228 BYTE* op = (BYTE*)dst;
Yann Colletecd651b2016-01-07 15:35:18 +01002229 size_t hbSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002230
Yann Colletecd651b2016-01-07 15:35:18 +01002231 /* empty frame */
Yann Colletfb810d62016-01-28 00:18:06 +01002232 if (zc->stage==0) {
Yann Colletecd651b2016-01-07 15:35:18 +01002233 hbSize = zc->hbSize;
2234 if (maxDstSize <= hbSize) return ERROR(dstSize_tooSmall);
2235 zc->stage = 1;
2236 memcpy(dst, zc->headerBuffer, hbSize);
2237 maxDstSize -= hbSize;
2238 op += hbSize;
2239 }
2240
2241 /* frame epilogue */
Yann Collet2acb5d32015-10-29 16:49:43 +01002242 if (maxDstSize < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002243 op[0] = (BYTE)(bt_end << 6);
2244 op[1] = 0;
2245 op[2] = 0;
2246
Yann Colletecd651b2016-01-07 15:35:18 +01002247 return 3+hbSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002248}
2249
Yann Colletfd416f12016-01-30 03:14:15 +01002250
2251size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
2252 void* dst, size_t maxDstSize,
2253 const void* src, size_t srcSize)
2254{
2255 size_t outSize;
2256 size_t errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2257 if (ZSTD_isError(errorCode)) return errorCode;
2258 errorCode = ZSTD_compressContinue(cctx, dst, maxDstSize, src, srcSize);
2259 if (ZSTD_isError(errorCode)) return errorCode;
2260 outSize = errorCode;
2261 errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, maxDstSize-outSize);
2262 if (ZSTD_isError(errorCode)) return errorCode;
2263 outSize += errorCode;
2264 return outSize;
2265}
2266
2267
Yann Collet5be2dd22015-11-11 13:43:58 +01002268size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
Yann Collet88fcd292015-11-25 14:42:45 +01002269 void* dst, size_t maxDstSize,
2270 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002271 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002272 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002273{
2274 BYTE* const ostart = (BYTE*)dst;
2275 BYTE* op = ostart;
Yann Collet4114f952015-10-30 06:40:22 +01002276 size_t oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002277
Yann Collet1c8e1942016-01-26 16:31:22 +01002278 /* Init */
2279 oSize = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params);
Yann Colletf3eca252015-10-22 15:31:46 +01002280 if(ZSTD_isError(oSize)) return oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002281
2282 /* body (compression) */
Yann Collet31683c02015-12-18 01:26:48 +01002283 oSize = ZSTD_compressContinue (ctx, op, maxDstSize, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002284 if(ZSTD_isError(oSize)) return oSize;
2285 op += oSize;
2286 maxDstSize -= oSize;
2287
2288 /* Close frame */
Yann Collet5be2dd22015-11-11 13:43:58 +01002289 oSize = ZSTD_compressEnd(ctx, op, maxDstSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002290 if(ZSTD_isError(oSize)) return oSize;
2291 op += oSize;
2292
2293 return (op - ostart);
2294}
2295
Yann Collet31683c02015-12-18 01:26:48 +01002296size_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)
2297{
Yann Collet2ce49232016-02-02 14:36:49 +01002298 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet31683c02015-12-18 01:26:48 +01002299}
2300
Yann Collet5be2dd22015-11-11 13:43:58 +01002301size_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 +01002302{
Yann Collet31683c02015-12-18 01:26:48 +01002303 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet083fcc82015-10-25 14:06:35 +01002304}
2305
Yann Collet5be2dd22015-11-11 13:43:58 +01002306size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002307{
Yann Collet44fe9912015-10-29 22:02:40 +01002308 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002309 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002310 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Collet5be2dd22015-11-11 13:43:58 +01002311 result = ZSTD_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel);
Yann Colletecd651b2016-01-07 15:35:18 +01002312 free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002313 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002314}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002315
Yann Colletfd416f12016-01-30 03:14:15 +01002316
2317/*- Pre-defined compression levels -*/
2318
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 */
2348 { 0, 32, 23, 21, 22, 5, 4, ZSTD_opt_bt }, /* level 24 */
Yann Colletfd416f12016-01-30 03:14:15 +01002349},
2350{ /* for srcSize <= 256 KB */
inikepf2fee4c2016-02-05 19:45:25 +01002351 /* SL, W, C, H, S, L, strat */
2352 { 0, 0, 18, 13, 14, 1, 7, ZSTD_fast }, /* level 0 - never used */
2353 { 0, 0, 18, 14, 15, 1, 6, ZSTD_fast }, /* level 1 */
2354 { 0, 0, 18, 14, 15, 1, 5, ZSTD_fast }, /* level 2 */
2355 { 0, 0, 18, 12, 15, 3, 4, ZSTD_greedy }, /* level 3 */
2356 { 0, 0, 18, 13, 15, 4, 4, ZSTD_greedy }, /* level 4 */
2357 { 0, 0, 18, 14, 15, 5, 4, ZSTD_greedy }, /* level 5 */
2358 { 0, 0, 18, 13, 15, 4, 4, ZSTD_lazy }, /* level 6 */
2359 { 0, 0, 18, 14, 16, 5, 4, ZSTD_lazy }, /* level 7 */
2360 { 0, 0, 18, 15, 16, 6, 4, ZSTD_lazy }, /* level 8 */
2361 { 0, 0, 18, 15, 15, 7, 4, ZSTD_lazy }, /* level 9 */
2362 { 0, 0, 18, 16, 16, 7, 4, ZSTD_lazy }, /* level 10 */
2363 { 0, 0, 18, 16, 16, 8, 4, ZSTD_lazy }, /* level 11 */
2364 { 0, 0, 18, 17, 16, 8, 4, ZSTD_lazy }, /* level 12 */
2365 { 0, 0, 18, 17, 16, 9, 4, ZSTD_lazy }, /* level 13 */
2366 { 0, 0, 18, 18, 16, 9, 4, ZSTD_lazy }, /* level 14 */
2367 { 0, 0, 18, 17, 17, 9, 4, ZSTD_lazy2 }, /* level 15 */
2368 { 0, 0, 18, 18, 18, 9, 4, ZSTD_lazy2 }, /* level 16 */
2369 { 0, 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level 17 */
2370 { 0, 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level 18 */
2371 { 0, 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level 19 */
2372 { 0, 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level 20 */
2373 { 0, 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level ??? */
2374 { 0, 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level ??? */
2375 { 0, 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level ??? */
2376 { 0, 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level ??? */
Yann Colletfd416f12016-01-30 03:14:15 +01002377},
2378{ /* for srcSize <= 128 KB */
2379 /* W, C, H, S, L, strat */
inikepf2fee4c2016-02-05 19:45:25 +01002380 { 0, 0, 17, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */
2381 { 0, 0, 17, 12, 13, 1, 6, ZSTD_fast }, /* level 1 */
2382 { 0, 0, 17, 14, 16, 1, 5, ZSTD_fast }, /* level 2 */
2383 { 0, 0, 17, 15, 17, 1, 5, ZSTD_fast }, /* level 3 */
2384 { 0, 0, 17, 13, 15, 2, 4, ZSTD_greedy }, /* level 4 */
2385 { 0, 0, 17, 15, 17, 3, 4, ZSTD_greedy }, /* level 5 */
2386 { 0, 0, 17, 14, 17, 3, 4, ZSTD_lazy }, /* level 6 */
2387 { 0, 0, 17, 16, 17, 4, 4, ZSTD_lazy }, /* level 7 */
2388 { 0, 0, 17, 16, 17, 4, 4, ZSTD_lazy2 }, /* level 8 */
2389 { 0, 0, 17, 17, 16, 5, 4, ZSTD_lazy2 }, /* level 9 */
2390 { 0, 0, 17, 17, 16, 6, 4, ZSTD_lazy2 }, /* level 10 */
2391 { 0, 0, 17, 17, 16, 7, 4, ZSTD_lazy2 }, /* level 11 */
2392 { 0, 0, 17, 17, 16, 8, 4, ZSTD_lazy2 }, /* level 12 */
2393 { 0, 0, 17, 18, 16, 4, 4, ZSTD_btlazy2 }, /* level 13 */
2394 { 0, 0, 17, 18, 16, 5, 4, ZSTD_btlazy2 }, /* level 14 */
2395 { 0, 0, 17, 18, 16, 6, 4, ZSTD_btlazy2 }, /* level 15 */
2396 { 0, 0, 17, 18, 16, 7, 4, ZSTD_btlazy2 }, /* level 16 */
2397 { 0, 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level 17 */
2398 { 0, 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level 18 */
2399 { 0, 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level 19 */
2400 { 0, 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level 20 */
2401 { 0, 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level ??? */
2402 { 0, 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level ??? */
2403 { 0, 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level ??? */
2404 { 0, 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level ??? */
Yann Colletfd416f12016-01-30 03:14:15 +01002405},
2406{ /* for srcSize <= 16 KB */
2407 /* W, C, H, S, L, strat */
inikepf2fee4c2016-02-05 19:45:25 +01002408 { 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2409 { 0, 0, 14, 14, 14, 1, 4, ZSTD_fast }, /* level 1 */
2410 { 0, 0, 14, 14, 16, 1, 4, ZSTD_fast }, /* level 2 */
2411 { 0, 0, 14, 14, 14, 5, 4, ZSTD_greedy }, /* level 3 */
2412 { 0, 0, 14, 14, 14, 8, 4, ZSTD_greedy }, /* level 4 */
2413 { 0, 0, 14, 11, 14, 6, 4, ZSTD_lazy }, /* level 5 */
2414 { 0, 0, 14, 14, 13, 6, 5, ZSTD_lazy }, /* level 6 */
2415 { 0, 0, 14, 14, 14, 7, 6, ZSTD_lazy }, /* level 7 */
2416 { 0, 0, 14, 14, 14, 8, 4, ZSTD_lazy }, /* level 8 */
2417 { 0, 0, 14, 14, 15, 9, 4, ZSTD_lazy }, /* level 9 */
2418 { 0, 0, 14, 14, 15, 10, 4, ZSTD_lazy }, /* level 10 */
2419 { 0, 0, 14, 15, 15, 6, 4, ZSTD_btlazy2 }, /* level 11 */
2420 { 0, 0, 14, 15, 15, 7, 4, ZSTD_btlazy2 }, /* level 12 */
2421 { 0, 0, 14, 15, 15, 8, 4, ZSTD_btlazy2 }, /* level 13 */
2422 { 0, 0, 14, 15, 15, 9, 4, ZSTD_btlazy2 }, /* level 14 */
2423 { 0, 0, 14, 15, 15, 10, 4, ZSTD_btlazy2 }, /* level 15 */
2424 { 0, 0, 14, 15, 15, 11, 4, ZSTD_btlazy2 }, /* level 16 */
2425 { 0, 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level 17 */
2426 { 0, 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level 18 */
2427 { 0, 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level 19 */
2428 { 0, 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level 20 */
2429 { 0, 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level ??? */
2430 { 0, 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level ??? */
2431 { 0, 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level ??? */
2432 { 0, 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level ??? */
Yann Colletfd416f12016-01-30 03:14:15 +01002433},
2434};
2435
2436/*! ZSTD_getParams
2437* @return ZSTD_parameters structure for a selected compression level and srcSize.
2438* @srcSizeHint value is optional, select 0 if not known */
2439ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint)
2440{
2441 ZSTD_parameters result;
2442 int tableID = ((srcSizeHint-1) <= 256 KB) + ((srcSizeHint-1) <= 128 KB) + ((srcSizeHint-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
2443 if (compressionLevel<=0) compressionLevel = 1;
2444 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
inikep3379c5d2016-02-05 09:21:20 +01002445#if ZSTD_OPT_DEBUG >= 1
2446 tableID=0;
2447#endif
Yann Colletfd416f12016-01-30 03:14:15 +01002448 result = ZSTD_defaultParameters[tableID][compressionLevel];
2449 result.srcSize = srcSizeHint;
2450 return result;
2451}
2452