blob: 47b55cfff2f2383fc803f0853178c2d0838cd493 [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;
91} seqStore_t;
92
93static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
94{
95 ssPtr->offset = ssPtr->offsetStart;
96 ssPtr->lit = ssPtr->litStart;
97 ssPtr->litLength = ssPtr->litLengthStart;
98 ssPtr->matchLength = ssPtr->matchLengthStart;
99 ssPtr->dumps = ssPtr->dumpsStart;
100}
101
102
103/* *************************************
104* Context memory management
105***************************************/
Yann Collet5be2dd22015-11-11 13:43:58 +0100106struct ZSTD_CCtx_s
Yann Colletf3eca252015-10-22 15:31:46 +0100107{
Yann Collet89db5e02015-11-13 11:27:46 +0100108 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100109 const BYTE* base; /* All regular indexes relative to this position */
110 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +0100111 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100112 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +0100113 U32 nextToUpdate; /* index from which to continue dictionary update */
Yann Collet2ce49232016-02-02 14:36:49 +0100114 U32 loadedDictEnd;
Yann Colletecd651b2016-01-07 15:35:18 +0100115 U32 stage;
Yann Collet5be2dd22015-11-11 13:43:58 +0100116 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +0100117 void* workSpace;
118 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100119 size_t blockSize;
Yann Colletecd651b2016-01-07 15:35:18 +0100120 size_t hbSize;
Yann Collet60096272016-01-08 17:27:50 +0100121 char headerBuffer[ZSTD_frameHeaderSize_max];
Yann Colletecd651b2016-01-07 15:35:18 +0100122
Yann Collet712def92015-10-29 18:41:45 +0100123 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100124 U32* hashTable;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100125 U32* contentTable;
Yann Colletb923f652016-01-26 03:14:20 +0100126 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +0100127 U32 flagStaticTables;
128 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
129 FSE_CTable matchlengthCTable [FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
130 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Colletf3eca252015-10-22 15:31:46 +0100131};
132
133
Yann Collet5be2dd22015-11-11 13:43:58 +0100134ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100135{
Yann Collet5be2dd22015-11-11 13:43:58 +0100136 return (ZSTD_CCtx*) calloc(1, sizeof(ZSTD_CCtx));
Yann Colletf3eca252015-10-22 15:31:46 +0100137}
138
Yann Collet5be2dd22015-11-11 13:43:58 +0100139size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100140{
Yann Collet712def92015-10-29 18:41:45 +0100141 free(cctx->workSpace);
Yann Collet083fcc82015-10-25 14:06:35 +0100142 free(cctx);
143 return 0;
144}
145
Yann Collet59d70632015-11-04 12:05:27 +0100146
Yann Collet14983e72015-11-11 21:38:21 +0100147static unsigned ZSTD_highbit(U32 val);
148
Yann Collet5be2dd22015-11-11 13:43:58 +0100149/** ZSTD_validateParams
Yann Collet59d70632015-11-04 12:05:27 +0100150 correct params value to remain within authorized range
151 optimize for srcSize if srcSize > 0 */
Yann Collet88fcd292015-11-25 14:42:45 +0100152void ZSTD_validateParams(ZSTD_parameters* params)
Yann Collet59d70632015-11-04 12:05:27 +0100153{
Yann Collet5be2dd22015-11-11 13:43:58 +0100154 const U32 btPlus = (params->strategy == ZSTD_btlazy2);
Yann Collet59d70632015-11-04 12:05:27 +0100155
156 /* validate params */
Yann Collet00fd7a22015-11-28 16:03:22 +0100157 if (MEM_32bits()) if (params->windowLog > 25) params->windowLog = 25; /* 32 bits mode cannot flush > 24 bits */
Yann Collet5be2dd22015-11-11 13:43:58 +0100158 if (params->windowLog > ZSTD_WINDOWLOG_MAX) params->windowLog = ZSTD_WINDOWLOG_MAX;
159 if (params->windowLog < ZSTD_WINDOWLOG_MIN) params->windowLog = ZSTD_WINDOWLOG_MIN;
Yann Collet59d70632015-11-04 12:05:27 +0100160
161 /* correct params, to use less memory */
Yann Colletfb810d62016-01-28 00:18:06 +0100162 if ((params->srcSize > 0) && (params->srcSize < (1<<ZSTD_WINDOWLOG_MAX))) {
Yann Collet88fcd292015-11-25 14:42:45 +0100163 U32 srcLog = ZSTD_highbit((U32)(params->srcSize)-1) + 1;
Yann Collet59d70632015-11-04 12:05:27 +0100164 if (params->windowLog > srcLog) params->windowLog = srcLog;
165 }
166
Yann Collet00fd7a22015-11-28 16:03:22 +0100167 if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet5be2dd22015-11-11 13:43:58 +0100168 if (params->contentLog > params->windowLog+btPlus) params->contentLog = params->windowLog+btPlus; /* <= ZSTD_CONTENTLOG_MAX */
169 if (params->contentLog < ZSTD_CONTENTLOG_MIN) params->contentLog = ZSTD_CONTENTLOG_MIN;
170 if (params->hashLog > ZSTD_HASHLOG_MAX) params->hashLog = ZSTD_HASHLOG_MAX;
171 if (params->hashLog < ZSTD_HASHLOG_MIN) params->hashLog = ZSTD_HASHLOG_MIN;
172 if (params->searchLog > ZSTD_SEARCHLOG_MAX) params->searchLog = ZSTD_SEARCHLOG_MAX;
173 if (params->searchLog < ZSTD_SEARCHLOG_MIN) params->searchLog = ZSTD_SEARCHLOG_MIN;
174 if (params->searchLength> ZSTD_SEARCHLENGTH_MAX) params->searchLength = ZSTD_SEARCHLENGTH_MAX;
175 if (params->searchLength< ZSTD_SEARCHLENGTH_MIN) params->searchLength = ZSTD_SEARCHLENGTH_MIN;
176 if ((U32)params->strategy>(U32)ZSTD_btlazy2) params->strategy = ZSTD_btlazy2;
Yann Collet59d70632015-11-04 12:05:27 +0100177}
178
179
Yann Collet5be2dd22015-11-11 13:43:58 +0100180static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Collet88fcd292015-11-25 14:42:45 +0100181 ZSTD_parameters params)
Yann Collet863ec402016-01-28 17:56:33 +0100182{ /* note : params considered validated here */
Yann Collet120230b2015-12-02 14:00:45 +0100183 const size_t blockSize = MIN(BLOCKSIZE, (size_t)1 << params.windowLog);
Yann Collet2acb5d32015-10-29 16:49:43 +0100184 /* reserve table memory */
Yann Collet863ec402016-01-28 17:56:33 +0100185 const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog;
186 const size_t tableSpace = ((1 << contentLog) + (1 << params.hashLog)) * sizeof(U32);
187 const size_t neededSpace = tableSpace + (256*sizeof(U32)) + (3*blockSize);
188 if (zc->workSpaceSize < neededSpace) {
189 free(zc->workSpace);
190 zc->workSpace = malloc(neededSpace);
191 if (zc->workSpace == NULL) return ERROR(memory_allocation);
192 zc->workSpaceSize = neededSpace;
Yann Collet083fcc82015-10-25 14:06:35 +0100193 }
Yann Collet863ec402016-01-28 17:56:33 +0100194 memset(zc->workSpace, 0, tableSpace ); /* reset only tables */
195 zc->hashTable = (U32*)(zc->workSpace);
196 zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog);
197 zc->seqStore.buffer = zc->contentTable + ((size_t)1 << contentLog);
198 zc->hufTable = (HUF_CElt*)zc->seqStore.buffer;
199 zc->flagStaticTables = 0;
200 zc->seqStore.buffer = (U32*)(zc->seqStore.buffer) + 256;
Yann Collet083fcc82015-10-25 14:06:35 +0100201
Yann Colletf48e35c2015-11-07 01:13:31 +0100202 zc->nextToUpdate = 1;
Yann Collet89db5e02015-11-13 11:27:46 +0100203 zc->nextSrc = NULL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100204 zc->base = NULL;
205 zc->dictBase = NULL;
206 zc->dictLimit = 0;
207 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100208 zc->params = params;
Yann Collet120230b2015-12-02 14:00:45 +0100209 zc->blockSize = blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100210 zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer);
Yann Collet120230b2015-12-02 14:00:45 +0100211 zc->seqStore.offCodeStart = (BYTE*) (zc->seqStore.offsetStart + (blockSize>>2));
212 zc->seqStore.litStart = zc->seqStore.offCodeStart + (blockSize>>2);
213 zc->seqStore.litLengthStart = zc->seqStore.litStart + blockSize;
214 zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + (blockSize>>2);
215 zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (blockSize>>2);
Yann Colletecd651b2016-01-07 15:35:18 +0100216 zc->hbSize = 0;
Yann Collet60096272016-01-08 17:27:50 +0100217 zc->stage = 0;
Yann Collet2ce49232016-02-02 14:36:49 +0100218 zc->loadedDictEnd = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +0100219
Yann Collet4114f952015-10-30 06:40:22 +0100220 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100221}
222
Yann Collet083fcc82015-10-25 14:06:35 +0100223
Yann Collet7b51a292016-01-26 15:58:49 +0100224/*! ZSTD_copyCCtx
225* Duplicate an existing context @srcCCtx into another one @dstCCtx.
226* Only works during stage 0 (i.e. before first call to ZSTD_compressContinue())
227* @return : 0, or an error code */
228size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
229{
230 const U32 contentLog = (srcCCtx->params.strategy == ZSTD_fast) ? 1 : srcCCtx->params.contentLog;
231 const size_t tableSpace = ((1 << contentLog) + (1 << srcCCtx->params.hashLog)) * sizeof(U32);
232
233 if (srcCCtx->stage!=0) return ERROR(stage_wrong);
234
235 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params);
236
237 /* copy tables */
238 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace);
239
240 /* copy frame header */
241 dstCCtx->hbSize = srcCCtx->hbSize;
242 memcpy(dstCCtx->headerBuffer , srcCCtx->headerBuffer, srcCCtx->hbSize);
243
244 /* copy dictionary pointers */
245 dstCCtx->nextToUpdate= srcCCtx->nextToUpdate;
246 dstCCtx->nextSrc = srcCCtx->nextSrc;
247 dstCCtx->base = srcCCtx->base;
248 dstCCtx->dictBase = srcCCtx->dictBase;
249 dstCCtx->dictLimit = srcCCtx->dictLimit;
250 dstCCtx->lowLimit = srcCCtx->lowLimit;
Yann Collet7a6343f2016-02-02 16:00:50 +0100251 dstCCtx->loadedDictEnd = srcCCtx->loadedDictEnd;
Yann Collet7b51a292016-01-26 15:58:49 +0100252
Yann Colletfb810d62016-01-28 00:18:06 +0100253 /* copy entropy tables */
254 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100255 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100256 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100257 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
258 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
259 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
260 }
Yann Collet7b51a292016-01-26 15:58:49 +0100261
262 return 0;
263}
264
265
Yann Collet863ec402016-01-28 17:56:33 +0100266/*! ZSTD_reduceIndex
Yann Collet88fcd292015-11-25 14:42:45 +0100267* rescale indexes to avoid future overflow (indexes are U32) */
Yann Collet89db5e02015-11-13 11:27:46 +0100268static void ZSTD_reduceIndex (ZSTD_CCtx* zc,
269 const U32 reducerValue)
270{
Yann Collet88fcd292015-11-25 14:42:45 +0100271 const U32 contentLog = (zc->params.strategy == ZSTD_fast) ? 1 : zc->params.contentLog;
Yann Collet89db5e02015-11-13 11:27:46 +0100272 const U32 tableSpaceU32 = (1 << contentLog) + (1 << zc->params.hashLog);
273 U32* table32 = zc->hashTable;
274 U32 index;
275
Yann Colletfb810d62016-01-28 00:18:06 +0100276 for (index=0 ; index < tableSpaceU32 ; index++) {
Yann Collet89db5e02015-11-13 11:27:46 +0100277 if (table32[index] < reducerValue) table32[index] = 0;
278 else table32[index] -= reducerValue;
279 }
280}
281
282
Yann Collet863ec402016-01-28 17:56:33 +0100283/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100284* Block entropic compression
285*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100286
Yann Collet59d1f792016-01-23 19:28:41 +0100287/* Block format description
288
289 Block = Literal Section - Sequences Section
290 Prerequisite : size of (compressed) block, maximum size of regenerated data
291
292 1) Literal Section
293
294 1.1) Header : 1-5 bytes
295 flags: 2 bits
296 00 compressed by Huff0
297 01 unused
298 10 is Raw (uncompressed)
299 11 is Rle
300 Note : using 01 => Huff0 with precomputed table ?
301 Note : delta map ? => compressed ?
302
303 1.1.1) Huff0-compressed literal block : 3-5 bytes
Yann Colletafe07092016-01-25 04:10:46 +0100304 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
Yann Collet59d1f792016-01-23 19:28:41 +0100305 srcSize < 1 KB => 3 bytes (2-2-10-10)
Yann Colleta1249dc2016-01-25 04:22:03 +0100306 srcSize < 16KB => 4 bytes (2-2-14-14)
Yann Collet59d1f792016-01-23 19:28:41 +0100307 else => 5 bytes (2-2-18-18)
308 big endian convention
309
310 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
311 size : 5 bits: (IS_RAW<<6) + (0<<4) + size
312 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
313 size&255
314 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
315 size>>8&255
316 size&255
317
318 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
319 size : 5 bits: (IS_RLE<<6) + (0<<4) + size
320 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
321 size&255
322 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
323 size>>8&255
324 size&255
325
Yann Colleta1249dc2016-01-25 04:22:03 +0100326 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
327 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
328 srcSize < 1 KB => 3 bytes (2-2-10-10)
329 srcSize < 16KB => 4 bytes (2-2-14-14)
330 else => 5 bytes (2-2-18-18)
331 big endian convention
332
333 1- CTable available (stored into workspace ?)
Yann Colletb923f652016-01-26 03:14:20 +0100334 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
Yann Colleta1249dc2016-01-25 04:22:03 +0100335
Yann Collet59d1f792016-01-23 19:28:41 +0100336
337 1.2) Literal block content
338
339 1.2.1) Huff0 block, using sizes from header
340 See Huff0 format
341
Yann Colletfb810d62016-01-28 00:18:06 +0100342 1.2.2) Huff0 block, using prepared table
Yann Collet59d1f792016-01-23 19:28:41 +0100343
Yann Colletfb810d62016-01-28 00:18:06 +0100344 1.2.3) Raw content
Yann Collet59d1f792016-01-23 19:28:41 +0100345
Yann Colletfb810d62016-01-28 00:18:06 +0100346 1.2.4) single byte
Yann Collet59d1f792016-01-23 19:28:41 +0100347
348
349 2) Sequences section
Yann Colletfb810d62016-01-28 00:18:06 +0100350
351 - Nb Sequences : 2 bytes, little endian
352 - Control Token : 1 byte (see below)
353 - Dumps Length : 1 or 2 bytes (depending on control token)
354 - Dumps : as stated by dumps length
355 - Literal Lengths FSE table (as needed depending on encoding method)
356 - Offset Codes FSE table (as needed depending on encoding method)
357 - Match Lengths FSE table (as needed depending on encoding method)
358
359 2.1) Control Token
360 8 bits, divided as :
361 0-1 : dumpsLength
362 2-3 : MatchLength, FSE encoding method
363 4-5 : Offset Codes, FSE encoding method
364 6-7 : Literal Lengths, FSE encoding method
365
366 FSE encoding method :
367 FSE_ENCODING_RAW : uncompressed; no header
368 FSE_ENCODING_RLE : single repeated value; header 1 byte
369 FSE_ENCODING_STATIC : use prepared table; no header
370 FSE_ENCODING_DYNAMIC : read NCount
Yann Collet59d1f792016-01-23 19:28:41 +0100371*/
Yann Collet14983e72015-11-11 21:38:21 +0100372
373size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
374{
375 BYTE* const ostart = (BYTE* const)dst;
376
377 if (srcSize + ZSTD_blockHeaderSize > maxDstSize) return ERROR(dstSize_tooSmall);
378 memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
379
380 /* Build header */
381 ostart[0] = (BYTE)(srcSize>>16);
382 ostart[1] = (BYTE)(srcSize>>8);
383 ostart[2] = (BYTE) srcSize;
384 ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
385
386 return ZSTD_blockHeaderSize+srcSize;
387}
388
389
390static size_t ZSTD_noCompressLiterals (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
391{
392 BYTE* const ostart = (BYTE* const)dst;
Yann Collet59d1f792016-01-23 19:28:41 +0100393 const U32 flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100394
Yann Collet59d1f792016-01-23 19:28:41 +0100395 if (srcSize + flSize > maxDstSize) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100396
Yann Collet59d1f792016-01-23 19:28:41 +0100397 switch(flSize)
398 {
399 case 1: /* 2 - 1 - 5 */
400 ostart[0] = (BYTE)((IS_RAW<<6) + (0<<5) + srcSize);
401 break;
402 case 2: /* 2 - 2 - 12 */
403 ostart[0] = (BYTE)((IS_RAW<<6) + (2<<4) + (srcSize >> 8));
404 ostart[1] = (BYTE)srcSize;
405 break;
406 default: /*note : should not be necessary : flSize is within {1,2,3} */
407 case 3: /* 2 - 2 - 20 */
408 ostart[0] = (BYTE)((IS_RAW<<6) + (3<<4) + (srcSize >> 16));
409 ostart[1] = (BYTE)(srcSize>>8);
410 ostart[2] = (BYTE)srcSize;
411 break;
412 }
413
414 memcpy(ostart + flSize, src, srcSize);
415 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100416}
417
418static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
419{
420 BYTE* const ostart = (BYTE* const)dst;
Yann Collet59d1f792016-01-23 19:28:41 +0100421 U32 flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100422
Yann Colletfb810d62016-01-28 00:18:06 +0100423 (void)maxDstSize; /* maxDstSize guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100424
425 switch(flSize)
426 {
427 case 1: /* 2 - 1 - 5 */
428 ostart[0] = (BYTE)((IS_RLE<<6) + (0<<5) + srcSize);
429 break;
430 case 2: /* 2 - 2 - 12 */
431 ostart[0] = (BYTE)((IS_RLE<<6) + (2<<4) + (srcSize >> 8));
432 ostart[1] = (BYTE)srcSize;
433 break;
434 default: /*note : should not be necessary : flSize is necessary within {1,2,3} */
435 case 3: /* 2 - 2 - 20 */
436 ostart[0] = (BYTE)((IS_RLE<<6) + (3<<4) + (srcSize >> 16));
437 ostart[1] = (BYTE)(srcSize>>8);
438 ostart[2] = (BYTE)srcSize;
439 break;
440 }
441
442 ostart[flSize] = *(const BYTE*)src;
443 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100444}
445
Yann Collet59d1f792016-01-23 19:28:41 +0100446
Yann Colletb923f652016-01-26 03:14:20 +0100447size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100448
Yann Colletb923f652016-01-26 03:14:20 +0100449static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
450 void* dst, size_t maxDstSize,
Yann Collet14983e72015-11-11 21:38:21 +0100451 const void* src, size_t srcSize)
452{
453 const size_t minGain = ZSTD_minGain(srcSize);
454 BYTE* const ostart = (BYTE*)dst;
Yann Colletb923f652016-01-26 03:14:20 +0100455 const size_t lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Colletafe07092016-01-25 04:10:46 +0100456 U32 singleStream = srcSize < 256;
Yann Colletb923f652016-01-26 03:14:20 +0100457 U32 hType = IS_HUF;
Yann Collet59d1f792016-01-23 19:28:41 +0100458 size_t clitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100459
Yann Collet35f7de52016-01-31 02:51:03 +0100460 if (maxDstSize < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Collet14983e72015-11-11 21:38:21 +0100461
Yann Colletfb810d62016-01-28 00:18:06 +0100462 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletb923f652016-01-26 03:14:20 +0100463 hType = IS_PCH;
464 singleStream = 1;
465 clitSize = HUF_compress1X_usingCTable(ostart+lhSize, maxDstSize-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100466 } else {
Yann Colletb923f652016-01-26 03:14:20 +0100467 clitSize = singleStream ? HUF_compress1X(ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12)
468 : HUF_compress2 (ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12);
469 }
Yann Collet14983e72015-11-11 21:38:21 +0100470
Yann Collet59d1f792016-01-23 19:28:41 +0100471 if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, maxDstSize, src, srcSize);
472 if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, maxDstSize, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100473
474 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100475 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100476 {
Yann Collet59d1f792016-01-23 19:28:41 +0100477 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletb923f652016-01-26 03:14:20 +0100478 ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100479 ostart[1] = (BYTE)((srcSize<<2) + (clitSize>>8));
480 ostart[2] = (BYTE)(clitSize);
481 break;
482 case 4: /* 2 - 2 - 14 - 14 */
Yann Colletb923f652016-01-26 03:14:20 +0100483 ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100484 ostart[1] = (BYTE)(srcSize>> 2);
485 ostart[2] = (BYTE)((srcSize<<6) + (clitSize>>8));
486 ostart[3] = (BYTE)(clitSize);
487 break;
488 default: /* should not be necessary, lhSize is {3,4,5} */
489 case 5: /* 2 - 2 - 18 - 18 */
Yann Colletb923f652016-01-26 03:14:20 +0100490 ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100491 ostart[1] = (BYTE)(srcSize>>6);
492 ostart[2] = (BYTE)((srcSize<<2) + (clitSize>>16));
493 ostart[3] = (BYTE)(clitSize>>8);
494 ostart[4] = (BYTE)(clitSize);
495 break;
Yann Collet14983e72015-11-11 21:38:21 +0100496 }
497
Yann Collet59d1f792016-01-23 19:28:41 +0100498 return lhSize+clitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100499}
500
501
Yann Colletafe07092016-01-25 04:10:46 +0100502#define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */
Yann Collet14983e72015-11-11 21:38:21 +0100503
Yann Colletb923f652016-01-26 03:14:20 +0100504size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
505 void* dst, size_t maxDstSize,
Yann Collet14983e72015-11-11 21:38:21 +0100506 size_t srcSize)
507{
Yann Colletb923f652016-01-26 03:14:20 +0100508 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100509 U32 count[MaxSeq+1];
510 S16 norm[MaxSeq+1];
511 size_t mostFrequent;
Yann Colletfb810d62016-01-28 00:18:06 +0100512 U32 max;
513 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
514 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
515 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100516 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
517 const BYTE* const op_lit_start = seqStorePtr->litStart;
518 const BYTE* const llTable = seqStorePtr->litLengthStart;
519 const BYTE* const llPtr = seqStorePtr->litLength;
520 const BYTE* const mlTable = seqStorePtr->matchLengthStart;
521 const U32* const offsetTable = seqStorePtr->offsetStart;
522 BYTE* const offCodeTable = seqStorePtr->offCodeStart;
Yann Collet5054ee02015-11-23 13:34:21 +0100523 BYTE* const ostart = (BYTE*)dst;
524 BYTE* op = ostart;
525 BYTE* const oend = ostart + maxDstSize;
Yann Collet14983e72015-11-11 21:38:21 +0100526 const size_t nbSeq = llPtr - llTable;
527 const size_t minGain = ZSTD_minGain(srcSize);
528 const size_t maxCSize = srcSize - minGain;
529 BYTE* seqHead;
530
531
532 /* Compress literals */
533 {
534 size_t cSize;
535 size_t litSize = seqStorePtr->lit - op_lit_start;
Yann Colletfb810d62016-01-28 00:18:06 +0100536 const size_t minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
Yann Collet14983e72015-11-11 21:38:21 +0100537
Yann Colletb923f652016-01-26 03:14:20 +0100538 if (litSize <= minLitSize)
Yann Collet14983e72015-11-11 21:38:21 +0100539 cSize = ZSTD_noCompressLiterals(op, maxDstSize, op_lit_start, litSize);
540 else
Yann Colletb923f652016-01-26 03:14:20 +0100541 cSize = ZSTD_compressLiterals(zc, op, maxDstSize, op_lit_start, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100542 if (ZSTD_isError(cSize)) return cSize;
543 op += cSize;
544 }
545
546 /* Sequences Header */
Yann Collet61e16ce2016-01-31 02:04:15 +0100547 if ((oend-op) < MIN_SEQUENCES_SIZE) return ERROR(dstSize_tooSmall);
548 if (nbSeq < 128) *op++ = (BYTE)nbSeq;
549 else {
Yann Collet35f7de52016-01-31 02:51:03 +0100550 op[0] = (BYTE)((nbSeq>>8) + 128); op[1] = (BYTE)nbSeq; op+=2;
Yann Collet61e16ce2016-01-31 02:04:15 +0100551 }
Yann Collete93d6ce2016-01-31 00:58:06 +0100552 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100553
Yann Collet863ec402016-01-28 17:56:33 +0100554 /* dumps : contains rests of large lengths */
Yann Collete93d6ce2016-01-31 00:58:06 +0100555 if ((oend-op) < 3 /* dumps */ + 1 /*seqHead*/)
556 return ERROR(dstSize_tooSmall);
557 seqHead = op;
Yann Collet14983e72015-11-11 21:38:21 +0100558 {
559 size_t dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart;
Yann Colletfb810d62016-01-28 00:18:06 +0100560 if (dumpsLength < 512) {
Yann Collet14983e72015-11-11 21:38:21 +0100561 op[0] = (BYTE)(dumpsLength >> 8);
562 op[1] = (BYTE)(dumpsLength);
563 op += 2;
Yann Colletfb810d62016-01-28 00:18:06 +0100564 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100565 op[0] = 2;
566 op[1] = (BYTE)(dumpsLength>>8);
567 op[2] = (BYTE)(dumpsLength);
568 op += 3;
569 }
570 if ((size_t)(oend-op) < dumpsLength+6) return ERROR(dstSize_tooSmall);
571 memcpy(op, seqStorePtr->dumpsStart, dumpsLength);
572 op += dumpsLength;
573 }
574
Yann Colletfb810d62016-01-28 00:18:06 +0100575#define MIN_SEQ_FOR_DYNAMIC_FSE 64
576#define MAX_SEQ_FOR_STATIC_FSE 1000
577
Yann Collet14983e72015-11-11 21:38:21 +0100578 /* CTable for Literal Lengths */
579 max = MaxLL;
Yann Collete93d6ce2016-01-31 00:58:06 +0100580 mostFrequent = FSE_countFast(count, &max, llTable, nbSeq);
Yann Colletfb810d62016-01-28 00:18:06 +0100581 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collete93d6ce2016-01-31 00:58:06 +0100582 *op++ = llTable[0];
Yann Collet14983e72015-11-11 21:38:21 +0100583 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletfb810d62016-01-28 00:18:06 +0100584 LLtype = FSE_ENCODING_RLE;
585 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
586 LLtype = FSE_ENCODING_STATIC;
587 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LLbits-1)))) {
Yann Collet14983e72015-11-11 21:38:21 +0100588 FSE_buildCTable_raw(CTable_LitLength, LLbits);
Yann Colletfb810d62016-01-28 00:18:06 +0100589 LLtype = FSE_ENCODING_RAW;
590 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100591 size_t NCountSize;
Yann Collete93d6ce2016-01-31 00:58:06 +0100592 size_t nbSeq_1 = nbSeq;
Yann Colletfb810d62016-01-28 00:18:06 +0100593 U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
Yann Collete93d6ce2016-01-31 00:58:06 +0100594 if (count[llTable[nbSeq-1]]>1) { count[llTable[nbSeq-1]]--; nbSeq_1--; }
595 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Collet14983e72015-11-11 21:38:21 +0100596 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
597 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
598 op += NCountSize;
599 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
Yann Colletfb810d62016-01-28 00:18:06 +0100600 LLtype = FSE_ENCODING_DYNAMIC;
Yann Collet14983e72015-11-11 21:38:21 +0100601 }
602
Yann Colletfb810d62016-01-28 00:18:06 +0100603 /* CTable for Offset codes */
604 { /* create Offset codes */
605 size_t i; for (i=0; i<nbSeq; i++) {
Yann Collet14983e72015-11-11 21:38:21 +0100606 offCodeTable[i] = (BYTE)ZSTD_highbit(offsetTable[i]) + 1;
607 if (offsetTable[i]==0) offCodeTable[i]=0;
608 }
Yann Collet14983e72015-11-11 21:38:21 +0100609 }
Yann Colletfb810d62016-01-28 00:18:06 +0100610 max = MaxOff;
611 mostFrequent = FSE_countFast(count, &max, offCodeTable, nbSeq);
612 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collete93d6ce2016-01-31 00:58:06 +0100613 *op++ = offCodeTable[0];
Yann Collet14983e72015-11-11 21:38:21 +0100614 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletfb810d62016-01-28 00:18:06 +0100615 Offtype = FSE_ENCODING_RLE;
616 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
617 Offtype = FSE_ENCODING_STATIC;
618 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (Offbits-1)))) {
Yann Collet14983e72015-11-11 21:38:21 +0100619 FSE_buildCTable_raw(CTable_OffsetBits, Offbits);
Yann Colletfb810d62016-01-28 00:18:06 +0100620 Offtype = FSE_ENCODING_RAW;
621 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100622 size_t NCountSize;
Yann Collete93d6ce2016-01-31 00:58:06 +0100623 size_t nbSeq_1 = nbSeq;
Yann Colletfb810d62016-01-28 00:18:06 +0100624 U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collete93d6ce2016-01-31 00:58:06 +0100625 if (count[offCodeTable[nbSeq-1]]>1) { count[offCodeTable[nbSeq-1]]--; nbSeq_1--; }
626 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Collet14983e72015-11-11 21:38:21 +0100627 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
628 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
629 op += NCountSize;
630 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
Yann Colletfb810d62016-01-28 00:18:06 +0100631 Offtype = FSE_ENCODING_DYNAMIC;
Yann Collet14983e72015-11-11 21:38:21 +0100632 }
633
634 /* CTable for MatchLengths */
635 max = MaxML;
Yann Collete93d6ce2016-01-31 00:58:06 +0100636 mostFrequent = FSE_countFast(count, &max, mlTable, nbSeq);
Yann Colletfb810d62016-01-28 00:18:06 +0100637 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collete93d6ce2016-01-31 00:58:06 +0100638 *op++ = *mlTable;
Yann Collet14983e72015-11-11 21:38:21 +0100639 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletfb810d62016-01-28 00:18:06 +0100640 MLtype = FSE_ENCODING_RLE;
641 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
642 MLtype = FSE_ENCODING_STATIC;
643 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (MLbits-1)))) {
Yann Collet14983e72015-11-11 21:38:21 +0100644 FSE_buildCTable_raw(CTable_MatchLength, MLbits);
Yann Colletfb810d62016-01-28 00:18:06 +0100645 MLtype = FSE_ENCODING_RAW;
646 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100647 size_t NCountSize;
Yann Colletfb810d62016-01-28 00:18:06 +0100648 U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
Yann Collet14983e72015-11-11 21:38:21 +0100649 FSE_normalizeCount(norm, tableLog, count, nbSeq, max);
650 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
651 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
652 op += NCountSize;
653 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
Yann Colletfb810d62016-01-28 00:18:06 +0100654 MLtype = FSE_ENCODING_DYNAMIC;
Yann Collet14983e72015-11-11 21:38:21 +0100655 }
656
657 seqHead[0] += (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100658 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100659
660 /* Encoding Sequences */
661 {
662 size_t streamSize, errorCode;
663 BIT_CStream_t blockStream;
664 FSE_CState_t stateMatchLength;
665 FSE_CState_t stateOffsetBits;
666 FSE_CState_t stateLitLength;
667 int i;
668
669 errorCode = BIT_initCStream(&blockStream, op, oend-op);
670 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100671
Yann Collete93d6ce2016-01-31 00:58:06 +0100672 /* first symbols */
673 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlTable[nbSeq-1]);
674 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, offCodeTable[nbSeq-1]);
675 FSE_initCState2(&stateLitLength, CTable_LitLength, llTable[nbSeq-1]);
676 BIT_addBits(&blockStream, offsetTable[nbSeq-1], offCodeTable[nbSeq-1] ? (offCodeTable[nbSeq-1]-1) : 0);
677 BIT_flushBits(&blockStream);
678
679 for (i=(int)nbSeq-2; i>=0; i--) {
Yann Colletfb810d62016-01-28 00:18:06 +0100680 BYTE mlCode = mlTable[i];
Yann Collet14983e72015-11-11 21:38:21 +0100681 U32 offset = offsetTable[i];
682 BYTE offCode = offCodeTable[i]; /* 32b*/ /* 64b*/
Yann Collete93d6ce2016-01-31 00:58:06 +0100683 U32 nbBits = (offCode-1) + (!offCode);
Yann Collet14983e72015-11-11 21:38:21 +0100684 BYTE litLength = llTable[i]; /* (7)*/ /* (7)*/
Yann Colletfb810d62016-01-28 00:18:06 +0100685 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 17 */ /* 17 */
Yann Collet743402c2015-11-20 12:03:53 +0100686 if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */
Yann Collet14983e72015-11-11 21:38:21 +0100687 FSE_encodeSymbol(&blockStream, &stateLitLength, litLength); /* 26 */ /* 61 */
Yann Collete93d6ce2016-01-31 00:58:06 +0100688 FSE_encodeSymbol(&blockStream, &stateOffsetBits, offCode); /* 16 */ /* 51 */
689 if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */
690 BIT_addBits(&blockStream, offset, nbBits); /* 31 */ /* 42 */ /* 24 bits max in 32-bits mode */
Yann Collet14983e72015-11-11 21:38:21 +0100691 BIT_flushBits(&blockStream); /* 7 */ /* 7 */
692 }
693
694 FSE_flushCState(&blockStream, &stateMatchLength);
695 FSE_flushCState(&blockStream, &stateOffsetBits);
696 FSE_flushCState(&blockStream, &stateLitLength);
697
698 streamSize = BIT_closeCStream(&blockStream);
699 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
700 op += streamSize;
701 }
702
703 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100704_check_compressibility:
Yann Collet5054ee02015-11-23 13:34:21 +0100705 if ((size_t)(op-ostart) >= maxCSize) return 0;
Yann Collet14983e72015-11-11 21:38:21 +0100706
Yann Collet5054ee02015-11-23 13:34:21 +0100707 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100708}
709
710
Yann Collete93d6ce2016-01-31 00:58:06 +0100711/*! ZSTD_storeSeq
712 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t
Yann Collet14983e72015-11-11 21:38:21 +0100713 @offsetCode : distance to match, or 0 == repCode
714 @matchCode : matchLength - MINMATCH
715*/
716MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode)
717{
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100718#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100719 static const BYTE* g_start = NULL;
720 if (g_start==NULL) g_start = literals;
Yann Colletfb810d62016-01-28 00:18:06 +0100721 //if (literals - g_start == 8695)
Yann Collet14983e72015-11-11 21:38:21 +0100722 printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n",
723 (U32)(literals - g_start), (U32)litLength, (U32)matchCode+4, (U32)offsetCode);
724#endif
725
726 /* copy Literals */
727 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
728 seqStorePtr->lit += litLength;
729
730 /* literal Length */
Yann Colletfb810d62016-01-28 00:18:06 +0100731 if (litLength >= MaxLL) {
Yann Collet14983e72015-11-11 21:38:21 +0100732 *(seqStorePtr->litLength++) = MaxLL;
Yann Colletfb810d62016-01-28 00:18:06 +0100733 if (litLength<255 + MaxLL) {
Yann Collet14983e72015-11-11 21:38:21 +0100734 *(seqStorePtr->dumps++) = (BYTE)(litLength - MaxLL);
Yann Colletfb810d62016-01-28 00:18:06 +0100735 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100736 *(seqStorePtr->dumps++) = 255;
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100737 if (litLength < (1<<15)) {
738 MEM_writeLE16(seqStorePtr->dumps, (U16)(litLength<<1));
739 seqStorePtr->dumps += 2;
740 } else {
741 MEM_writeLE32(seqStorePtr->dumps, (U32)((litLength<<1)+1));
742 seqStorePtr->dumps += 3;
743 }
Yann Colletfb810d62016-01-28 00:18:06 +0100744 } }
Yann Collet14983e72015-11-11 21:38:21 +0100745 else *(seqStorePtr->litLength++) = (BYTE)litLength;
746
747 /* match offset */
748 *(seqStorePtr->offset++) = (U32)offsetCode;
749
750 /* match Length */
Yann Colletfb810d62016-01-28 00:18:06 +0100751 if (matchCode >= MaxML) {
Yann Collet14983e72015-11-11 21:38:21 +0100752 *(seqStorePtr->matchLength++) = MaxML;
Yann Colletfb810d62016-01-28 00:18:06 +0100753 if (matchCode < 255+MaxML) {
Yann Collet14983e72015-11-11 21:38:21 +0100754 *(seqStorePtr->dumps++) = (BYTE)(matchCode - MaxML);
Yann Colletfb810d62016-01-28 00:18:06 +0100755 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100756 *(seqStorePtr->dumps++) = 255;
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100757 if (matchCode < (1<<15)) {
758 MEM_writeLE16(seqStorePtr->dumps, (U16)(matchCode<<1));
759 seqStorePtr->dumps += 2;
760 } else {
761 MEM_writeLE32(seqStorePtr->dumps, (U32)((matchCode<<1)+1));
762 seqStorePtr->dumps += 3;
763 }
Yann Colletfb810d62016-01-28 00:18:06 +0100764 } }
Yann Collet14983e72015-11-11 21:38:21 +0100765 else *(seqStorePtr->matchLength++) = (BYTE)matchCode;
766}
767
768
Yann Colletf3eca252015-10-22 15:31:46 +0100769/* *************************************
Yann Collet14983e72015-11-11 21:38:21 +0100770* Match length counter
771***************************************/
772static size_t ZSTD_read_ARCH(const void* p) { size_t r; memcpy(&r, p, sizeof(r)); return r; }
773
774static unsigned ZSTD_highbit(U32 val)
775{
776# if defined(_MSC_VER) /* Visual */
777 unsigned long r=0;
778 _BitScanReverse(&r, val);
779 return (unsigned)r;
780# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
781 return 31 - __builtin_clz(val);
782# else /* Software version */
783 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 };
784 U32 v = val;
785 int r;
786 v |= v >> 1;
787 v |= v >> 2;
788 v |= v >> 4;
789 v |= v >> 8;
790 v |= v >> 16;
791 r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];
792 return r;
793# endif
794}
795
Yann Collet5054ee02015-11-23 13:34:21 +0100796static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100797{
Yann Collet863ec402016-01-28 17:56:33 +0100798 if (MEM_isLittleEndian()) {
799 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100800# if defined(_MSC_VER) && defined(_WIN64)
801 unsigned long r = 0;
802 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100803 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100804# elif defined(__GNUC__) && (__GNUC__ >= 3)
805 return (__builtin_ctzll((U64)val) >> 3);
806# else
807 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 };
808 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
809# endif
Yann Collet863ec402016-01-28 17:56:33 +0100810 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100811# if defined(_MSC_VER)
812 unsigned long r=0;
813 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100814 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100815# elif defined(__GNUC__) && (__GNUC__ >= 3)
816 return (__builtin_ctz((U32)val) >> 3);
817# else
818 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 };
819 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
820# endif
821 }
Yann Collet863ec402016-01-28 17:56:33 +0100822 } else { /* Big Endian CPU */
823 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100824# if defined(_MSC_VER) && defined(_WIN64)
825 unsigned long r = 0;
826 _BitScanReverse64( &r, val );
827 return (unsigned)(r>>3);
828# elif defined(__GNUC__) && (__GNUC__ >= 3)
829 return (__builtin_clzll(val) >> 3);
830# else
831 unsigned r;
832 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
833 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
834 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
835 r += (!val);
836 return r;
837# endif
Yann Collet863ec402016-01-28 17:56:33 +0100838 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100839# if defined(_MSC_VER)
840 unsigned long r = 0;
841 _BitScanReverse( &r, (unsigned long)val );
842 return (unsigned)(r>>3);
843# elif defined(__GNUC__) && (__GNUC__ >= 3)
844 return (__builtin_clz((U32)val) >> 3);
845# else
846 unsigned r;
847 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
848 r += (!val);
849 return r;
850# endif
Yann Collet863ec402016-01-28 17:56:33 +0100851 } }
Yann Collet14983e72015-11-11 21:38:21 +0100852}
853
854
Yann Collet5054ee02015-11-23 13:34:21 +0100855static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100856{
857 const BYTE* const pStart = pIn;
858
Yann Colletfb810d62016-01-28 00:18:06 +0100859 while ((pIn<pInLimit-(sizeof(size_t)-1))) {
Yann Collet14983e72015-11-11 21:38:21 +0100860 size_t diff = ZSTD_read_ARCH(pMatch) ^ ZSTD_read_ARCH(pIn);
861 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
862 pIn += ZSTD_NbCommonBytes(diff);
863 return (size_t)(pIn - pStart);
864 }
865
866 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
867 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
868 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
869 return (size_t)(pIn - pStart);
870}
871
Yann Collet5054ee02015-11-23 13:34:21 +0100872/** ZSTD_count_2segments
873* can count match length with ip & match in potentially 2 different segments.
874* convention : on reaching mEnd, match count continue starting from iStart
875*/
876static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
877{
878 size_t matchLength;
879 const BYTE* vEnd = ip + (mEnd - match);
880 if (vEnd > iEnd) vEnd = iEnd;
881 matchLength = ZSTD_count(ip, match, vEnd);
882 if (match + matchLength == mEnd)
883 matchLength += ZSTD_count(ip+matchLength, iStart, iEnd);
884 return matchLength;
885}
886
Yann Collet14983e72015-11-11 21:38:21 +0100887
888
Yann Collet863ec402016-01-28 17:56:33 +0100889/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100890* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100891***************************************/
Yann Collet4b100f42015-10-30 15:49:48 +0100892static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100893static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100894static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100895
Yann Collet4b100f42015-10-30 15:49:48 +0100896static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100897static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100898static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_read64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100899
900static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100901static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100902static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_read64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100903
Yann Collet14983e72015-11-11 21:38:21 +0100904static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100905static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100906static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_read64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100907
Yann Collet5be2dd22015-11-11 13:43:58 +0100908static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100909{
910 switch(mls)
911 {
912 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100913 case 4: return ZSTD_hash4Ptr(p, hBits);
914 case 5: return ZSTD_hash5Ptr(p, hBits);
915 case 6: return ZSTD_hash6Ptr(p, hBits);
916 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100917 }
918}
Yann Collet2acb5d32015-10-29 16:49:43 +0100919
Yann Collet863ec402016-01-28 17:56:33 +0100920
Yann Collet2ce49232016-02-02 14:36:49 +0100921/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +0100922* Fast Scan
923***************************************/
Yann Collet417890c2015-12-04 17:16:37 +0100924#define FILLHASHSTEP 3
925static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
926{
927 U32* const hashTable = zc->hashTable;
928 const U32 hBits = zc->params.hashLog;
929 const BYTE* const base = zc->base;
930 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet2ce49232016-02-02 14:36:49 +0100931 const BYTE* const iend = ((const BYTE*)end) - 8;
Yann Collet417890c2015-12-04 17:16:37 +0100932
Yann Colletfb810d62016-01-28 00:18:06 +0100933 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +0100934 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
935 ip += FILLHASHSTEP;
936 }
937}
938
939
Yann Collet1f44b3f2015-11-05 17:32:18 +0100940FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +0100941void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc,
Yann Collet89db5e02015-11-13 11:27:46 +0100942 const void* src, size_t srcSize,
943 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100944{
Yann Collet417890c2015-12-04 17:16:37 +0100945 U32* const hashTable = zc->hashTable;
Yann Colletc3652152015-11-24 14:06:07 +0100946 const U32 hBits = zc->params.hashLog;
947 seqStore_t* seqStorePtr = &(zc->seqStore);
948 const BYTE* const base = zc->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100949 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100950 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100951 const BYTE* anchor = istart;
Yann Colletd94efbf2015-12-29 14:29:08 +0100952 const U32 lowIndex = zc->dictLimit;
953 const BYTE* const lowest = base + lowIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100954 const BYTE* const iend = istart + srcSize;
955 const BYTE* const ilimit = iend - 8;
956
Yann Collet89db5e02015-11-13 11:27:46 +0100957 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100958
959
960 /* init */
Yann Collet743402c2015-11-20 12:03:53 +0100961 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +0100962 if (ip < lowest+REPCODE_STARTVALUE) ip = lowest+REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100963
964 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +0100965 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Collet5054ee02015-11-23 13:34:21 +0100966 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +0100967 size_t offset;
Yann Collet5be2dd22015-11-11 13:43:58 +0100968 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Colletd94efbf2015-12-29 14:29:08 +0100969 const U32 matchIndex = hashTable[h];
970 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +0100971 const U32 current = (U32)(ip-base);
972 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100973
Yann Colletfb810d62016-01-28 00:18:06 +0100974 if (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)) { /* note : by construction, offset_1 <= current */
Yann Collet5054ee02015-11-23 13:34:21 +0100975 mlCode = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +0100976 ip++;
977 offset = 0;
Yann Colletfb810d62016-01-28 00:18:06 +0100978 } else {
Yann Colletd94efbf2015-12-29 14:29:08 +0100979 if ( (matchIndex <= lowIndex) ||
Yann Colletfb810d62016-01-28 00:18:06 +0100980 (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100981 ip += ((ip-anchor) >> g_searchStrength) + 1;
982 continue;
983 }
Yann Collet5054ee02015-11-23 13:34:21 +0100984 mlCode = ZSTD_count(ip+MINMATCH, match+MINMATCH, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +0100985 offset = ip-match;
Yann Collet5054ee02015-11-23 13:34:21 +0100986 while ((ip>anchor) && (match>lowest) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +0100987 offset_2 = offset_1;
988 offset_1 = offset;
989 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100990
Yann Collet402fdcf2015-11-20 12:46:08 +0100991 /* match found */
Yann Collet6bcdeac2015-11-26 11:43:00 +0100992 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +0100993 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +0100994 anchor = ip;
995
Yann Colletfb810d62016-01-28 00:18:06 +0100996 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100997 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +0100998 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 +0100999 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1000 /* check immediate repcode */
1001 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001002 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001003 /* store sequence */
Yann Collet06eade52015-11-23 14:23:47 +01001004 size_t rlCode = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +01001005 size_t tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
1006 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Collet06eade52015-11-23 14:23:47 +01001007 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rlCode);
1008 ip += rlCode+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001009 anchor = ip;
1010 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001011 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001012
1013 /* Last Literals */
1014 {
1015 size_t lastLLSize = iend - anchor;
1016 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1017 seqStorePtr->lit += lastLLSize;
1018 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001019}
1020
1021
Yann Collet59d1f792016-01-23 19:28:41 +01001022void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
1023 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001024{
1025 const U32 mls = ctx->params.searchLength;
1026 switch(mls)
1027 {
1028 default:
1029 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001030 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001031 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001032 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001033 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001034 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001035 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001036 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001037 }
1038}
Yann Colletf3eca252015-10-22 15:31:46 +01001039
Yann Colletf3eca252015-10-22 15:31:46 +01001040
Yann Collet93a823c2015-11-13 15:08:43 +01001041//FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001042void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
1043 const void* src, size_t srcSize,
1044 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001045{
1046 U32* hashTable = ctx->hashTable;
1047 const U32 hBits = ctx->params.hashLog;
1048 seqStore_t* seqStorePtr = &(ctx->seqStore);
1049 const BYTE* const base = ctx->base;
1050 const BYTE* const dictBase = ctx->dictBase;
1051 const BYTE* const istart = (const BYTE*)src;
1052 const BYTE* ip = istart;
1053 const BYTE* anchor = istart;
1054 const U32 lowLimit = ctx->lowLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001055 const BYTE* const dictStart = dictBase + lowLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001056 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001057 const BYTE* const lowPrefixPtr = base + dictLimit;
1058 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001059 const BYTE* const iend = istart + srcSize;
1060 const BYTE* const ilimit = iend - 8;
1061
Yann Collet138e89c2015-11-17 14:26:54 +01001062 U32 offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001063
1064
1065 /* init */
1066 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001067 /* skip first position to avoid read overflow during repcode match check */
Yann Colletfb810d62016-01-28 00:18:06 +01001068 hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0);
Yann Collet61e16ce2016-01-31 02:04:15 +01001069 ip += REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001070
1071 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001072 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001073 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001074 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001075 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001076 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001077 const U32 current = (U32)(ip-base);
Yann Collet743402c2015-11-20 12:03:53 +01001078 const U32 repIndex = current + 1 - offset_1;
Yann Collet402fdcf2015-11-20 12:46:08 +01001079 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001080 const BYTE* repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001081 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001082 U32 offset;
Yann Collet89db5e02015-11-13 11:27:46 +01001083 hashTable[h] = current; /* update hash table */
1084
1085 if ( ((repIndex <= dictLimit-4) || (repIndex >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001086 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001087 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001088 mlCode = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repMatchEnd, lowPrefixPtr);
Yann Collet743402c2015-11-20 12:03:53 +01001089 ip++;
Yann Collet402fdcf2015-11-20 12:46:08 +01001090 offset = 0;
Yann Colletfb810d62016-01-28 00:18:06 +01001091 } else {
Yann Collet402fdcf2015-11-20 12:46:08 +01001092 if ( (matchIndex < lowLimit) ||
1093 (MEM_read32(match) != MEM_read32(ip)) )
1094 { ip += ((ip-anchor) >> g_searchStrength) + 1; continue; }
1095 {
1096 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001097 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1098 mlCode = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iend, matchEnd, lowPrefixPtr);
Yann Colletfb810d62016-01-28 00:18:06 +01001099 while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001100 offset = current - matchIndex;
1101 offset_2 = offset_1;
1102 offset_1 = offset;
Yann Colletfb810d62016-01-28 00:18:06 +01001103 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001104
Yann Collet5054ee02015-11-23 13:34:21 +01001105 /* found a match : store it */
1106 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +01001107 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001108 anchor = ip;
1109
Yann Colletfb810d62016-01-28 00:18:06 +01001110 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001111 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001112 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001113 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1114 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001115 while (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001116 U32 current2 = (U32)(ip-base);
1117 const U32 repIndex2 = current2 - offset_2;
1118 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet743402c2015-11-20 12:03:53 +01001119 if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001120 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001121 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1122 size_t repLength2 = ZSTD_count_2segments(ip+MINMATCH, repMatch2+MINMATCH, iend, repEnd2, lowPrefixPtr);
1123 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1124 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2);
1125 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
1126 ip += repLength2+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001127 anchor = ip;
1128 continue;
1129 }
Yann Collet743402c2015-11-20 12:03:53 +01001130 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001131 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001132
1133 /* Last Literals */
1134 {
1135 size_t lastLLSize = iend - anchor;
1136 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1137 seqStorePtr->lit += lastLLSize;
1138 }
Yann Collet89db5e02015-11-13 11:27:46 +01001139}
1140
1141
Yann Collet59d1f792016-01-23 19:28:41 +01001142void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001143 const void* src, size_t srcSize)
1144{
1145 const U32 mls = ctx->params.searchLength;
1146 switch(mls)
1147 {
1148 default:
1149 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001150 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001151 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001152 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001153 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001154 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001155 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001156 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001157 }
1158}
1159
1160
Yann Colletf3eca252015-10-22 15:31:46 +01001161/* *************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001162* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001163***************************************/
Yann Collet1358f912016-01-01 07:29:39 +01001164/** ZSTD_insertBt1 : add one or multiple positions to tree
Yann Collet6bcdeac2015-11-26 11:43:00 +01001165* @ip : assumed <= iend-8
Yann Collet06eade52015-11-23 14:23:47 +01001166* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001167static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1168 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001169{
1170 U32* const hashTable = zc->hashTable;
1171 const U32 hashLog = zc->params.hashLog;
Yann Collet5be2dd22015-11-11 13:43:58 +01001172 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet1f44b3f2015-11-05 17:32:18 +01001173 U32* const bt = zc->contentTable;
1174 const U32 btLog = zc->params.contentLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001175 const U32 btMask= (1 << btLog) - 1;
1176 U32 matchIndex = hashTable[h];
1177 size_t commonLengthSmaller=0, commonLengthLarger=0;
1178 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001179 const BYTE* const dictBase = zc->dictBase;
1180 const U32 dictLimit = zc->dictLimit;
1181 const BYTE* const dictEnd = dictBase + dictLimit;
1182 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001183 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001184 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001185 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001186 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001187 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001188 U32 dummy32; /* to be nullified at the end */
Yann Collet03526e12015-11-23 15:29:15 +01001189 const U32 windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001190 U32 matchEndIdx = current+8;
Yann Collet7beaa052016-01-21 11:57:45 +01001191 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1192 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1193 predictedSmall += (predictedSmall>0);
1194 predictedLarge += (predictedLarge>0);
Yann Colletf48e35c2015-11-07 01:13:31 +01001195
Yann Collet6c3e2e72015-12-11 10:44:07 +01001196 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001197
Yann Colletfb810d62016-01-28 00:18:06 +01001198 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001199 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001200 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001201 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1202
Yann Colletfb810d62016-01-28 00:18:06 +01001203 if (matchIndex == predictedSmall) {
1204 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001205 *smallerPtr = matchIndex;
1206 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1207 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1208 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001209 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001210 continue;
1211 }
1212
Yann Colletfb810d62016-01-28 00:18:06 +01001213 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001214 *largerPtr = matchIndex;
1215 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1216 largerPtr = nextPtr;
1217 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001218 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001219 continue;
1220 }
1221
Yann Colletfb810d62016-01-28 00:18:06 +01001222 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001223 match = base + matchIndex;
1224 if (match[matchLength] == ip[matchLength])
1225 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001226 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001227 match = dictBase + matchIndex;
1228 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1229 if (matchIndex+matchLength >= dictLimit)
1230 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1231 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001232
Yann Colletee3f4512015-12-29 22:26:09 +01001233 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001234 matchEndIdx = matchIndex + (U32)matchLength;
Yann Colletee3f4512015-12-29 22:26:09 +01001235
Yann Collet59d70632015-11-04 12:05:27 +01001236 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001237 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001238
Yann Colletfb810d62016-01-28 00:18:06 +01001239 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001240 /* match is smaller than current */
1241 *smallerPtr = matchIndex; /* update smaller idx */
1242 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001243 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001244 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001245 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001246 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001247 /* match is larger than current */
1248 *largerPtr = matchIndex;
1249 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001250 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001251 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001252 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001253 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001254
Yann Collet59d70632015-11-04 12:05:27 +01001255 *smallerPtr = *largerPtr = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001256 return (matchEndIdx > current + 8) ? matchEndIdx - current - 8 : 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001257}
1258
1259
Yann Colletee3f4512015-12-29 22:26:09 +01001260static 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 +01001261{
1262 const BYTE* const base = zc->base;
1263 const U32 target = (U32)(ip - base);
1264 U32 idx = zc->nextToUpdate;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001265
Yann Colletf48e35c2015-11-07 01:13:31 +01001266 for( ; idx < target ; )
Yann Collet1358f912016-01-01 07:29:39 +01001267 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001268}
1269
Yann Collet96b9f0b2015-11-04 03:52:54 +01001270FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Collet2cc12cb2016-01-01 07:47:58 +01001271size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001272 ZSTD_CCtx* zc,
1273 const BYTE* const ip, const BYTE* const iend,
1274 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001275 U32 nbCompares, const U32 mls,
1276 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001277{
1278 U32* const hashTable = zc->hashTable;
1279 const U32 hashLog = zc->params.hashLog;
1280 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
1281 U32* const bt = zc->contentTable;
1282 const U32 btLog = zc->params.contentLog - 1;
1283 const U32 btMask= (1 << btLog) - 1;
1284 U32 matchIndex = hashTable[h];
1285 size_t commonLengthSmaller=0, commonLengthLarger=0;
1286 const BYTE* const base = zc->base;
1287 const BYTE* const dictBase = zc->dictBase;
1288 const U32 dictLimit = zc->dictLimit;
1289 const BYTE* const dictEnd = dictBase + dictLimit;
1290 const BYTE* const prefixStart = base + dictLimit;
1291 const U32 current = (U32)(ip-base);
1292 const U32 btLow = btMask >= current ? 0 : current - btMask;
1293 const U32 windowLow = zc->lowLimit;
1294 U32* smallerPtr = bt + 2*(current&btMask);
1295 U32* largerPtr = bt + 2*(current&btMask) + 1;
1296 size_t bestLength = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001297 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001298 U32 dummy32; /* to be nullified at the end */
1299
Yann Collet6c3e2e72015-12-11 10:44:07 +01001300 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001301
Yann Colletfb810d62016-01-28 00:18:06 +01001302 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001303 U32* nextPtr = bt + 2*(matchIndex & btMask);
1304 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1305 const BYTE* match;
1306
Yann Colletfb810d62016-01-28 00:18:06 +01001307 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001308 match = base + matchIndex;
1309 if (match[matchLength] == ip[matchLength])
1310 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001311 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001312 match = dictBase + matchIndex;
1313 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001314 if (matchIndex+matchLength >= dictLimit)
1315 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001316 }
1317
Yann Colletfb810d62016-01-28 00:18:06 +01001318 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001319 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001320 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet03526e12015-11-23 15:29:15 +01001321 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
1322 bestLength = matchLength, *offsetPtr = current - matchIndex;
1323 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1324 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1325 }
1326
Yann Colletfb810d62016-01-28 00:18:06 +01001327 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001328 /* match is smaller than current */
1329 *smallerPtr = matchIndex; /* update smaller idx */
1330 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1331 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1332 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1333 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001334 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001335 /* match is larger than current */
1336 *largerPtr = matchIndex;
1337 commonLengthLarger = matchLength;
1338 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1339 largerPtr = nextPtr;
1340 matchIndex = nextPtr[0];
1341 }
1342 }
1343
1344 *smallerPtr = *largerPtr = 0;
1345
Yann Collet72e84cf2015-12-31 19:08:44 +01001346 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
Yann Collet03526e12015-11-23 15:29:15 +01001347 return bestLength;
1348}
1349
Yann Collet2cc12cb2016-01-01 07:47:58 +01001350
1351/** Tree updater, providing best match */
1352FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1353size_t ZSTD_BtFindBestMatch (
1354 ZSTD_CCtx* zc,
1355 const BYTE* const ip, const BYTE* const iLimit,
1356 size_t* offsetPtr,
1357 const U32 maxNbAttempts, const U32 mls)
1358{
1359 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1360 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
1361 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1362}
1363
1364
1365FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS (
1366 ZSTD_CCtx* zc, /* Index table will be updated */
1367 const BYTE* ip, const BYTE* const iLimit,
1368 size_t* offsetPtr,
1369 const U32 maxNbAttempts, const U32 matchLengthSearch)
1370{
1371 switch(matchLengthSearch)
1372 {
1373 default :
1374 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1375 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1376 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1377 }
1378}
1379
1380
1381static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1382{
1383 const BYTE* const base = zc->base;
1384 const U32 target = (U32)(ip - base);
1385 U32 idx = zc->nextToUpdate;
1386
1387 for( ; idx < target ; )
1388 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1389}
1390
1391
Yann Collet03526e12015-11-23 15:29:15 +01001392/** Tree updater, providing best match */
1393FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1394size_t ZSTD_BtFindBestMatch_extDict (
1395 ZSTD_CCtx* zc,
1396 const BYTE* const ip, const BYTE* const iLimit,
1397 size_t* offsetPtr,
1398 const U32 maxNbAttempts, const U32 mls)
1399{
Yann Colletee3f4512015-12-29 22:26:09 +01001400 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
1401 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001402 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001403}
1404
1405
1406FORCE_INLINE size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
1407 ZSTD_CCtx* zc, /* Index table will be updated */
1408 const BYTE* ip, const BYTE* const iLimit,
1409 size_t* offsetPtr,
1410 const U32 maxNbAttempts, const U32 matchLengthSearch)
1411{
1412 switch(matchLengthSearch)
1413 {
1414 default :
1415 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1416 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1417 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1418 }
1419}
1420
1421
Yann Collet5106a762015-11-05 15:00:24 +01001422/* ***********************
1423* Hash Chain
1424*************************/
1425
Yann Collet1f44b3f2015-11-05 17:32:18 +01001426#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1427
Yann Collet6bcdeac2015-11-26 11:43:00 +01001428/* Update chains up to ip (excluded)
Yann Collet06eade52015-11-23 14:23:47 +01001429 Assumption : always within prefix (ie. not within extDict) */
1430static U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
Yann Collet5106a762015-11-05 15:00:24 +01001431{
1432 U32* const hashTable = zc->hashTable;
1433 const U32 hashLog = zc->params.hashLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001434 U32* const chainTable = zc->contentTable;
1435 const U32 chainMask = (1 << zc->params.contentLog) - 1;
Yann Collet5106a762015-11-05 15:00:24 +01001436 const BYTE* const base = zc->base;
1437 const U32 target = (U32)(ip - base);
1438 U32 idx = zc->nextToUpdate;
1439
Yann Colletfb810d62016-01-28 00:18:06 +01001440 while(idx < target) {
Yann Collet5be2dd22015-11-11 13:43:58 +01001441 size_t h = ZSTD_hashPtr(base+idx, hashLog, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001442 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1443 hashTable[h] = idx;
1444 idx++;
1445 }
1446
1447 zc->nextToUpdate = target;
Yann Collet5be2dd22015-11-11 13:43:58 +01001448 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
Yann Collet5106a762015-11-05 15:00:24 +01001449}
1450
1451
1452FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Colletc1e52f02015-11-23 14:37:59 +01001453size_t ZSTD_HcFindBestMatch_generic (
Yann Collet5be2dd22015-11-11 13:43:58 +01001454 ZSTD_CCtx* zc, /* Index table will be updated */
Yann Collet5106a762015-11-05 15:00:24 +01001455 const BYTE* const ip, const BYTE* const iLimit,
1456 size_t* offsetPtr,
Yann Colletc1e52f02015-11-23 14:37:59 +01001457 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
Yann Collet287b7d92015-11-22 13:24:05 +01001458{
Yann Collet1f44b3f2015-11-05 17:32:18 +01001459 U32* const chainTable = zc->contentTable;
1460 const U32 chainSize = (1 << zc->params.contentLog);
Yann Collet5106a762015-11-05 15:00:24 +01001461 const U32 chainMask = chainSize-1;
1462 const BYTE* const base = zc->base;
1463 const BYTE* const dictBase = zc->dictBase;
1464 const U32 dictLimit = zc->dictLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001465 const BYTE* const prefixStart = base + dictLimit;
1466 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001467 const U32 lowLimit = zc->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001468 const U32 current = (U32)(ip-base);
1469 const U32 minChain = current > chainSize ? current - chainSize : 0;
Yann Collet5106a762015-11-05 15:00:24 +01001470 U32 matchIndex;
1471 const BYTE* match;
1472 int nbAttempts=maxNbAttempts;
Yann Collet5054ee02015-11-23 13:34:21 +01001473 size_t ml=MINMATCH-1;
Yann Collet5106a762015-11-05 15:00:24 +01001474
1475 /* HC4 match finder */
Yann Colletc1e52f02015-11-23 14:37:59 +01001476 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001477
Yann Colletfb810d62016-01-28 00:18:06 +01001478 while ((matchIndex>lowLimit) && (nbAttempts)) {
Yann Collet5054ee02015-11-23 13:34:21 +01001479 size_t currentMl=0;
Yann Collet5106a762015-11-05 15:00:24 +01001480 nbAttempts--;
Yann Colletfb810d62016-01-28 00:18:06 +01001481 if ((!extDict) || matchIndex >= dictLimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001482 match = base + matchIndex;
Yann Collet4baee502015-11-09 03:19:33 +01001483 if (match[ml] == ip[ml]) /* potentially better */
Yann Collet5054ee02015-11-23 13:34:21 +01001484 currentMl = ZSTD_count(ip, match, iLimit);
Yann Colletfb810d62016-01-28 00:18:06 +01001485 } else {
Yann Collet5106a762015-11-05 15:00:24 +01001486 match = dictBase + matchIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001487 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1488 currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
Yann Collet5106a762015-11-05 15:00:24 +01001489 }
1490
Yann Collet5054ee02015-11-23 13:34:21 +01001491 /* save best solution */
Yann Collet239cc282015-11-23 16:17:21 +01001492 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 +01001493
Yann Collet9a24e592015-11-22 02:53:43 +01001494 if (matchIndex <= minChain) break;
Yann Collet5106a762015-11-05 15:00:24 +01001495 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1496 }
1497
1498 return ml;
1499}
1500
1501
Yann Colletc1e52f02015-11-23 14:37:59 +01001502FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1503 ZSTD_CCtx* zc,
Yann Collet5106a762015-11-05 15:00:24 +01001504 const BYTE* ip, const BYTE* const iLimit,
1505 size_t* offsetPtr,
1506 const U32 maxNbAttempts, const U32 matchLengthSearch)
1507{
1508 switch(matchLengthSearch)
1509 {
1510 default :
Yann Colletc1e52f02015-11-23 14:37:59 +01001511 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1512 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1513 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1514 }
1515}
1516
1517
1518FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1519 ZSTD_CCtx* zc,
1520 const BYTE* ip, const BYTE* const iLimit,
1521 size_t* offsetPtr,
1522 const U32 maxNbAttempts, const U32 matchLengthSearch)
1523{
1524 switch(matchLengthSearch)
1525 {
1526 default :
1527 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1528 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1529 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001530 }
1531}
1532
1533
Yann Collet287b7d92015-11-22 13:24:05 +01001534/* *******************************
Yann Collet9a24e592015-11-22 02:53:43 +01001535* Common parser - lazy strategy
Yann Collet287b7d92015-11-22 13:24:05 +01001536*********************************/
Yann Collet5106a762015-11-05 15:00:24 +01001537FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001538void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1539 const void* src, size_t srcSize,
Yann Collet007c1c62015-11-22 02:42:28 +01001540 const U32 searchMethod, const U32 depth)
Yann Collet5106a762015-11-05 15:00:24 +01001541{
1542 seqStore_t* seqStorePtr = &(ctx->seqStore);
1543 const BYTE* const istart = (const BYTE*)src;
1544 const BYTE* ip = istart;
1545 const BYTE* anchor = istart;
1546 const BYTE* const iend = istart + srcSize;
1547 const BYTE* const ilimit = iend - 8;
Yann Collete47c4e52015-12-05 09:23:53 +01001548 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet5106a762015-11-05 15:00:24 +01001549
1550 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1551 const U32 maxSearches = 1 << ctx->params.searchLog;
1552 const U32 mls = ctx->params.searchLength;
1553
Yann Collet5be2dd22015-11-11 13:43:58 +01001554 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
Yann Collet5106a762015-11-05 15:00:24 +01001555 size_t* offsetPtr,
1556 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet5be2dd22015-11-11 13:43:58 +01001557 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet5106a762015-11-05 15:00:24 +01001558
1559 /* init */
1560 ZSTD_resetSeqStore(seqStorePtr);
Yann Collete47c4e52015-12-05 09:23:53 +01001561 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet5106a762015-11-05 15:00:24 +01001562
1563 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001564 while (ip < ilimit) {
Yann Collet7a231792015-11-21 15:27:35 +01001565 size_t matchLength=0;
1566 size_t offset=0;
1567 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001568
Yann Collet743402c2015-11-20 12:03:53 +01001569 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001570 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1)) {
Yann Collet743402c2015-11-20 12:03:53 +01001571 /* repcode : we take it */
Yann Collet7a231792015-11-21 15:27:35 +01001572 matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH;
Yann Collet007c1c62015-11-22 02:42:28 +01001573 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001574 }
1575
Yann Colletfc2afcf2015-11-06 15:40:14 +01001576 {
Yann Collet239cc282015-11-23 16:17:21 +01001577 /* first search (depth 0) */
1578 size_t offsetFound = 99999999;
1579 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1580 if (ml2 > matchLength)
1581 matchLength = ml2, start = ip, offset=offsetFound;
1582 }
Yann Collet9a24e592015-11-22 02:53:43 +01001583
Yann Colletfb810d62016-01-28 00:18:06 +01001584 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001585 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1586 continue;
1587 }
Yann Collet5106a762015-11-05 15:00:24 +01001588
1589 /* let's try to find a better solution */
Yann Collet007c1c62015-11-22 02:42:28 +01001590 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001591 while (ip<ilimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001592 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001593 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet007c1c62015-11-22 02:42:28 +01001594 size_t mlRep = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1595 int gain2 = (int)(mlRep * 3);
Yann Collet5106a762015-11-05 15:00:24 +01001596 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet007c1c62015-11-22 02:42:28 +01001597 if ((mlRep >= MINMATCH) && (gain2 > gain1))
1598 matchLength = mlRep, offset = 0, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001599 }
1600 {
1601 size_t offset2=999999;
1602 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet007c1c62015-11-22 02:42:28 +01001603 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1604 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001605 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001606 matchLength = ml2, offset = offset2, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001607 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001608 } }
Yann Collet5106a762015-11-05 15:00:24 +01001609
1610 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001611 if ((depth==2) && (ip<ilimit)) {
Yann Collet5106a762015-11-05 15:00:24 +01001612 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001613 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet5106a762015-11-05 15:00:24 +01001614 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1615 int gain2 = (int)(ml2 * 4);
1616 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet4baee502015-11-09 03:19:33 +01001617 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001618 matchLength = ml2, offset = 0, start = ip;
1619 }
1620 {
1621 size_t offset2=999999;
1622 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet628065c2015-11-06 18:44:54 +01001623 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1624 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001625 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001626 matchLength = ml2, offset = offset2, start = ip;
1627 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001628 } } }
Yann Collet5106a762015-11-05 15:00:24 +01001629 break; /* nothing found : store previous solution */
1630 }
1631
Yann Collet4baee502015-11-09 03:19:33 +01001632 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001633 if (offset) {
Yann Collete47c4e52015-12-05 09:23:53 +01001634 while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */
Yann Collet4baee502015-11-09 03:19:33 +01001635 { start--; matchLength++; }
Yann Collet743402c2015-11-20 12:03:53 +01001636 offset_2 = offset_1; offset_1 = offset;
Yann Collet4baee502015-11-09 03:19:33 +01001637 }
1638
1639 /* store sequence */
Yann Collet7a231792015-11-21 15:27:35 +01001640_storeSequence:
Yann Collet5106a762015-11-05 15:00:24 +01001641 {
1642 size_t litLength = start - anchor;
Yann Collet5106a762015-11-05 15:00:24 +01001643 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
Yann Collet4baee502015-11-09 03:19:33 +01001644 anchor = ip = start + matchLength;
Yann Collet5106a762015-11-05 15:00:24 +01001645 }
1646
Yann Collet743402c2015-11-20 12:03:53 +01001647 /* check immediate repcode */
1648 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001649 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet743402c2015-11-20 12:03:53 +01001650 /* store sequence */
1651 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
1652 offset = offset_2;
1653 offset_2 = offset_1;
1654 offset_1 = offset;
1655 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength);
1656 ip += matchLength+MINMATCH;
1657 anchor = ip;
1658 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001659 } }
Yann Collet5106a762015-11-05 15:00:24 +01001660
1661 /* Last Literals */
1662 {
1663 size_t lastLLSize = iend - anchor;
1664 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1665 seqStorePtr->lit += lastLLSize;
1666 }
Yann Collet5106a762015-11-05 15:00:24 +01001667}
1668
Yann Collet59d1f792016-01-23 19:28:41 +01001669static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001670{
Yann Colleta1249dc2016-01-25 04:22:03 +01001671 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001672}
1673
Yann Collet59d1f792016-01-23 19:28:41 +01001674static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001675{
Yann Colleta1249dc2016-01-25 04:22:03 +01001676 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001677}
1678
Yann Collet59d1f792016-01-23 19:28:41 +01001679static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001680{
Yann Colleta1249dc2016-01-25 04:22:03 +01001681 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001682}
1683
Yann Collet59d1f792016-01-23 19:28:41 +01001684static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01001685{
Yann Colleta1249dc2016-01-25 04:22:03 +01001686 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
Yann Colletbe2010e2015-10-31 12:57:14 +01001687}
1688
1689
Yann Collet9a24e592015-11-22 02:53:43 +01001690FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001691void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1692 const void* src, size_t srcSize,
Yann Collet9a24e592015-11-22 02:53:43 +01001693 const U32 searchMethod, const U32 depth)
1694{
1695 seqStore_t* seqStorePtr = &(ctx->seqStore);
1696 const BYTE* const istart = (const BYTE*)src;
1697 const BYTE* ip = istart;
1698 const BYTE* anchor = istart;
1699 const BYTE* const iend = istart + srcSize;
1700 const BYTE* const ilimit = iend - 8;
1701 const BYTE* const base = ctx->base;
1702 const U32 dictLimit = ctx->dictLimit;
1703 const BYTE* const prefixStart = base + dictLimit;
1704 const BYTE* const dictBase = ctx->dictBase;
1705 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001706 const BYTE* const dictStart = dictBase + ctx->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001707
1708 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1709 const U32 maxSearches = 1 << ctx->params.searchLog;
1710 const U32 mls = ctx->params.searchLength;
1711
1712 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1713 size_t* offsetPtr,
1714 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet03526e12015-11-23 15:29:15 +01001715 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
Yann Collet9a24e592015-11-22 02:53:43 +01001716
1717 /* init */
1718 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet6c3e2e72015-12-11 10:44:07 +01001719 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Collet9a24e592015-11-22 02:53:43 +01001720
1721 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001722 while (ip < ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001723 size_t matchLength=0;
1724 size_t offset=0;
1725 const BYTE* start=ip+1;
1726 U32 current = (U32)(ip-base);
1727
1728 /* check repCode */
1729 {
1730 const U32 repIndex = (U32)(current+1 - offset_1);
1731 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1732 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001733 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001734 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001735 /* repcode detected we should take it */
1736 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001737 matchLength = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
Yann Collet9a24e592015-11-22 02:53:43 +01001738 if (depth==0) goto _storeSequence;
Yann Colletfb810d62016-01-28 00:18:06 +01001739 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001740
1741 {
Yann Collet239cc282015-11-23 16:17:21 +01001742 /* first search (depth 0) */
1743 size_t offsetFound = 99999999;
1744 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1745 if (ml2 > matchLength)
1746 matchLength = ml2, start = ip, offset=offsetFound;
1747 }
Yann Collet9a24e592015-11-22 02:53:43 +01001748
Yann Colletfb810d62016-01-28 00:18:06 +01001749 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001750 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1751 continue;
1752 }
Yann Collet9a24e592015-11-22 02:53:43 +01001753
1754 /* let's try to find a better solution */
1755 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001756 while (ip<ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001757 ip ++;
1758 current++;
1759 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001760 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001761 const U32 repIndex = (U32)(current - offset_1);
1762 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1763 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001764 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001765 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001766 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001767 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001768 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1769 int gain2 = (int)(repLength * 3);
1770 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1771 if ((repLength >= MINMATCH) && (gain2 > gain1))
1772 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001773 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001774
1775 /* search match, depth 1 */
1776 {
1777 size_t offset2=999999;
1778 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1779 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1780 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001781 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001782 matchLength = ml2, offset = offset2, start = ip;
1783 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001784 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001785
1786 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001787 if ((depth==2) && (ip<ilimit)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001788 ip ++;
1789 current++;
1790 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001791 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001792 const U32 repIndex = (U32)(current - offset_1);
1793 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1794 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001795 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001796 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001797 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001798 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001799 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1800 int gain2 = (int)(repLength * 4);
1801 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1802 if ((repLength >= MINMATCH) && (gain2 > gain1))
1803 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001804 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001805
1806 /* search match, depth 2 */
1807 {
1808 size_t offset2=999999;
1809 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1810 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1811 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001812 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001813 matchLength = ml2, offset = offset2, start = ip;
1814 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001815 } } }
Yann Collet9a24e592015-11-22 02:53:43 +01001816 break; /* nothing found : store previous solution */
1817 }
1818
1819 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001820 if (offset) {
Yann Colletc3652152015-11-24 14:06:07 +01001821 U32 matchIndex = (U32)((start-base) - offset);
1822 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1823 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
1824 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet9a24e592015-11-22 02:53:43 +01001825 offset_2 = offset_1; offset_1 = offset;
1826 }
1827
1828 /* store sequence */
1829_storeSequence:
1830 {
1831 size_t litLength = start - anchor;
1832 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1833 anchor = ip = start + matchLength;
1834 }
1835
1836 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001837 while (ip <= ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001838 const U32 repIndex = (U32)((ip-base) - offset_2);
1839 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1840 const BYTE* const repMatch = repBase + repIndex;
Yann Collet239cc282015-11-23 16:17:21 +01001841 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001842 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001843 /* repcode detected we should take it */
1844 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001845 matchLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1846 offset = offset_2; offset_2 = offset_1; offset_1 = offset; /* swap offset history */
Yann Collet9a24e592015-11-22 02:53:43 +01001847 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1848 ip += matchLength;
1849 anchor = ip;
1850 continue; /* faster when present ... (?) */
1851 }
1852 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001853 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001854
1855 /* Last Literals */
1856 {
1857 size_t lastLLSize = iend - anchor;
1858 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1859 seqStorePtr->lit += lastLLSize;
1860 }
Yann Collet9a24e592015-11-22 02:53:43 +01001861}
1862
Yann Collet59d1f792016-01-23 19:28:41 +01001863void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01001864{
Yann Colleta1249dc2016-01-25 04:22:03 +01001865 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01001866}
1867
Yann Collet59d1f792016-01-23 19:28:41 +01001868static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01001869{
Yann Colleta1249dc2016-01-25 04:22:03 +01001870 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01001871}
Yann Collet9a24e592015-11-22 02:53:43 +01001872
Yann Collet59d1f792016-01-23 19:28:41 +01001873static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01001874{
Yann Colleta1249dc2016-01-25 04:22:03 +01001875 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01001876}
1877
Yann Collet59d1f792016-01-23 19:28:41 +01001878static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01001879{
Yann Colleta1249dc2016-01-25 04:22:03 +01001880 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001881}
1882
Yann Collet7a231792015-11-21 15:27:35 +01001883
Yann Collet59d1f792016-01-23 19:28:41 +01001884typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01001885
Yann Colletb923f652016-01-26 03:14:20 +01001886static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01001887{
Yann Collet7fe531e2015-11-29 02:38:09 +01001888 static const ZSTD_blockCompressor blockCompressor[2][5] = {
1889 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy,ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2 },
1890 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict }
1891 };
1892
1893 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01001894}
1895
1896
Yann Colletbf42c8e2016-01-09 01:08:23 +01001897static 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 +01001898{
Yann Collet03526e12015-11-23 15:29:15 +01001899 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01001900 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 +01001901 blockCompressor(zc, src, srcSize);
Yann Colletb923f652016-01-26 03:14:20 +01001902 return ZSTD_compressSequences(zc, dst, maxDstSize, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01001903}
1904
1905
Yann Collet2ce49232016-02-02 14:36:49 +01001906static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
Yann Colletf3eca252015-10-22 15:31:46 +01001907 void* dst, size_t maxDstSize,
1908 const void* src, size_t srcSize)
1909{
Yann Collet2ce49232016-02-02 14:36:49 +01001910 size_t blockSize = zc->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001911 size_t remaining = srcSize;
1912 const BYTE* ip = (const BYTE*)src;
1913 BYTE* const ostart = (BYTE*)dst;
1914 BYTE* op = ostart;
Yann Collet2ce49232016-02-02 14:36:49 +01001915 const U32 maxDist = 1 << zc->params.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01001916
Yann Collet2ce49232016-02-02 14:36:49 +01001917 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01001918 size_t cSize;
1919
Yann Collet2ce49232016-02-02 14:36:49 +01001920 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 +01001921 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01001922
Yann Collet2ce49232016-02-02 14:36:49 +01001923 if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */
Yann Collet7a6343f2016-02-02 16:00:50 +01001924 U32 newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist;
1925 if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01001926 if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001927 }
Yann Collet89db5e02015-11-13 11:27:46 +01001928
Yann Collet2ce49232016-02-02 14:36:49 +01001929 cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, maxDstSize-ZSTD_blockHeaderSize, ip, blockSize);
Yann Collet3e358272015-11-04 18:19:39 +01001930 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001931
Yann Collet2ce49232016-02-02 14:36:49 +01001932 if (cSize == 0) { /* block is not compressible */
1933 cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize);
Yann Collet523b5942016-01-09 02:10:40 +01001934 if (ZSTD_isError(cSize)) return cSize;
Yann Collet2ce49232016-02-02 14:36:49 +01001935 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01001936 op[0] = (BYTE)(cSize>>16);
1937 op[1] = (BYTE)(cSize>>8);
1938 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01001939 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01001940 cSize += 3;
1941 }
1942
1943 remaining -= blockSize;
Yann Collet3e358272015-11-04 18:19:39 +01001944 maxDstSize -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001945 ip += blockSize;
1946 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001947 }
1948
1949 return op-ostart;
1950}
1951
1952
Yann Colletbf42c8e2016-01-09 01:08:23 +01001953static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
1954 void* dst, size_t dstSize,
1955 const void* src, size_t srcSize,
1956 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01001957{
Yann Collet2acb5d32015-10-29 16:49:43 +01001958 const BYTE* const ip = (const BYTE*) src;
Yann Colletecd651b2016-01-07 15:35:18 +01001959 size_t hbSize = 0;
1960
Yann Collet2ce49232016-02-02 14:36:49 +01001961 if (frame && (zc->stage==0)) {
Yann Colletecd651b2016-01-07 15:35:18 +01001962 hbSize = zc->hbSize;
1963 if (dstSize <= hbSize) return ERROR(dstSize_tooSmall);
1964 zc->stage = 1;
1965 memcpy(dst, zc->headerBuffer, hbSize);
1966 dstSize -= hbSize;
1967 dst = (char*)dst + hbSize;
1968 }
Yann Colletf3eca252015-10-22 15:31:46 +01001969
Yann Collet417890c2015-12-04 17:16:37 +01001970 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01001971 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01001972 /* not contiguous */
1973 size_t delta = zc->nextSrc - ip;
1974 zc->lowLimit = zc->dictLimit;
1975 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
1976 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01001977 zc->base -= delta;
1978 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01001979 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01001980 }
1981
Yann Collet89db5e02015-11-13 11:27:46 +01001982 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01001983 if (zc->lowLimit > (1<<30)) {
Yann Collet6c3e2e72015-12-11 10:44:07 +01001984 U32 btplus = (zc->params.strategy == ZSTD_btlazy2);
1985 U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1;
1986 U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */
1987 U32 correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001988 ZSTD_reduceIndex(zc, correction);
1989 zc->base += correction;
1990 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001991 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001992 zc->dictLimit -= correction;
1993 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
1994 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01001995 }
1996
Yann Colletbf42c8e2016-01-09 01:08:23 +01001997 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01001998 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01001999 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2000 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002001 }
2002
Yann Colletc3652152015-11-24 14:06:07 +01002003 zc->nextSrc = ip + srcSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002004 {
Yann Colletbf42c8e2016-01-09 01:08:23 +01002005 size_t cSize;
2006 if (frame) cSize = ZSTD_compress_generic (zc, dst, dstSize, src, srcSize);
2007 else cSize = ZSTD_compressBlock_internal (zc, dst, dstSize, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002008 if (ZSTD_isError(cSize)) return cSize;
2009 return cSize + hbSize;
2010 }
Yann Colletf3eca252015-10-22 15:31:46 +01002011}
2012
Yann Colletbf42c8e2016-01-09 01:08:23 +01002013
2014size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
2015 void* dst, size_t dstSize,
2016 const void* src, size_t srcSize)
2017{
2018 return ZSTD_compressContinue_internal(zc, dst, dstSize, src, srcSize, 1);
2019}
2020
2021
2022size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
2023{
2024 if (srcSize > BLOCKSIZE) return ERROR(srcSize_wrong);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002025 return ZSTD_compressContinue_internal(zc, dst, maxDstSize, src, srcSize, 0);
2026}
2027
2028
Yann Colletb923f652016-01-26 03:14:20 +01002029static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002030{
2031 const BYTE* const ip = (const BYTE*) src;
2032 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002033
Yann Collet417890c2015-12-04 17:16:37 +01002034 /* input becomes current prefix */
2035 zc->lowLimit = zc->dictLimit;
2036 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2037 zc->dictBase = zc->base;
2038 zc->base += ip - zc->nextSrc;
2039 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002040 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002041
2042 zc->nextSrc = iend;
2043 if (srcSize <= 8) return 0;
2044
2045 switch(zc->params.strategy)
2046 {
2047 case ZSTD_fast:
Yann Collet2ce49232016-02-02 14:36:49 +01002048 ZSTD_fillHashTable (zc, iend, zc->params.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002049 break;
2050
2051 case ZSTD_greedy:
2052 case ZSTD_lazy:
2053 case ZSTD_lazy2:
2054 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength);
2055 break;
2056
2057 case ZSTD_btlazy2:
2058 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength);
2059 break;
2060
2061 default:
2062 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2063 }
2064
Yann Collet2ce49232016-02-02 14:36:49 +01002065 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002066 return 0;
2067}
2068
2069
Yann Colletb923f652016-01-26 03:14:20 +01002070/* Dictionary format :
2071 Magic == ZSTD_DICT_MAGIC (4 bytes)
2072 Huff0 CTable (256 * 4 bytes) => to be changed to read from writeCTable
2073 Dictionary content
2074*/
2075/*! ZSTD_loadDictEntropyStats
2076 @return : size read from dictionary */
2077static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2078{
2079 /* note : magic number already checked */
Yann Colletfb810d62016-01-28 00:18:06 +01002080 size_t offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize, errorCode;
2081 short offcodeNCount[MaxOff+1];
2082 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2083 short matchlengthNCount[MaxML+1];
2084 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2085 short litlengthNCount[MaxLL+1];
2086 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2087
Yann Colletb923f652016-01-26 03:14:20 +01002088 const size_t hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize);
2089 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Colletfb810d62016-01-28 00:18:06 +01002090 zc->flagStaticTables = 1;
2091 dict = (const char*)dict + hufHeaderSize;
2092 dictSize -= hufHeaderSize;
2093
2094 offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
2095 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2096 errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2097 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2098 dict = (const char*)dict + offcodeHeaderSize;
2099 dictSize -= offcodeHeaderSize;
2100
2101 matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
2102 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2103 errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2104 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2105 dict = (const char*)dict + matchlengthHeaderSize;
2106 dictSize -= matchlengthHeaderSize;
2107
2108 litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
2109 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2110 errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2111 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2112
2113 return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
Yann Colletb923f652016-01-26 03:14:20 +01002114}
2115
Yann Colletfb810d62016-01-28 00:18:06 +01002116
Yann Collet1c8e1942016-01-26 16:31:22 +01002117static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002118{
Yann Collet2ce49232016-02-02 14:36:49 +01002119 if (dict && (dictSize>4)) {
Yann Collet7b51a292016-01-26 15:58:49 +01002120 U32 magic = MEM_readLE32(dict);
2121 size_t eSize;
2122 if (magic != ZSTD_DICT_MAGIC)
2123 return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletb923f652016-01-26 03:14:20 +01002124
Yann Collet7b51a292016-01-26 15:58:49 +01002125 eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4, dictSize-4) + 4;
2126 if (ZSTD_isError(eSize)) return eSize;
2127 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
2128 }
Yann Colletecd651b2016-01-07 15:35:18 +01002129 return 0;
2130}
2131
2132
Yann Collet417890c2015-12-04 17:16:37 +01002133/*! ZSTD_compressBegin_advanced
Yann Colletecd651b2016-01-07 15:35:18 +01002134* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002135size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
2136 const void* dict, size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002137 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002138{
Yann Collet4114f952015-10-30 06:40:22 +01002139 size_t errorCode;
Yann Collet88fcd292015-11-25 14:42:45 +01002140
2141 ZSTD_validateParams(&params);
2142
Yann Collet1c8e1942016-01-26 16:31:22 +01002143 errorCode = ZSTD_resetCCtx_advanced(zc, params);
Yann Collet4114f952015-10-30 06:40:22 +01002144 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet89db5e02015-11-13 11:27:46 +01002145
Yann Collet1c8e1942016-01-26 16:31:22 +01002146 MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */
2147 ((BYTE*)zc->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN);
2148 zc->hbSize = ZSTD_frameHeaderSize_min;
2149 zc->stage = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002150
Yann Collet1c8e1942016-01-26 16:31:22 +01002151 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002152}
2153
2154
Yann Collet1c8e1942016-01-26 16:31:22 +01002155size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002156{
Yann Collet953ce722016-02-04 15:28:14 +01002157 return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, MAX(128 KB, dictSize)));
Yann Collet1c8e1942016-01-26 16:31:22 +01002158}
Yann Collet083fcc82015-10-25 14:06:35 +01002159
Yann Collet1c8e1942016-01-26 16:31:22 +01002160size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002161{
Yann Collet1c8e1942016-01-26 16:31:22 +01002162 return ZSTD_compressBegin_advanced(zc, NULL, 0, ZSTD_getParams(compressionLevel, 0));
Yann Collet083fcc82015-10-25 14:06:35 +01002163}
2164
2165
Yann Collet31683c02015-12-18 01:26:48 +01002166/*! ZSTD_compressEnd
Yann Collet88fcd292015-11-25 14:42:45 +01002167* Write frame epilogue
2168* @return : nb of bytes written into dst (or an error code) */
Yann Colletecd651b2016-01-07 15:35:18 +01002169size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize)
Yann Collet2acb5d32015-10-29 16:49:43 +01002170{
2171 BYTE* op = (BYTE*)dst;
Yann Colletecd651b2016-01-07 15:35:18 +01002172 size_t hbSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002173
Yann Colletecd651b2016-01-07 15:35:18 +01002174 /* empty frame */
Yann Colletfb810d62016-01-28 00:18:06 +01002175 if (zc->stage==0) {
Yann Colletecd651b2016-01-07 15:35:18 +01002176 hbSize = zc->hbSize;
2177 if (maxDstSize <= hbSize) return ERROR(dstSize_tooSmall);
2178 zc->stage = 1;
2179 memcpy(dst, zc->headerBuffer, hbSize);
2180 maxDstSize -= hbSize;
2181 op += hbSize;
2182 }
2183
2184 /* frame epilogue */
Yann Collet2acb5d32015-10-29 16:49:43 +01002185 if (maxDstSize < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002186 op[0] = (BYTE)(bt_end << 6);
2187 op[1] = 0;
2188 op[2] = 0;
2189
Yann Colletecd651b2016-01-07 15:35:18 +01002190 return 3+hbSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002191}
2192
Yann Colletfd416f12016-01-30 03:14:15 +01002193
2194size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
2195 void* dst, size_t maxDstSize,
2196 const void* src, size_t srcSize)
2197{
2198 size_t outSize;
2199 size_t errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2200 if (ZSTD_isError(errorCode)) return errorCode;
2201 errorCode = ZSTD_compressContinue(cctx, dst, maxDstSize, src, srcSize);
2202 if (ZSTD_isError(errorCode)) return errorCode;
2203 outSize = errorCode;
2204 errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, maxDstSize-outSize);
2205 if (ZSTD_isError(errorCode)) return errorCode;
2206 outSize += errorCode;
2207 return outSize;
2208}
2209
2210
Yann Collet5be2dd22015-11-11 13:43:58 +01002211size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
Yann Collet88fcd292015-11-25 14:42:45 +01002212 void* dst, size_t maxDstSize,
2213 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002214 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002215 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002216{
2217 BYTE* const ostart = (BYTE*)dst;
2218 BYTE* op = ostart;
Yann Collet4114f952015-10-30 06:40:22 +01002219 size_t oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002220
Yann Collet1c8e1942016-01-26 16:31:22 +01002221 /* Init */
2222 oSize = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params);
Yann Colletf3eca252015-10-22 15:31:46 +01002223 if(ZSTD_isError(oSize)) return oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002224
2225 /* body (compression) */
Yann Collet31683c02015-12-18 01:26:48 +01002226 oSize = ZSTD_compressContinue (ctx, op, maxDstSize, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002227 if(ZSTD_isError(oSize)) return oSize;
2228 op += oSize;
2229 maxDstSize -= oSize;
2230
2231 /* Close frame */
Yann Collet5be2dd22015-11-11 13:43:58 +01002232 oSize = ZSTD_compressEnd(ctx, op, maxDstSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002233 if(ZSTD_isError(oSize)) return oSize;
2234 op += oSize;
2235
2236 return (op - ostart);
2237}
2238
Yann Collet31683c02015-12-18 01:26:48 +01002239size_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)
2240{
Yann Collet2ce49232016-02-02 14:36:49 +01002241 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet31683c02015-12-18 01:26:48 +01002242}
2243
Yann Collet5be2dd22015-11-11 13:43:58 +01002244size_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 +01002245{
Yann Collet31683c02015-12-18 01:26:48 +01002246 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet083fcc82015-10-25 14:06:35 +01002247}
2248
Yann Collet5be2dd22015-11-11 13:43:58 +01002249size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002250{
Yann Collet44fe9912015-10-29 22:02:40 +01002251 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002252 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002253 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Collet5be2dd22015-11-11 13:43:58 +01002254 result = ZSTD_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel);
Yann Colletecd651b2016-01-07 15:35:18 +01002255 free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002256 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002257}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002258
Yann Colletfd416f12016-01-30 03:14:15 +01002259
2260/*- Pre-defined compression levels -*/
2261
Yann Collet7d968c72016-02-03 02:11:32 +01002262unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2263
Yann Colletfd416f12016-01-30 03:14:15 +01002264static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = {
2265{ /* "default" */
2266 /* W, C, H, S, L, strat */
2267 { 0, 18, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */
2268 { 0, 19, 13, 14, 1, 7, ZSTD_fast }, /* level 1 */
2269 { 0, 19, 15, 16, 1, 6, ZSTD_fast }, /* level 2 */
2270 { 0, 20, 18, 20, 1, 6, ZSTD_fast }, /* level 3 */
2271 { 0, 21, 19, 21, 1, 6, ZSTD_fast }, /* level 4 */
2272 { 0, 20, 14, 18, 3, 5, ZSTD_greedy }, /* level 5 */
2273 { 0, 20, 18, 19, 3, 5, ZSTD_greedy }, /* level 6 */
2274 { 0, 21, 17, 20, 3, 5, ZSTD_lazy }, /* level 7 */
2275 { 0, 21, 19, 20, 3, 5, ZSTD_lazy }, /* level 8 */
2276 { 0, 21, 20, 20, 3, 5, ZSTD_lazy2 }, /* level 9 */
2277 { 0, 21, 19, 21, 4, 5, ZSTD_lazy2 }, /* level 10 */
2278 { 0, 22, 20, 22, 4, 5, ZSTD_lazy2 }, /* level 11 */
2279 { 0, 22, 20, 22, 5, 5, ZSTD_lazy2 }, /* level 12 */
2280 { 0, 22, 21, 22, 5, 5, ZSTD_lazy2 }, /* level 13 */
2281 { 0, 22, 22, 23, 5, 5, ZSTD_lazy2 }, /* level 14 */
2282 { 0, 23, 23, 23, 5, 5, ZSTD_lazy2 }, /* level 15 */
2283 { 0, 23, 21, 22, 5, 5, ZSTD_btlazy2 }, /* level 16 */
2284 { 0, 23, 24, 23, 4, 5, ZSTD_btlazy2 }, /* level 17 */
2285 { 0, 25, 24, 23, 5, 5, ZSTD_btlazy2 }, /* level 18 */
2286 { 0, 25, 26, 23, 5, 5, ZSTD_btlazy2 }, /* level 19 */
2287 { 0, 26, 27, 25, 9, 5, ZSTD_btlazy2 }, /* level 20 */
2288},
2289{ /* for srcSize <= 256 KB */
2290 /* W, C, H, S, L, strat */
2291 { 0, 18, 13, 14, 1, 7, ZSTD_fast }, /* level 0 - never used */
2292 { 0, 18, 14, 15, 1, 6, ZSTD_fast }, /* level 1 */
2293 { 0, 18, 14, 15, 1, 5, ZSTD_fast }, /* level 2 */
2294 { 0, 18, 12, 15, 3, 4, ZSTD_greedy }, /* level 3 */
2295 { 0, 18, 13, 15, 4, 4, ZSTD_greedy }, /* level 4 */
2296 { 0, 18, 14, 15, 5, 4, ZSTD_greedy }, /* level 5 */
2297 { 0, 18, 13, 15, 4, 4, ZSTD_lazy }, /* level 6 */
2298 { 0, 18, 14, 16, 5, 4, ZSTD_lazy }, /* level 7 */
2299 { 0, 18, 15, 16, 6, 4, ZSTD_lazy }, /* level 8 */
2300 { 0, 18, 15, 15, 7, 4, ZSTD_lazy }, /* level 9 */
2301 { 0, 18, 16, 16, 7, 4, ZSTD_lazy }, /* level 10 */
2302 { 0, 18, 16, 16, 8, 4, ZSTD_lazy }, /* level 11 */
2303 { 0, 18, 17, 16, 8, 4, ZSTD_lazy }, /* level 12 */
2304 { 0, 18, 17, 16, 9, 4, ZSTD_lazy }, /* level 13 */
2305 { 0, 18, 18, 16, 9, 4, ZSTD_lazy }, /* level 14 */
2306 { 0, 18, 17, 17, 9, 4, ZSTD_lazy2 }, /* level 15 */
2307 { 0, 18, 18, 18, 9, 4, ZSTD_lazy2 }, /* level 16 */
2308 { 0, 18, 18, 18, 10, 4, ZSTD_lazy2 }, /* level 17 */
2309 { 0, 18, 18, 18, 11, 4, ZSTD_lazy2 }, /* level 18 */
2310 { 0, 18, 18, 18, 12, 4, ZSTD_lazy2 }, /* level 19 */
2311 { 0, 18, 18, 18, 13, 4, ZSTD_lazy2 }, /* level 20 */
2312},
2313{ /* for srcSize <= 128 KB */
2314 /* W, C, H, S, L, strat */
2315 { 0, 17, 12, 12, 1, 4, ZSTD_fast }, /* level 0 - never used */
2316 { 0, 17, 12, 13, 1, 6, ZSTD_fast }, /* level 1 */
2317 { 0, 17, 14, 16, 1, 5, ZSTD_fast }, /* level 2 */
2318 { 0, 17, 15, 17, 1, 5, ZSTD_fast }, /* level 3 */
2319 { 0, 17, 13, 15, 2, 4, ZSTD_greedy }, /* level 4 */
2320 { 0, 17, 15, 17, 3, 4, ZSTD_greedy }, /* level 5 */
2321 { 0, 17, 14, 17, 3, 4, ZSTD_lazy }, /* level 6 */
2322 { 0, 17, 16, 17, 4, 4, ZSTD_lazy }, /* level 7 */
2323 { 0, 17, 16, 17, 4, 4, ZSTD_lazy2 }, /* level 8 */
2324 { 0, 17, 17, 16, 5, 4, ZSTD_lazy2 }, /* level 9 */
2325 { 0, 17, 17, 16, 6, 4, ZSTD_lazy2 }, /* level 10 */
2326 { 0, 17, 17, 16, 7, 4, ZSTD_lazy2 }, /* level 11 */
2327 { 0, 17, 17, 16, 8, 4, ZSTD_lazy2 }, /* level 12 */
2328 { 0, 17, 18, 16, 4, 4, ZSTD_btlazy2 }, /* level 13 */
2329 { 0, 17, 18, 16, 5, 4, ZSTD_btlazy2 }, /* level 14 */
2330 { 0, 17, 18, 16, 6, 4, ZSTD_btlazy2 }, /* level 15 */
2331 { 0, 17, 18, 16, 7, 4, ZSTD_btlazy2 }, /* level 16 */
2332 { 0, 17, 18, 16, 8, 4, ZSTD_btlazy2 }, /* level 17 */
2333 { 0, 17, 18, 16, 9, 4, ZSTD_btlazy2 }, /* level 18 */
2334 { 0, 17, 18, 16, 10, 4, ZSTD_btlazy2 }, /* level 19 */
2335 { 0, 17, 18, 18, 12, 4, ZSTD_btlazy2 }, /* level 20 */
2336},
2337{ /* for srcSize <= 16 KB */
2338 /* W, C, H, S, L, strat */
2339 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2340 { 0, 14, 14, 14, 1, 4, ZSTD_fast }, /* level 1 */
2341 { 0, 14, 14, 16, 1, 4, ZSTD_fast }, /* level 2 */
2342 { 0, 14, 14, 14, 5, 4, ZSTD_greedy }, /* level 3 */
2343 { 0, 14, 14, 14, 8, 4, ZSTD_greedy }, /* level 4 */
2344 { 0, 14, 11, 14, 6, 4, ZSTD_lazy }, /* level 5 */
2345 { 0, 14, 14, 13, 6, 5, ZSTD_lazy }, /* level 6 */
2346 { 0, 14, 14, 14, 7, 6, ZSTD_lazy }, /* level 7 */
2347 { 0, 14, 14, 14, 8, 4, ZSTD_lazy }, /* level 8 */
2348 { 0, 14, 14, 15, 9, 4, ZSTD_lazy }, /* level 9 */
2349 { 0, 14, 14, 15, 10, 4, ZSTD_lazy }, /* level 10 */
2350 { 0, 14, 15, 15, 6, 4, ZSTD_btlazy2 }, /* level 11 */
2351 { 0, 14, 15, 15, 7, 4, ZSTD_btlazy2 }, /* level 12 */
2352 { 0, 14, 15, 15, 8, 4, ZSTD_btlazy2 }, /* level 13 */
2353 { 0, 14, 15, 15, 9, 4, ZSTD_btlazy2 }, /* level 14 */
2354 { 0, 14, 15, 15, 10, 4, ZSTD_btlazy2 }, /* level 15 */
2355 { 0, 14, 15, 15, 11, 4, ZSTD_btlazy2 }, /* level 16 */
2356 { 0, 14, 15, 15, 12, 4, ZSTD_btlazy2 }, /* level 17 */
2357 { 0, 14, 15, 15, 13, 4, ZSTD_btlazy2 }, /* level 18 */
2358 { 0, 14, 15, 15, 14, 4, ZSTD_btlazy2 }, /* level 19 */
2359 { 0, 14, 15, 15, 15, 4, ZSTD_btlazy2 }, /* level 20 */
2360},
2361};
2362
2363/*! ZSTD_getParams
2364* @return ZSTD_parameters structure for a selected compression level and srcSize.
2365* @srcSizeHint value is optional, select 0 if not known */
2366ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint)
2367{
2368 ZSTD_parameters result;
2369 int tableID = ((srcSizeHint-1) <= 256 KB) + ((srcSizeHint-1) <= 128 KB) + ((srcSizeHint-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
2370 if (compressionLevel<=0) compressionLevel = 1;
2371 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
2372 result = ZSTD_defaultParameters[tableID][compressionLevel];
2373 result.srcSize = srcSizeHint;
2374 return result;
2375}
2376