blob: c9847dafa4d64542819094d8a7af681cc00a8cbd [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 Collet7d360282016-02-12 00:07:30 +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
Yann Collet7d360282016-02-12 00:07:30 +010062/*-*************************************
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
Yann Collet7d360282016-02-12 00:07:30 +010068/*-*************************************
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
Yann Collet7d360282016-02-12 00:07:30 +010074/*-*************************************
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 +010077
Yann Collet14983e72015-11-11 21:38:21 +010078static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
79{
80 ssPtr->offset = ssPtr->offsetStart;
81 ssPtr->lit = ssPtr->litStart;
82 ssPtr->litLength = ssPtr->litLengthStart;
83 ssPtr->matchLength = ssPtr->matchLengthStart;
84 ssPtr->dumps = ssPtr->dumpsStart;
85}
86
87
Yann Collet7d360282016-02-12 00:07:30 +010088/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010089* Context memory management
90***************************************/
Yann Collet5be2dd22015-11-11 13:43:58 +010091struct ZSTD_CCtx_s
Yann Colletf3eca252015-10-22 15:31:46 +010092{
Yann Collet89db5e02015-11-13 11:27:46 +010093 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010094 const BYTE* base; /* All regular indexes relative to this position */
95 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010096 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010097 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010098 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010099 U32 nextToUpdate3; /* index from which to continue dictionary update */
Yann Collet2ce49232016-02-02 14:36:49 +0100100 U32 loadedDictEnd;
Yann Colletecd651b2016-01-07 15:35:18 +0100101 U32 stage;
Yann Collet5be2dd22015-11-11 13:43:58 +0100102 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +0100103 void* workSpace;
104 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100105 size_t blockSize;
Yann Colletecd651b2016-01-07 15:35:18 +0100106 size_t hbSize;
Yann Collet60096272016-01-08 17:27:50 +0100107 char headerBuffer[ZSTD_frameHeaderSize_max];
Yann Colletecd651b2016-01-07 15:35:18 +0100108
Yann Collet712def92015-10-29 18:41:45 +0100109 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100110 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +0100111 U32* hashTable3;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100112 U32* contentTable;
Yann Colletb923f652016-01-26 03:14:20 +0100113 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +0100114 U32 flagStaticTables;
115 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
116 FSE_CTable matchlengthCTable [FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
117 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Colletf3eca252015-10-22 15:31:46 +0100118};
119
Yann Collet5be2dd22015-11-11 13:43:58 +0100120ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100121{
Yann Collet5be2dd22015-11-11 13:43:58 +0100122 return (ZSTD_CCtx*) calloc(1, sizeof(ZSTD_CCtx));
Yann Colletf3eca252015-10-22 15:31:46 +0100123}
124
Yann Collet5be2dd22015-11-11 13:43:58 +0100125size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100126{
Yann Collet712def92015-10-29 18:41:45 +0100127 free(cctx->workSpace);
Yann Collet083fcc82015-10-25 14:06:35 +0100128 free(cctx);
Yann Collet982ffc72016-02-05 02:33:10 +0100129 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100130}
131
Yann Collet7d360282016-02-12 00:07:30 +0100132seqStore_t ZSTD_copySeqStore(const ZSTD_CCtx* ctx)
133{
134 return ctx->seqStore;
135}
136
Yann Collet59d70632015-11-04 12:05:27 +0100137
Yann Collet14983e72015-11-11 21:38:21 +0100138static unsigned ZSTD_highbit(U32 val);
139
Yann Collet70e8c382016-02-10 13:37:52 +0100140#define CLAMP(val,min,max) { if (val<min) val=min; else if (val>max) val=max; }
141
Yann Collet7d360282016-02-12 00:07:30 +0100142/** ZSTD_validateParams() :
143 correct params value to remain within authorized range,
144 optimize for `srcSize` if srcSize > 0 */
Yann Collet88fcd292015-11-25 14:42:45 +0100145void ZSTD_validateParams(ZSTD_parameters* params)
Yann Collet59d70632015-11-04 12:05:27 +0100146{
Yann Colletcefef8c2016-02-15 07:21:54 +0100147 const U32 btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_btopt);
Yann Collet59d70632015-11-04 12:05:27 +0100148
149 /* validate params */
Yann Collet00fd7a22015-11-28 16:03:22 +0100150 if (MEM_32bits()) if (params->windowLog > 25) params->windowLog = 25; /* 32 bits mode cannot flush > 24 bits */
Yann Collet70e8c382016-02-10 13:37:52 +0100151 CLAMP(params->windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
152 CLAMP(params->contentLog, ZSTD_CONTENTLOG_MIN, ZSTD_CONTENTLOG_MAX);
153 CLAMP(params->hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
inikepcc52a972016-02-19 10:09:35 +0100154 CLAMP(params->hashLog3, ZSTD_HASHLOG3_MIN, ZSTD_HASHLOG3_MAX);
Yann Collet70e8c382016-02-10 13:37:52 +0100155 CLAMP(params->searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
156 CLAMP(params->searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
Yann Colletbd828d92016-02-11 04:38:55 +0100157 CLAMP(params->targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Colletcefef8c2016-02-15 07:21:54 +0100158 if ((U32)params->strategy>(U32)ZSTD_btopt) params->strategy = ZSTD_btopt;
Yann Collet59d70632015-11-04 12:05:27 +0100159
160 /* correct params, to use less memory */
Yann Colletfb810d62016-01-28 00:18:06 +0100161 if ((params->srcSize > 0) && (params->srcSize < (1<<ZSTD_WINDOWLOG_MAX))) {
Yann Collet88fcd292015-11-25 14:42:45 +0100162 U32 srcLog = ZSTD_highbit((U32)(params->srcSize)-1) + 1;
Yann Collet59d70632015-11-04 12:05:27 +0100163 if (params->windowLog > srcLog) params->windowLog = srcLog;
164 }
Yann Collet00fd7a22015-11-28 16:03:22 +0100165 if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet5be2dd22015-11-11 13:43:58 +0100166 if (params->contentLog > params->windowLog+btPlus) params->contentLog = params->windowLog+btPlus; /* <= ZSTD_CONTENTLOG_MAX */
Yann Collet59d70632015-11-04 12:05:27 +0100167}
168
169
Yann Collet5be2dd22015-11-11 13:43:58 +0100170static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Collet88fcd292015-11-25 14:42:45 +0100171 ZSTD_parameters params)
Yann Collet863ec402016-01-28 17:56:33 +0100172{ /* note : params considered validated here */
Yann Collet120230b2015-12-02 14:00:45 +0100173 const size_t blockSize = MIN(BLOCKSIZE, (size_t)1 << params.windowLog);
Yann Collet2acb5d32015-10-29 16:49:43 +0100174 /* reserve table memory */
Yann Collet863ec402016-01-28 17:56:33 +0100175 const U32 contentLog = (params.strategy == ZSTD_fast) ? 1 : params.contentLog;
inikepcc52a972016-02-19 10:09:35 +0100176 const size_t tableSpace = ((1 << contentLog) + (1 << params.hashLog) + (1 << params.hashLog3)) * sizeof(U32);
inikep70b05452016-02-03 22:56:55 +0100177 const size_t neededSpace = tableSpace + (256*sizeof(U32)) + (3*blockSize) + ((1<<MLbits) + (1<<LLbits) + (1<<Offbits) + (1<<Litbits))*sizeof(U32);
Yann Collet863ec402016-01-28 17:56:33 +0100178 if (zc->workSpaceSize < neededSpace) {
179 free(zc->workSpace);
180 zc->workSpace = malloc(neededSpace);
181 if (zc->workSpace == NULL) return ERROR(memory_allocation);
182 zc->workSpaceSize = neededSpace;
Yann Collet083fcc82015-10-25 14:06:35 +0100183 }
Yann Collet863ec402016-01-28 17:56:33 +0100184 memset(zc->workSpace, 0, tableSpace ); /* reset only tables */
inikepcc52a972016-02-19 10:09:35 +0100185 zc->hashTable3 = (U32*)(zc->workSpace);
186 zc->hashTable = zc->hashTable3 + ((size_t)1 << params.hashLog3);
Yann Collet863ec402016-01-28 17:56:33 +0100187 zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog);
188 zc->seqStore.buffer = zc->contentTable + ((size_t)1 << contentLog);
189 zc->hufTable = (HUF_CElt*)zc->seqStore.buffer;
190 zc->flagStaticTables = 0;
191 zc->seqStore.buffer = (U32*)(zc->seqStore.buffer) + 256;
Yann Collet083fcc82015-10-25 14:06:35 +0100192
Yann Colletf48e35c2015-11-07 01:13:31 +0100193 zc->nextToUpdate = 1;
Yann Collet89db5e02015-11-13 11:27:46 +0100194 zc->nextSrc = NULL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100195 zc->base = NULL;
196 zc->dictBase = NULL;
197 zc->dictLimit = 0;
198 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100199 zc->params = params;
Yann Collet120230b2015-12-02 14:00:45 +0100200 zc->blockSize = blockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100201
202 zc->seqStore.litFreq = (U32*) (zc->seqStore.buffer);
203 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
204 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (1<<LLbits);
205 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (1<<MLbits);
206
207 zc->seqStore.offsetStart = zc->seqStore.offCodeFreq + (1<<Offbits);
Yann Collet120230b2015-12-02 14:00:45 +0100208 zc->seqStore.offCodeStart = (BYTE*) (zc->seqStore.offsetStart + (blockSize>>2));
209 zc->seqStore.litStart = zc->seqStore.offCodeStart + (blockSize>>2);
210 zc->seqStore.litLengthStart = zc->seqStore.litStart + blockSize;
211 zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + (blockSize>>2);
212 zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (blockSize>>2);
Yann Collet70e8c382016-02-10 13:37:52 +0100213 // zc->seqStore.XXX = zc->seqStore.dumpsStart + (blockSize>>4);
inikepcc52a972016-02-19 10:09:35 +0100214 zc->seqStore.litLengthSum = 0;
inikep3bfcfc72016-02-03 18:47:30 +0100215
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;
inikepf4146472016-02-25 22:31:07 +0100231 const size_t tableSpace = ((1 << contentLog) + (1 << srcCCtx->params.hashLog) + (1 << srcCCtx->params.hashLog3)) * sizeof(U32);
232
Yann Collet7b51a292016-01-26 15:58:49 +0100233 if (srcCCtx->stage!=0) return ERROR(stage_wrong);
234
235 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params);
236
237 /* copy tables */
inikepcc52a972016-02-19 10:09:35 +0100238 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
Yann Collet7b51a292016-01-26 15:58:49 +0100239
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;
inikepf4146472016-02-25 22:31:07 +0100246 dstCCtx->nextToUpdate3 = srcCCtx->nextToUpdate3;
Yann Collet7b51a292016-01-26 15:58:49 +0100247 dstCCtx->nextSrc = srcCCtx->nextSrc;
248 dstCCtx->base = srcCCtx->base;
249 dstCCtx->dictBase = srcCCtx->dictBase;
250 dstCCtx->dictLimit = srcCCtx->dictLimit;
251 dstCCtx->lowLimit = srcCCtx->lowLimit;
Yann Collet7a6343f2016-02-02 16:00:50 +0100252 dstCCtx->loadedDictEnd = srcCCtx->loadedDictEnd;
Yann Collet7b51a292016-01-26 15:58:49 +0100253
Yann Colletfb810d62016-01-28 00:18:06 +0100254 /* copy entropy tables */
255 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100256 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100257 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100258 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
259 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
260 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
261 }
Yann Collet7b51a292016-01-26 15:58:49 +0100262
263 return 0;
264}
265
266
Yann Collet863ec402016-01-28 17:56:33 +0100267/*! ZSTD_reduceIndex
Yann Collet88fcd292015-11-25 14:42:45 +0100268* rescale indexes to avoid future overflow (indexes are U32) */
Yann Collet89db5e02015-11-13 11:27:46 +0100269static void ZSTD_reduceIndex (ZSTD_CCtx* zc,
270 const U32 reducerValue)
271{
Yann Collet88fcd292015-11-25 14:42:45 +0100272 const U32 contentLog = (zc->params.strategy == ZSTD_fast) ? 1 : zc->params.contentLog;
Yann Collet89db5e02015-11-13 11:27:46 +0100273 const U32 tableSpaceU32 = (1 << contentLog) + (1 << zc->params.hashLog);
274 U32* table32 = zc->hashTable;
275 U32 index;
276
Yann Colletfb810d62016-01-28 00:18:06 +0100277 for (index=0 ; index < tableSpaceU32 ; index++) {
Yann Collet89db5e02015-11-13 11:27:46 +0100278 if (table32[index] < reducerValue) table32[index] = 0;
279 else table32[index] -= reducerValue;
280 }
281}
282
283
Yann Collet863ec402016-01-28 17:56:33 +0100284/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100285* Block entropic compression
286*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100287
Yann Collet59d1f792016-01-23 19:28:41 +0100288/* Block format description
289
290 Block = Literal Section - Sequences Section
291 Prerequisite : size of (compressed) block, maximum size of regenerated data
292
293 1) Literal Section
294
295 1.1) Header : 1-5 bytes
296 flags: 2 bits
297 00 compressed by Huff0
298 01 unused
299 10 is Raw (uncompressed)
300 11 is Rle
301 Note : using 01 => Huff0 with precomputed table ?
302 Note : delta map ? => compressed ?
303
304 1.1.1) Huff0-compressed literal block : 3-5 bytes
Yann Colletafe07092016-01-25 04:10:46 +0100305 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
Yann Collet59d1f792016-01-23 19:28:41 +0100306 srcSize < 1 KB => 3 bytes (2-2-10-10)
Yann Colleta1249dc2016-01-25 04:22:03 +0100307 srcSize < 16KB => 4 bytes (2-2-14-14)
Yann Collet59d1f792016-01-23 19:28:41 +0100308 else => 5 bytes (2-2-18-18)
309 big endian convention
310
311 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
312 size : 5 bits: (IS_RAW<<6) + (0<<4) + size
313 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
314 size&255
315 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
316 size>>8&255
317 size&255
318
319 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
320 size : 5 bits: (IS_RLE<<6) + (0<<4) + size
321 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
322 size&255
323 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
324 size>>8&255
325 size&255
326
Yann Colleta1249dc2016-01-25 04:22:03 +0100327 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
328 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
329 srcSize < 1 KB => 3 bytes (2-2-10-10)
330 srcSize < 16KB => 4 bytes (2-2-14-14)
331 else => 5 bytes (2-2-18-18)
332 big endian convention
333
334 1- CTable available (stored into workspace ?)
Yann Colletb923f652016-01-26 03:14:20 +0100335 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
Yann Colleta1249dc2016-01-25 04:22:03 +0100336
Yann Collet59d1f792016-01-23 19:28:41 +0100337
338 1.2) Literal block content
339
340 1.2.1) Huff0 block, using sizes from header
341 See Huff0 format
342
Yann Colletfb810d62016-01-28 00:18:06 +0100343 1.2.2) Huff0 block, using prepared table
Yann Collet59d1f792016-01-23 19:28:41 +0100344
Yann Colletfb810d62016-01-28 00:18:06 +0100345 1.2.3) Raw content
Yann Collet59d1f792016-01-23 19:28:41 +0100346
Yann Colletfb810d62016-01-28 00:18:06 +0100347 1.2.4) single byte
Yann Collet59d1f792016-01-23 19:28:41 +0100348
349
350 2) Sequences section
Yann Colletfb810d62016-01-28 00:18:06 +0100351
352 - Nb Sequences : 2 bytes, little endian
353 - Control Token : 1 byte (see below)
354 - Dumps Length : 1 or 2 bytes (depending on control token)
355 - Dumps : as stated by dumps length
356 - Literal Lengths FSE table (as needed depending on encoding method)
357 - Offset Codes FSE table (as needed depending on encoding method)
358 - Match Lengths FSE table (as needed depending on encoding method)
359
360 2.1) Control Token
361 8 bits, divided as :
362 0-1 : dumpsLength
363 2-3 : MatchLength, FSE encoding method
364 4-5 : Offset Codes, FSE encoding method
365 6-7 : Literal Lengths, FSE encoding method
366
367 FSE encoding method :
368 FSE_ENCODING_RAW : uncompressed; no header
369 FSE_ENCODING_RLE : single repeated value; header 1 byte
370 FSE_ENCODING_STATIC : use prepared table; no header
371 FSE_ENCODING_DYNAMIC : read NCount
Yann Collet59d1f792016-01-23 19:28:41 +0100372*/
Yann Collet14983e72015-11-11 21:38:21 +0100373
374size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
375{
376 BYTE* const ostart = (BYTE* const)dst;
377
378 if (srcSize + ZSTD_blockHeaderSize > maxDstSize) return ERROR(dstSize_tooSmall);
379 memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
380
381 /* Build header */
382 ostart[0] = (BYTE)(srcSize>>16);
383 ostart[1] = (BYTE)(srcSize>>8);
384 ostart[2] = (BYTE) srcSize;
385 ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
386
387 return ZSTD_blockHeaderSize+srcSize;
388}
389
390
391static size_t ZSTD_noCompressLiterals (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
392{
393 BYTE* const ostart = (BYTE* const)dst;
Yann Collet59d1f792016-01-23 19:28:41 +0100394 const U32 flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100395
Yann Collet59d1f792016-01-23 19:28:41 +0100396 if (srcSize + flSize > maxDstSize) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100397
Yann Collet59d1f792016-01-23 19:28:41 +0100398 switch(flSize)
399 {
400 case 1: /* 2 - 1 - 5 */
401 ostart[0] = (BYTE)((IS_RAW<<6) + (0<<5) + srcSize);
402 break;
403 case 2: /* 2 - 2 - 12 */
404 ostart[0] = (BYTE)((IS_RAW<<6) + (2<<4) + (srcSize >> 8));
405 ostart[1] = (BYTE)srcSize;
406 break;
407 default: /*note : should not be necessary : flSize is within {1,2,3} */
408 case 3: /* 2 - 2 - 20 */
409 ostart[0] = (BYTE)((IS_RAW<<6) + (3<<4) + (srcSize >> 16));
410 ostart[1] = (BYTE)(srcSize>>8);
411 ostart[2] = (BYTE)srcSize;
412 break;
413 }
414
415 memcpy(ostart + flSize, src, srcSize);
416 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100417}
418
419static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
420{
421 BYTE* const ostart = (BYTE* const)dst;
Yann Collet59d1f792016-01-23 19:28:41 +0100422 U32 flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100423
Yann Colletfb810d62016-01-28 00:18:06 +0100424 (void)maxDstSize; /* maxDstSize guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100425
426 switch(flSize)
427 {
428 case 1: /* 2 - 1 - 5 */
429 ostart[0] = (BYTE)((IS_RLE<<6) + (0<<5) + srcSize);
430 break;
431 case 2: /* 2 - 2 - 12 */
432 ostart[0] = (BYTE)((IS_RLE<<6) + (2<<4) + (srcSize >> 8));
433 ostart[1] = (BYTE)srcSize;
434 break;
435 default: /*note : should not be necessary : flSize is necessary within {1,2,3} */
436 case 3: /* 2 - 2 - 20 */
437 ostart[0] = (BYTE)((IS_RLE<<6) + (3<<4) + (srcSize >> 16));
438 ostart[1] = (BYTE)(srcSize>>8);
439 ostart[2] = (BYTE)srcSize;
440 break;
441 }
442
443 ostart[flSize] = *(const BYTE*)src;
444 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100445}
446
Yann Collet59d1f792016-01-23 19:28:41 +0100447
Yann Colletb923f652016-01-26 03:14:20 +0100448size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100449
Yann Colletb923f652016-01-26 03:14:20 +0100450static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
451 void* dst, size_t maxDstSize,
Yann Collet14983e72015-11-11 21:38:21 +0100452 const void* src, size_t srcSize)
453{
454 const size_t minGain = ZSTD_minGain(srcSize);
455 BYTE* const ostart = (BYTE*)dst;
Yann Colletb923f652016-01-26 03:14:20 +0100456 const size_t lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Colletafe07092016-01-25 04:10:46 +0100457 U32 singleStream = srcSize < 256;
Yann Colletb923f652016-01-26 03:14:20 +0100458 U32 hType = IS_HUF;
Yann Collet59d1f792016-01-23 19:28:41 +0100459 size_t clitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100460
Yann Collet35f7de52016-01-31 02:51:03 +0100461 if (maxDstSize < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Collet14983e72015-11-11 21:38:21 +0100462
Yann Colletfb810d62016-01-28 00:18:06 +0100463 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletb923f652016-01-26 03:14:20 +0100464 hType = IS_PCH;
465 singleStream = 1;
466 clitSize = HUF_compress1X_usingCTable(ostart+lhSize, maxDstSize-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100467 } else {
Yann Colletb923f652016-01-26 03:14:20 +0100468 clitSize = singleStream ? HUF_compress1X(ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12)
469 : HUF_compress2 (ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12);
470 }
Yann Collet14983e72015-11-11 21:38:21 +0100471
Yann Collet59d1f792016-01-23 19:28:41 +0100472 if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, maxDstSize, src, srcSize);
473 if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, maxDstSize, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100474
475 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100476 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100477 {
Yann Collet59d1f792016-01-23 19:28:41 +0100478 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletb923f652016-01-26 03:14:20 +0100479 ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100480 ostart[1] = (BYTE)((srcSize<<2) + (clitSize>>8));
481 ostart[2] = (BYTE)(clitSize);
482 break;
483 case 4: /* 2 - 2 - 14 - 14 */
Yann Colletb923f652016-01-26 03:14:20 +0100484 ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100485 ostart[1] = (BYTE)(srcSize>> 2);
486 ostart[2] = (BYTE)((srcSize<<6) + (clitSize>>8));
487 ostart[3] = (BYTE)(clitSize);
488 break;
489 default: /* should not be necessary, lhSize is {3,4,5} */
490 case 5: /* 2 - 2 - 18 - 18 */
Yann Colletb923f652016-01-26 03:14:20 +0100491 ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100492 ostart[1] = (BYTE)(srcSize>>6);
493 ostart[2] = (BYTE)((srcSize<<2) + (clitSize>>16));
494 ostart[3] = (BYTE)(clitSize>>8);
495 ostart[4] = (BYTE)(clitSize);
496 break;
Yann Collet14983e72015-11-11 21:38:21 +0100497 }
498
Yann Collet59d1f792016-01-23 19:28:41 +0100499 return lhSize+clitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100500}
501
502
Yann Colletafe07092016-01-25 04:10:46 +0100503#define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */
Yann Collet14983e72015-11-11 21:38:21 +0100504
Yann Colletb923f652016-01-26 03:14:20 +0100505size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
506 void* dst, size_t maxDstSize,
Yann Collet14983e72015-11-11 21:38:21 +0100507 size_t srcSize)
508{
Yann Colletb923f652016-01-26 03:14:20 +0100509 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100510 U32 count[MaxSeq+1];
511 S16 norm[MaxSeq+1];
512 size_t mostFrequent;
Yann Colletfb810d62016-01-28 00:18:06 +0100513 U32 max;
514 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
515 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
516 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100517 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
518 const BYTE* const op_lit_start = seqStorePtr->litStart;
519 const BYTE* const llTable = seqStorePtr->litLengthStart;
520 const BYTE* const llPtr = seqStorePtr->litLength;
521 const BYTE* const mlTable = seqStorePtr->matchLengthStart;
522 const U32* const offsetTable = seqStorePtr->offsetStart;
523 BYTE* const offCodeTable = seqStorePtr->offCodeStart;
Yann Collet5054ee02015-11-23 13:34:21 +0100524 BYTE* const ostart = (BYTE*)dst;
525 BYTE* op = ostart;
526 BYTE* const oend = ostart + maxDstSize;
Yann Collet14983e72015-11-11 21:38:21 +0100527 const size_t nbSeq = llPtr - llTable;
528 const size_t minGain = ZSTD_minGain(srcSize);
529 const size_t maxCSize = srcSize - minGain;
530 BYTE* seqHead;
531
Yann Collet14983e72015-11-11 21:38:21 +0100532 /* 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
inikepcc52a972016-02-19 10:09:35 +0100546#if ZSTD_OPT_DEBUG >= 5
547 if (nbSeq >= 32768)
548 printf("ERROR: nbSeq=%d\n", (int)nbSeq);
549#endif
550
Yann Collet14983e72015-11-11 21:38:21 +0100551 /* Sequences Header */
Yann Collet61e16ce2016-01-31 02:04:15 +0100552 if ((oend-op) < MIN_SEQUENCES_SIZE) return ERROR(dstSize_tooSmall);
553 if (nbSeq < 128) *op++ = (BYTE)nbSeq;
554 else {
Yann Collet35f7de52016-01-31 02:51:03 +0100555 op[0] = (BYTE)((nbSeq>>8) + 128); op[1] = (BYTE)nbSeq; op+=2;
Yann Collet61e16ce2016-01-31 02:04:15 +0100556 }
Yann Collete93d6ce2016-01-31 00:58:06 +0100557 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100558
Yann Collet863ec402016-01-28 17:56:33 +0100559 /* dumps : contains rests of large lengths */
Yann Collete93d6ce2016-01-31 00:58:06 +0100560 if ((oend-op) < 3 /* dumps */ + 1 /*seqHead*/)
561 return ERROR(dstSize_tooSmall);
562 seqHead = op;
Yann Collet14983e72015-11-11 21:38:21 +0100563 {
564 size_t dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart;
Yann Colletfb810d62016-01-28 00:18:06 +0100565 if (dumpsLength < 512) {
Yann Collet14983e72015-11-11 21:38:21 +0100566 op[0] = (BYTE)(dumpsLength >> 8);
567 op[1] = (BYTE)(dumpsLength);
568 op += 2;
Yann Colletfb810d62016-01-28 00:18:06 +0100569 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100570 op[0] = 2;
571 op[1] = (BYTE)(dumpsLength>>8);
572 op[2] = (BYTE)(dumpsLength);
573 op += 3;
574 }
575 if ((size_t)(oend-op) < dumpsLength+6) return ERROR(dstSize_tooSmall);
576 memcpy(op, seqStorePtr->dumpsStart, dumpsLength);
577 op += dumpsLength;
578 }
579
Yann Colletfb810d62016-01-28 00:18:06 +0100580#define MIN_SEQ_FOR_DYNAMIC_FSE 64
581#define MAX_SEQ_FOR_STATIC_FSE 1000
582
Yann Collet14983e72015-11-11 21:38:21 +0100583 /* CTable for Literal Lengths */
584 max = MaxLL;
Yann Collete93d6ce2016-01-31 00:58:06 +0100585 mostFrequent = FSE_countFast(count, &max, llTable, nbSeq);
Yann Colletfb810d62016-01-28 00:18:06 +0100586 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collete93d6ce2016-01-31 00:58:06 +0100587 *op++ = llTable[0];
Yann Collet14983e72015-11-11 21:38:21 +0100588 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletfb810d62016-01-28 00:18:06 +0100589 LLtype = FSE_ENCODING_RLE;
590 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
591 LLtype = FSE_ENCODING_STATIC;
592 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LLbits-1)))) {
Yann Collet14983e72015-11-11 21:38:21 +0100593 FSE_buildCTable_raw(CTable_LitLength, LLbits);
Yann Colletfb810d62016-01-28 00:18:06 +0100594 LLtype = FSE_ENCODING_RAW;
595 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100596 size_t NCountSize;
Yann Collete93d6ce2016-01-31 00:58:06 +0100597 size_t nbSeq_1 = nbSeq;
Yann Colletfb810d62016-01-28 00:18:06 +0100598 U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
Yann Collete93d6ce2016-01-31 00:58:06 +0100599 if (count[llTable[nbSeq-1]]>1) { count[llTable[nbSeq-1]]--; nbSeq_1--; }
600 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Collet14983e72015-11-11 21:38:21 +0100601 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
602 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
603 op += NCountSize;
604 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
Yann Colletfb810d62016-01-28 00:18:06 +0100605 LLtype = FSE_ENCODING_DYNAMIC;
Yann Collet14983e72015-11-11 21:38:21 +0100606 }
607
Yann Colletfb810d62016-01-28 00:18:06 +0100608 /* CTable for Offset codes */
609 { /* create Offset codes */
610 size_t i; for (i=0; i<nbSeq; i++) {
Yann Collet14983e72015-11-11 21:38:21 +0100611 offCodeTable[i] = (BYTE)ZSTD_highbit(offsetTable[i]) + 1;
612 if (offsetTable[i]==0) offCodeTable[i]=0;
613 }
Yann Collet14983e72015-11-11 21:38:21 +0100614 }
Yann Colletfb810d62016-01-28 00:18:06 +0100615 max = MaxOff;
616 mostFrequent = FSE_countFast(count, &max, offCodeTable, nbSeq);
617 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collete93d6ce2016-01-31 00:58:06 +0100618 *op++ = offCodeTable[0];
Yann Collet14983e72015-11-11 21:38:21 +0100619 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletfb810d62016-01-28 00:18:06 +0100620 Offtype = FSE_ENCODING_RLE;
621 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
622 Offtype = FSE_ENCODING_STATIC;
623 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (Offbits-1)))) {
Yann Collet14983e72015-11-11 21:38:21 +0100624 FSE_buildCTable_raw(CTable_OffsetBits, Offbits);
Yann Colletfb810d62016-01-28 00:18:06 +0100625 Offtype = FSE_ENCODING_RAW;
626 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100627 size_t NCountSize;
Yann Collete93d6ce2016-01-31 00:58:06 +0100628 size_t nbSeq_1 = nbSeq;
Yann Colletfb810d62016-01-28 00:18:06 +0100629 U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collete93d6ce2016-01-31 00:58:06 +0100630 if (count[offCodeTable[nbSeq-1]]>1) { count[offCodeTable[nbSeq-1]]--; nbSeq_1--; }
631 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Collet14983e72015-11-11 21:38:21 +0100632 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
633 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
634 op += NCountSize;
635 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
Yann Colletfb810d62016-01-28 00:18:06 +0100636 Offtype = FSE_ENCODING_DYNAMIC;
Yann Collet14983e72015-11-11 21:38:21 +0100637 }
638
639 /* CTable for MatchLengths */
640 max = MaxML;
Yann Collete93d6ce2016-01-31 00:58:06 +0100641 mostFrequent = FSE_countFast(count, &max, mlTable, nbSeq);
Yann Colletfb810d62016-01-28 00:18:06 +0100642 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collete93d6ce2016-01-31 00:58:06 +0100643 *op++ = *mlTable;
Yann Collet14983e72015-11-11 21:38:21 +0100644 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletfb810d62016-01-28 00:18:06 +0100645 MLtype = FSE_ENCODING_RLE;
646 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
647 MLtype = FSE_ENCODING_STATIC;
648 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (MLbits-1)))) {
Yann Collet14983e72015-11-11 21:38:21 +0100649 FSE_buildCTable_raw(CTable_MatchLength, MLbits);
Yann Colletfb810d62016-01-28 00:18:06 +0100650 MLtype = FSE_ENCODING_RAW;
651 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100652 size_t NCountSize;
Yann Colletfb810d62016-01-28 00:18:06 +0100653 U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
Yann Collet14983e72015-11-11 21:38:21 +0100654 FSE_normalizeCount(norm, tableLog, count, nbSeq, max);
655 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
656 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
657 op += NCountSize;
658 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
Yann Colletfb810d62016-01-28 00:18:06 +0100659 MLtype = FSE_ENCODING_DYNAMIC;
Yann Collet14983e72015-11-11 21:38:21 +0100660 }
661
662 seqHead[0] += (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100663 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100664
665 /* Encoding Sequences */
666 {
667 size_t streamSize, errorCode;
668 BIT_CStream_t blockStream;
669 FSE_CState_t stateMatchLength;
670 FSE_CState_t stateOffsetBits;
671 FSE_CState_t stateLitLength;
672 int i;
673
674 errorCode = BIT_initCStream(&blockStream, op, oend-op);
675 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100676
Yann Collete93d6ce2016-01-31 00:58:06 +0100677 /* first symbols */
678 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlTable[nbSeq-1]);
679 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, offCodeTable[nbSeq-1]);
680 FSE_initCState2(&stateLitLength, CTable_LitLength, llTable[nbSeq-1]);
681 BIT_addBits(&blockStream, offsetTable[nbSeq-1], offCodeTable[nbSeq-1] ? (offCodeTable[nbSeq-1]-1) : 0);
682 BIT_flushBits(&blockStream);
683
684 for (i=(int)nbSeq-2; i>=0; i--) {
Yann Colletfb810d62016-01-28 00:18:06 +0100685 BYTE mlCode = mlTable[i];
Yann Collet14983e72015-11-11 21:38:21 +0100686 U32 offset = offsetTable[i];
687 BYTE offCode = offCodeTable[i]; /* 32b*/ /* 64b*/
Yann Collete93d6ce2016-01-31 00:58:06 +0100688 U32 nbBits = (offCode-1) + (!offCode);
Yann Collet14983e72015-11-11 21:38:21 +0100689 BYTE litLength = llTable[i]; /* (7)*/ /* (7)*/
Yann Colletfb810d62016-01-28 00:18:06 +0100690 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 17 */ /* 17 */
Yann Collet743402c2015-11-20 12:03:53 +0100691 if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */
Yann Collet14983e72015-11-11 21:38:21 +0100692 FSE_encodeSymbol(&blockStream, &stateLitLength, litLength); /* 26 */ /* 61 */
Yann Collete93d6ce2016-01-31 00:58:06 +0100693 FSE_encodeSymbol(&blockStream, &stateOffsetBits, offCode); /* 16 */ /* 51 */
694 if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */
695 BIT_addBits(&blockStream, offset, nbBits); /* 31 */ /* 42 */ /* 24 bits max in 32-bits mode */
Yann Collet14983e72015-11-11 21:38:21 +0100696 BIT_flushBits(&blockStream); /* 7 */ /* 7 */
697 }
698
699 FSE_flushCState(&blockStream, &stateMatchLength);
700 FSE_flushCState(&blockStream, &stateOffsetBits);
701 FSE_flushCState(&blockStream, &stateLitLength);
702
703 streamSize = BIT_closeCStream(&blockStream);
704 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
705 op += streamSize;
706 }
707
708 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100709_check_compressibility:
Yann Collet5054ee02015-11-23 13:34:21 +0100710 if ((size_t)(op-ostart) >= maxCSize) return 0;
Yann Collet14983e72015-11-11 21:38:21 +0100711
Yann Collet5054ee02015-11-23 13:34:21 +0100712 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100713}
714
715
Yann Collete93d6ce2016-01-31 00:58:06 +0100716/*! ZSTD_storeSeq
717 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t
Yann Collet14983e72015-11-11 21:38:21 +0100718 @offsetCode : distance to match, or 0 == repCode
719 @matchCode : matchLength - MINMATCH
720*/
721MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode)
722{
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100723#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100724 static const BYTE* g_start = NULL;
725 if (g_start==NULL) g_start = literals;
Yann Colletfb810d62016-01-28 00:18:06 +0100726 //if (literals - g_start == 8695)
Yann Collet14983e72015-11-11 21:38:21 +0100727 printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n",
inikepcc52a972016-02-19 10:09:35 +0100728 (U32)(literals - g_start), (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +0100729#endif
inikep15174b02016-02-23 12:41:56 +0100730#if ZSTD_OPT_DEBUG >= 3
731 if (offsetCode == 0) seqStorePtr->realRepSum++;
732 seqStorePtr->realSeqSum++;
733 seqStorePtr->realMatchSum += matchCode;
734 seqStorePtr->realLitSum += litLength;
735#endif
Yann Collet14983e72015-11-11 21:38:21 +0100736
737 /* copy Literals */
738 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
739 seqStorePtr->lit += litLength;
740
741 /* literal Length */
Yann Colletfb810d62016-01-28 00:18:06 +0100742 if (litLength >= MaxLL) {
Yann Collet14983e72015-11-11 21:38:21 +0100743 *(seqStorePtr->litLength++) = MaxLL;
Yann Colletfb810d62016-01-28 00:18:06 +0100744 if (litLength<255 + MaxLL) {
Yann Collet14983e72015-11-11 21:38:21 +0100745 *(seqStorePtr->dumps++) = (BYTE)(litLength - MaxLL);
Yann Colletfb810d62016-01-28 00:18:06 +0100746 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100747 *(seqStorePtr->dumps++) = 255;
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100748 if (litLength < (1<<15)) {
749 MEM_writeLE16(seqStorePtr->dumps, (U16)(litLength<<1));
750 seqStorePtr->dumps += 2;
751 } else {
752 MEM_writeLE32(seqStorePtr->dumps, (U32)((litLength<<1)+1));
753 seqStorePtr->dumps += 3;
754 }
Yann Colletfb810d62016-01-28 00:18:06 +0100755 } }
Yann Collet14983e72015-11-11 21:38:21 +0100756 else *(seqStorePtr->litLength++) = (BYTE)litLength;
757
758 /* match offset */
759 *(seqStorePtr->offset++) = (U32)offsetCode;
760
761 /* match Length */
Yann Colletfb810d62016-01-28 00:18:06 +0100762 if (matchCode >= MaxML) {
Yann Collet14983e72015-11-11 21:38:21 +0100763 *(seqStorePtr->matchLength++) = MaxML;
Yann Colletfb810d62016-01-28 00:18:06 +0100764 if (matchCode < 255+MaxML) {
Yann Collet14983e72015-11-11 21:38:21 +0100765 *(seqStorePtr->dumps++) = (BYTE)(matchCode - MaxML);
Yann Colletfb810d62016-01-28 00:18:06 +0100766 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100767 *(seqStorePtr->dumps++) = 255;
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100768 if (matchCode < (1<<15)) {
769 MEM_writeLE16(seqStorePtr->dumps, (U16)(matchCode<<1));
770 seqStorePtr->dumps += 2;
771 } else {
772 MEM_writeLE32(seqStorePtr->dumps, (U32)((matchCode<<1)+1));
773 seqStorePtr->dumps += 3;
774 }
Yann Colletfb810d62016-01-28 00:18:06 +0100775 } }
Yann Collet14983e72015-11-11 21:38:21 +0100776 else *(seqStorePtr->matchLength++) = (BYTE)matchCode;
777}
778
779
Yann Collet7d360282016-02-12 00:07:30 +0100780/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100781* Match length counter
782***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100783static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100784{
Yann Collet863ec402016-01-28 17:56:33 +0100785 if (MEM_isLittleEndian()) {
786 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100787# if defined(_MSC_VER) && defined(_WIN64)
788 unsigned long r = 0;
789 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100790 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100791# elif defined(__GNUC__) && (__GNUC__ >= 3)
792 return (__builtin_ctzll((U64)val) >> 3);
793# else
794 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 };
795 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
796# endif
Yann Collet863ec402016-01-28 17:56:33 +0100797 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100798# if defined(_MSC_VER)
799 unsigned long r=0;
800 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100801 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100802# elif defined(__GNUC__) && (__GNUC__ >= 3)
803 return (__builtin_ctz((U32)val) >> 3);
804# else
805 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 };
806 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
807# endif
808 }
Yann Collet863ec402016-01-28 17:56:33 +0100809 } else { /* Big Endian CPU */
810 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100811# if defined(_MSC_VER) && defined(_WIN64)
812 unsigned long r = 0;
813 _BitScanReverse64( &r, val );
814 return (unsigned)(r>>3);
815# elif defined(__GNUC__) && (__GNUC__ >= 3)
816 return (__builtin_clzll(val) >> 3);
817# else
818 unsigned r;
819 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
820 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
821 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
822 r += (!val);
823 return r;
824# endif
Yann Collet863ec402016-01-28 17:56:33 +0100825 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100826# if defined(_MSC_VER)
827 unsigned long r = 0;
828 _BitScanReverse( &r, (unsigned long)val );
829 return (unsigned)(r>>3);
830# elif defined(__GNUC__) && (__GNUC__ >= 3)
831 return (__builtin_clz((U32)val) >> 3);
832# else
833 unsigned r;
834 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
835 r += (!val);
836 return r;
837# endif
Yann Collet863ec402016-01-28 17:56:33 +0100838 } }
Yann Collet14983e72015-11-11 21:38:21 +0100839}
840
841
Yann Collet5054ee02015-11-23 13:34:21 +0100842static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100843{
844 const BYTE* const pStart = pIn;
845
Yann Colletfb810d62016-01-28 00:18:06 +0100846 while ((pIn<pInLimit-(sizeof(size_t)-1))) {
Yann Collet7d360282016-02-12 00:07:30 +0100847 size_t diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100848 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
849 pIn += ZSTD_NbCommonBytes(diff);
850 return (size_t)(pIn - pStart);
851 }
Yann Collet14983e72015-11-11 21:38:21 +0100852 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
853 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
854 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
855 return (size_t)(pIn - pStart);
856}
857
Yann Collet04b12d82016-02-11 06:23:24 +0100858/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100859* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100860* convention : on reaching mEnd, match count continue starting from iStart
861*/
862static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
863{
864 size_t matchLength;
865 const BYTE* vEnd = ip + (mEnd - match);
866 if (vEnd > iEnd) vEnd = iEnd;
867 matchLength = ZSTD_count(ip, match, vEnd);
868 if (match + matchLength == mEnd)
869 matchLength += ZSTD_count(ip+matchLength, iStart, iEnd);
870 return matchLength;
871}
872
Yann Collet14983e72015-11-11 21:38:21 +0100873
Yann Collet863ec402016-01-28 17:56:33 +0100874/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100875* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100876***************************************/
inikepcc52a972016-02-19 10:09:35 +0100877static const U32 prime3bytes = 506832829U;
878static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
879static size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_read32(ptr), h); }
880
Yann Collet4b100f42015-10-30 15:49:48 +0100881static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100882static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100883static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100884
Yann Collet4b100f42015-10-30 15:49:48 +0100885static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100886static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100887static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100888
889static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100890static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100891static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100892
Yann Collet14983e72015-11-11 21:38:21 +0100893static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100894static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100895static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100896
Yann Collet5be2dd22015-11-11 13:43:58 +0100897static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100898{
899 switch(mls)
900 {
901 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100902 case 4: return ZSTD_hash4Ptr(p, hBits);
903 case 5: return ZSTD_hash5Ptr(p, hBits);
904 case 6: return ZSTD_hash6Ptr(p, hBits);
905 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100906 }
907}
Yann Collet2acb5d32015-10-29 16:49:43 +0100908
Yann Collet863ec402016-01-28 17:56:33 +0100909
Yann Collet2ce49232016-02-02 14:36:49 +0100910/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +0100911* Fast Scan
912***************************************/
Yann Collet417890c2015-12-04 17:16:37 +0100913#define FILLHASHSTEP 3
914static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
915{
916 U32* const hashTable = zc->hashTable;
917 const U32 hBits = zc->params.hashLog;
918 const BYTE* const base = zc->base;
919 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet2ce49232016-02-02 14:36:49 +0100920 const BYTE* const iend = ((const BYTE*)end) - 8;
Yann Collet417890c2015-12-04 17:16:37 +0100921
Yann Colletfb810d62016-01-28 00:18:06 +0100922 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +0100923 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
924 ip += FILLHASHSTEP;
925 }
926}
927
928
Yann Collet1f44b3f2015-11-05 17:32:18 +0100929FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +0100930void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc,
Yann Collet89db5e02015-11-13 11:27:46 +0100931 const void* src, size_t srcSize,
932 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100933{
Yann Collet417890c2015-12-04 17:16:37 +0100934 U32* const hashTable = zc->hashTable;
Yann Colletc3652152015-11-24 14:06:07 +0100935 const U32 hBits = zc->params.hashLog;
936 seqStore_t* seqStorePtr = &(zc->seqStore);
937 const BYTE* const base = zc->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100938 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100939 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100940 const BYTE* anchor = istart;
Yann Colletd94efbf2015-12-29 14:29:08 +0100941 const U32 lowIndex = zc->dictLimit;
942 const BYTE* const lowest = base + lowIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100943 const BYTE* const iend = istart + srcSize;
944 const BYTE* const ilimit = iend - 8;
945
Yann Collet89db5e02015-11-13 11:27:46 +0100946 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100947
948
949 /* init */
Yann Collet743402c2015-11-20 12:03:53 +0100950 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +0100951 if (ip < lowest+REPCODE_STARTVALUE) ip = lowest+REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100952
953 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +0100954 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Collet5054ee02015-11-23 13:34:21 +0100955 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +0100956 size_t offset;
Yann Collet5be2dd22015-11-11 13:43:58 +0100957 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Colletd94efbf2015-12-29 14:29:08 +0100958 const U32 matchIndex = hashTable[h];
959 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +0100960 const U32 current = (U32)(ip-base);
961 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100962
Yann Colletfb810d62016-01-28 00:18:06 +0100963 if (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)) { /* note : by construction, offset_1 <= current */
Yann Collet5054ee02015-11-23 13:34:21 +0100964 mlCode = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +0100965 ip++;
966 offset = 0;
Yann Colletfb810d62016-01-28 00:18:06 +0100967 } else {
Yann Colletd94efbf2015-12-29 14:29:08 +0100968 if ( (matchIndex <= lowIndex) ||
Yann Colletfb810d62016-01-28 00:18:06 +0100969 (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100970 ip += ((ip-anchor) >> g_searchStrength) + 1;
971 continue;
972 }
Yann Collet5054ee02015-11-23 13:34:21 +0100973 mlCode = ZSTD_count(ip+MINMATCH, match+MINMATCH, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +0100974 offset = ip-match;
Yann Collet5054ee02015-11-23 13:34:21 +0100975 while ((ip>anchor) && (match>lowest) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +0100976 offset_2 = offset_1;
977 offset_1 = offset;
978 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100979
Yann Collet402fdcf2015-11-20 12:46:08 +0100980 /* match found */
Yann Collet6bcdeac2015-11-26 11:43:00 +0100981 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +0100982 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +0100983 anchor = ip;
984
Yann Colletfb810d62016-01-28 00:18:06 +0100985 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100986 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +0100987 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 +0100988 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
989 /* check immediate repcode */
990 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +0100991 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100992 /* store sequence */
Yann Collet06eade52015-11-23 14:23:47 +0100993 size_t rlCode = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +0100994 size_t tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
995 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Collet06eade52015-11-23 14:23:47 +0100996 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rlCode);
997 ip += rlCode+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +0100998 anchor = ip;
999 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001000 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001001
Yann Collet44886612016-02-11 04:17:50 +01001002 { /* Last Literals */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001003 size_t lastLLSize = iend - anchor;
1004 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1005 seqStorePtr->lit += lastLLSize;
1006 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001007}
1008
1009
Yann Collet82260dd2016-02-11 07:14:25 +01001010static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001011 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001012{
1013 const U32 mls = ctx->params.searchLength;
1014 switch(mls)
1015 {
1016 default:
1017 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001018 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001019 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001020 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001021 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001022 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001023 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001024 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001025 }
1026}
Yann Colletf3eca252015-10-22 15:31:46 +01001027
Yann Colletf3eca252015-10-22 15:31:46 +01001028
Yann Collet82260dd2016-02-11 07:14:25 +01001029static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001030 const void* src, size_t srcSize,
1031 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001032{
1033 U32* hashTable = ctx->hashTable;
1034 const U32 hBits = ctx->params.hashLog;
1035 seqStore_t* seqStorePtr = &(ctx->seqStore);
1036 const BYTE* const base = ctx->base;
1037 const BYTE* const dictBase = ctx->dictBase;
1038 const BYTE* const istart = (const BYTE*)src;
1039 const BYTE* ip = istart;
1040 const BYTE* anchor = istart;
1041 const U32 lowLimit = ctx->lowLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001042 const BYTE* const dictStart = dictBase + lowLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001043 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001044 const BYTE* const lowPrefixPtr = base + dictLimit;
1045 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001046 const BYTE* const iend = istart + srcSize;
1047 const BYTE* const ilimit = iend - 8;
1048
Yann Collet138e89c2015-11-17 14:26:54 +01001049 U32 offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001050
1051
1052 /* init */
1053 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001054 /* skip first position to avoid read overflow during repcode match check */
Yann Colletfb810d62016-01-28 00:18:06 +01001055 hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0);
Yann Collet61e16ce2016-01-31 02:04:15 +01001056 ip += REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001057
1058 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001059 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001060 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001061 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001062 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001063 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001064 const U32 current = (U32)(ip-base);
Yann Collet743402c2015-11-20 12:03:53 +01001065 const U32 repIndex = current + 1 - offset_1;
Yann Collet402fdcf2015-11-20 12:46:08 +01001066 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001067 const BYTE* repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001068 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001069 U32 offset;
Yann Collet89db5e02015-11-13 11:27:46 +01001070 hashTable[h] = current; /* update hash table */
1071
1072 if ( ((repIndex <= dictLimit-4) || (repIndex >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001073 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001074 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001075 mlCode = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repMatchEnd, lowPrefixPtr);
Yann Collet743402c2015-11-20 12:03:53 +01001076 ip++;
Yann Collet402fdcf2015-11-20 12:46:08 +01001077 offset = 0;
Yann Colletfb810d62016-01-28 00:18:06 +01001078 } else {
Yann Collet402fdcf2015-11-20 12:46:08 +01001079 if ( (matchIndex < lowLimit) ||
1080 (MEM_read32(match) != MEM_read32(ip)) )
1081 { ip += ((ip-anchor) >> g_searchStrength) + 1; continue; }
1082 {
1083 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001084 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1085 mlCode = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iend, matchEnd, lowPrefixPtr);
Yann Colletfb810d62016-01-28 00:18:06 +01001086 while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001087 offset = current - matchIndex;
1088 offset_2 = offset_1;
1089 offset_1 = offset;
Yann Colletfb810d62016-01-28 00:18:06 +01001090 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001091
Yann Collet5054ee02015-11-23 13:34:21 +01001092 /* found a match : store it */
1093 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +01001094 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001095 anchor = ip;
1096
Yann Colletfb810d62016-01-28 00:18:06 +01001097 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001098 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001099 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001100 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1101 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001102 while (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001103 U32 current2 = (U32)(ip-base);
1104 const U32 repIndex2 = current2 - offset_2;
1105 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet743402c2015-11-20 12:03:53 +01001106 if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001107 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001108 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1109 size_t repLength2 = ZSTD_count_2segments(ip+MINMATCH, repMatch2+MINMATCH, iend, repEnd2, lowPrefixPtr);
1110 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1111 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2);
1112 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
1113 ip += repLength2+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001114 anchor = ip;
1115 continue;
1116 }
Yann Collet743402c2015-11-20 12:03:53 +01001117 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001118 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001119
1120 /* Last Literals */
1121 {
1122 size_t lastLLSize = iend - anchor;
1123 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1124 seqStorePtr->lit += lastLLSize;
1125 }
Yann Collet89db5e02015-11-13 11:27:46 +01001126}
1127
1128
Yann Collet82260dd2016-02-11 07:14:25 +01001129static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001130 const void* src, size_t srcSize)
1131{
1132 const U32 mls = ctx->params.searchLength;
1133 switch(mls)
1134 {
1135 default:
1136 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001137 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001138 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001139 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001140 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001141 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001142 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001143 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001144 }
1145}
1146
1147
Yann Collet04b12d82016-02-11 06:23:24 +01001148/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001149* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001150***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001151/** ZSTD_insertBt1() : add one or multiple positions to tree.
1152* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001153* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001154static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1155 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001156{
1157 U32* const hashTable = zc->hashTable;
1158 const U32 hashLog = zc->params.hashLog;
Yann Collet5be2dd22015-11-11 13:43:58 +01001159 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet1f44b3f2015-11-05 17:32:18 +01001160 U32* const bt = zc->contentTable;
1161 const U32 btLog = zc->params.contentLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001162 const U32 btMask= (1 << btLog) - 1;
1163 U32 matchIndex = hashTable[h];
1164 size_t commonLengthSmaller=0, commonLengthLarger=0;
1165 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001166 const BYTE* const dictBase = zc->dictBase;
1167 const U32 dictLimit = zc->dictLimit;
1168 const BYTE* const dictEnd = dictBase + dictLimit;
1169 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001170 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001171 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001172 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001173 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001174 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001175 U32 dummy32; /* to be nullified at the end */
Yann Collet03526e12015-11-23 15:29:15 +01001176 const U32 windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001177 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001178 size_t bestLength = 8;
Yann Collet7beaa052016-01-21 11:57:45 +01001179 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1180 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1181 predictedSmall += (predictedSmall>0);
1182 predictedLarge += (predictedLarge>0);
Yann Colletf48e35c2015-11-07 01:13:31 +01001183
Yann Collet6c3e2e72015-12-11 10:44:07 +01001184 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001185
Yann Colletfb810d62016-01-28 00:18:06 +01001186 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001187 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001188 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet04b12d82016-02-11 06:23:24 +01001189#if 1 /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001190 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001191 if (matchIndex == predictedSmall) {
1192 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001193 *smallerPtr = matchIndex;
1194 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1195 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1196 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001197 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001198 continue;
1199 }
Yann Colletfb810d62016-01-28 00:18:06 +01001200 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001201 *largerPtr = matchIndex;
1202 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1203 largerPtr = nextPtr;
1204 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001205 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001206 continue;
1207 }
Yann Collet04b12d82016-02-11 06:23:24 +01001208#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001209 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001210 match = base + matchIndex;
1211 if (match[matchLength] == ip[matchLength])
1212 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001213 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001214 match = dictBase + matchIndex;
1215 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1216 if (matchIndex+matchLength >= dictLimit)
1217 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1218 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001219
Yann Colletb8a6f682016-02-15 17:06:29 +01001220 if (matchLength > bestLength) {
1221 bestLength = matchLength;
1222 if (matchLength > matchEndIdx - matchIndex)
1223 matchEndIdx = matchIndex + (U32)matchLength;
1224 }
Yann Colletee3f4512015-12-29 22:26:09 +01001225
Yann Collet59d70632015-11-04 12:05:27 +01001226 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001227 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001228
Yann Colletfb810d62016-01-28 00:18:06 +01001229 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001230 /* match is smaller than current */
1231 *smallerPtr = matchIndex; /* update smaller idx */
1232 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001233 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001234 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001235 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001236 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001237 /* match is larger than current */
1238 *largerPtr = matchIndex;
1239 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001240 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001241 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001242 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001243 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001244
Yann Collet59d70632015-11-04 12:05:27 +01001245 *smallerPtr = *largerPtr = 0;
Yann Colletb8a6f682016-02-15 17:06:29 +01001246 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384));
1247 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1248 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001249}
1250
1251
Yann Collet82260dd2016-02-11 07:14:25 +01001252static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001253 ZSTD_CCtx* zc,
1254 const BYTE* const ip, const BYTE* const iend,
1255 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001256 U32 nbCompares, const U32 mls,
1257 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001258{
1259 U32* const hashTable = zc->hashTable;
1260 const U32 hashLog = zc->params.hashLog;
1261 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
1262 U32* const bt = zc->contentTable;
1263 const U32 btLog = zc->params.contentLog - 1;
1264 const U32 btMask= (1 << btLog) - 1;
1265 U32 matchIndex = hashTable[h];
1266 size_t commonLengthSmaller=0, commonLengthLarger=0;
1267 const BYTE* const base = zc->base;
1268 const BYTE* const dictBase = zc->dictBase;
1269 const U32 dictLimit = zc->dictLimit;
1270 const BYTE* const dictEnd = dictBase + dictLimit;
1271 const BYTE* const prefixStart = base + dictLimit;
1272 const U32 current = (U32)(ip-base);
1273 const U32 btLow = btMask >= current ? 0 : current - btMask;
1274 const U32 windowLow = zc->lowLimit;
1275 U32* smallerPtr = bt + 2*(current&btMask);
1276 U32* largerPtr = bt + 2*(current&btMask) + 1;
1277 size_t bestLength = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001278 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001279 U32 dummy32; /* to be nullified at the end */
1280
Yann Collet6c3e2e72015-12-11 10:44:07 +01001281 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001282
Yann Colletfb810d62016-01-28 00:18:06 +01001283 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001284 U32* nextPtr = bt + 2*(matchIndex & btMask);
1285 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1286 const BYTE* match;
1287
Yann Colletfb810d62016-01-28 00:18:06 +01001288 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001289 match = base + matchIndex;
1290 if (match[matchLength] == ip[matchLength])
1291 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001292 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001293 match = dictBase + matchIndex;
1294 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001295 if (matchIndex+matchLength >= dictLimit)
1296 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001297 }
1298
Yann Colletfb810d62016-01-28 00:18:06 +01001299 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001300 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001301 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet03526e12015-11-23 15:29:15 +01001302 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
1303 bestLength = matchLength, *offsetPtr = current - matchIndex;
1304 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1305 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1306 }
1307
Yann Colletfb810d62016-01-28 00:18:06 +01001308 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001309 /* match is smaller than current */
1310 *smallerPtr = matchIndex; /* update smaller idx */
1311 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1312 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1313 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1314 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001315 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001316 /* match is larger than current */
1317 *largerPtr = matchIndex;
1318 commonLengthLarger = matchLength;
1319 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1320 largerPtr = nextPtr;
1321 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001322 } }
Yann Collet03526e12015-11-23 15:29:15 +01001323
1324 *smallerPtr = *largerPtr = 0;
1325
Yann Collet72e84cf2015-12-31 19:08:44 +01001326 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
Yann Collet03526e12015-11-23 15:29:15 +01001327 return bestLength;
1328}
1329
Yann Collet2cc12cb2016-01-01 07:47:58 +01001330
Yann Colletb8a6f682016-02-15 17:06:29 +01001331static void ZSTD_updateTree(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
Yann Collet82260dd2016-02-11 07:14:25 +01001332{
1333 const BYTE* const base = zc->base;
1334 const U32 target = (U32)(ip - base);
1335 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001336
1337 while(idx < target)
1338 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001339}
1340
Yann Collet2cc12cb2016-01-01 07:47:58 +01001341/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001342static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001343 ZSTD_CCtx* zc,
1344 const BYTE* const ip, const BYTE* const iLimit,
1345 size_t* offsetPtr,
1346 const U32 maxNbAttempts, const U32 mls)
1347{
1348 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001349 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001350 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1351}
1352
1353
Yann Collet768c6bc2016-02-10 14:01:49 +01001354static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001355 ZSTD_CCtx* zc, /* Index table will be updated */
1356 const BYTE* ip, const BYTE* const iLimit,
1357 size_t* offsetPtr,
1358 const U32 maxNbAttempts, const U32 matchLengthSearch)
1359{
1360 switch(matchLengthSearch)
1361 {
1362 default :
1363 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1364 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1365 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1366 }
1367}
1368
1369
Yann Colletb8a6f682016-02-15 17:06:29 +01001370static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1371{
1372 const BYTE* const base = zc->base;
1373 const U32 target = (U32)(ip - base);
1374 U32 idx = zc->nextToUpdate;
1375
1376 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1377}
1378
inikep84f43e22016-02-22 11:34:07 +01001379#include "zstd_opt_internal.h"
Yann Collet2cc12cb2016-01-01 07:47:58 +01001380
Yann Collet03526e12015-11-23 15:29:15 +01001381/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001382static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001383 ZSTD_CCtx* zc,
1384 const BYTE* const ip, const BYTE* const iLimit,
1385 size_t* offsetPtr,
1386 const U32 maxNbAttempts, const U32 mls)
1387{
Yann Colletee3f4512015-12-29 22:26:09 +01001388 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001389 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001390 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001391}
1392
1393
Yann Collet82260dd2016-02-11 07:14:25 +01001394static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001395 ZSTD_CCtx* zc, /* Index table will be updated */
1396 const BYTE* ip, const BYTE* const iLimit,
1397 size_t* offsetPtr,
1398 const U32 maxNbAttempts, const U32 matchLengthSearch)
1399{
1400 switch(matchLengthSearch)
1401 {
1402 default :
1403 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1404 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1405 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1406 }
1407}
1408
1409
Yann Collet5106a762015-11-05 15:00:24 +01001410/* ***********************
1411* Hash Chain
1412*************************/
1413
Yann Collet1f44b3f2015-11-05 17:32:18 +01001414#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1415
Yann Collet6bcdeac2015-11-26 11:43:00 +01001416/* Update chains up to ip (excluded)
Yann Collet06eade52015-11-23 14:23:47 +01001417 Assumption : always within prefix (ie. not within extDict) */
Yann Collet6062b152016-02-16 17:41:03 +01001418FORCE_INLINE
1419U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
Yann Collet5106a762015-11-05 15:00:24 +01001420{
1421 U32* const hashTable = zc->hashTable;
1422 const U32 hashLog = zc->params.hashLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001423 U32* const chainTable = zc->contentTable;
1424 const U32 chainMask = (1 << zc->params.contentLog) - 1;
Yann Collet5106a762015-11-05 15:00:24 +01001425 const BYTE* const base = zc->base;
1426 const U32 target = (U32)(ip - base);
1427 U32 idx = zc->nextToUpdate;
1428
Yann Colletfb810d62016-01-28 00:18:06 +01001429 while(idx < target) {
Yann Collet5be2dd22015-11-11 13:43:58 +01001430 size_t h = ZSTD_hashPtr(base+idx, hashLog, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001431 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1432 hashTable[h] = idx;
1433 idx++;
1434 }
1435
1436 zc->nextToUpdate = target;
Yann Collet5be2dd22015-11-11 13:43:58 +01001437 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
Yann Collet5106a762015-11-05 15:00:24 +01001438}
1439
1440
1441FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Colletc1e52f02015-11-23 14:37:59 +01001442size_t ZSTD_HcFindBestMatch_generic (
Yann Collet5be2dd22015-11-11 13:43:58 +01001443 ZSTD_CCtx* zc, /* Index table will be updated */
Yann Collet5106a762015-11-05 15:00:24 +01001444 const BYTE* const ip, const BYTE* const iLimit,
1445 size_t* offsetPtr,
Yann Colletc1e52f02015-11-23 14:37:59 +01001446 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
Yann Collet287b7d92015-11-22 13:24:05 +01001447{
Yann Collet1f44b3f2015-11-05 17:32:18 +01001448 U32* const chainTable = zc->contentTable;
1449 const U32 chainSize = (1 << zc->params.contentLog);
Yann Collet5106a762015-11-05 15:00:24 +01001450 const U32 chainMask = chainSize-1;
1451 const BYTE* const base = zc->base;
1452 const BYTE* const dictBase = zc->dictBase;
1453 const U32 dictLimit = zc->dictLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001454 const BYTE* const prefixStart = base + dictLimit;
1455 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001456 const U32 lowLimit = zc->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001457 const U32 current = (U32)(ip-base);
1458 const U32 minChain = current > chainSize ? current - chainSize : 0;
Yann Collet5106a762015-11-05 15:00:24 +01001459 U32 matchIndex;
1460 const BYTE* match;
1461 int nbAttempts=maxNbAttempts;
Yann Collet5054ee02015-11-23 13:34:21 +01001462 size_t ml=MINMATCH-1;
Yann Collet5106a762015-11-05 15:00:24 +01001463
1464 /* HC4 match finder */
Yann Colletc1e52f02015-11-23 14:37:59 +01001465 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001466
Yann Colletfb810d62016-01-28 00:18:06 +01001467 while ((matchIndex>lowLimit) && (nbAttempts)) {
Yann Collet5054ee02015-11-23 13:34:21 +01001468 size_t currentMl=0;
Yann Collet5106a762015-11-05 15:00:24 +01001469 nbAttempts--;
Yann Colletfb810d62016-01-28 00:18:06 +01001470 if ((!extDict) || matchIndex >= dictLimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001471 match = base + matchIndex;
Yann Collet4baee502015-11-09 03:19:33 +01001472 if (match[ml] == ip[ml]) /* potentially better */
Yann Collet5054ee02015-11-23 13:34:21 +01001473 currentMl = ZSTD_count(ip, match, iLimit);
Yann Colletfb810d62016-01-28 00:18:06 +01001474 } else {
Yann Collet5106a762015-11-05 15:00:24 +01001475 match = dictBase + matchIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001476 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1477 currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
Yann Collet5106a762015-11-05 15:00:24 +01001478 }
1479
Yann Collet5054ee02015-11-23 13:34:21 +01001480 /* save best solution */
Yann Collet239cc282015-11-23 16:17:21 +01001481 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 +01001482
Yann Collet9a24e592015-11-22 02:53:43 +01001483 if (matchIndex <= minChain) break;
Yann Collet5106a762015-11-05 15:00:24 +01001484 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1485 }
1486
1487 return ml;
1488}
1489
1490
Yann Colletc1e52f02015-11-23 14:37:59 +01001491FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1492 ZSTD_CCtx* zc,
Yann Collet5106a762015-11-05 15:00:24 +01001493 const BYTE* ip, const BYTE* const iLimit,
1494 size_t* offsetPtr,
1495 const U32 maxNbAttempts, const U32 matchLengthSearch)
1496{
1497 switch(matchLengthSearch)
1498 {
1499 default :
Yann Colletc1e52f02015-11-23 14:37:59 +01001500 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1501 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1502 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1503 }
1504}
1505
1506
1507FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1508 ZSTD_CCtx* zc,
1509 const BYTE* ip, const BYTE* const iLimit,
1510 size_t* offsetPtr,
1511 const U32 maxNbAttempts, const U32 matchLengthSearch)
1512{
1513 switch(matchLengthSearch)
1514 {
1515 default :
1516 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1517 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1518 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001519 }
1520}
1521
1522
Yann Collet287b7d92015-11-22 13:24:05 +01001523/* *******************************
Yann Collet9a24e592015-11-22 02:53:43 +01001524* Common parser - lazy strategy
Yann Collet287b7d92015-11-22 13:24:05 +01001525*********************************/
Yann Collet5106a762015-11-05 15:00:24 +01001526FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001527void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1528 const void* src, size_t srcSize,
Yann Collet007c1c62015-11-22 02:42:28 +01001529 const U32 searchMethod, const U32 depth)
Yann Collet5106a762015-11-05 15:00:24 +01001530{
1531 seqStore_t* seqStorePtr = &(ctx->seqStore);
1532 const BYTE* const istart = (const BYTE*)src;
1533 const BYTE* ip = istart;
1534 const BYTE* anchor = istart;
1535 const BYTE* const iend = istart + srcSize;
1536 const BYTE* const ilimit = iend - 8;
Yann Collete47c4e52015-12-05 09:23:53 +01001537 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet5106a762015-11-05 15:00:24 +01001538
1539 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1540 const U32 maxSearches = 1 << ctx->params.searchLog;
1541 const U32 mls = ctx->params.searchLength;
1542
Yann Collet5be2dd22015-11-11 13:43:58 +01001543 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
Yann Collet5106a762015-11-05 15:00:24 +01001544 size_t* offsetPtr,
1545 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet5be2dd22015-11-11 13:43:58 +01001546 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet5106a762015-11-05 15:00:24 +01001547
1548 /* init */
1549 ZSTD_resetSeqStore(seqStorePtr);
Yann Collete47c4e52015-12-05 09:23:53 +01001550 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet5106a762015-11-05 15:00:24 +01001551
1552 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001553 while (ip < ilimit) {
Yann Collet7a231792015-11-21 15:27:35 +01001554 size_t matchLength=0;
1555 size_t offset=0;
1556 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001557
Yann Collet743402c2015-11-20 12:03:53 +01001558 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001559 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1)) {
Yann Collet743402c2015-11-20 12:03:53 +01001560 /* repcode : we take it */
Yann Collet7a231792015-11-21 15:27:35 +01001561 matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH;
Yann Collet007c1c62015-11-22 02:42:28 +01001562 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001563 }
1564
Yann Colletfc2afcf2015-11-06 15:40:14 +01001565 {
Yann Collet239cc282015-11-23 16:17:21 +01001566 /* first search (depth 0) */
1567 size_t offsetFound = 99999999;
1568 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1569 if (ml2 > matchLength)
1570 matchLength = ml2, start = ip, offset=offsetFound;
1571 }
Yann Collet9a24e592015-11-22 02:53:43 +01001572
Yann Colletfb810d62016-01-28 00:18:06 +01001573 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001574 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1575 continue;
1576 }
Yann Collet5106a762015-11-05 15:00:24 +01001577
1578 /* let's try to find a better solution */
Yann Collet007c1c62015-11-22 02:42:28 +01001579 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001580 while (ip<ilimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001581 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001582 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet007c1c62015-11-22 02:42:28 +01001583 size_t mlRep = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1584 int gain2 = (int)(mlRep * 3);
Yann Collet5106a762015-11-05 15:00:24 +01001585 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet007c1c62015-11-22 02:42:28 +01001586 if ((mlRep >= MINMATCH) && (gain2 > gain1))
1587 matchLength = mlRep, offset = 0, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001588 }
1589 {
1590 size_t offset2=999999;
1591 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet007c1c62015-11-22 02:42:28 +01001592 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1593 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001594 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001595 matchLength = ml2, offset = offset2, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001596 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001597 } }
Yann Collet5106a762015-11-05 15:00:24 +01001598
1599 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001600 if ((depth==2) && (ip<ilimit)) {
Yann Collet5106a762015-11-05 15:00:24 +01001601 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001602 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet5106a762015-11-05 15:00:24 +01001603 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1604 int gain2 = (int)(ml2 * 4);
1605 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet4baee502015-11-09 03:19:33 +01001606 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001607 matchLength = ml2, offset = 0, start = ip;
1608 }
1609 {
1610 size_t offset2=999999;
1611 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet628065c2015-11-06 18:44:54 +01001612 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1613 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001614 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001615 matchLength = ml2, offset = offset2, start = ip;
1616 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001617 } } }
Yann Collet5106a762015-11-05 15:00:24 +01001618 break; /* nothing found : store previous solution */
1619 }
1620
Yann Collet6062b152016-02-16 17:41:03 +01001621 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001622 if (offset) {
Yann Collete47c4e52015-12-05 09:23:53 +01001623 while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */
Yann Collet4baee502015-11-09 03:19:33 +01001624 { start--; matchLength++; }
Yann Collet743402c2015-11-20 12:03:53 +01001625 offset_2 = offset_1; offset_1 = offset;
Yann Collet4baee502015-11-09 03:19:33 +01001626 }
1627
1628 /* store sequence */
Yann Collet7a231792015-11-21 15:27:35 +01001629_storeSequence:
Yann Collet5106a762015-11-05 15:00:24 +01001630 {
1631 size_t litLength = start - anchor;
Yann Collet5106a762015-11-05 15:00:24 +01001632 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
Yann Collet4baee502015-11-09 03:19:33 +01001633 anchor = ip = start + matchLength;
Yann Collet5106a762015-11-05 15:00:24 +01001634 }
1635
Yann Collet743402c2015-11-20 12:03:53 +01001636 /* check immediate repcode */
1637 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001638 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet743402c2015-11-20 12:03:53 +01001639 /* store sequence */
1640 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
1641 offset = offset_2;
1642 offset_2 = offset_1;
1643 offset_1 = offset;
1644 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength);
1645 ip += matchLength+MINMATCH;
1646 anchor = ip;
1647 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001648 } }
Yann Collet5106a762015-11-05 15:00:24 +01001649
1650 /* Last Literals */
1651 {
1652 size_t lastLLSize = iend - anchor;
1653 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1654 seqStorePtr->lit += lastLLSize;
1655 }
Yann Collet5106a762015-11-05 15:00:24 +01001656}
1657
inikepe2bfe242016-01-31 11:25:48 +01001658
inikepd3b8d7a2016-02-22 10:06:17 +01001659static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01001660{
inikep84f43e22016-02-22 11:34:07 +01001661 if (ctx->params.searchLength == 3)
1662 ZSTD_compressBlock_opt_generic3(ctx, src, srcSize, 2);
1663 else
1664 ZSTD_compressBlock_opt_generic4(ctx, src, srcSize, 2);
inikepe2bfe242016-01-31 11:25:48 +01001665}
1666
Yann Collet59d1f792016-01-23 19:28:41 +01001667static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001668{
Yann Colleta1249dc2016-01-25 04:22:03 +01001669 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001670}
1671
Yann Collet59d1f792016-01-23 19:28:41 +01001672static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001673{
Yann Colleta1249dc2016-01-25 04:22:03 +01001674 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001675}
1676
Yann Collet59d1f792016-01-23 19:28:41 +01001677static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001678{
Yann Colleta1249dc2016-01-25 04:22:03 +01001679 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001680}
1681
Yann Collet59d1f792016-01-23 19:28:41 +01001682static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01001683{
Yann Colleta1249dc2016-01-25 04:22:03 +01001684 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
Yann Colletbe2010e2015-10-31 12:57:14 +01001685}
1686
1687
Yann Collet9a24e592015-11-22 02:53:43 +01001688FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001689void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1690 const void* src, size_t srcSize,
Yann Collet9a24e592015-11-22 02:53:43 +01001691 const U32 searchMethod, const U32 depth)
1692{
1693 seqStore_t* seqStorePtr = &(ctx->seqStore);
1694 const BYTE* const istart = (const BYTE*)src;
1695 const BYTE* ip = istart;
1696 const BYTE* anchor = istart;
1697 const BYTE* const iend = istart + srcSize;
1698 const BYTE* const ilimit = iend - 8;
1699 const BYTE* const base = ctx->base;
1700 const U32 dictLimit = ctx->dictLimit;
1701 const BYTE* const prefixStart = base + dictLimit;
1702 const BYTE* const dictBase = ctx->dictBase;
1703 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001704 const BYTE* const dictStart = dictBase + ctx->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001705
1706 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1707 const U32 maxSearches = 1 << ctx->params.searchLog;
1708 const U32 mls = ctx->params.searchLength;
1709
1710 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1711 size_t* offsetPtr,
1712 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet03526e12015-11-23 15:29:15 +01001713 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
Yann Collet9a24e592015-11-22 02:53:43 +01001714
1715 /* init */
1716 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet6c3e2e72015-12-11 10:44:07 +01001717 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Collet9a24e592015-11-22 02:53:43 +01001718
1719 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001720 while (ip < ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001721 size_t matchLength=0;
1722 size_t offset=0;
1723 const BYTE* start=ip+1;
1724 U32 current = (U32)(ip-base);
1725
1726 /* check repCode */
1727 {
1728 const U32 repIndex = (U32)(current+1 - offset_1);
1729 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1730 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001731 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001732 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001733 /* repcode detected we should take it */
1734 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001735 matchLength = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
Yann Collet9a24e592015-11-22 02:53:43 +01001736 if (depth==0) goto _storeSequence;
Yann Colletfb810d62016-01-28 00:18:06 +01001737 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001738
1739 {
Yann Collet239cc282015-11-23 16:17:21 +01001740 /* first search (depth 0) */
1741 size_t offsetFound = 99999999;
1742 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1743 if (ml2 > matchLength)
1744 matchLength = ml2, start = ip, offset=offsetFound;
1745 }
Yann Collet9a24e592015-11-22 02:53:43 +01001746
Yann Colletfb810d62016-01-28 00:18:06 +01001747 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001748 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1749 continue;
1750 }
Yann Collet9a24e592015-11-22 02:53:43 +01001751
1752 /* let's try to find a better solution */
1753 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001754 while (ip<ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001755 ip ++;
1756 current++;
1757 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001758 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001759 const U32 repIndex = (U32)(current - offset_1);
1760 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1761 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001762 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001763 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001764 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001765 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001766 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1767 int gain2 = (int)(repLength * 3);
1768 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1769 if ((repLength >= MINMATCH) && (gain2 > gain1))
1770 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001771 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001772
1773 /* search match, depth 1 */
1774 {
1775 size_t offset2=999999;
1776 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1777 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1778 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001779 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001780 matchLength = ml2, offset = offset2, start = ip;
1781 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001782 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001783
1784 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001785 if ((depth==2) && (ip<ilimit)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001786 ip ++;
1787 current++;
1788 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001789 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001790 const U32 repIndex = (U32)(current - offset_1);
1791 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1792 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001793 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001794 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001795 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001796 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001797 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1798 int gain2 = (int)(repLength * 4);
1799 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1800 if ((repLength >= MINMATCH) && (gain2 > gain1))
1801 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001802 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001803
1804 /* search match, depth 2 */
1805 {
1806 size_t offset2=999999;
1807 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1808 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1809 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001810 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001811 matchLength = ml2, offset = offset2, start = ip;
1812 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001813 } } }
Yann Collet9a24e592015-11-22 02:53:43 +01001814 break; /* nothing found : store previous solution */
1815 }
1816
1817 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001818 if (offset) {
Yann Colletc3652152015-11-24 14:06:07 +01001819 U32 matchIndex = (U32)((start-base) - offset);
1820 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1821 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
1822 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet9a24e592015-11-22 02:53:43 +01001823 offset_2 = offset_1; offset_1 = offset;
1824 }
1825
1826 /* store sequence */
1827_storeSequence:
1828 {
1829 size_t litLength = start - anchor;
1830 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1831 anchor = ip = start + matchLength;
1832 }
1833
1834 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001835 while (ip <= ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001836 const U32 repIndex = (U32)((ip-base) - offset_2);
1837 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1838 const BYTE* const repMatch = repBase + repIndex;
Yann Collet239cc282015-11-23 16:17:21 +01001839 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001840 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001841 /* repcode detected we should take it */
1842 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001843 matchLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1844 offset = offset_2; offset_2 = offset_1; offset_1 = offset; /* swap offset history */
Yann Collet9a24e592015-11-22 02:53:43 +01001845 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1846 ip += matchLength;
1847 anchor = ip;
1848 continue; /* faster when present ... (?) */
1849 }
1850 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001851 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001852
1853 /* Last Literals */
1854 {
1855 size_t lastLLSize = iend - anchor;
1856 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1857 seqStorePtr->lit += lastLLSize;
1858 }
Yann Collet9a24e592015-11-22 02:53:43 +01001859}
1860
Yann Collet59d1f792016-01-23 19:28:41 +01001861void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01001862{
Yann Colleta1249dc2016-01-25 04:22:03 +01001863 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01001864}
1865
Yann Collet59d1f792016-01-23 19:28:41 +01001866static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01001867{
Yann Colleta1249dc2016-01-25 04:22:03 +01001868 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01001869}
Yann Collet9a24e592015-11-22 02:53:43 +01001870
Yann Collet59d1f792016-01-23 19:28:41 +01001871static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01001872{
Yann Colleta1249dc2016-01-25 04:22:03 +01001873 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01001874}
1875
Yann Collet59d1f792016-01-23 19:28:41 +01001876static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01001877{
Yann Colleta1249dc2016-01-25 04:22:03 +01001878 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001879}
1880
inikepd3b8d7a2016-02-22 10:06:17 +01001881static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01001882{
inikep84f43e22016-02-22 11:34:07 +01001883 if (ctx->params.searchLength == 3)
1884 ZSTD_compressBlock_opt_extDict_generic3(ctx, src, srcSize, 2);
1885 else
1886 ZSTD_compressBlock_opt_extDict_generic4(ctx, src, srcSize, 2);
inikepe2bfe242016-01-31 11:25:48 +01001887}
1888
Yann Collet7a231792015-11-21 15:27:35 +01001889
Yann Collet59d1f792016-01-23 19:28:41 +01001890typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01001891
Yann Colletb923f652016-01-26 03:14:20 +01001892static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01001893{
inikepd3b8d7a2016-02-22 10:06:17 +01001894 static const ZSTD_blockCompressor blockCompressor[2][6] = {
1895 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt },
1896 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01001897 };
1898
1899 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01001900}
1901
1902
Yann Colletbf42c8e2016-01-09 01:08:23 +01001903static 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 +01001904{
Yann Collet03526e12015-11-23 15:29:15 +01001905 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01001906 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 +01001907 blockCompressor(zc, src, srcSize);
Yann Colletb923f652016-01-26 03:14:20 +01001908 return ZSTD_compressSequences(zc, dst, maxDstSize, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01001909}
1910
1911
Yann Collet2ce49232016-02-02 14:36:49 +01001912static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
Yann Colletf3eca252015-10-22 15:31:46 +01001913 void* dst, size_t maxDstSize,
1914 const void* src, size_t srcSize)
1915{
Yann Collet2ce49232016-02-02 14:36:49 +01001916 size_t blockSize = zc->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001917 size_t remaining = srcSize;
1918 const BYTE* ip = (const BYTE*)src;
1919 BYTE* const ostart = (BYTE*)dst;
1920 BYTE* op = ostart;
Yann Collet2ce49232016-02-02 14:36:49 +01001921 const U32 maxDist = 1 << zc->params.windowLog;
inikep15174b02016-02-23 12:41:56 +01001922 seqStore_t* ssPtr = &zc->seqStore;
inikepe0010e92016-02-23 16:25:04 +01001923 static U32 priceFunc = 0;
inikep15174b02016-02-23 12:41:56 +01001924
inikepe0010e92016-02-23 16:25:04 +01001925 ssPtr->realMatchSum = ssPtr->realLitSum = ssPtr->realSeqSum = ssPtr->realRepSum = 1;
1926 ssPtr->priceFunc = priceFunc;
Yann Collet9b11b462015-11-01 12:40:22 +01001927
Yann Collet2ce49232016-02-02 14:36:49 +01001928 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01001929 size_t cSize;
1930
Yann Collet2ce49232016-02-02 14:36:49 +01001931 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 +01001932 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01001933
Yann Collet2ce49232016-02-02 14:36:49 +01001934 if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */
Yann Collet7a6343f2016-02-02 16:00:50 +01001935 U32 newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist;
1936 if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01001937 if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001938 }
Yann Collet89db5e02015-11-13 11:27:46 +01001939
Yann Collet2ce49232016-02-02 14:36:49 +01001940 cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, maxDstSize-ZSTD_blockHeaderSize, ip, blockSize);
Yann Collet3e358272015-11-04 18:19:39 +01001941 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001942
Yann Collet2ce49232016-02-02 14:36:49 +01001943 if (cSize == 0) { /* block is not compressible */
1944 cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize);
Yann Collet523b5942016-01-09 02:10:40 +01001945 if (ZSTD_isError(cSize)) return cSize;
Yann Collet2ce49232016-02-02 14:36:49 +01001946 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01001947 op[0] = (BYTE)(cSize>>16);
1948 op[1] = (BYTE)(cSize>>8);
1949 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01001950 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01001951 cSize += 3;
1952 }
1953
1954 remaining -= blockSize;
Yann Collet3e358272015-11-04 18:19:39 +01001955 maxDstSize -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001956 ip += blockSize;
1957 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001958 }
1959
inikepe0010e92016-02-23 16:25:04 +01001960
inikepf647d992016-02-29 12:33:08 +01001961#if ZSTD_OPT_DEBUG == 3
inikep15174b02016-02-23 12:41:56 +01001962 ssPtr->realMatchSum += ssPtr->realSeqSum * ((zc->params.searchLength == 3) ? 3 : 4);
inikepe0010e92016-02-23 16:25:04 +01001963 printf("avgMatchL=%.2f avgLitL=%.2f match=%.1f%% lit=%.1f%% reps=%d seq=%d priceFunc=%d\n", (float)ssPtr->realMatchSum/ssPtr->realSeqSum, (float)ssPtr->realLitSum/ssPtr->realSeqSum, 100.0*ssPtr->realMatchSum/(ssPtr->realMatchSum+ssPtr->realLitSum), 100.0*ssPtr->realLitSum/(ssPtr->realMatchSum+ssPtr->realLitSum), ssPtr->realRepSum, ssPtr->realSeqSum, ssPtr->priceFunc);
1964 priceFunc++;
inikep15174b02016-02-23 12:41:56 +01001965#endif
1966
Yann Colletf3eca252015-10-22 15:31:46 +01001967 return op-ostart;
1968}
1969
1970
Yann Colletbf42c8e2016-01-09 01:08:23 +01001971static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
1972 void* dst, size_t dstSize,
1973 const void* src, size_t srcSize,
1974 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01001975{
Yann Collet2acb5d32015-10-29 16:49:43 +01001976 const BYTE* const ip = (const BYTE*) src;
Yann Colletecd651b2016-01-07 15:35:18 +01001977 size_t hbSize = 0;
1978
Yann Collet2ce49232016-02-02 14:36:49 +01001979 if (frame && (zc->stage==0)) {
Yann Colletecd651b2016-01-07 15:35:18 +01001980 hbSize = zc->hbSize;
1981 if (dstSize <= hbSize) return ERROR(dstSize_tooSmall);
1982 zc->stage = 1;
1983 memcpy(dst, zc->headerBuffer, hbSize);
1984 dstSize -= hbSize;
1985 dst = (char*)dst + hbSize;
1986 }
Yann Colletf3eca252015-10-22 15:31:46 +01001987
Yann Collet417890c2015-12-04 17:16:37 +01001988 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01001989 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01001990 /* not contiguous */
1991 size_t delta = zc->nextSrc - ip;
1992 zc->lowLimit = zc->dictLimit;
1993 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
1994 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01001995 zc->base -= delta;
1996 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01001997 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01001998 }
1999
Yann Collet89db5e02015-11-13 11:27:46 +01002000 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01002001 if (zc->lowLimit > (1<<30)) {
Yann Colletcefef8c2016-02-15 07:21:54 +01002002 U32 btplus = (zc->params.strategy == ZSTD_btlazy2) || (zc->params.strategy == ZSTD_btopt);
Yann Collet6c3e2e72015-12-11 10:44:07 +01002003 U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1;
2004 U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */
2005 U32 correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002006 ZSTD_reduceIndex(zc, correction);
2007 zc->base += correction;
2008 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002009 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002010 zc->dictLimit -= correction;
2011 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2012 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01002013 }
2014
Yann Colletbf42c8e2016-01-09 01:08:23 +01002015 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01002016 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01002017 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2018 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002019 }
2020
Yann Colletc3652152015-11-24 14:06:07 +01002021 zc->nextSrc = ip + srcSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002022 {
Yann Colletbf42c8e2016-01-09 01:08:23 +01002023 size_t cSize;
2024 if (frame) cSize = ZSTD_compress_generic (zc, dst, dstSize, src, srcSize);
2025 else cSize = ZSTD_compressBlock_internal (zc, dst, dstSize, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002026 if (ZSTD_isError(cSize)) return cSize;
2027 return cSize + hbSize;
2028 }
Yann Colletf3eca252015-10-22 15:31:46 +01002029}
2030
Yann Colletbf42c8e2016-01-09 01:08:23 +01002031
2032size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
2033 void* dst, size_t dstSize,
2034 const void* src, size_t srcSize)
2035{
2036 return ZSTD_compressContinue_internal(zc, dst, dstSize, src, srcSize, 1);
2037}
2038
2039
2040size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
2041{
2042 if (srcSize > BLOCKSIZE) return ERROR(srcSize_wrong);
inikepa4dde252016-03-01 14:14:35 +01002043 zc->params.searchLength = MINMATCH; /* force ZSTD_btopt to MINMATCH in block mode */
2044 ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.searchLength);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002045 return ZSTD_compressContinue_internal(zc, dst, maxDstSize, src, srcSize, 0);
2046}
2047
2048
Yann Colletb923f652016-01-26 03:14:20 +01002049static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002050{
2051 const BYTE* const ip = (const BYTE*) src;
2052 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002053
Yann Collet417890c2015-12-04 17:16:37 +01002054 /* input becomes current prefix */
2055 zc->lowLimit = zc->dictLimit;
2056 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2057 zc->dictBase = zc->base;
2058 zc->base += ip - zc->nextSrc;
2059 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002060 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002061
2062 zc->nextSrc = iend;
2063 if (srcSize <= 8) return 0;
2064
2065 switch(zc->params.strategy)
2066 {
2067 case ZSTD_fast:
Yann Collet2ce49232016-02-02 14:36:49 +01002068 ZSTD_fillHashTable (zc, iend, zc->params.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002069 break;
2070
2071 case ZSTD_greedy:
2072 case ZSTD_lazy:
2073 case ZSTD_lazy2:
2074 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength);
2075 break;
2076
2077 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002078 case ZSTD_btopt:
Yann Colletb8a6f682016-02-15 17:06:29 +01002079 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002080 break;
2081
2082 default:
2083 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2084 }
2085
Yann Collet2ce49232016-02-02 14:36:49 +01002086 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002087 return 0;
2088}
2089
2090
Yann Colletb923f652016-01-26 03:14:20 +01002091/* Dictionary format :
2092 Magic == ZSTD_DICT_MAGIC (4 bytes)
2093 Huff0 CTable (256 * 4 bytes) => to be changed to read from writeCTable
2094 Dictionary content
2095*/
2096/*! ZSTD_loadDictEntropyStats
2097 @return : size read from dictionary */
2098static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2099{
2100 /* note : magic number already checked */
Yann Colletfb810d62016-01-28 00:18:06 +01002101 size_t offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize, errorCode;
2102 short offcodeNCount[MaxOff+1];
2103 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2104 short matchlengthNCount[MaxML+1];
2105 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2106 short litlengthNCount[MaxLL+1];
2107 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2108
Yann Colletb923f652016-01-26 03:14:20 +01002109 const size_t hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize);
2110 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Colletfb810d62016-01-28 00:18:06 +01002111 zc->flagStaticTables = 1;
2112 dict = (const char*)dict + hufHeaderSize;
2113 dictSize -= hufHeaderSize;
2114
2115 offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
2116 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2117 errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2118 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2119 dict = (const char*)dict + offcodeHeaderSize;
2120 dictSize -= offcodeHeaderSize;
2121
2122 matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
2123 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2124 errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2125 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2126 dict = (const char*)dict + matchlengthHeaderSize;
2127 dictSize -= matchlengthHeaderSize;
2128
2129 litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
2130 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2131 errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2132 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2133
2134 return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
Yann Colletb923f652016-01-26 03:14:20 +01002135}
2136
Yann Colletfb810d62016-01-28 00:18:06 +01002137
Yann Collet1c8e1942016-01-26 16:31:22 +01002138static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002139{
Yann Collet2ce49232016-02-02 14:36:49 +01002140 if (dict && (dictSize>4)) {
Yann Collet7b51a292016-01-26 15:58:49 +01002141 U32 magic = MEM_readLE32(dict);
2142 size_t eSize;
2143 if (magic != ZSTD_DICT_MAGIC)
2144 return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletb923f652016-01-26 03:14:20 +01002145
Yann Collet7b51a292016-01-26 15:58:49 +01002146 eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4, dictSize-4) + 4;
2147 if (ZSTD_isError(eSize)) return eSize;
2148 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
2149 }
Yann Colletecd651b2016-01-07 15:35:18 +01002150 return 0;
2151}
2152
2153
Yann Collet417890c2015-12-04 17:16:37 +01002154/*! ZSTD_compressBegin_advanced
Yann Colletecd651b2016-01-07 15:35:18 +01002155* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002156size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
2157 const void* dict, size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002158 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002159{
Yann Collet4114f952015-10-30 06:40:22 +01002160 size_t errorCode;
Yann Collet88fcd292015-11-25 14:42:45 +01002161
2162 ZSTD_validateParams(&params);
2163
Yann Collet1c8e1942016-01-26 16:31:22 +01002164 errorCode = ZSTD_resetCCtx_advanced(zc, params);
Yann Collet4114f952015-10-30 06:40:22 +01002165 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet89db5e02015-11-13 11:27:46 +01002166
Yann Collet1c8e1942016-01-26 16:31:22 +01002167 MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */
inikep6b3739c2016-02-22 15:53:42 +01002168 ((BYTE*)zc->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN + ((params.searchLength==3)<<4));
Yann Collet1c8e1942016-01-26 16:31:22 +01002169 zc->hbSize = ZSTD_frameHeaderSize_min;
2170 zc->stage = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002171
Yann Collet1c8e1942016-01-26 16:31:22 +01002172 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002173}
2174
2175
Yann Collet1c8e1942016-01-26 16:31:22 +01002176size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002177{
inikepa4dde252016-03-01 14:14:35 +01002178 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet953ce722016-02-04 15:28:14 +01002179 return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, MAX(128 KB, dictSize)));
Yann Collet1c8e1942016-01-26 16:31:22 +01002180}
Yann Collet083fcc82015-10-25 14:06:35 +01002181
Yann Collet1c8e1942016-01-26 16:31:22 +01002182size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002183{
inikepa4dde252016-03-01 14:14:35 +01002184 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet1c8e1942016-01-26 16:31:22 +01002185 return ZSTD_compressBegin_advanced(zc, NULL, 0, ZSTD_getParams(compressionLevel, 0));
Yann Collet083fcc82015-10-25 14:06:35 +01002186}
2187
2188
Yann Collet31683c02015-12-18 01:26:48 +01002189/*! ZSTD_compressEnd
Yann Collet88fcd292015-11-25 14:42:45 +01002190* Write frame epilogue
2191* @return : nb of bytes written into dst (or an error code) */
Yann Colletecd651b2016-01-07 15:35:18 +01002192size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize)
Yann Collet2acb5d32015-10-29 16:49:43 +01002193{
2194 BYTE* op = (BYTE*)dst;
Yann Colletecd651b2016-01-07 15:35:18 +01002195 size_t hbSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002196
Yann Colletecd651b2016-01-07 15:35:18 +01002197 /* empty frame */
Yann Colletfb810d62016-01-28 00:18:06 +01002198 if (zc->stage==0) {
Yann Colletecd651b2016-01-07 15:35:18 +01002199 hbSize = zc->hbSize;
2200 if (maxDstSize <= hbSize) return ERROR(dstSize_tooSmall);
2201 zc->stage = 1;
2202 memcpy(dst, zc->headerBuffer, hbSize);
2203 maxDstSize -= hbSize;
2204 op += hbSize;
2205 }
2206
2207 /* frame epilogue */
Yann Collet2acb5d32015-10-29 16:49:43 +01002208 if (maxDstSize < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002209 op[0] = (BYTE)(bt_end << 6);
2210 op[1] = 0;
2211 op[2] = 0;
2212
Yann Colletecd651b2016-01-07 15:35:18 +01002213 return 3+hbSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002214}
2215
Yann Colletfd416f12016-01-30 03:14:15 +01002216
2217size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
2218 void* dst, size_t maxDstSize,
2219 const void* src, size_t srcSize)
2220{
2221 size_t outSize;
2222 size_t errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2223 if (ZSTD_isError(errorCode)) return errorCode;
2224 errorCode = ZSTD_compressContinue(cctx, dst, maxDstSize, src, srcSize);
2225 if (ZSTD_isError(errorCode)) return errorCode;
2226 outSize = errorCode;
2227 errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, maxDstSize-outSize);
2228 if (ZSTD_isError(errorCode)) return errorCode;
2229 outSize += errorCode;
2230 return outSize;
2231}
2232
2233
Yann Collet5be2dd22015-11-11 13:43:58 +01002234size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
Yann Collet88fcd292015-11-25 14:42:45 +01002235 void* dst, size_t maxDstSize,
2236 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002237 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002238 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002239{
2240 BYTE* const ostart = (BYTE*)dst;
2241 BYTE* op = ostart;
Yann Collet4114f952015-10-30 06:40:22 +01002242 size_t oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002243
Yann Collet1c8e1942016-01-26 16:31:22 +01002244 /* Init */
2245 oSize = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params);
Yann Colletf3eca252015-10-22 15:31:46 +01002246 if(ZSTD_isError(oSize)) return oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002247
2248 /* body (compression) */
Yann Collet31683c02015-12-18 01:26:48 +01002249 oSize = ZSTD_compressContinue (ctx, op, maxDstSize, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002250 if(ZSTD_isError(oSize)) return oSize;
2251 op += oSize;
2252 maxDstSize -= oSize;
2253
2254 /* Close frame */
Yann Collet5be2dd22015-11-11 13:43:58 +01002255 oSize = ZSTD_compressEnd(ctx, op, maxDstSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002256 if(ZSTD_isError(oSize)) return oSize;
2257 op += oSize;
2258
2259 return (op - ostart);
2260}
2261
Yann Collet31683c02015-12-18 01:26:48 +01002262size_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)
2263{
inikepa4dde252016-03-01 14:14:35 +01002264 ZSTD_LOG_BLOCK("%p: ZSTD_compress_usingDict srcSize=%d dictSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, (int)dictSize, compressionLevel);
Yann Collet2ce49232016-02-02 14:36:49 +01002265 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet31683c02015-12-18 01:26:48 +01002266}
2267
Yann Collet5be2dd22015-11-11 13:43:58 +01002268size_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 +01002269{
inikepa4dde252016-03-01 14:14:35 +01002270 ZSTD_LOG_BLOCK("%p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, compressionLevel);
Yann Collet31683c02015-12-18 01:26:48 +01002271 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet083fcc82015-10-25 14:06:35 +01002272}
2273
Yann Collet5be2dd22015-11-11 13:43:58 +01002274size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002275{
Yann Collet44fe9912015-10-29 22:02:40 +01002276 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002277 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002278 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Collet5be2dd22015-11-11 13:43:58 +01002279 result = ZSTD_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel);
Yann Colletecd651b2016-01-07 15:35:18 +01002280 free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002281 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002282}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002283
Yann Colletfd416f12016-01-30 03:14:15 +01002284
Yann Collet70e8c382016-02-10 13:37:52 +01002285/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01002286
inikep6b3739c2016-02-22 15:53:42 +01002287#define ZSTD_MAX_CLEVEL 25
Yann Collet7d968c72016-02-03 02:11:32 +01002288unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2289
inikepcc52a972016-02-19 10:09:35 +01002290
Yann Colletfd416f12016-01-30 03:14:15 +01002291static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = {
2292{ /* "default" */
inikepcc52a972016-02-19 10:09:35 +01002293 /* l, W, C, H, H3, S, L, SL, strat */
2294 { 0, 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2295 { 0, 19, 13, 14, 0, 1, 7, 4, ZSTD_fast }, /* level 1 */
2296 { 0, 19, 15, 16, 0, 1, 6, 4, ZSTD_fast }, /* level 2 */
2297 { 0, 20, 18, 20, 0, 1, 6, 4, ZSTD_fast }, /* level 3 */
2298 { 0, 21, 19, 21, 0, 1, 6, 4, ZSTD_fast }, /* level 4 */
2299 { 0, 20, 14, 18, 0, 3, 5, 4, ZSTD_greedy }, /* level 5 */
2300 { 0, 20, 18, 19, 0, 3, 5, 4, ZSTD_greedy }, /* level 6 */
2301 { 0, 21, 17, 20, 0, 3, 5, 4, ZSTD_lazy }, /* level 7 */
2302 { 0, 21, 19, 20, 0, 3, 5, 4, ZSTD_lazy }, /* level 8 */
2303 { 0, 21, 20, 20, 0, 3, 5, 4, ZSTD_lazy2 }, /* level 9 */
2304 { 0, 21, 19, 21, 0, 4, 5, 4, ZSTD_lazy2 }, /* level 10 */
2305 { 0, 22, 20, 22, 0, 4, 5, 4, ZSTD_lazy2 }, /* level 11 */
2306 { 0, 22, 20, 22, 0, 5, 5, 4, ZSTD_lazy2 }, /* level 12 */
2307 { 0, 22, 21, 22, 0, 5, 5, 4, ZSTD_lazy2 }, /* level 13 */
2308 { 0, 22, 22, 23, 0, 5, 5, 4, ZSTD_lazy2 }, /* level 14 */
2309 { 0, 23, 23, 23, 0, 5, 5, 4, ZSTD_lazy2 }, /* level 15 */
2310 { 0, 23, 22, 22, 0, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */
2311 { 0, 24, 24, 23, 0, 4, 5, 4, ZSTD_btlazy2 }, /* level 17 */
inikep6b3739c2016-02-22 15:53:42 +01002312 { 0, 24, 24, 23, 0, 5, 5, 30, ZSTD_btopt }, /* level 18 */
2313 { 0, 25, 25, 24, 0, 5, 4, 40, ZSTD_btopt }, /* level 19 */
2314 { 0, 26, 26, 25, 0, 8, 4,256, ZSTD_btopt }, /* level 20 */
2315 { 0, 26, 27, 25, 0, 10, 4,256, ZSTD_btopt }, /* level 21 */
2316 { 0, 24, 24, 23, 16, 5, 3, 30, ZSTD_btopt }, /* level 22 */
2317 { 0, 25, 25, 24, 16, 5, 3, 40, ZSTD_btopt }, /* level 23 */
2318 { 0, 26, 26, 25, 16, 8, 3,256, ZSTD_btopt }, /* level 24 */
2319 { 0, 26, 27, 25, 24, 10, 3,256, ZSTD_btopt }, /* level 25 */
Yann Colletfd416f12016-01-30 03:14:15 +01002320},
2321{ /* for srcSize <= 256 KB */
inikepcc52a972016-02-19 10:09:35 +01002322 /* l, W, C, H, H3, S, L, T, strat */
2323 { 0, 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 */
2324 { 0, 18, 14, 15, 0, 1, 6, 4, ZSTD_fast }, /* level 1 */
2325 { 0, 18, 14, 16, 0, 1, 5, 4, ZSTD_fast }, /* level 2 */
2326 { 0, 18, 14, 17, 0, 1, 5, 4, ZSTD_fast }, /* level 3.*/
2327 { 0, 18, 14, 15, 0, 4, 4, 4, ZSTD_greedy }, /* level 4 */
2328 { 0, 18, 16, 17, 0, 4, 4, 4, ZSTD_greedy }, /* level 5 */
2329 { 0, 18, 17, 17, 0, 3, 4, 4, ZSTD_lazy }, /* level 6 */
2330 { 0, 18, 17, 17, 0, 4, 4, 4, ZSTD_lazy }, /* level 7 */
2331 { 0, 18, 17, 17, 0, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2332 { 0, 18, 17, 17, 0, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2333 { 0, 18, 17, 17, 0, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
2334 { 0, 18, 17, 17, 0, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */
2335 { 0, 18, 18, 17, 0, 4, 4, 4, ZSTD_btlazy2 }, /* level 12 */
2336 { 0, 18, 19, 17, 0, 7, 4, 4, ZSTD_btlazy2 }, /* level 13.*/
2337 { 0, 18, 17, 19, 0, 8, 4, 24, ZSTD_btopt }, /* level 14.*/
2338 { 0, 18, 19, 19, 0, 8, 4, 48, ZSTD_btopt }, /* level 15.*/
2339 { 0, 18, 19, 18, 0, 9, 4,128, ZSTD_btopt }, /* level 16.*/
2340 { 0, 18, 19, 18, 0, 9, 4,192, ZSTD_btopt }, /* level 17.*/
2341 { 0, 18, 19, 18, 0, 9, 4,256, ZSTD_btopt }, /* level 18.*/
2342 { 0, 18, 19, 18, 0, 10, 4,256, ZSTD_btopt }, /* level 19.*/
2343 { 0, 18, 19, 18, 0, 11, 4,256, ZSTD_btopt }, /* level 20.*/
2344 { 0, 18, 19, 18, 0, 12, 4,256, ZSTD_btopt }, /* level 21.*/
inikep9f754d22016-02-22 17:00:04 +01002345 { 0, 18, 19, 18, 0, 12, 4,256, ZSTD_btopt }, /* level 21-2*/
2346 { 0, 18, 19, 18, 0, 12, 4,256, ZSTD_btopt }, /* level 21-3*/
2347 { 0, 18, 19, 18, 0, 12, 4,256, ZSTD_btopt }, /* level 21-4*/
2348 { 0, 18, 19, 18, 0, 12, 4,256, ZSTD_btopt }, /* level 21-5*/
Yann Colletfd416f12016-01-30 03:14:15 +01002349},
2350{ /* for srcSize <= 128 KB */
inikepcc52a972016-02-19 10:09:35 +01002351 /* l, W, C, H, H3, S, L, T, strat */
2352 { 0, 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2353 { 0, 17, 12, 13, 0, 1, 6, 4, ZSTD_fast }, /* level 1 */
2354 { 0, 17, 13, 16, 0, 1, 5, 4, ZSTD_fast }, /* level 2 */
2355 { 0, 17, 13, 14, 0, 2, 5, 4, ZSTD_greedy }, /* level 3 */
2356 { 0, 17, 13, 15, 0, 3, 4, 4, ZSTD_greedy }, /* level 4 */
2357 { 0, 17, 15, 17, 0, 4, 4, 4, ZSTD_greedy }, /* level 5 */
2358 { 0, 17, 16, 17, 0, 3, 4, 4, ZSTD_lazy }, /* level 6 */
2359 { 0, 17, 16, 17, 0, 4, 4, 4, ZSTD_lazy }, /* level 7 */
2360 { 0, 17, 17, 16, 0, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2361 { 0, 17, 17, 16, 0, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2362 { 0, 17, 17, 16, 0, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
2363 { 0, 17, 17, 17, 0, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */
2364 { 0, 17, 17, 17, 0, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */
2365 { 0, 17, 17, 17, 0, 9, 4, 4, ZSTD_lazy2 }, /* level 13 */
2366 { 0, 17, 18, 16, 0, 5, 4, 20, ZSTD_btopt }, /* level 14 */
2367 { 0, 17, 18, 16, 0, 9, 4, 48, ZSTD_btopt }, /* level 15 */
2368 { 0, 17, 18, 17, 0, 7, 4,128, ZSTD_btopt }, /* level 16 */
2369 { 0, 17, 18, 17, 0, 8, 4,128, ZSTD_btopt }, /* level 17 */
2370 { 0, 17, 18, 17, 0, 8, 4,256, ZSTD_btopt }, /* level 18 */
2371 { 0, 17, 18, 17, 0, 9, 4,256, ZSTD_btopt }, /* level 19 */
2372 { 0, 17, 18, 17, 0, 10, 4,512, ZSTD_btopt }, /* level 20 */
2373 { 0, 17, 18, 17, 0, 11, 4,512, ZSTD_btopt }, /* level 21 */
inikep9f754d22016-02-22 17:00:04 +01002374 { 0, 17, 18, 17, 0, 11, 4,512, ZSTD_btopt }, /* level 21-2 */
2375 { 0, 17, 18, 17, 0, 11, 4,512, ZSTD_btopt }, /* level 21-3 */
2376 { 0, 17, 18, 17, 0, 11, 4,512, ZSTD_btopt }, /* level 21-4 */
2377 { 0, 17, 18, 17, 0, 11, 4,512, ZSTD_btopt }, /* level 21-5 */
Yann Collet38fba562016-02-13 11:20:23 +01002378
Yann Colletfd416f12016-01-30 03:14:15 +01002379},
2380{ /* for srcSize <= 16 KB */
inikepcc52a972016-02-19 10:09:35 +01002381 /* l, W, C, H, H3, S, L, T, strat */
2382 { 0, 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 -- never used */
2383 { 0, 14, 14, 14, 0, 1, 4, 4, ZSTD_fast }, /* level 1 */
2384 { 0, 14, 14, 15, 0, 1, 4, 4, ZSTD_fast }, /* level 2 */
2385 { 0, 14, 13, 15, 0, 4, 4, 4, ZSTD_greedy }, /* level 3 */
2386 { 0, 14, 14, 15, 0, 3, 4, 4, ZSTD_lazy }, /* level 4 */
2387 { 0, 14, 14, 14, 0, 6, 4, 4, ZSTD_lazy }, /* level 5 */
2388 { 0, 14, 14, 14, 0, 5, 4, 4, ZSTD_lazy2 }, /* level 6 */
2389 { 0, 14, 14, 14, 0, 7, 4, 4, ZSTD_lazy2 }, /* level 7 */
2390 { 0, 14, 14, 14, 0, 8, 4, 4, ZSTD_lazy2 }, /* level 8 */
2391 { 0, 14, 14, 14, 0, 9, 4, 4, ZSTD_lazy2 }, /* level 9 */
2392 { 0, 14, 14, 14, 0, 10, 4, 4, ZSTD_lazy2 }, /* level 10 */
2393 { 0, 14, 14, 14, 0, 11, 4, 4, ZSTD_lazy2 }, /* level 11 */
2394 { 0, 14, 15, 15, 0, 12, 4, 32, ZSTD_btopt }, /* level 12 */
2395 { 0, 14, 15, 15, 0, 12, 4, 64, ZSTD_btopt }, /* level 13 */
2396 { 0, 14, 15, 15, 0, 12, 4, 96, ZSTD_btopt }, /* level 14 */
2397 { 0, 14, 15, 15, 0, 12, 4,128, ZSTD_btopt }, /* level 15 */
2398 { 0, 14, 15, 15, 0, 12, 4,256, ZSTD_btopt }, /* level 16 */
2399 { 0, 14, 15, 15, 0, 13, 4,256, ZSTD_btopt }, /* level 17 */
2400 { 0, 14, 15, 15, 0, 14, 4,256, ZSTD_btopt }, /* level 18 */
2401 { 0, 14, 15, 15, 0, 15, 4,256, ZSTD_btopt }, /* level 19 */
2402 { 0, 14, 15, 15, 0, 16, 4,256, ZSTD_btopt }, /* level 20 */
2403 { 0, 14, 15, 15, 0, 17, 4,256, ZSTD_btopt }, /* level 21 */
inikep9f754d22016-02-22 17:00:04 +01002404 { 0, 14, 15, 15, 0, 17, 4,256, ZSTD_btopt }, /* level 21-2 */
2405 { 0, 14, 15, 15, 0, 17, 4,256, ZSTD_btopt }, /* level 21-3 */
2406 { 0, 14, 15, 15, 0, 17, 4,256, ZSTD_btopt }, /* level 21-4 */
2407 { 0, 14, 15, 15, 0, 17, 4,256, ZSTD_btopt }, /* level 21-5 */
Yann Colletfd416f12016-01-30 03:14:15 +01002408},
2409};
2410
2411/*! ZSTD_getParams
2412* @return ZSTD_parameters structure for a selected compression level and srcSize.
2413* @srcSizeHint value is optional, select 0 if not known */
2414ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint)
2415{
2416 ZSTD_parameters result;
2417 int tableID = ((srcSizeHint-1) <= 256 KB) + ((srcSizeHint-1) <= 128 KB) + ((srcSizeHint-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
2418 if (compressionLevel<=0) compressionLevel = 1;
2419 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
inikep3379c5d2016-02-05 09:21:20 +01002420#if ZSTD_OPT_DEBUG >= 1
2421 tableID=0;
2422#endif
Yann Colletfd416f12016-01-30 03:14:15 +01002423 result = ZSTD_defaultParameters[tableID][compressionLevel];
2424 result.srcSize = srcSizeHint;
2425 return result;
2426}
2427