blob: 50fa2fdc26537879d9beb36bcb3c43173d1060bb [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);
inikep87d4f3d2016-03-02 15:56:24 +0100177 const size_t neededSpace = tableSpace + (256*sizeof(U32)) + (3*blockSize)
178 + ((params.strategy == ZSTD_btopt) ? ((1<<MLbits) + (1<<LLbits) + (1<<Offbits) + (1<<Litbits))*sizeof(U32) + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t)) : 0);
179
Yann Collet863ec402016-01-28 17:56:33 +0100180 if (zc->workSpaceSize < neededSpace) {
181 free(zc->workSpace);
182 zc->workSpace = malloc(neededSpace);
183 if (zc->workSpace == NULL) return ERROR(memory_allocation);
184 zc->workSpaceSize = neededSpace;
Yann Collet083fcc82015-10-25 14:06:35 +0100185 }
Yann Collet863ec402016-01-28 17:56:33 +0100186 memset(zc->workSpace, 0, tableSpace ); /* reset only tables */
inikepcc52a972016-02-19 10:09:35 +0100187 zc->hashTable3 = (U32*)(zc->workSpace);
188 zc->hashTable = zc->hashTable3 + ((size_t)1 << params.hashLog3);
Yann Collet863ec402016-01-28 17:56:33 +0100189 zc->contentTable = zc->hashTable + ((size_t)1 << params.hashLog);
190 zc->seqStore.buffer = zc->contentTable + ((size_t)1 << contentLog);
191 zc->hufTable = (HUF_CElt*)zc->seqStore.buffer;
192 zc->flagStaticTables = 0;
193 zc->seqStore.buffer = (U32*)(zc->seqStore.buffer) + 256;
Yann Collet083fcc82015-10-25 14:06:35 +0100194
Yann Colletf48e35c2015-11-07 01:13:31 +0100195 zc->nextToUpdate = 1;
Yann Collet89db5e02015-11-13 11:27:46 +0100196 zc->nextSrc = NULL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100197 zc->base = NULL;
198 zc->dictBase = NULL;
199 zc->dictLimit = 0;
200 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100201 zc->params = params;
Yann Collet120230b2015-12-02 14:00:45 +0100202 zc->blockSize = blockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100203
inikep87d4f3d2016-03-02 15:56:24 +0100204 zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer);
inikep51bb9a02016-03-02 19:17:13 +0100205 zc->seqStore.offCodeStart = (BYTE*) (zc->seqStore.offsetStart) + blockSize;
Yann Collet120230b2015-12-02 14:00:45 +0100206 zc->seqStore.litStart = zc->seqStore.offCodeStart + (blockSize>>2);
207 zc->seqStore.litLengthStart = zc->seqStore.litStart + blockSize;
208 zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + (blockSize>>2);
inikep51bb9a02016-03-02 19:17:13 +0100209 zc->seqStore.dumpsStart = zc->seqStore.matchLengthStart + (blockSize>>2);
inikep5cccd772016-03-02 20:37:49 +0100210
211 zc->seqStore.litFreq = (U32*)((void*)(zc->seqStore.dumpsStart + (blockSize>>2)));
inikep87d4f3d2016-03-02 15:56:24 +0100212 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
213 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (1<<LLbits);
214 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (1<<MLbits);
215 zc->seqStore.matchTable = (ZSTD_match_t*)(zc->seqStore.offCodeFreq + (1<<Offbits));
216 zc->seqStore.priceTable = (ZSTD_optimal_t*)(zc->seqStore.matchTable + ZSTD_OPT_NUM+1);
217
218 zc->seqStore.litLengthSum = 0;
Yann Colletecd651b2016-01-07 15:35:18 +0100219 zc->hbSize = 0;
Yann Collet60096272016-01-08 17:27:50 +0100220 zc->stage = 0;
Yann Collet2ce49232016-02-02 14:36:49 +0100221 zc->loadedDictEnd = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +0100222
Yann Collet4114f952015-10-30 06:40:22 +0100223 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100224}
225
Yann Collet083fcc82015-10-25 14:06:35 +0100226
Yann Collet7b51a292016-01-26 15:58:49 +0100227/*! ZSTD_copyCCtx
228* Duplicate an existing context @srcCCtx into another one @dstCCtx.
229* Only works during stage 0 (i.e. before first call to ZSTD_compressContinue())
230* @return : 0, or an error code */
231size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
232{
233 const U32 contentLog = (srcCCtx->params.strategy == ZSTD_fast) ? 1 : srcCCtx->params.contentLog;
inikepf4146472016-02-25 22:31:07 +0100234 const size_t tableSpace = ((1 << contentLog) + (1 << srcCCtx->params.hashLog) + (1 << srcCCtx->params.hashLog3)) * sizeof(U32);
235
Yann Collet7b51a292016-01-26 15:58:49 +0100236 if (srcCCtx->stage!=0) return ERROR(stage_wrong);
237
238 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params);
239
240 /* copy tables */
inikepcc52a972016-02-19 10:09:35 +0100241 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
Yann Collet7b51a292016-01-26 15:58:49 +0100242
243 /* copy frame header */
244 dstCCtx->hbSize = srcCCtx->hbSize;
245 memcpy(dstCCtx->headerBuffer , srcCCtx->headerBuffer, srcCCtx->hbSize);
246
247 /* copy dictionary pointers */
248 dstCCtx->nextToUpdate= srcCCtx->nextToUpdate;
inikepf4146472016-02-25 22:31:07 +0100249 dstCCtx->nextToUpdate3 = srcCCtx->nextToUpdate3;
Yann Collet7b51a292016-01-26 15:58:49 +0100250 dstCCtx->nextSrc = srcCCtx->nextSrc;
251 dstCCtx->base = srcCCtx->base;
252 dstCCtx->dictBase = srcCCtx->dictBase;
253 dstCCtx->dictLimit = srcCCtx->dictLimit;
254 dstCCtx->lowLimit = srcCCtx->lowLimit;
Yann Collet7a6343f2016-02-02 16:00:50 +0100255 dstCCtx->loadedDictEnd = srcCCtx->loadedDictEnd;
Yann Collet7b51a292016-01-26 15:58:49 +0100256
Yann Colletfb810d62016-01-28 00:18:06 +0100257 /* copy entropy tables */
258 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100259 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100260 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100261 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
262 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
263 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
264 }
Yann Collet7b51a292016-01-26 15:58:49 +0100265
266 return 0;
267}
268
269
Yann Collet863ec402016-01-28 17:56:33 +0100270/*! ZSTD_reduceIndex
Yann Collet88fcd292015-11-25 14:42:45 +0100271* rescale indexes to avoid future overflow (indexes are U32) */
Yann Collet89db5e02015-11-13 11:27:46 +0100272static void ZSTD_reduceIndex (ZSTD_CCtx* zc,
273 const U32 reducerValue)
274{
Yann Collet88fcd292015-11-25 14:42:45 +0100275 const U32 contentLog = (zc->params.strategy == ZSTD_fast) ? 1 : zc->params.contentLog;
Yann Collet89db5e02015-11-13 11:27:46 +0100276 const U32 tableSpaceU32 = (1 << contentLog) + (1 << zc->params.hashLog);
277 U32* table32 = zc->hashTable;
278 U32 index;
279
Yann Colletfb810d62016-01-28 00:18:06 +0100280 for (index=0 ; index < tableSpaceU32 ; index++) {
Yann Collet89db5e02015-11-13 11:27:46 +0100281 if (table32[index] < reducerValue) table32[index] = 0;
282 else table32[index] -= reducerValue;
283 }
284}
285
286
Yann Collet863ec402016-01-28 17:56:33 +0100287/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100288* Block entropic compression
289*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100290
Yann Collet59d1f792016-01-23 19:28:41 +0100291/* Block format description
292
293 Block = Literal Section - Sequences Section
294 Prerequisite : size of (compressed) block, maximum size of regenerated data
295
296 1) Literal Section
297
298 1.1) Header : 1-5 bytes
299 flags: 2 bits
300 00 compressed by Huff0
301 01 unused
302 10 is Raw (uncompressed)
303 11 is Rle
304 Note : using 01 => Huff0 with precomputed table ?
305 Note : delta map ? => compressed ?
306
307 1.1.1) Huff0-compressed literal block : 3-5 bytes
Yann Colletafe07092016-01-25 04:10:46 +0100308 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
Yann Collet59d1f792016-01-23 19:28:41 +0100309 srcSize < 1 KB => 3 bytes (2-2-10-10)
Yann Colleta1249dc2016-01-25 04:22:03 +0100310 srcSize < 16KB => 4 bytes (2-2-14-14)
Yann Collet59d1f792016-01-23 19:28:41 +0100311 else => 5 bytes (2-2-18-18)
312 big endian convention
313
314 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
315 size : 5 bits: (IS_RAW<<6) + (0<<4) + size
316 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
317 size&255
318 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
319 size>>8&255
320 size&255
321
322 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
323 size : 5 bits: (IS_RLE<<6) + (0<<4) + size
324 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
325 size&255
326 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
327 size>>8&255
328 size&255
329
Yann Colleta1249dc2016-01-25 04:22:03 +0100330 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
331 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
332 srcSize < 1 KB => 3 bytes (2-2-10-10)
333 srcSize < 16KB => 4 bytes (2-2-14-14)
334 else => 5 bytes (2-2-18-18)
335 big endian convention
336
337 1- CTable available (stored into workspace ?)
Yann Colletb923f652016-01-26 03:14:20 +0100338 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
Yann Colleta1249dc2016-01-25 04:22:03 +0100339
Yann Collet59d1f792016-01-23 19:28:41 +0100340
341 1.2) Literal block content
342
343 1.2.1) Huff0 block, using sizes from header
344 See Huff0 format
345
Yann Colletfb810d62016-01-28 00:18:06 +0100346 1.2.2) Huff0 block, using prepared table
Yann Collet59d1f792016-01-23 19:28:41 +0100347
Yann Colletfb810d62016-01-28 00:18:06 +0100348 1.2.3) Raw content
Yann Collet59d1f792016-01-23 19:28:41 +0100349
Yann Colletfb810d62016-01-28 00:18:06 +0100350 1.2.4) single byte
Yann Collet59d1f792016-01-23 19:28:41 +0100351
352
353 2) Sequences section
Yann Colletfb810d62016-01-28 00:18:06 +0100354
355 - Nb Sequences : 2 bytes, little endian
356 - Control Token : 1 byte (see below)
357 - Dumps Length : 1 or 2 bytes (depending on control token)
358 - Dumps : as stated by dumps length
359 - Literal Lengths FSE table (as needed depending on encoding method)
360 - Offset Codes FSE table (as needed depending on encoding method)
361 - Match Lengths FSE table (as needed depending on encoding method)
362
363 2.1) Control Token
364 8 bits, divided as :
365 0-1 : dumpsLength
366 2-3 : MatchLength, FSE encoding method
367 4-5 : Offset Codes, FSE encoding method
368 6-7 : Literal Lengths, FSE encoding method
369
370 FSE encoding method :
371 FSE_ENCODING_RAW : uncompressed; no header
372 FSE_ENCODING_RLE : single repeated value; header 1 byte
373 FSE_ENCODING_STATIC : use prepared table; no header
374 FSE_ENCODING_DYNAMIC : read NCount
Yann Collet59d1f792016-01-23 19:28:41 +0100375*/
Yann Collet14983e72015-11-11 21:38:21 +0100376
377size_t ZSTD_noCompressBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
378{
379 BYTE* const ostart = (BYTE* const)dst;
380
381 if (srcSize + ZSTD_blockHeaderSize > maxDstSize) return ERROR(dstSize_tooSmall);
382 memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
383
384 /* Build header */
385 ostart[0] = (BYTE)(srcSize>>16);
386 ostart[1] = (BYTE)(srcSize>>8);
387 ostart[2] = (BYTE) srcSize;
388 ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
389
390 return ZSTD_blockHeaderSize+srcSize;
391}
392
393
394static size_t ZSTD_noCompressLiterals (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
395{
396 BYTE* const ostart = (BYTE* const)dst;
Yann Collet59d1f792016-01-23 19:28:41 +0100397 const U32 flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100398
Yann Collet59d1f792016-01-23 19:28:41 +0100399 if (srcSize + flSize > maxDstSize) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100400
Yann Collet59d1f792016-01-23 19:28:41 +0100401 switch(flSize)
402 {
403 case 1: /* 2 - 1 - 5 */
404 ostart[0] = (BYTE)((IS_RAW<<6) + (0<<5) + srcSize);
405 break;
406 case 2: /* 2 - 2 - 12 */
407 ostart[0] = (BYTE)((IS_RAW<<6) + (2<<4) + (srcSize >> 8));
408 ostart[1] = (BYTE)srcSize;
409 break;
410 default: /*note : should not be necessary : flSize is within {1,2,3} */
411 case 3: /* 2 - 2 - 20 */
412 ostart[0] = (BYTE)((IS_RAW<<6) + (3<<4) + (srcSize >> 16));
413 ostart[1] = (BYTE)(srcSize>>8);
414 ostart[2] = (BYTE)srcSize;
415 break;
416 }
417
418 memcpy(ostart + flSize, src, srcSize);
419 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100420}
421
422static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t maxDstSize, const void* src, size_t srcSize)
423{
424 BYTE* const ostart = (BYTE* const)dst;
Yann Collet59d1f792016-01-23 19:28:41 +0100425 U32 flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100426
Yann Colletfb810d62016-01-28 00:18:06 +0100427 (void)maxDstSize; /* maxDstSize guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100428
429 switch(flSize)
430 {
431 case 1: /* 2 - 1 - 5 */
432 ostart[0] = (BYTE)((IS_RLE<<6) + (0<<5) + srcSize);
433 break;
434 case 2: /* 2 - 2 - 12 */
435 ostart[0] = (BYTE)((IS_RLE<<6) + (2<<4) + (srcSize >> 8));
436 ostart[1] = (BYTE)srcSize;
437 break;
438 default: /*note : should not be necessary : flSize is necessary within {1,2,3} */
439 case 3: /* 2 - 2 - 20 */
440 ostart[0] = (BYTE)((IS_RLE<<6) + (3<<4) + (srcSize >> 16));
441 ostart[1] = (BYTE)(srcSize>>8);
442 ostart[2] = (BYTE)srcSize;
443 break;
444 }
445
446 ostart[flSize] = *(const BYTE*)src;
447 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100448}
449
Yann Collet59d1f792016-01-23 19:28:41 +0100450
Yann Colletb923f652016-01-26 03:14:20 +0100451size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100452
Yann Colletb923f652016-01-26 03:14:20 +0100453static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
454 void* dst, size_t maxDstSize,
Yann Collet14983e72015-11-11 21:38:21 +0100455 const void* src, size_t srcSize)
456{
457 const size_t minGain = ZSTD_minGain(srcSize);
458 BYTE* const ostart = (BYTE*)dst;
Yann Colletb923f652016-01-26 03:14:20 +0100459 const size_t lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Colletafe07092016-01-25 04:10:46 +0100460 U32 singleStream = srcSize < 256;
Yann Colletb923f652016-01-26 03:14:20 +0100461 U32 hType = IS_HUF;
Yann Collet59d1f792016-01-23 19:28:41 +0100462 size_t clitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100463
Yann Collet35f7de52016-01-31 02:51:03 +0100464 if (maxDstSize < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Collet14983e72015-11-11 21:38:21 +0100465
Yann Colletfb810d62016-01-28 00:18:06 +0100466 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletb923f652016-01-26 03:14:20 +0100467 hType = IS_PCH;
468 singleStream = 1;
469 clitSize = HUF_compress1X_usingCTable(ostart+lhSize, maxDstSize-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100470 } else {
Yann Colletb923f652016-01-26 03:14:20 +0100471 clitSize = singleStream ? HUF_compress1X(ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12)
472 : HUF_compress2 (ostart+lhSize, maxDstSize-lhSize, src, srcSize, 255, 12);
473 }
Yann Collet14983e72015-11-11 21:38:21 +0100474
Yann Collet59d1f792016-01-23 19:28:41 +0100475 if ((clitSize==0) || (clitSize >= srcSize - minGain)) return ZSTD_noCompressLiterals(dst, maxDstSize, src, srcSize);
476 if (clitSize==1) return ZSTD_compressRleLiteralsBlock(dst, maxDstSize, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100477
478 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100479 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100480 {
Yann Collet59d1f792016-01-23 19:28:41 +0100481 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletb923f652016-01-26 03:14:20 +0100482 ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100483 ostart[1] = (BYTE)((srcSize<<2) + (clitSize>>8));
484 ostart[2] = (BYTE)(clitSize);
485 break;
486 case 4: /* 2 - 2 - 14 - 14 */
Yann Colletb923f652016-01-26 03:14:20 +0100487 ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100488 ostart[1] = (BYTE)(srcSize>> 2);
489 ostart[2] = (BYTE)((srcSize<<6) + (clitSize>>8));
490 ostart[3] = (BYTE)(clitSize);
491 break;
492 default: /* should not be necessary, lhSize is {3,4,5} */
493 case 5: /* 2 - 2 - 18 - 18 */
Yann Colletb923f652016-01-26 03:14:20 +0100494 ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100495 ostart[1] = (BYTE)(srcSize>>6);
496 ostart[2] = (BYTE)((srcSize<<2) + (clitSize>>16));
497 ostart[3] = (BYTE)(clitSize>>8);
498 ostart[4] = (BYTE)(clitSize);
499 break;
Yann Collet14983e72015-11-11 21:38:21 +0100500 }
501
Yann Collet59d1f792016-01-23 19:28:41 +0100502 return lhSize+clitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100503}
504
505
Yann Colletafe07092016-01-25 04:10:46 +0100506#define LITERAL_NOENTROPY 63 /* don't even attempt to compress literals below this threshold (cheap heuristic) */
Yann Collet14983e72015-11-11 21:38:21 +0100507
Yann Colletb923f652016-01-26 03:14:20 +0100508size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
509 void* dst, size_t maxDstSize,
Yann Collet14983e72015-11-11 21:38:21 +0100510 size_t srcSize)
511{
Yann Colletb923f652016-01-26 03:14:20 +0100512 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100513 U32 count[MaxSeq+1];
514 S16 norm[MaxSeq+1];
515 size_t mostFrequent;
Yann Colletfb810d62016-01-28 00:18:06 +0100516 U32 max;
517 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
518 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
519 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100520 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
521 const BYTE* const op_lit_start = seqStorePtr->litStart;
522 const BYTE* const llTable = seqStorePtr->litLengthStart;
523 const BYTE* const llPtr = seqStorePtr->litLength;
524 const BYTE* const mlTable = seqStorePtr->matchLengthStart;
525 const U32* const offsetTable = seqStorePtr->offsetStart;
526 BYTE* const offCodeTable = seqStorePtr->offCodeStart;
Yann Collet5054ee02015-11-23 13:34:21 +0100527 BYTE* const ostart = (BYTE*)dst;
528 BYTE* op = ostart;
529 BYTE* const oend = ostart + maxDstSize;
Yann Collet14983e72015-11-11 21:38:21 +0100530 const size_t nbSeq = llPtr - llTable;
531 const size_t minGain = ZSTD_minGain(srcSize);
532 const size_t maxCSize = srcSize - minGain;
533 BYTE* seqHead;
534
Yann Collet14983e72015-11-11 21:38:21 +0100535 /* Compress literals */
536 {
537 size_t cSize;
538 size_t litSize = seqStorePtr->lit - op_lit_start;
Yann Colletfb810d62016-01-28 00:18:06 +0100539 const size_t minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
Yann Collet14983e72015-11-11 21:38:21 +0100540
Yann Colletb923f652016-01-26 03:14:20 +0100541 if (litSize <= minLitSize)
Yann Collet14983e72015-11-11 21:38:21 +0100542 cSize = ZSTD_noCompressLiterals(op, maxDstSize, op_lit_start, litSize);
543 else
Yann Colletb923f652016-01-26 03:14:20 +0100544 cSize = ZSTD_compressLiterals(zc, op, maxDstSize, op_lit_start, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100545 if (ZSTD_isError(cSize)) return cSize;
546 op += cSize;
547 }
548
inikepcc52a972016-02-19 10:09:35 +0100549#if ZSTD_OPT_DEBUG >= 5
550 if (nbSeq >= 32768)
551 printf("ERROR: nbSeq=%d\n", (int)nbSeq);
552#endif
553
Yann Collet14983e72015-11-11 21:38:21 +0100554 /* Sequences Header */
Yann Collet61e16ce2016-01-31 02:04:15 +0100555 if ((oend-op) < MIN_SEQUENCES_SIZE) return ERROR(dstSize_tooSmall);
556 if (nbSeq < 128) *op++ = (BYTE)nbSeq;
557 else {
Yann Collet35f7de52016-01-31 02:51:03 +0100558 op[0] = (BYTE)((nbSeq>>8) + 128); op[1] = (BYTE)nbSeq; op+=2;
Yann Collet61e16ce2016-01-31 02:04:15 +0100559 }
Yann Collete93d6ce2016-01-31 00:58:06 +0100560 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100561
Yann Collet863ec402016-01-28 17:56:33 +0100562 /* dumps : contains rests of large lengths */
Yann Collete93d6ce2016-01-31 00:58:06 +0100563 if ((oend-op) < 3 /* dumps */ + 1 /*seqHead*/)
564 return ERROR(dstSize_tooSmall);
565 seqHead = op;
Yann Collet14983e72015-11-11 21:38:21 +0100566 {
567 size_t dumpsLength = seqStorePtr->dumps - seqStorePtr->dumpsStart;
Yann Colletfb810d62016-01-28 00:18:06 +0100568 if (dumpsLength < 512) {
Yann Collet14983e72015-11-11 21:38:21 +0100569 op[0] = (BYTE)(dumpsLength >> 8);
570 op[1] = (BYTE)(dumpsLength);
571 op += 2;
Yann Colletfb810d62016-01-28 00:18:06 +0100572 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100573 op[0] = 2;
574 op[1] = (BYTE)(dumpsLength>>8);
575 op[2] = (BYTE)(dumpsLength);
576 op += 3;
577 }
578 if ((size_t)(oend-op) < dumpsLength+6) return ERROR(dstSize_tooSmall);
579 memcpy(op, seqStorePtr->dumpsStart, dumpsLength);
580 op += dumpsLength;
581 }
582
Yann Colletfb810d62016-01-28 00:18:06 +0100583#define MIN_SEQ_FOR_DYNAMIC_FSE 64
584#define MAX_SEQ_FOR_STATIC_FSE 1000
585
Yann Collet14983e72015-11-11 21:38:21 +0100586 /* CTable for Literal Lengths */
587 max = MaxLL;
Yann Collete93d6ce2016-01-31 00:58:06 +0100588 mostFrequent = FSE_countFast(count, &max, llTable, nbSeq);
Yann Colletfb810d62016-01-28 00:18:06 +0100589 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collete93d6ce2016-01-31 00:58:06 +0100590 *op++ = llTable[0];
Yann Collet14983e72015-11-11 21:38:21 +0100591 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletfb810d62016-01-28 00:18:06 +0100592 LLtype = FSE_ENCODING_RLE;
593 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
594 LLtype = FSE_ENCODING_STATIC;
595 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LLbits-1)))) {
Yann Collet14983e72015-11-11 21:38:21 +0100596 FSE_buildCTable_raw(CTable_LitLength, LLbits);
Yann Colletfb810d62016-01-28 00:18:06 +0100597 LLtype = FSE_ENCODING_RAW;
598 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100599 size_t NCountSize;
Yann Collete93d6ce2016-01-31 00:58:06 +0100600 size_t nbSeq_1 = nbSeq;
Yann Colletfb810d62016-01-28 00:18:06 +0100601 U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
Yann Collete93d6ce2016-01-31 00:58:06 +0100602 if (count[llTable[nbSeq-1]]>1) { count[llTable[nbSeq-1]]--; nbSeq_1--; }
603 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Collet14983e72015-11-11 21:38:21 +0100604 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
605 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
606 op += NCountSize;
607 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
Yann Colletfb810d62016-01-28 00:18:06 +0100608 LLtype = FSE_ENCODING_DYNAMIC;
Yann Collet14983e72015-11-11 21:38:21 +0100609 }
610
Yann Colletfb810d62016-01-28 00:18:06 +0100611 /* CTable for Offset codes */
612 { /* create Offset codes */
613 size_t i; for (i=0; i<nbSeq; i++) {
Yann Collet14983e72015-11-11 21:38:21 +0100614 offCodeTable[i] = (BYTE)ZSTD_highbit(offsetTable[i]) + 1;
615 if (offsetTable[i]==0) offCodeTable[i]=0;
616 }
Yann Collet14983e72015-11-11 21:38:21 +0100617 }
Yann Colletfb810d62016-01-28 00:18:06 +0100618 max = MaxOff;
619 mostFrequent = FSE_countFast(count, &max, offCodeTable, nbSeq);
620 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collete93d6ce2016-01-31 00:58:06 +0100621 *op++ = offCodeTable[0];
Yann Collet14983e72015-11-11 21:38:21 +0100622 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletfb810d62016-01-28 00:18:06 +0100623 Offtype = FSE_ENCODING_RLE;
624 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
625 Offtype = FSE_ENCODING_STATIC;
626 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (Offbits-1)))) {
Yann Collet14983e72015-11-11 21:38:21 +0100627 FSE_buildCTable_raw(CTable_OffsetBits, Offbits);
Yann Colletfb810d62016-01-28 00:18:06 +0100628 Offtype = FSE_ENCODING_RAW;
629 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100630 size_t NCountSize;
Yann Collete93d6ce2016-01-31 00:58:06 +0100631 size_t nbSeq_1 = nbSeq;
Yann Colletfb810d62016-01-28 00:18:06 +0100632 U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collete93d6ce2016-01-31 00:58:06 +0100633 if (count[offCodeTable[nbSeq-1]]>1) { count[offCodeTable[nbSeq-1]]--; nbSeq_1--; }
634 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Collet14983e72015-11-11 21:38:21 +0100635 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
636 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
637 op += NCountSize;
638 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
Yann Colletfb810d62016-01-28 00:18:06 +0100639 Offtype = FSE_ENCODING_DYNAMIC;
Yann Collet14983e72015-11-11 21:38:21 +0100640 }
641
642 /* CTable for MatchLengths */
643 max = MaxML;
Yann Collete93d6ce2016-01-31 00:58:06 +0100644 mostFrequent = FSE_countFast(count, &max, mlTable, nbSeq);
Yann Colletfb810d62016-01-28 00:18:06 +0100645 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collete93d6ce2016-01-31 00:58:06 +0100646 *op++ = *mlTable;
Yann Collet14983e72015-11-11 21:38:21 +0100647 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletfb810d62016-01-28 00:18:06 +0100648 MLtype = FSE_ENCODING_RLE;
649 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
650 MLtype = FSE_ENCODING_STATIC;
651 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (MLbits-1)))) {
Yann Collet14983e72015-11-11 21:38:21 +0100652 FSE_buildCTable_raw(CTable_MatchLength, MLbits);
Yann Colletfb810d62016-01-28 00:18:06 +0100653 MLtype = FSE_ENCODING_RAW;
654 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100655 size_t NCountSize;
Yann Colletfb810d62016-01-28 00:18:06 +0100656 U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
Yann Collet14983e72015-11-11 21:38:21 +0100657 FSE_normalizeCount(norm, tableLog, count, nbSeq, max);
658 NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
659 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
660 op += NCountSize;
661 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
Yann Colletfb810d62016-01-28 00:18:06 +0100662 MLtype = FSE_ENCODING_DYNAMIC;
Yann Collet14983e72015-11-11 21:38:21 +0100663 }
664
665 seqHead[0] += (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100666 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100667
668 /* Encoding Sequences */
669 {
670 size_t streamSize, errorCode;
671 BIT_CStream_t blockStream;
672 FSE_CState_t stateMatchLength;
673 FSE_CState_t stateOffsetBits;
674 FSE_CState_t stateLitLength;
675 int i;
676
677 errorCode = BIT_initCStream(&blockStream, op, oend-op);
678 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100679
Yann Collete93d6ce2016-01-31 00:58:06 +0100680 /* first symbols */
681 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlTable[nbSeq-1]);
682 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, offCodeTable[nbSeq-1]);
683 FSE_initCState2(&stateLitLength, CTable_LitLength, llTable[nbSeq-1]);
684 BIT_addBits(&blockStream, offsetTable[nbSeq-1], offCodeTable[nbSeq-1] ? (offCodeTable[nbSeq-1]-1) : 0);
685 BIT_flushBits(&blockStream);
686
687 for (i=(int)nbSeq-2; i>=0; i--) {
Yann Colletfb810d62016-01-28 00:18:06 +0100688 BYTE mlCode = mlTable[i];
Yann Collet14983e72015-11-11 21:38:21 +0100689 U32 offset = offsetTable[i];
690 BYTE offCode = offCodeTable[i]; /* 32b*/ /* 64b*/
Yann Collete93d6ce2016-01-31 00:58:06 +0100691 U32 nbBits = (offCode-1) + (!offCode);
Yann Collet14983e72015-11-11 21:38:21 +0100692 BYTE litLength = llTable[i]; /* (7)*/ /* (7)*/
Yann Colletfb810d62016-01-28 00:18:06 +0100693 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 17 */ /* 17 */
Yann Collet743402c2015-11-20 12:03:53 +0100694 if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */
Yann Collet14983e72015-11-11 21:38:21 +0100695 FSE_encodeSymbol(&blockStream, &stateLitLength, litLength); /* 26 */ /* 61 */
Yann Collete93d6ce2016-01-31 00:58:06 +0100696 FSE_encodeSymbol(&blockStream, &stateOffsetBits, offCode); /* 16 */ /* 51 */
697 if (MEM_32bits()) BIT_flushBits(&blockStream); /* 7 */
698 BIT_addBits(&blockStream, offset, nbBits); /* 31 */ /* 42 */ /* 24 bits max in 32-bits mode */
Yann Collet14983e72015-11-11 21:38:21 +0100699 BIT_flushBits(&blockStream); /* 7 */ /* 7 */
700 }
701
702 FSE_flushCState(&blockStream, &stateMatchLength);
703 FSE_flushCState(&blockStream, &stateOffsetBits);
704 FSE_flushCState(&blockStream, &stateLitLength);
705
706 streamSize = BIT_closeCStream(&blockStream);
707 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
708 op += streamSize;
709 }
710
711 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100712_check_compressibility:
Yann Collet5054ee02015-11-23 13:34:21 +0100713 if ((size_t)(op-ostart) >= maxCSize) return 0;
Yann Collet14983e72015-11-11 21:38:21 +0100714
Yann Collet5054ee02015-11-23 13:34:21 +0100715 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100716}
717
718
Yann Collete93d6ce2016-01-31 00:58:06 +0100719/*! ZSTD_storeSeq
720 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t
Yann Collet14983e72015-11-11 21:38:21 +0100721 @offsetCode : distance to match, or 0 == repCode
722 @matchCode : matchLength - MINMATCH
723*/
724MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode)
725{
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100726#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100727 static const BYTE* g_start = NULL;
728 if (g_start==NULL) g_start = literals;
Yann Colletfb810d62016-01-28 00:18:06 +0100729 //if (literals - g_start == 8695)
Yann Collet14983e72015-11-11 21:38:21 +0100730 printf("pos %6u : %3u literals & match %3u bytes at distance %6u \n",
inikepcc52a972016-02-19 10:09:35 +0100731 (U32)(literals - g_start), (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +0100732#endif
inikep15174b02016-02-23 12:41:56 +0100733#if ZSTD_OPT_DEBUG >= 3
734 if (offsetCode == 0) seqStorePtr->realRepSum++;
735 seqStorePtr->realSeqSum++;
736 seqStorePtr->realMatchSum += matchCode;
737 seqStorePtr->realLitSum += litLength;
738#endif
Yann Collet14983e72015-11-11 21:38:21 +0100739
740 /* copy Literals */
741 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
742 seqStorePtr->lit += litLength;
743
744 /* literal Length */
Yann Colletfb810d62016-01-28 00:18:06 +0100745 if (litLength >= MaxLL) {
Yann Collet14983e72015-11-11 21:38:21 +0100746 *(seqStorePtr->litLength++) = MaxLL;
Yann Colletfb810d62016-01-28 00:18:06 +0100747 if (litLength<255 + MaxLL) {
Yann Collet14983e72015-11-11 21:38:21 +0100748 *(seqStorePtr->dumps++) = (BYTE)(litLength - MaxLL);
Yann Colletfb810d62016-01-28 00:18:06 +0100749 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100750 *(seqStorePtr->dumps++) = 255;
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100751 if (litLength < (1<<15)) {
752 MEM_writeLE16(seqStorePtr->dumps, (U16)(litLength<<1));
753 seqStorePtr->dumps += 2;
754 } else {
755 MEM_writeLE32(seqStorePtr->dumps, (U32)((litLength<<1)+1));
756 seqStorePtr->dumps += 3;
757 }
Yann Colletfb810d62016-01-28 00:18:06 +0100758 } }
Yann Collet14983e72015-11-11 21:38:21 +0100759 else *(seqStorePtr->litLength++) = (BYTE)litLength;
760
761 /* match offset */
762 *(seqStorePtr->offset++) = (U32)offsetCode;
763
764 /* match Length */
Yann Colletfb810d62016-01-28 00:18:06 +0100765 if (matchCode >= MaxML) {
Yann Collet14983e72015-11-11 21:38:21 +0100766 *(seqStorePtr->matchLength++) = MaxML;
Yann Colletfb810d62016-01-28 00:18:06 +0100767 if (matchCode < 255+MaxML) {
Yann Collet14983e72015-11-11 21:38:21 +0100768 *(seqStorePtr->dumps++) = (BYTE)(matchCode - MaxML);
Yann Colletfb810d62016-01-28 00:18:06 +0100769 } else {
Yann Collet14983e72015-11-11 21:38:21 +0100770 *(seqStorePtr->dumps++) = 255;
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100771 if (matchCode < (1<<15)) {
772 MEM_writeLE16(seqStorePtr->dumps, (U16)(matchCode<<1));
773 seqStorePtr->dumps += 2;
774 } else {
775 MEM_writeLE32(seqStorePtr->dumps, (U32)((matchCode<<1)+1));
776 seqStorePtr->dumps += 3;
777 }
Yann Colletfb810d62016-01-28 00:18:06 +0100778 } }
Yann Collet14983e72015-11-11 21:38:21 +0100779 else *(seqStorePtr->matchLength++) = (BYTE)matchCode;
780}
781
782
Yann Collet7d360282016-02-12 00:07:30 +0100783/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100784* Match length counter
785***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100786static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100787{
Yann Collet863ec402016-01-28 17:56:33 +0100788 if (MEM_isLittleEndian()) {
789 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100790# if defined(_MSC_VER) && defined(_WIN64)
791 unsigned long r = 0;
792 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100793 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100794# elif defined(__GNUC__) && (__GNUC__ >= 3)
795 return (__builtin_ctzll((U64)val) >> 3);
796# else
797 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 };
798 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
799# endif
Yann Collet863ec402016-01-28 17:56:33 +0100800 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100801# if defined(_MSC_VER)
802 unsigned long r=0;
803 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100804 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100805# elif defined(__GNUC__) && (__GNUC__ >= 3)
806 return (__builtin_ctz((U32)val) >> 3);
807# else
808 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 };
809 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
810# endif
811 }
Yann Collet863ec402016-01-28 17:56:33 +0100812 } else { /* Big Endian CPU */
813 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100814# if defined(_MSC_VER) && defined(_WIN64)
815 unsigned long r = 0;
816 _BitScanReverse64( &r, val );
817 return (unsigned)(r>>3);
818# elif defined(__GNUC__) && (__GNUC__ >= 3)
819 return (__builtin_clzll(val) >> 3);
820# else
821 unsigned r;
822 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
823 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
824 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
825 r += (!val);
826 return r;
827# endif
Yann Collet863ec402016-01-28 17:56:33 +0100828 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100829# if defined(_MSC_VER)
830 unsigned long r = 0;
831 _BitScanReverse( &r, (unsigned long)val );
832 return (unsigned)(r>>3);
833# elif defined(__GNUC__) && (__GNUC__ >= 3)
834 return (__builtin_clz((U32)val) >> 3);
835# else
836 unsigned r;
837 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
838 r += (!val);
839 return r;
840# endif
Yann Collet863ec402016-01-28 17:56:33 +0100841 } }
Yann Collet14983e72015-11-11 21:38:21 +0100842}
843
844
Yann Collet5054ee02015-11-23 13:34:21 +0100845static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100846{
847 const BYTE* const pStart = pIn;
848
Yann Colletfb810d62016-01-28 00:18:06 +0100849 while ((pIn<pInLimit-(sizeof(size_t)-1))) {
Yann Collet7d360282016-02-12 00:07:30 +0100850 size_t diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100851 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
852 pIn += ZSTD_NbCommonBytes(diff);
853 return (size_t)(pIn - pStart);
854 }
Yann Collet14983e72015-11-11 21:38:21 +0100855 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
856 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
857 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
858 return (size_t)(pIn - pStart);
859}
860
Yann Collet04b12d82016-02-11 06:23:24 +0100861/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100862* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100863* convention : on reaching mEnd, match count continue starting from iStart
864*/
865static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
866{
867 size_t matchLength;
868 const BYTE* vEnd = ip + (mEnd - match);
869 if (vEnd > iEnd) vEnd = iEnd;
870 matchLength = ZSTD_count(ip, match, vEnd);
871 if (match + matchLength == mEnd)
872 matchLength += ZSTD_count(ip+matchLength, iStart, iEnd);
873 return matchLength;
874}
875
Yann Collet14983e72015-11-11 21:38:21 +0100876
Yann Collet863ec402016-01-28 17:56:33 +0100877/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100878* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100879***************************************/
inikepcc52a972016-02-19 10:09:35 +0100880static const U32 prime3bytes = 506832829U;
881static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
882static size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_read32(ptr), h); }
883
Yann Collet4b100f42015-10-30 15:49:48 +0100884static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100885static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100886static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100887
Yann Collet4b100f42015-10-30 15:49:48 +0100888static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100889static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100890static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100891
892static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100893static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100894static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100895
Yann Collet14983e72015-11-11 21:38:21 +0100896static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100897static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100898static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100899
Yann Collet5be2dd22015-11-11 13:43:58 +0100900static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100901{
902 switch(mls)
903 {
904 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100905 case 4: return ZSTD_hash4Ptr(p, hBits);
906 case 5: return ZSTD_hash5Ptr(p, hBits);
907 case 6: return ZSTD_hash6Ptr(p, hBits);
908 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100909 }
910}
Yann Collet2acb5d32015-10-29 16:49:43 +0100911
Yann Collet863ec402016-01-28 17:56:33 +0100912
Yann Collet2ce49232016-02-02 14:36:49 +0100913/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +0100914* Fast Scan
915***************************************/
Yann Collet417890c2015-12-04 17:16:37 +0100916#define FILLHASHSTEP 3
917static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
918{
919 U32* const hashTable = zc->hashTable;
920 const U32 hBits = zc->params.hashLog;
921 const BYTE* const base = zc->base;
922 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet2ce49232016-02-02 14:36:49 +0100923 const BYTE* const iend = ((const BYTE*)end) - 8;
Yann Collet417890c2015-12-04 17:16:37 +0100924
Yann Colletfb810d62016-01-28 00:18:06 +0100925 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +0100926 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
927 ip += FILLHASHSTEP;
928 }
929}
930
931
Yann Collet1f44b3f2015-11-05 17:32:18 +0100932FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +0100933void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc,
Yann Collet89db5e02015-11-13 11:27:46 +0100934 const void* src, size_t srcSize,
935 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100936{
Yann Collet417890c2015-12-04 17:16:37 +0100937 U32* const hashTable = zc->hashTable;
Yann Colletc3652152015-11-24 14:06:07 +0100938 const U32 hBits = zc->params.hashLog;
939 seqStore_t* seqStorePtr = &(zc->seqStore);
940 const BYTE* const base = zc->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100941 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100942 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100943 const BYTE* anchor = istart;
Yann Colletd94efbf2015-12-29 14:29:08 +0100944 const U32 lowIndex = zc->dictLimit;
945 const BYTE* const lowest = base + lowIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100946 const BYTE* const iend = istart + srcSize;
947 const BYTE* const ilimit = iend - 8;
948
Yann Collet89db5e02015-11-13 11:27:46 +0100949 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100950
951
952 /* init */
Yann Collet743402c2015-11-20 12:03:53 +0100953 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +0100954 if (ip < lowest+REPCODE_STARTVALUE) ip = lowest+REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100955
956 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +0100957 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Collet5054ee02015-11-23 13:34:21 +0100958 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +0100959 size_t offset;
Yann Collet5be2dd22015-11-11 13:43:58 +0100960 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Colletd94efbf2015-12-29 14:29:08 +0100961 const U32 matchIndex = hashTable[h];
962 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +0100963 const U32 current = (U32)(ip-base);
964 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100965
Yann Colletfb810d62016-01-28 00:18:06 +0100966 if (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)) { /* note : by construction, offset_1 <= current */
Yann Collet5054ee02015-11-23 13:34:21 +0100967 mlCode = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +0100968 ip++;
969 offset = 0;
Yann Colletfb810d62016-01-28 00:18:06 +0100970 } else {
Yann Colletd94efbf2015-12-29 14:29:08 +0100971 if ( (matchIndex <= lowIndex) ||
Yann Colletfb810d62016-01-28 00:18:06 +0100972 (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100973 ip += ((ip-anchor) >> g_searchStrength) + 1;
974 continue;
975 }
Yann Collet5054ee02015-11-23 13:34:21 +0100976 mlCode = ZSTD_count(ip+MINMATCH, match+MINMATCH, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +0100977 offset = ip-match;
Yann Collet5054ee02015-11-23 13:34:21 +0100978 while ((ip>anchor) && (match>lowest) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +0100979 offset_2 = offset_1;
980 offset_1 = offset;
981 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100982
Yann Collet402fdcf2015-11-20 12:46:08 +0100983 /* match found */
Yann Collet6bcdeac2015-11-26 11:43:00 +0100984 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +0100985 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +0100986 anchor = ip;
987
Yann Colletfb810d62016-01-28 00:18:06 +0100988 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100989 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +0100990 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 +0100991 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
992 /* check immediate repcode */
993 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +0100994 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100995 /* store sequence */
Yann Collet06eade52015-11-23 14:23:47 +0100996 size_t rlCode = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +0100997 size_t tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; /* swap offset_2 <=> offset_1 */
998 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Collet06eade52015-11-23 14:23:47 +0100999 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rlCode);
1000 ip += rlCode+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001001 anchor = ip;
1002 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001003 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001004
Yann Collet44886612016-02-11 04:17:50 +01001005 { /* Last Literals */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001006 size_t lastLLSize = iend - anchor;
1007 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1008 seqStorePtr->lit += lastLLSize;
1009 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001010}
1011
1012
Yann Collet82260dd2016-02-11 07:14:25 +01001013static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001014 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001015{
1016 const U32 mls = ctx->params.searchLength;
1017 switch(mls)
1018 {
1019 default:
1020 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001021 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001022 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001023 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001024 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001025 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001026 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001027 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001028 }
1029}
Yann Colletf3eca252015-10-22 15:31:46 +01001030
Yann Colletf3eca252015-10-22 15:31:46 +01001031
Yann Collet82260dd2016-02-11 07:14:25 +01001032static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001033 const void* src, size_t srcSize,
1034 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001035{
1036 U32* hashTable = ctx->hashTable;
1037 const U32 hBits = ctx->params.hashLog;
1038 seqStore_t* seqStorePtr = &(ctx->seqStore);
1039 const BYTE* const base = ctx->base;
1040 const BYTE* const dictBase = ctx->dictBase;
1041 const BYTE* const istart = (const BYTE*)src;
1042 const BYTE* ip = istart;
1043 const BYTE* anchor = istart;
1044 const U32 lowLimit = ctx->lowLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001045 const BYTE* const dictStart = dictBase + lowLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001046 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001047 const BYTE* const lowPrefixPtr = base + dictLimit;
1048 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001049 const BYTE* const iend = istart + srcSize;
1050 const BYTE* const ilimit = iend - 8;
1051
Yann Collet138e89c2015-11-17 14:26:54 +01001052 U32 offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001053
1054
1055 /* init */
1056 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001057 /* skip first position to avoid read overflow during repcode match check */
Yann Colletfb810d62016-01-28 00:18:06 +01001058 hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0);
Yann Collet61e16ce2016-01-31 02:04:15 +01001059 ip += REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001060
1061 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001062 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001063 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001064 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001065 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001066 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001067 const U32 current = (U32)(ip-base);
Yann Collet743402c2015-11-20 12:03:53 +01001068 const U32 repIndex = current + 1 - offset_1;
Yann Collet402fdcf2015-11-20 12:46:08 +01001069 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001070 const BYTE* repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001071 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001072 U32 offset;
Yann Collet89db5e02015-11-13 11:27:46 +01001073 hashTable[h] = current; /* update hash table */
1074
1075 if ( ((repIndex <= dictLimit-4) || (repIndex >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001076 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001077 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001078 mlCode = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repMatchEnd, lowPrefixPtr);
Yann Collet743402c2015-11-20 12:03:53 +01001079 ip++;
Yann Collet402fdcf2015-11-20 12:46:08 +01001080 offset = 0;
Yann Colletfb810d62016-01-28 00:18:06 +01001081 } else {
Yann Collet402fdcf2015-11-20 12:46:08 +01001082 if ( (matchIndex < lowLimit) ||
1083 (MEM_read32(match) != MEM_read32(ip)) )
1084 { ip += ((ip-anchor) >> g_searchStrength) + 1; continue; }
1085 {
1086 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001087 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1088 mlCode = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iend, matchEnd, lowPrefixPtr);
Yann Colletfb810d62016-01-28 00:18:06 +01001089 while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001090 offset = current - matchIndex;
1091 offset_2 = offset_1;
1092 offset_1 = offset;
Yann Colletfb810d62016-01-28 00:18:06 +01001093 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001094
Yann Collet5054ee02015-11-23 13:34:21 +01001095 /* found a match : store it */
1096 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +01001097 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001098 anchor = ip;
1099
Yann Colletfb810d62016-01-28 00:18:06 +01001100 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001101 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001102 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001103 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1104 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001105 while (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001106 U32 current2 = (U32)(ip-base);
1107 const U32 repIndex2 = current2 - offset_2;
1108 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet743402c2015-11-20 12:03:53 +01001109 if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001110 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001111 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1112 size_t repLength2 = ZSTD_count_2segments(ip+MINMATCH, repMatch2+MINMATCH, iend, repEnd2, lowPrefixPtr);
1113 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1114 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2);
1115 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
1116 ip += repLength2+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001117 anchor = ip;
1118 continue;
1119 }
Yann Collet743402c2015-11-20 12:03:53 +01001120 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001121 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001122
1123 /* Last Literals */
1124 {
1125 size_t lastLLSize = iend - anchor;
1126 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1127 seqStorePtr->lit += lastLLSize;
1128 }
Yann Collet89db5e02015-11-13 11:27:46 +01001129}
1130
1131
Yann Collet82260dd2016-02-11 07:14:25 +01001132static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001133 const void* src, size_t srcSize)
1134{
1135 const U32 mls = ctx->params.searchLength;
1136 switch(mls)
1137 {
1138 default:
1139 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001140 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001141 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001142 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001143 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001144 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001145 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001146 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001147 }
1148}
1149
1150
Yann Collet04b12d82016-02-11 06:23:24 +01001151/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001152* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001153***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001154/** ZSTD_insertBt1() : add one or multiple positions to tree.
1155* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001156* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001157static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1158 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001159{
1160 U32* const hashTable = zc->hashTable;
1161 const U32 hashLog = zc->params.hashLog;
Yann Collet5be2dd22015-11-11 13:43:58 +01001162 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet1f44b3f2015-11-05 17:32:18 +01001163 U32* const bt = zc->contentTable;
1164 const U32 btLog = zc->params.contentLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001165 const U32 btMask= (1 << btLog) - 1;
1166 U32 matchIndex = hashTable[h];
1167 size_t commonLengthSmaller=0, commonLengthLarger=0;
1168 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001169 const BYTE* const dictBase = zc->dictBase;
1170 const U32 dictLimit = zc->dictLimit;
1171 const BYTE* const dictEnd = dictBase + dictLimit;
1172 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001173 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001174 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001175 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001176 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001177 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001178 U32 dummy32; /* to be nullified at the end */
Yann Collet03526e12015-11-23 15:29:15 +01001179 const U32 windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001180 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001181 size_t bestLength = 8;
Yann Collet7beaa052016-01-21 11:57:45 +01001182 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1183 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1184 predictedSmall += (predictedSmall>0);
1185 predictedLarge += (predictedLarge>0);
Yann Colletf48e35c2015-11-07 01:13:31 +01001186
Yann Collet6c3e2e72015-12-11 10:44:07 +01001187 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001188
Yann Colletfb810d62016-01-28 00:18:06 +01001189 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001190 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001191 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet04b12d82016-02-11 06:23:24 +01001192#if 1 /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001193 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001194 if (matchIndex == predictedSmall) {
1195 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001196 *smallerPtr = matchIndex;
1197 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1198 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1199 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001200 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001201 continue;
1202 }
Yann Colletfb810d62016-01-28 00:18:06 +01001203 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001204 *largerPtr = matchIndex;
1205 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1206 largerPtr = nextPtr;
1207 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001208 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001209 continue;
1210 }
Yann Collet04b12d82016-02-11 06:23:24 +01001211#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001212 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001213 match = base + matchIndex;
1214 if (match[matchLength] == ip[matchLength])
1215 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001216 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001217 match = dictBase + matchIndex;
1218 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1219 if (matchIndex+matchLength >= dictLimit)
1220 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1221 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001222
Yann Colletb8a6f682016-02-15 17:06:29 +01001223 if (matchLength > bestLength) {
1224 bestLength = matchLength;
1225 if (matchLength > matchEndIdx - matchIndex)
1226 matchEndIdx = matchIndex + (U32)matchLength;
1227 }
Yann Colletee3f4512015-12-29 22:26:09 +01001228
Yann Collet59d70632015-11-04 12:05:27 +01001229 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001230 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001231
Yann Colletfb810d62016-01-28 00:18:06 +01001232 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001233 /* match is smaller than current */
1234 *smallerPtr = matchIndex; /* update smaller idx */
1235 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001236 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001237 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001238 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001239 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001240 /* match is larger than current */
1241 *largerPtr = matchIndex;
1242 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001243 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001244 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001245 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001246 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001247
Yann Collet59d70632015-11-04 12:05:27 +01001248 *smallerPtr = *largerPtr = 0;
Yann Colletb8a6f682016-02-15 17:06:29 +01001249 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384));
1250 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1251 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001252}
1253
1254
Yann Collet82260dd2016-02-11 07:14:25 +01001255static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001256 ZSTD_CCtx* zc,
1257 const BYTE* const ip, const BYTE* const iend,
1258 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001259 U32 nbCompares, const U32 mls,
1260 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001261{
1262 U32* const hashTable = zc->hashTable;
1263 const U32 hashLog = zc->params.hashLog;
1264 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
1265 U32* const bt = zc->contentTable;
1266 const U32 btLog = zc->params.contentLog - 1;
1267 const U32 btMask= (1 << btLog) - 1;
1268 U32 matchIndex = hashTable[h];
1269 size_t commonLengthSmaller=0, commonLengthLarger=0;
1270 const BYTE* const base = zc->base;
1271 const BYTE* const dictBase = zc->dictBase;
1272 const U32 dictLimit = zc->dictLimit;
1273 const BYTE* const dictEnd = dictBase + dictLimit;
1274 const BYTE* const prefixStart = base + dictLimit;
1275 const U32 current = (U32)(ip-base);
1276 const U32 btLow = btMask >= current ? 0 : current - btMask;
1277 const U32 windowLow = zc->lowLimit;
1278 U32* smallerPtr = bt + 2*(current&btMask);
1279 U32* largerPtr = bt + 2*(current&btMask) + 1;
1280 size_t bestLength = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001281 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001282 U32 dummy32; /* to be nullified at the end */
1283
Yann Collet6c3e2e72015-12-11 10:44:07 +01001284 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001285
Yann Colletfb810d62016-01-28 00:18:06 +01001286 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001287 U32* nextPtr = bt + 2*(matchIndex & btMask);
1288 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1289 const BYTE* match;
1290
Yann Colletfb810d62016-01-28 00:18:06 +01001291 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001292 match = base + matchIndex;
1293 if (match[matchLength] == ip[matchLength])
1294 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001295 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001296 match = dictBase + matchIndex;
1297 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001298 if (matchIndex+matchLength >= dictLimit)
1299 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001300 }
1301
Yann Colletfb810d62016-01-28 00:18:06 +01001302 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001303 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001304 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet03526e12015-11-23 15:29:15 +01001305 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
1306 bestLength = matchLength, *offsetPtr = current - matchIndex;
1307 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1308 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1309 }
1310
Yann Colletfb810d62016-01-28 00:18:06 +01001311 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001312 /* match is smaller than current */
1313 *smallerPtr = matchIndex; /* update smaller idx */
1314 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1315 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1316 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1317 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001318 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001319 /* match is larger than current */
1320 *largerPtr = matchIndex;
1321 commonLengthLarger = matchLength;
1322 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1323 largerPtr = nextPtr;
1324 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001325 } }
Yann Collet03526e12015-11-23 15:29:15 +01001326
1327 *smallerPtr = *largerPtr = 0;
1328
Yann Collet72e84cf2015-12-31 19:08:44 +01001329 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
Yann Collet03526e12015-11-23 15:29:15 +01001330 return bestLength;
1331}
1332
Yann Collet2cc12cb2016-01-01 07:47:58 +01001333
Yann Colletb8a6f682016-02-15 17:06:29 +01001334static 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 +01001335{
1336 const BYTE* const base = zc->base;
1337 const U32 target = (U32)(ip - base);
1338 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001339
1340 while(idx < target)
1341 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001342}
1343
Yann Collet2cc12cb2016-01-01 07:47:58 +01001344/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001345static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001346 ZSTD_CCtx* zc,
1347 const BYTE* const ip, const BYTE* const iLimit,
1348 size_t* offsetPtr,
1349 const U32 maxNbAttempts, const U32 mls)
1350{
1351 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001352 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001353 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1354}
1355
1356
Yann Collet768c6bc2016-02-10 14:01:49 +01001357static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001358 ZSTD_CCtx* zc, /* Index table will be updated */
1359 const BYTE* ip, const BYTE* const iLimit,
1360 size_t* offsetPtr,
1361 const U32 maxNbAttempts, const U32 matchLengthSearch)
1362{
1363 switch(matchLengthSearch)
1364 {
1365 default :
1366 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1367 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1368 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1369 }
1370}
1371
1372
Yann Colletb8a6f682016-02-15 17:06:29 +01001373static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1374{
1375 const BYTE* const base = zc->base;
1376 const U32 target = (U32)(ip - base);
1377 U32 idx = zc->nextToUpdate;
1378
1379 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1380}
1381
inikep84f43e22016-02-22 11:34:07 +01001382#include "zstd_opt_internal.h"
Yann Collet2cc12cb2016-01-01 07:47:58 +01001383
Yann Collet03526e12015-11-23 15:29:15 +01001384/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001385static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001386 ZSTD_CCtx* zc,
1387 const BYTE* const ip, const BYTE* const iLimit,
1388 size_t* offsetPtr,
1389 const U32 maxNbAttempts, const U32 mls)
1390{
Yann Colletee3f4512015-12-29 22:26:09 +01001391 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001392 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001393 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001394}
1395
1396
Yann Collet82260dd2016-02-11 07:14:25 +01001397static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001398 ZSTD_CCtx* zc, /* Index table will be updated */
1399 const BYTE* ip, const BYTE* const iLimit,
1400 size_t* offsetPtr,
1401 const U32 maxNbAttempts, const U32 matchLengthSearch)
1402{
1403 switch(matchLengthSearch)
1404 {
1405 default :
1406 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1407 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1408 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1409 }
1410}
1411
1412
Yann Collet5106a762015-11-05 15:00:24 +01001413/* ***********************
1414* Hash Chain
1415*************************/
1416
Yann Collet1f44b3f2015-11-05 17:32:18 +01001417#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1418
Yann Collet6bcdeac2015-11-26 11:43:00 +01001419/* Update chains up to ip (excluded)
Yann Collet06eade52015-11-23 14:23:47 +01001420 Assumption : always within prefix (ie. not within extDict) */
Yann Collet6062b152016-02-16 17:41:03 +01001421FORCE_INLINE
1422U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
Yann Collet5106a762015-11-05 15:00:24 +01001423{
1424 U32* const hashTable = zc->hashTable;
1425 const U32 hashLog = zc->params.hashLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001426 U32* const chainTable = zc->contentTable;
1427 const U32 chainMask = (1 << zc->params.contentLog) - 1;
Yann Collet5106a762015-11-05 15:00:24 +01001428 const BYTE* const base = zc->base;
1429 const U32 target = (U32)(ip - base);
1430 U32 idx = zc->nextToUpdate;
1431
Yann Colletfb810d62016-01-28 00:18:06 +01001432 while(idx < target) {
Yann Collet5be2dd22015-11-11 13:43:58 +01001433 size_t h = ZSTD_hashPtr(base+idx, hashLog, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001434 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1435 hashTable[h] = idx;
1436 idx++;
1437 }
1438
1439 zc->nextToUpdate = target;
Yann Collet5be2dd22015-11-11 13:43:58 +01001440 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
Yann Collet5106a762015-11-05 15:00:24 +01001441}
1442
1443
1444FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Colletc1e52f02015-11-23 14:37:59 +01001445size_t ZSTD_HcFindBestMatch_generic (
Yann Collet5be2dd22015-11-11 13:43:58 +01001446 ZSTD_CCtx* zc, /* Index table will be updated */
Yann Collet5106a762015-11-05 15:00:24 +01001447 const BYTE* const ip, const BYTE* const iLimit,
1448 size_t* offsetPtr,
Yann Colletc1e52f02015-11-23 14:37:59 +01001449 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
Yann Collet287b7d92015-11-22 13:24:05 +01001450{
Yann Collet1f44b3f2015-11-05 17:32:18 +01001451 U32* const chainTable = zc->contentTable;
1452 const U32 chainSize = (1 << zc->params.contentLog);
Yann Collet5106a762015-11-05 15:00:24 +01001453 const U32 chainMask = chainSize-1;
1454 const BYTE* const base = zc->base;
1455 const BYTE* const dictBase = zc->dictBase;
1456 const U32 dictLimit = zc->dictLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001457 const BYTE* const prefixStart = base + dictLimit;
1458 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001459 const U32 lowLimit = zc->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001460 const U32 current = (U32)(ip-base);
1461 const U32 minChain = current > chainSize ? current - chainSize : 0;
Yann Collet5106a762015-11-05 15:00:24 +01001462 U32 matchIndex;
1463 const BYTE* match;
1464 int nbAttempts=maxNbAttempts;
Yann Collet5054ee02015-11-23 13:34:21 +01001465 size_t ml=MINMATCH-1;
Yann Collet5106a762015-11-05 15:00:24 +01001466
1467 /* HC4 match finder */
Yann Colletc1e52f02015-11-23 14:37:59 +01001468 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001469
Yann Colletfb810d62016-01-28 00:18:06 +01001470 while ((matchIndex>lowLimit) && (nbAttempts)) {
Yann Collet5054ee02015-11-23 13:34:21 +01001471 size_t currentMl=0;
Yann Collet5106a762015-11-05 15:00:24 +01001472 nbAttempts--;
Yann Colletfb810d62016-01-28 00:18:06 +01001473 if ((!extDict) || matchIndex >= dictLimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001474 match = base + matchIndex;
Yann Collet4baee502015-11-09 03:19:33 +01001475 if (match[ml] == ip[ml]) /* potentially better */
Yann Collet5054ee02015-11-23 13:34:21 +01001476 currentMl = ZSTD_count(ip, match, iLimit);
Yann Colletfb810d62016-01-28 00:18:06 +01001477 } else {
Yann Collet5106a762015-11-05 15:00:24 +01001478 match = dictBase + matchIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001479 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1480 currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
Yann Collet5106a762015-11-05 15:00:24 +01001481 }
1482
Yann Collet5054ee02015-11-23 13:34:21 +01001483 /* save best solution */
Yann Collet239cc282015-11-23 16:17:21 +01001484 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 +01001485
Yann Collet9a24e592015-11-22 02:53:43 +01001486 if (matchIndex <= minChain) break;
Yann Collet5106a762015-11-05 15:00:24 +01001487 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1488 }
1489
1490 return ml;
1491}
1492
1493
Yann Colletc1e52f02015-11-23 14:37:59 +01001494FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1495 ZSTD_CCtx* zc,
Yann Collet5106a762015-11-05 15:00:24 +01001496 const BYTE* ip, const BYTE* const iLimit,
1497 size_t* offsetPtr,
1498 const U32 maxNbAttempts, const U32 matchLengthSearch)
1499{
1500 switch(matchLengthSearch)
1501 {
1502 default :
Yann Colletc1e52f02015-11-23 14:37:59 +01001503 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1504 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1505 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1506 }
1507}
1508
1509
1510FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1511 ZSTD_CCtx* zc,
1512 const BYTE* ip, const BYTE* const iLimit,
1513 size_t* offsetPtr,
1514 const U32 maxNbAttempts, const U32 matchLengthSearch)
1515{
1516 switch(matchLengthSearch)
1517 {
1518 default :
1519 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1520 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1521 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001522 }
1523}
1524
1525
Yann Collet287b7d92015-11-22 13:24:05 +01001526/* *******************************
Yann Collet9a24e592015-11-22 02:53:43 +01001527* Common parser - lazy strategy
Yann Collet287b7d92015-11-22 13:24:05 +01001528*********************************/
Yann Collet5106a762015-11-05 15:00:24 +01001529FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001530void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1531 const void* src, size_t srcSize,
Yann Collet007c1c62015-11-22 02:42:28 +01001532 const U32 searchMethod, const U32 depth)
Yann Collet5106a762015-11-05 15:00:24 +01001533{
1534 seqStore_t* seqStorePtr = &(ctx->seqStore);
1535 const BYTE* const istart = (const BYTE*)src;
1536 const BYTE* ip = istart;
1537 const BYTE* anchor = istart;
1538 const BYTE* const iend = istart + srcSize;
1539 const BYTE* const ilimit = iend - 8;
Yann Collete47c4e52015-12-05 09:23:53 +01001540 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet5106a762015-11-05 15:00:24 +01001541
1542 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1543 const U32 maxSearches = 1 << ctx->params.searchLog;
1544 const U32 mls = ctx->params.searchLength;
1545
Yann Collet5be2dd22015-11-11 13:43:58 +01001546 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
Yann Collet5106a762015-11-05 15:00:24 +01001547 size_t* offsetPtr,
1548 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet5be2dd22015-11-11 13:43:58 +01001549 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet5106a762015-11-05 15:00:24 +01001550
1551 /* init */
1552 ZSTD_resetSeqStore(seqStorePtr);
Yann Collete47c4e52015-12-05 09:23:53 +01001553 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet5106a762015-11-05 15:00:24 +01001554
1555 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001556 while (ip < ilimit) {
Yann Collet7a231792015-11-21 15:27:35 +01001557 size_t matchLength=0;
1558 size_t offset=0;
1559 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001560
Yann Collet743402c2015-11-20 12:03:53 +01001561 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001562 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1)) {
Yann Collet743402c2015-11-20 12:03:53 +01001563 /* repcode : we take it */
Yann Collet7a231792015-11-21 15:27:35 +01001564 matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH;
Yann Collet007c1c62015-11-22 02:42:28 +01001565 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001566 }
1567
Yann Colletfc2afcf2015-11-06 15:40:14 +01001568 {
Yann Collet239cc282015-11-23 16:17:21 +01001569 /* first search (depth 0) */
1570 size_t offsetFound = 99999999;
1571 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1572 if (ml2 > matchLength)
1573 matchLength = ml2, start = ip, offset=offsetFound;
1574 }
Yann Collet9a24e592015-11-22 02:53:43 +01001575
Yann Colletfb810d62016-01-28 00:18:06 +01001576 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001577 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1578 continue;
1579 }
Yann Collet5106a762015-11-05 15:00:24 +01001580
1581 /* let's try to find a better solution */
Yann Collet007c1c62015-11-22 02:42:28 +01001582 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001583 while (ip<ilimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001584 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001585 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet007c1c62015-11-22 02:42:28 +01001586 size_t mlRep = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1587 int gain2 = (int)(mlRep * 3);
Yann Collet5106a762015-11-05 15:00:24 +01001588 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet007c1c62015-11-22 02:42:28 +01001589 if ((mlRep >= MINMATCH) && (gain2 > gain1))
1590 matchLength = mlRep, offset = 0, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001591 }
1592 {
1593 size_t offset2=999999;
1594 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet007c1c62015-11-22 02:42:28 +01001595 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1596 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001597 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001598 matchLength = ml2, offset = offset2, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001599 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001600 } }
Yann Collet5106a762015-11-05 15:00:24 +01001601
1602 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001603 if ((depth==2) && (ip<ilimit)) {
Yann Collet5106a762015-11-05 15:00:24 +01001604 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001605 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet5106a762015-11-05 15:00:24 +01001606 size_t ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1607 int gain2 = (int)(ml2 * 4);
1608 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet4baee502015-11-09 03:19:33 +01001609 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001610 matchLength = ml2, offset = 0, start = ip;
1611 }
1612 {
1613 size_t offset2=999999;
1614 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet628065c2015-11-06 18:44:54 +01001615 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1616 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001617 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001618 matchLength = ml2, offset = offset2, start = ip;
1619 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001620 } } }
Yann Collet5106a762015-11-05 15:00:24 +01001621 break; /* nothing found : store previous solution */
1622 }
1623
Yann Collet6062b152016-02-16 17:41:03 +01001624 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001625 if (offset) {
Yann Collete47c4e52015-12-05 09:23:53 +01001626 while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */
Yann Collet4baee502015-11-09 03:19:33 +01001627 { start--; matchLength++; }
Yann Collet743402c2015-11-20 12:03:53 +01001628 offset_2 = offset_1; offset_1 = offset;
Yann Collet4baee502015-11-09 03:19:33 +01001629 }
1630
1631 /* store sequence */
Yann Collet7a231792015-11-21 15:27:35 +01001632_storeSequence:
Yann Collet5106a762015-11-05 15:00:24 +01001633 {
1634 size_t litLength = start - anchor;
Yann Collet5106a762015-11-05 15:00:24 +01001635 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
Yann Collet4baee502015-11-09 03:19:33 +01001636 anchor = ip = start + matchLength;
Yann Collet5106a762015-11-05 15:00:24 +01001637 }
1638
Yann Collet743402c2015-11-20 12:03:53 +01001639 /* check immediate repcode */
1640 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001641 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet743402c2015-11-20 12:03:53 +01001642 /* store sequence */
1643 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
1644 offset = offset_2;
1645 offset_2 = offset_1;
1646 offset_1 = offset;
1647 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength);
1648 ip += matchLength+MINMATCH;
1649 anchor = ip;
1650 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001651 } }
Yann Collet5106a762015-11-05 15:00:24 +01001652
1653 /* Last Literals */
1654 {
1655 size_t lastLLSize = iend - anchor;
1656 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1657 seqStorePtr->lit += lastLLSize;
1658 }
Yann Collet5106a762015-11-05 15:00:24 +01001659}
1660
inikepe2bfe242016-01-31 11:25:48 +01001661
inikepd3b8d7a2016-02-22 10:06:17 +01001662static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01001663{
inikep84f43e22016-02-22 11:34:07 +01001664 if (ctx->params.searchLength == 3)
1665 ZSTD_compressBlock_opt_generic3(ctx, src, srcSize, 2);
1666 else
1667 ZSTD_compressBlock_opt_generic4(ctx, src, srcSize, 2);
inikepe2bfe242016-01-31 11:25:48 +01001668}
1669
Yann Collet59d1f792016-01-23 19:28:41 +01001670static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001671{
Yann Colleta1249dc2016-01-25 04:22:03 +01001672 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001673}
1674
Yann Collet59d1f792016-01-23 19:28:41 +01001675static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001676{
Yann Colleta1249dc2016-01-25 04:22:03 +01001677 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001678}
1679
Yann Collet59d1f792016-01-23 19:28:41 +01001680static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001681{
Yann Colleta1249dc2016-01-25 04:22:03 +01001682 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001683}
1684
Yann Collet59d1f792016-01-23 19:28:41 +01001685static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01001686{
Yann Colleta1249dc2016-01-25 04:22:03 +01001687 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
Yann Colletbe2010e2015-10-31 12:57:14 +01001688}
1689
1690
Yann Collet9a24e592015-11-22 02:53:43 +01001691FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001692void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1693 const void* src, size_t srcSize,
Yann Collet9a24e592015-11-22 02:53:43 +01001694 const U32 searchMethod, const U32 depth)
1695{
1696 seqStore_t* seqStorePtr = &(ctx->seqStore);
1697 const BYTE* const istart = (const BYTE*)src;
1698 const BYTE* ip = istart;
1699 const BYTE* anchor = istart;
1700 const BYTE* const iend = istart + srcSize;
1701 const BYTE* const ilimit = iend - 8;
1702 const BYTE* const base = ctx->base;
1703 const U32 dictLimit = ctx->dictLimit;
1704 const BYTE* const prefixStart = base + dictLimit;
1705 const BYTE* const dictBase = ctx->dictBase;
1706 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001707 const BYTE* const dictStart = dictBase + ctx->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001708
1709 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
1710 const U32 maxSearches = 1 << ctx->params.searchLog;
1711 const U32 mls = ctx->params.searchLength;
1712
1713 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1714 size_t* offsetPtr,
1715 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet03526e12015-11-23 15:29:15 +01001716 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
Yann Collet9a24e592015-11-22 02:53:43 +01001717
1718 /* init */
1719 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet6c3e2e72015-12-11 10:44:07 +01001720 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Collet9a24e592015-11-22 02:53:43 +01001721
1722 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001723 while (ip < ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001724 size_t matchLength=0;
1725 size_t offset=0;
1726 const BYTE* start=ip+1;
1727 U32 current = (U32)(ip-base);
1728
1729 /* check repCode */
1730 {
1731 const U32 repIndex = (U32)(current+1 - offset_1);
1732 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1733 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001734 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001735 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001736 /* repcode detected we should take it */
1737 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001738 matchLength = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
Yann Collet9a24e592015-11-22 02:53:43 +01001739 if (depth==0) goto _storeSequence;
Yann Colletfb810d62016-01-28 00:18:06 +01001740 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001741
1742 {
Yann Collet239cc282015-11-23 16:17:21 +01001743 /* first search (depth 0) */
1744 size_t offsetFound = 99999999;
1745 size_t ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
1746 if (ml2 > matchLength)
1747 matchLength = ml2, start = ip, offset=offsetFound;
1748 }
Yann Collet9a24e592015-11-22 02:53:43 +01001749
Yann Colletfb810d62016-01-28 00:18:06 +01001750 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001751 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1752 continue;
1753 }
Yann Collet9a24e592015-11-22 02:53:43 +01001754
1755 /* let's try to find a better solution */
1756 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001757 while (ip<ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001758 ip ++;
1759 current++;
1760 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001761 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001762 const U32 repIndex = (U32)(current - offset_1);
1763 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1764 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001765 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001766 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001767 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001768 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001769 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1770 int gain2 = (int)(repLength * 3);
1771 int gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1772 if ((repLength >= MINMATCH) && (gain2 > gain1))
1773 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001774 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001775
1776 /* search match, depth 1 */
1777 {
1778 size_t offset2=999999;
1779 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1780 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1781 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001782 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001783 matchLength = ml2, offset = offset2, start = ip;
1784 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001785 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001786
1787 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001788 if ((depth==2) && (ip<ilimit)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001789 ip ++;
1790 current++;
1791 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001792 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001793 const U32 repIndex = (U32)(current - offset_1);
1794 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1795 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001796 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001797 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001798 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001799 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001800 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1801 int gain2 = (int)(repLength * 4);
1802 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1803 if ((repLength >= MINMATCH) && (gain2 > gain1))
1804 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001805 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001806
1807 /* search match, depth 2 */
1808 {
1809 size_t offset2=999999;
1810 size_t ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1811 int gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1812 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001813 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001814 matchLength = ml2, offset = offset2, start = ip;
1815 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001816 } } }
Yann Collet9a24e592015-11-22 02:53:43 +01001817 break; /* nothing found : store previous solution */
1818 }
1819
1820 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001821 if (offset) {
Yann Colletc3652152015-11-24 14:06:07 +01001822 U32 matchIndex = (U32)((start-base) - offset);
1823 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1824 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
1825 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet9a24e592015-11-22 02:53:43 +01001826 offset_2 = offset_1; offset_1 = offset;
1827 }
1828
1829 /* store sequence */
1830_storeSequence:
1831 {
1832 size_t litLength = start - anchor;
1833 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1834 anchor = ip = start + matchLength;
1835 }
1836
1837 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001838 while (ip <= ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001839 const U32 repIndex = (U32)((ip-base) - offset_2);
1840 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1841 const BYTE* const repMatch = repBase + repIndex;
Yann Collet239cc282015-11-23 16:17:21 +01001842 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001843 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001844 /* repcode detected we should take it */
1845 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001846 matchLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1847 offset = offset_2; offset_2 = offset_1; offset_1 = offset; /* swap offset history */
Yann Collet9a24e592015-11-22 02:53:43 +01001848 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1849 ip += matchLength;
1850 anchor = ip;
1851 continue; /* faster when present ... (?) */
1852 }
1853 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001854 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001855
1856 /* Last Literals */
1857 {
1858 size_t lastLLSize = iend - anchor;
1859 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1860 seqStorePtr->lit += lastLLSize;
1861 }
Yann Collet9a24e592015-11-22 02:53:43 +01001862}
1863
Yann Collet59d1f792016-01-23 19:28:41 +01001864void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01001865{
Yann Colleta1249dc2016-01-25 04:22:03 +01001866 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01001867}
1868
Yann Collet59d1f792016-01-23 19:28:41 +01001869static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01001870{
Yann Colleta1249dc2016-01-25 04:22:03 +01001871 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01001872}
Yann Collet9a24e592015-11-22 02:53:43 +01001873
Yann Collet59d1f792016-01-23 19:28:41 +01001874static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01001875{
Yann Colleta1249dc2016-01-25 04:22:03 +01001876 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01001877}
1878
Yann Collet59d1f792016-01-23 19:28:41 +01001879static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01001880{
Yann Colleta1249dc2016-01-25 04:22:03 +01001881 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001882}
1883
inikepd3b8d7a2016-02-22 10:06:17 +01001884static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01001885{
inikep84f43e22016-02-22 11:34:07 +01001886 if (ctx->params.searchLength == 3)
1887 ZSTD_compressBlock_opt_extDict_generic3(ctx, src, srcSize, 2);
1888 else
1889 ZSTD_compressBlock_opt_extDict_generic4(ctx, src, srcSize, 2);
inikepe2bfe242016-01-31 11:25:48 +01001890}
1891
Yann Collet7a231792015-11-21 15:27:35 +01001892
Yann Collet59d1f792016-01-23 19:28:41 +01001893typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01001894
Yann Colletb923f652016-01-26 03:14:20 +01001895static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01001896{
inikepd3b8d7a2016-02-22 10:06:17 +01001897 static const ZSTD_blockCompressor blockCompressor[2][6] = {
1898 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt },
1899 { 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 +01001900 };
1901
1902 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01001903}
1904
1905
Yann Colletbf42c8e2016-01-09 01:08:23 +01001906static 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 +01001907{
Yann Collet03526e12015-11-23 15:29:15 +01001908 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01001909 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 +01001910 blockCompressor(zc, src, srcSize);
Yann Colletb923f652016-01-26 03:14:20 +01001911 return ZSTD_compressSequences(zc, dst, maxDstSize, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01001912}
1913
1914
Yann Collet2ce49232016-02-02 14:36:49 +01001915static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
Yann Colletf3eca252015-10-22 15:31:46 +01001916 void* dst, size_t maxDstSize,
1917 const void* src, size_t srcSize)
1918{
Yann Collet2ce49232016-02-02 14:36:49 +01001919 size_t blockSize = zc->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001920 size_t remaining = srcSize;
1921 const BYTE* ip = (const BYTE*)src;
1922 BYTE* const ostart = (BYTE*)dst;
1923 BYTE* op = ostart;
Yann Collet2ce49232016-02-02 14:36:49 +01001924 const U32 maxDist = 1 << zc->params.windowLog;
inikep15174b02016-02-23 12:41:56 +01001925 seqStore_t* ssPtr = &zc->seqStore;
inikepe0010e92016-02-23 16:25:04 +01001926 static U32 priceFunc = 0;
inikep15174b02016-02-23 12:41:56 +01001927
inikepe0010e92016-02-23 16:25:04 +01001928 ssPtr->realMatchSum = ssPtr->realLitSum = ssPtr->realSeqSum = ssPtr->realRepSum = 1;
1929 ssPtr->priceFunc = priceFunc;
Yann Collet9b11b462015-11-01 12:40:22 +01001930
Yann Collet2ce49232016-02-02 14:36:49 +01001931 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01001932 size_t cSize;
1933
Yann Collet2ce49232016-02-02 14:36:49 +01001934 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 +01001935 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01001936
Yann Collet2ce49232016-02-02 14:36:49 +01001937 if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) { /* enforce maxDist */
Yann Collet7a6343f2016-02-02 16:00:50 +01001938 U32 newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist;
1939 if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01001940 if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001941 }
Yann Collet89db5e02015-11-13 11:27:46 +01001942
Yann Collet2ce49232016-02-02 14:36:49 +01001943 cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, maxDstSize-ZSTD_blockHeaderSize, ip, blockSize);
Yann Collet3e358272015-11-04 18:19:39 +01001944 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001945
Yann Collet2ce49232016-02-02 14:36:49 +01001946 if (cSize == 0) { /* block is not compressible */
1947 cSize = ZSTD_noCompressBlock(op, maxDstSize, ip, blockSize);
Yann Collet523b5942016-01-09 02:10:40 +01001948 if (ZSTD_isError(cSize)) return cSize;
Yann Collet2ce49232016-02-02 14:36:49 +01001949 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01001950 op[0] = (BYTE)(cSize>>16);
1951 op[1] = (BYTE)(cSize>>8);
1952 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01001953 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01001954 cSize += 3;
1955 }
1956
1957 remaining -= blockSize;
Yann Collet3e358272015-11-04 18:19:39 +01001958 maxDstSize -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001959 ip += blockSize;
1960 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01001961 }
1962
inikepe0010e92016-02-23 16:25:04 +01001963
inikepf647d992016-02-29 12:33:08 +01001964#if ZSTD_OPT_DEBUG == 3
inikep15174b02016-02-23 12:41:56 +01001965 ssPtr->realMatchSum += ssPtr->realSeqSum * ((zc->params.searchLength == 3) ? 3 : 4);
inikepe0010e92016-02-23 16:25:04 +01001966 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);
1967 priceFunc++;
inikep15174b02016-02-23 12:41:56 +01001968#endif
1969
Yann Colletf3eca252015-10-22 15:31:46 +01001970 return op-ostart;
1971}
1972
1973
Yann Colletbf42c8e2016-01-09 01:08:23 +01001974static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
1975 void* dst, size_t dstSize,
1976 const void* src, size_t srcSize,
1977 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01001978{
Yann Collet2acb5d32015-10-29 16:49:43 +01001979 const BYTE* const ip = (const BYTE*) src;
Yann Colletecd651b2016-01-07 15:35:18 +01001980 size_t hbSize = 0;
1981
Yann Collet2ce49232016-02-02 14:36:49 +01001982 if (frame && (zc->stage==0)) {
Yann Colletecd651b2016-01-07 15:35:18 +01001983 hbSize = zc->hbSize;
1984 if (dstSize <= hbSize) return ERROR(dstSize_tooSmall);
1985 zc->stage = 1;
1986 memcpy(dst, zc->headerBuffer, hbSize);
1987 dstSize -= hbSize;
1988 dst = (char*)dst + hbSize;
1989 }
Yann Colletf3eca252015-10-22 15:31:46 +01001990
Yann Collet417890c2015-12-04 17:16:37 +01001991 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01001992 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01001993 /* not contiguous */
1994 size_t delta = zc->nextSrc - ip;
1995 zc->lowLimit = zc->dictLimit;
1996 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
1997 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01001998 zc->base -= delta;
1999 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01002000 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002001 }
2002
Yann Collet89db5e02015-11-13 11:27:46 +01002003 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01002004 if (zc->lowLimit > (1<<30)) {
Yann Colletcefef8c2016-02-15 07:21:54 +01002005 U32 btplus = (zc->params.strategy == ZSTD_btlazy2) || (zc->params.strategy == ZSTD_btopt);
Yann Collet6c3e2e72015-12-11 10:44:07 +01002006 U32 contentMask = (1 << (zc->params.contentLog - btplus)) - 1;
2007 U32 newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */
2008 U32 correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002009 ZSTD_reduceIndex(zc, correction);
2010 zc->base += correction;
2011 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002012 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002013 zc->dictLimit -= correction;
2014 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2015 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01002016 }
2017
Yann Colletbf42c8e2016-01-09 01:08:23 +01002018 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01002019 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01002020 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2021 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002022 }
2023
Yann Colletc3652152015-11-24 14:06:07 +01002024 zc->nextSrc = ip + srcSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002025 {
Yann Colletbf42c8e2016-01-09 01:08:23 +01002026 size_t cSize;
2027 if (frame) cSize = ZSTD_compress_generic (zc, dst, dstSize, src, srcSize);
2028 else cSize = ZSTD_compressBlock_internal (zc, dst, dstSize, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002029 if (ZSTD_isError(cSize)) return cSize;
2030 return cSize + hbSize;
2031 }
Yann Colletf3eca252015-10-22 15:31:46 +01002032}
2033
Yann Colletbf42c8e2016-01-09 01:08:23 +01002034
2035size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
2036 void* dst, size_t dstSize,
2037 const void* src, size_t srcSize)
2038{
2039 return ZSTD_compressContinue_internal(zc, dst, dstSize, src, srcSize, 1);
2040}
2041
2042
2043size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t maxDstSize, const void* src, size_t srcSize)
2044{
2045 if (srcSize > BLOCKSIZE) return ERROR(srcSize_wrong);
inikepa4dde252016-03-01 14:14:35 +01002046 zc->params.searchLength = MINMATCH; /* force ZSTD_btopt to MINMATCH in block mode */
2047 ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.searchLength);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002048 return ZSTD_compressContinue_internal(zc, dst, maxDstSize, src, srcSize, 0);
2049}
2050
2051
Yann Colletb923f652016-01-26 03:14:20 +01002052static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002053{
2054 const BYTE* const ip = (const BYTE*) src;
2055 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002056
Yann Collet417890c2015-12-04 17:16:37 +01002057 /* input becomes current prefix */
2058 zc->lowLimit = zc->dictLimit;
2059 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2060 zc->dictBase = zc->base;
2061 zc->base += ip - zc->nextSrc;
2062 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002063 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002064
2065 zc->nextSrc = iend;
2066 if (srcSize <= 8) return 0;
2067
2068 switch(zc->params.strategy)
2069 {
2070 case ZSTD_fast:
Yann Collet2ce49232016-02-02 14:36:49 +01002071 ZSTD_fillHashTable (zc, iend, zc->params.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002072 break;
2073
2074 case ZSTD_greedy:
2075 case ZSTD_lazy:
2076 case ZSTD_lazy2:
2077 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.searchLength);
2078 break;
2079
2080 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002081 case ZSTD_btopt:
Yann Colletb8a6f682016-02-15 17:06:29 +01002082 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.searchLog, zc->params.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002083 break;
2084
2085 default:
2086 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2087 }
2088
Yann Collet2ce49232016-02-02 14:36:49 +01002089 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002090 return 0;
2091}
2092
2093
Yann Colletb923f652016-01-26 03:14:20 +01002094/* Dictionary format :
2095 Magic == ZSTD_DICT_MAGIC (4 bytes)
2096 Huff0 CTable (256 * 4 bytes) => to be changed to read from writeCTable
2097 Dictionary content
2098*/
2099/*! ZSTD_loadDictEntropyStats
2100 @return : size read from dictionary */
2101static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2102{
2103 /* note : magic number already checked */
Yann Colletfb810d62016-01-28 00:18:06 +01002104 size_t offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize, errorCode;
2105 short offcodeNCount[MaxOff+1];
2106 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2107 short matchlengthNCount[MaxML+1];
2108 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2109 short litlengthNCount[MaxLL+1];
2110 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2111
Yann Colletb923f652016-01-26 03:14:20 +01002112 const size_t hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize);
2113 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Colletfb810d62016-01-28 00:18:06 +01002114 zc->flagStaticTables = 1;
2115 dict = (const char*)dict + hufHeaderSize;
2116 dictSize -= hufHeaderSize;
2117
2118 offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
2119 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2120 errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2121 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2122 dict = (const char*)dict + offcodeHeaderSize;
2123 dictSize -= offcodeHeaderSize;
2124
2125 matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
2126 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2127 errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2128 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2129 dict = (const char*)dict + matchlengthHeaderSize;
2130 dictSize -= matchlengthHeaderSize;
2131
2132 litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
2133 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2134 errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2135 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2136
2137 return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
Yann Colletb923f652016-01-26 03:14:20 +01002138}
2139
Yann Colletfb810d62016-01-28 00:18:06 +01002140
Yann Collet1c8e1942016-01-26 16:31:22 +01002141static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002142{
Yann Collet2ce49232016-02-02 14:36:49 +01002143 if (dict && (dictSize>4)) {
Yann Collet7b51a292016-01-26 15:58:49 +01002144 U32 magic = MEM_readLE32(dict);
2145 size_t eSize;
2146 if (magic != ZSTD_DICT_MAGIC)
2147 return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletb923f652016-01-26 03:14:20 +01002148
Yann Collet7b51a292016-01-26 15:58:49 +01002149 eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4, dictSize-4) + 4;
2150 if (ZSTD_isError(eSize)) return eSize;
2151 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
2152 }
Yann Colletecd651b2016-01-07 15:35:18 +01002153 return 0;
2154}
2155
2156
Yann Collet417890c2015-12-04 17:16:37 +01002157/*! ZSTD_compressBegin_advanced
Yann Colletecd651b2016-01-07 15:35:18 +01002158* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002159size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
2160 const void* dict, size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002161 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002162{
Yann Collet4114f952015-10-30 06:40:22 +01002163 size_t errorCode;
Yann Collet88fcd292015-11-25 14:42:45 +01002164
2165 ZSTD_validateParams(&params);
2166
Yann Collet1c8e1942016-01-26 16:31:22 +01002167 errorCode = ZSTD_resetCCtx_advanced(zc, params);
Yann Collet4114f952015-10-30 06:40:22 +01002168 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet89db5e02015-11-13 11:27:46 +01002169
Yann Collet1c8e1942016-01-26 16:31:22 +01002170 MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER); /* Write Header */
inikep6b3739c2016-02-22 15:53:42 +01002171 ((BYTE*)zc->headerBuffer)[4] = (BYTE)(params.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN + ((params.searchLength==3)<<4));
Yann Collet1c8e1942016-01-26 16:31:22 +01002172 zc->hbSize = ZSTD_frameHeaderSize_min;
2173 zc->stage = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002174
Yann Collet1c8e1942016-01-26 16:31:22 +01002175 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002176}
2177
2178
Yann Collet1c8e1942016-01-26 16:31:22 +01002179size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002180{
inikepa4dde252016-03-01 14:14:35 +01002181 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet953ce722016-02-04 15:28:14 +01002182 return ZSTD_compressBegin_advanced(zc, dict, dictSize, ZSTD_getParams(compressionLevel, MAX(128 KB, dictSize)));
Yann Collet1c8e1942016-01-26 16:31:22 +01002183}
Yann Collet083fcc82015-10-25 14:06:35 +01002184
Yann Collet1c8e1942016-01-26 16:31:22 +01002185size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002186{
inikepa4dde252016-03-01 14:14:35 +01002187 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet1c8e1942016-01-26 16:31:22 +01002188 return ZSTD_compressBegin_advanced(zc, NULL, 0, ZSTD_getParams(compressionLevel, 0));
Yann Collet083fcc82015-10-25 14:06:35 +01002189}
2190
2191
Yann Collet31683c02015-12-18 01:26:48 +01002192/*! ZSTD_compressEnd
Yann Collet88fcd292015-11-25 14:42:45 +01002193* Write frame epilogue
2194* @return : nb of bytes written into dst (or an error code) */
Yann Colletecd651b2016-01-07 15:35:18 +01002195size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t maxDstSize)
Yann Collet2acb5d32015-10-29 16:49:43 +01002196{
2197 BYTE* op = (BYTE*)dst;
Yann Colletecd651b2016-01-07 15:35:18 +01002198 size_t hbSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002199
Yann Colletecd651b2016-01-07 15:35:18 +01002200 /* empty frame */
Yann Colletfb810d62016-01-28 00:18:06 +01002201 if (zc->stage==0) {
Yann Colletecd651b2016-01-07 15:35:18 +01002202 hbSize = zc->hbSize;
2203 if (maxDstSize <= hbSize) return ERROR(dstSize_tooSmall);
2204 zc->stage = 1;
2205 memcpy(dst, zc->headerBuffer, hbSize);
2206 maxDstSize -= hbSize;
2207 op += hbSize;
2208 }
2209
2210 /* frame epilogue */
Yann Collet2acb5d32015-10-29 16:49:43 +01002211 if (maxDstSize < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002212 op[0] = (BYTE)(bt_end << 6);
2213 op[1] = 0;
2214 op[2] = 0;
2215
Yann Colletecd651b2016-01-07 15:35:18 +01002216 return 3+hbSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002217}
2218
Yann Colletfd416f12016-01-30 03:14:15 +01002219
2220size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
2221 void* dst, size_t maxDstSize,
2222 const void* src, size_t srcSize)
2223{
2224 size_t outSize;
2225 size_t errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2226 if (ZSTD_isError(errorCode)) return errorCode;
2227 errorCode = ZSTD_compressContinue(cctx, dst, maxDstSize, src, srcSize);
2228 if (ZSTD_isError(errorCode)) return errorCode;
2229 outSize = errorCode;
2230 errorCode = ZSTD_compressEnd(cctx, (char*)dst+outSize, maxDstSize-outSize);
2231 if (ZSTD_isError(errorCode)) return errorCode;
2232 outSize += errorCode;
2233 return outSize;
2234}
2235
2236
Yann Collet5be2dd22015-11-11 13:43:58 +01002237size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
Yann Collet88fcd292015-11-25 14:42:45 +01002238 void* dst, size_t maxDstSize,
2239 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002240 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002241 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002242{
2243 BYTE* const ostart = (BYTE*)dst;
2244 BYTE* op = ostart;
Yann Collet4114f952015-10-30 06:40:22 +01002245 size_t oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002246
Yann Collet1c8e1942016-01-26 16:31:22 +01002247 /* Init */
2248 oSize = ZSTD_compressBegin_advanced(ctx, dict, dictSize, params);
Yann Colletf3eca252015-10-22 15:31:46 +01002249 if(ZSTD_isError(oSize)) return oSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002250
2251 /* body (compression) */
Yann Collet31683c02015-12-18 01:26:48 +01002252 oSize = ZSTD_compressContinue (ctx, op, maxDstSize, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002253 if(ZSTD_isError(oSize)) return oSize;
2254 op += oSize;
2255 maxDstSize -= oSize;
2256
2257 /* Close frame */
Yann Collet5be2dd22015-11-11 13:43:58 +01002258 oSize = ZSTD_compressEnd(ctx, op, maxDstSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002259 if(ZSTD_isError(oSize)) return oSize;
2260 op += oSize;
2261
2262 return (op - ostart);
2263}
2264
Yann Collet31683c02015-12-18 01:26:48 +01002265size_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)
2266{
inikepa4dde252016-03-01 14:14:35 +01002267 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 +01002268 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, dict, dictSize, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet31683c02015-12-18 01:26:48 +01002269}
2270
Yann Collet5be2dd22015-11-11 13:43:58 +01002271size_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 +01002272{
inikepa4dde252016-03-01 14:14:35 +01002273 ZSTD_LOG_BLOCK("%p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, compressionLevel);
Yann Collet31683c02015-12-18 01:26:48 +01002274 return ZSTD_compress_advanced(ctx, dst, maxDstSize, src, srcSize, NULL, 0, ZSTD_getParams(compressionLevel, srcSize));
Yann Collet083fcc82015-10-25 14:06:35 +01002275}
2276
Yann Collet5be2dd22015-11-11 13:43:58 +01002277size_t ZSTD_compress(void* dst, size_t maxDstSize, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002278{
Yann Collet44fe9912015-10-29 22:02:40 +01002279 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002280 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002281 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Collet5be2dd22015-11-11 13:43:58 +01002282 result = ZSTD_compressCCtx(&ctxBody, dst, maxDstSize, src, srcSize, compressionLevel);
Yann Colletecd651b2016-01-07 15:35:18 +01002283 free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002284 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002285}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002286
Yann Colletfd416f12016-01-30 03:14:15 +01002287
Yann Collet70e8c382016-02-10 13:37:52 +01002288/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01002289
inikep6b3739c2016-02-22 15:53:42 +01002290#define ZSTD_MAX_CLEVEL 25
Yann Collet7d968c72016-02-03 02:11:32 +01002291unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2292
inikepcc52a972016-02-19 10:09:35 +01002293
Yann Colletfd416f12016-01-30 03:14:15 +01002294static const ZSTD_parameters ZSTD_defaultParameters[4][ZSTD_MAX_CLEVEL+1] = {
2295{ /* "default" */
inikepcc52a972016-02-19 10:09:35 +01002296 /* l, W, C, H, H3, S, L, SL, strat */
2297 { 0, 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2298 { 0, 19, 13, 14, 0, 1, 7, 4, ZSTD_fast }, /* level 1 */
2299 { 0, 19, 15, 16, 0, 1, 6, 4, ZSTD_fast }, /* level 2 */
2300 { 0, 20, 18, 20, 0, 1, 6, 4, ZSTD_fast }, /* level 3 */
2301 { 0, 21, 19, 21, 0, 1, 6, 4, ZSTD_fast }, /* level 4 */
2302 { 0, 20, 14, 18, 0, 3, 5, 4, ZSTD_greedy }, /* level 5 */
2303 { 0, 20, 18, 19, 0, 3, 5, 4, ZSTD_greedy }, /* level 6 */
2304 { 0, 21, 17, 20, 0, 3, 5, 4, ZSTD_lazy }, /* level 7 */
2305 { 0, 21, 19, 20, 0, 3, 5, 4, ZSTD_lazy }, /* level 8 */
2306 { 0, 21, 20, 20, 0, 3, 5, 4, ZSTD_lazy2 }, /* level 9 */
2307 { 0, 21, 19, 21, 0, 4, 5, 4, ZSTD_lazy2 }, /* level 10 */
2308 { 0, 22, 20, 22, 0, 4, 5, 4, ZSTD_lazy2 }, /* level 11 */
2309 { 0, 22, 20, 22, 0, 5, 5, 4, ZSTD_lazy2 }, /* level 12 */
2310 { 0, 22, 21, 22, 0, 5, 5, 4, ZSTD_lazy2 }, /* level 13 */
2311 { 0, 22, 22, 23, 0, 5, 5, 4, ZSTD_lazy2 }, /* level 14 */
2312 { 0, 23, 23, 23, 0, 5, 5, 4, ZSTD_lazy2 }, /* level 15 */
2313 { 0, 23, 22, 22, 0, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */
2314 { 0, 24, 24, 23, 0, 4, 5, 4, ZSTD_btlazy2 }, /* level 17 */
inikep6b3739c2016-02-22 15:53:42 +01002315 { 0, 24, 24, 23, 0, 5, 5, 30, ZSTD_btopt }, /* level 18 */
2316 { 0, 25, 25, 24, 0, 5, 4, 40, ZSTD_btopt }, /* level 19 */
2317 { 0, 26, 26, 25, 0, 8, 4,256, ZSTD_btopt }, /* level 20 */
2318 { 0, 26, 27, 25, 0, 10, 4,256, ZSTD_btopt }, /* level 21 */
2319 { 0, 24, 24, 23, 16, 5, 3, 30, ZSTD_btopt }, /* level 22 */
2320 { 0, 25, 25, 24, 16, 5, 3, 40, ZSTD_btopt }, /* level 23 */
2321 { 0, 26, 26, 25, 16, 8, 3,256, ZSTD_btopt }, /* level 24 */
2322 { 0, 26, 27, 25, 24, 10, 3,256, ZSTD_btopt }, /* level 25 */
Yann Colletfd416f12016-01-30 03:14:15 +01002323},
2324{ /* for srcSize <= 256 KB */
inikepcc52a972016-02-19 10:09:35 +01002325 /* l, W, C, H, H3, S, L, T, strat */
2326 { 0, 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 */
2327 { 0, 18, 14, 15, 0, 1, 6, 4, ZSTD_fast }, /* level 1 */
2328 { 0, 18, 14, 16, 0, 1, 5, 4, ZSTD_fast }, /* level 2 */
2329 { 0, 18, 14, 17, 0, 1, 5, 4, ZSTD_fast }, /* level 3.*/
2330 { 0, 18, 14, 15, 0, 4, 4, 4, ZSTD_greedy }, /* level 4 */
2331 { 0, 18, 16, 17, 0, 4, 4, 4, ZSTD_greedy }, /* level 5 */
2332 { 0, 18, 17, 17, 0, 3, 4, 4, ZSTD_lazy }, /* level 6 */
2333 { 0, 18, 17, 17, 0, 4, 4, 4, ZSTD_lazy }, /* level 7 */
2334 { 0, 18, 17, 17, 0, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2335 { 0, 18, 17, 17, 0, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2336 { 0, 18, 17, 17, 0, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
2337 { 0, 18, 17, 17, 0, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */
2338 { 0, 18, 18, 17, 0, 4, 4, 4, ZSTD_btlazy2 }, /* level 12 */
2339 { 0, 18, 19, 17, 0, 7, 4, 4, ZSTD_btlazy2 }, /* level 13.*/
2340 { 0, 18, 17, 19, 0, 8, 4, 24, ZSTD_btopt }, /* level 14.*/
2341 { 0, 18, 19, 19, 0, 8, 4, 48, ZSTD_btopt }, /* level 15.*/
2342 { 0, 18, 19, 18, 0, 9, 4,128, ZSTD_btopt }, /* level 16.*/
2343 { 0, 18, 19, 18, 0, 9, 4,192, ZSTD_btopt }, /* level 17.*/
2344 { 0, 18, 19, 18, 0, 9, 4,256, ZSTD_btopt }, /* level 18.*/
2345 { 0, 18, 19, 18, 0, 10, 4,256, ZSTD_btopt }, /* level 19.*/
2346 { 0, 18, 19, 18, 0, 11, 4,256, ZSTD_btopt }, /* level 20.*/
2347 { 0, 18, 19, 18, 0, 12, 4,256, ZSTD_btopt }, /* level 21.*/
inikep9f754d22016-02-22 17:00:04 +01002348 { 0, 18, 19, 18, 0, 12, 4,256, ZSTD_btopt }, /* level 21-2*/
2349 { 0, 18, 19, 18, 0, 12, 4,256, ZSTD_btopt }, /* level 21-3*/
2350 { 0, 18, 19, 18, 0, 12, 4,256, ZSTD_btopt }, /* level 21-4*/
2351 { 0, 18, 19, 18, 0, 12, 4,256, ZSTD_btopt }, /* level 21-5*/
Yann Colletfd416f12016-01-30 03:14:15 +01002352},
2353{ /* for srcSize <= 128 KB */
inikepcc52a972016-02-19 10:09:35 +01002354 /* l, W, C, H, H3, S, L, T, strat */
2355 { 0, 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2356 { 0, 17, 12, 13, 0, 1, 6, 4, ZSTD_fast }, /* level 1 */
2357 { 0, 17, 13, 16, 0, 1, 5, 4, ZSTD_fast }, /* level 2 */
2358 { 0, 17, 13, 14, 0, 2, 5, 4, ZSTD_greedy }, /* level 3 */
2359 { 0, 17, 13, 15, 0, 3, 4, 4, ZSTD_greedy }, /* level 4 */
2360 { 0, 17, 15, 17, 0, 4, 4, 4, ZSTD_greedy }, /* level 5 */
2361 { 0, 17, 16, 17, 0, 3, 4, 4, ZSTD_lazy }, /* level 6 */
2362 { 0, 17, 16, 17, 0, 4, 4, 4, ZSTD_lazy }, /* level 7 */
2363 { 0, 17, 17, 16, 0, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2364 { 0, 17, 17, 16, 0, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2365 { 0, 17, 17, 16, 0, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
2366 { 0, 17, 17, 17, 0, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */
2367 { 0, 17, 17, 17, 0, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */
2368 { 0, 17, 17, 17, 0, 9, 4, 4, ZSTD_lazy2 }, /* level 13 */
2369 { 0, 17, 18, 16, 0, 5, 4, 20, ZSTD_btopt }, /* level 14 */
2370 { 0, 17, 18, 16, 0, 9, 4, 48, ZSTD_btopt }, /* level 15 */
2371 { 0, 17, 18, 17, 0, 7, 4,128, ZSTD_btopt }, /* level 16 */
2372 { 0, 17, 18, 17, 0, 8, 4,128, ZSTD_btopt }, /* level 17 */
2373 { 0, 17, 18, 17, 0, 8, 4,256, ZSTD_btopt }, /* level 18 */
2374 { 0, 17, 18, 17, 0, 9, 4,256, ZSTD_btopt }, /* level 19 */
2375 { 0, 17, 18, 17, 0, 10, 4,512, ZSTD_btopt }, /* level 20 */
2376 { 0, 17, 18, 17, 0, 11, 4,512, ZSTD_btopt }, /* level 21 */
inikep9f754d22016-02-22 17:00:04 +01002377 { 0, 17, 18, 17, 0, 11, 4,512, ZSTD_btopt }, /* level 21-2 */
2378 { 0, 17, 18, 17, 0, 11, 4,512, ZSTD_btopt }, /* level 21-3 */
2379 { 0, 17, 18, 17, 0, 11, 4,512, ZSTD_btopt }, /* level 21-4 */
2380 { 0, 17, 18, 17, 0, 11, 4,512, ZSTD_btopt }, /* level 21-5 */
Yann Collet38fba562016-02-13 11:20:23 +01002381
Yann Colletfd416f12016-01-30 03:14:15 +01002382},
2383{ /* for srcSize <= 16 KB */
inikepcc52a972016-02-19 10:09:35 +01002384 /* l, W, C, H, H3, S, L, T, strat */
2385 { 0, 0, 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 -- never used */
2386 { 0, 14, 14, 14, 0, 1, 4, 4, ZSTD_fast }, /* level 1 */
2387 { 0, 14, 14, 15, 0, 1, 4, 4, ZSTD_fast }, /* level 2 */
2388 { 0, 14, 13, 15, 0, 4, 4, 4, ZSTD_greedy }, /* level 3 */
2389 { 0, 14, 14, 15, 0, 3, 4, 4, ZSTD_lazy }, /* level 4 */
2390 { 0, 14, 14, 14, 0, 6, 4, 4, ZSTD_lazy }, /* level 5 */
2391 { 0, 14, 14, 14, 0, 5, 4, 4, ZSTD_lazy2 }, /* level 6 */
2392 { 0, 14, 14, 14, 0, 7, 4, 4, ZSTD_lazy2 }, /* level 7 */
2393 { 0, 14, 14, 14, 0, 8, 4, 4, ZSTD_lazy2 }, /* level 8 */
2394 { 0, 14, 14, 14, 0, 9, 4, 4, ZSTD_lazy2 }, /* level 9 */
2395 { 0, 14, 14, 14, 0, 10, 4, 4, ZSTD_lazy2 }, /* level 10 */
2396 { 0, 14, 14, 14, 0, 11, 4, 4, ZSTD_lazy2 }, /* level 11 */
2397 { 0, 14, 15, 15, 0, 12, 4, 32, ZSTD_btopt }, /* level 12 */
2398 { 0, 14, 15, 15, 0, 12, 4, 64, ZSTD_btopt }, /* level 13 */
2399 { 0, 14, 15, 15, 0, 12, 4, 96, ZSTD_btopt }, /* level 14 */
2400 { 0, 14, 15, 15, 0, 12, 4,128, ZSTD_btopt }, /* level 15 */
2401 { 0, 14, 15, 15, 0, 12, 4,256, ZSTD_btopt }, /* level 16 */
2402 { 0, 14, 15, 15, 0, 13, 4,256, ZSTD_btopt }, /* level 17 */
2403 { 0, 14, 15, 15, 0, 14, 4,256, ZSTD_btopt }, /* level 18 */
2404 { 0, 14, 15, 15, 0, 15, 4,256, ZSTD_btopt }, /* level 19 */
2405 { 0, 14, 15, 15, 0, 16, 4,256, ZSTD_btopt }, /* level 20 */
2406 { 0, 14, 15, 15, 0, 17, 4,256, ZSTD_btopt }, /* level 21 */
inikep9f754d22016-02-22 17:00:04 +01002407 { 0, 14, 15, 15, 0, 17, 4,256, ZSTD_btopt }, /* level 21-2 */
2408 { 0, 14, 15, 15, 0, 17, 4,256, ZSTD_btopt }, /* level 21-3 */
2409 { 0, 14, 15, 15, 0, 17, 4,256, ZSTD_btopt }, /* level 21-4 */
2410 { 0, 14, 15, 15, 0, 17, 4,256, ZSTD_btopt }, /* level 21-5 */
Yann Colletfd416f12016-01-30 03:14:15 +01002411},
2412};
2413
2414/*! ZSTD_getParams
2415* @return ZSTD_parameters structure for a selected compression level and srcSize.
2416* @srcSizeHint value is optional, select 0 if not known */
2417ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSizeHint)
2418{
2419 ZSTD_parameters result;
2420 int tableID = ((srcSizeHint-1) <= 256 KB) + ((srcSizeHint-1) <= 128 KB) + ((srcSizeHint-1) <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
2421 if (compressionLevel<=0) compressionLevel = 1;
2422 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
inikep3379c5d2016-02-05 09:21:20 +01002423#if ZSTD_OPT_DEBUG >= 1
2424 tableID=0;
2425#endif
Yann Colletfd416f12016-01-30 03:14:15 +01002426 result = ZSTD_defaultParameters[tableID][compressionLevel];
2427 result.srcSize = srcSizeHint;
2428 return result;
2429}
2430