blob: e9960a91a23c3899d6d67f0e3dbaef43ffc82ed8 [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 Colletbb604482016-03-19 15:18:42 +010065static const U32 g_searchStrength = 8; /* control skip over incompressible data */
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 +010077static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
78{
79 ssPtr->offset = ssPtr->offsetStart;
80 ssPtr->lit = ssPtr->litStart;
81 ssPtr->litLength = ssPtr->litLengthStart;
82 ssPtr->matchLength = ssPtr->matchLengthStart;
Yann Collet5d393572016-04-07 17:19:00 +020083 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010084}
85
86
Yann Collet7d360282016-02-12 00:07:30 +010087/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010088* Context memory management
89***************************************/
Yann Collet5be2dd22015-11-11 13:43:58 +010090struct ZSTD_CCtx_s
Yann Colletf3eca252015-10-22 15:31:46 +010091{
Yann Collet89db5e02015-11-13 11:27:46 +010092 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010093 const BYTE* base; /* All regular indexes relative to this position */
94 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010095 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010096 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010097 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010098 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +010099 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Collet2ce49232016-02-02 14:36:49 +0100100 U32 loadedDictEnd;
Yann Collet887e7da2016-04-11 20:12:27 +0200101 U32 stage; /* 0: created; 1: init,dictLoad; 2:started */
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 Collet0e491c02016-03-11 21:58:04 +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 Collet8a57b922016-04-04 13:49:18 +0200112 U32* chainTable;
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 Colletb44be742016-03-26 20:52:14 +0100132const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100133{
Yann Colletb44be742016-03-26 20:52:14 +0100134 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100135}
136
Yann Collet59d70632015-11-04 12:05:27 +0100137
Yann Collet21588e32016-03-30 16:50:44 +0200138#define CLAMP(val,min,max) { if (val<min) val=min; else if (val>max) val=max; }
139#define CLAMPCHECK(val,min,max) { if ((val<min) || (val>max)) return ERROR(compressionParameter_unsupported); }
140
141/** ZSTD_checkParams() :
142 ensure param values remain within authorized range.
143 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200144size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200145{
Yann Collet15354142016-04-04 04:22:53 +0200146 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200147 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200148 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
149 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
inikep75716852016-04-06 12:34:42 +0200150 { U32 const searchLengthMin = (cParams.strategy == ZSTD_fast || cParams.strategy == ZSTD_greedy) ? ZSTD_SEARCHLENGTH_MIN+1 : ZSTD_SEARCHLENGTH_MIN;
Yann Collet3b719252016-03-30 19:48:05 +0200151 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
152 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
153 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Collet9bb87e52016-03-30 21:28:15 +0200154 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200155 return 0;
156}
157
158
Yann Collet14983e72015-11-11 21:38:21 +0100159static unsigned ZSTD_highbit(U32 val);
160
Yann Collet3b719252016-03-30 19:48:05 +0200161/** ZSTD_checkCParams_advanced() :
162 temporary work-around, while the compressor compatibility remains limited regarding windowLog < 18 */
163size_t ZSTD_checkCParams_advanced(ZSTD_compressionParameters cParams, U64 srcSize)
164{
Yann Colletefb18302016-04-01 18:54:13 +0200165 if (srcSize > (1ULL << ZSTD_WINDOWLOG_MIN)) return ZSTD_checkCParams(cParams);
Yann Collet3b719252016-03-30 19:48:05 +0200166 if (cParams.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) return ERROR(compressionParameter_unsupported);
Yann Collet8a57b922016-04-04 13:49:18 +0200167 if (srcSize <= (1ULL << cParams.windowLog)) cParams.windowLog = ZSTD_WINDOWLOG_MIN; /* fake value - temporary work around */
168 if (srcSize <= (1ULL << cParams.chainLog)) cParams.chainLog = ZSTD_CHAINLOG_MIN; /* fake value - temporary work around */
Yann Colletef363902016-04-02 00:46:40 +0200169 if ((srcSize <= (1ULL << cParams.hashLog)) && ((U32)cParams.strategy < (U32)ZSTD_btlazy2)) cParams.hashLog = ZSTD_HASHLOG_MIN; /* fake value - temporary work around */
Yann Collet3b719252016-03-30 19:48:05 +0200170 return ZSTD_checkCParams(cParams);
171}
172
173
Yann Collet21588e32016-03-30 16:50:44 +0200174/** ZSTD_adjustParams() :
175 optimize params for q given input (`srcSize` and `dictSize`).
176 mostly downsizing to reduce memory consumption and initialization.
177 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
178 but if both are 0, no optimization can be done.
179 Note : params is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Colletdd6466a2016-03-30 20:06:26 +0200180void ZSTD_adjustCParams(ZSTD_compressionParameters* params, U64 srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100181{
Yann Collet21588e32016-03-30 16:50:44 +0200182 if (srcSize+dictSize == 0) return; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100183
Yann Collet70e45772016-03-19 18:08:32 +0100184 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200185 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
186 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200187 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Collet21588e32016-03-30 16:50:44 +0200188 U32 const srcLog = ZSTD_highbit((U32)(rSize)-1) + 1;
189 if (params->windowLog > srcLog) params->windowLog = srcLog;
190 } }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100191 if (params->hashLog > params->windowLog) params->hashLog = params->windowLog;
Yann Collet21588e32016-03-30 16:50:44 +0200192 { U32 const btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_btopt);
Yann Collet8a57b922016-04-04 13:49:18 +0200193 U32 const maxChainLog = params->windowLog+btPlus;
194 if (params->chainLog > maxChainLog) params->chainLog = maxChainLog; } /* <= ZSTD_CHAINLOG_MAX */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100195
196 if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet40358d02016-04-02 00:40:09 +0200197 if ((params->hashLog < ZSTD_HASHLOG_MIN) && ((U32)params->strategy >= (U32)ZSTD_btlazy2)) params->hashLog = ZSTD_HASHLOG_MIN; /* required to ensure collision resistance in bt */
Yann Collet59d70632015-11-04 12:05:27 +0100198}
199
200
Yann Collet51d50042016-03-30 20:42:19 +0200201size_t ZSTD_sizeofCCtx(ZSTD_compressionParameters cParams) /* hidden interface, for paramagrill */
Yann Collete74215e2016-03-19 16:09:09 +0100202{
203 ZSTD_CCtx* zc = ZSTD_createCCtx();
Yann Collet51d50042016-03-30 20:42:19 +0200204 ZSTD_parameters params;
205 params.cParams = cParams;
206 params.fParams.contentSizeFlag = 1;
Yann Collet3b719252016-03-30 19:48:05 +0200207 ZSTD_compressBegin_advanced(zc, NULL, 0, params, 0);
Yann Colletd64f4352016-03-21 00:07:42 +0100208 { size_t const ccsize = sizeof(*zc) + zc->workSpaceSize;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100209 ZSTD_freeCCtx(zc);
Yann Colletd64f4352016-03-21 00:07:42 +0100210 return ccsize; }
Yann Collet2e91dde2016-03-08 12:22:11 +0100211}
212
Yann Collet27caf2a2016-04-01 15:48:48 +0200213/*! ZSTD_resetCCtx_advanced() :
214 note : 'params' is expected to be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100215static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Colletabb5c652016-04-11 20:42:31 +0200216 ZSTD_parameters params, U32 reset)
Yann Collet863ec402016-01-28 17:56:33 +0100217{ /* note : params considered validated here */
Yann Collet3b719252016-03-30 19:48:05 +0200218 const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
219 const U32 divider = (params.cParams.searchLength==3) ? 3 : 4;
Yann Colletdd54bbc2016-03-08 02:35:34 +0100220 const size_t maxNbSeq = blockSize / divider;
Yann Colletbe391432016-03-22 23:19:28 +0100221 const size_t tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet8a57b922016-04-04 13:49:18 +0200222 const size_t chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
Yann Collet3b719252016-03-30 19:48:05 +0200223 const size_t hSize = 1 << params.cParams.hashLog;
inikep7adceef2016-03-23 15:53:38 +0100224 const size_t h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Collet8a57b922016-04-04 13:49:18 +0200225 const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
inikep87d4f3d2016-03-02 15:56:24 +0100226
Yann Collete74215e2016-03-19 16:09:09 +0100227 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Collet48537162016-04-07 15:24:29 +0200228 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
Yann Collete74215e2016-03-19 16:09:09 +0100229 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
230 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Yann Collet1005fc12016-04-04 13:28:28 +0200231 + ((params.cParams.strategy == ZSTD_btopt) ? optSpace : 0);
Yann Collete74215e2016-03-19 16:09:09 +0100232 if (zc->workSpaceSize < neededSpace) {
233 free(zc->workSpace);
234 zc->workSpace = malloc(neededSpace);
235 if (zc->workSpace == NULL) return ERROR(memory_allocation);
236 zc->workSpaceSize = neededSpace;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100237 } }
Yann Collete74215e2016-03-19 16:09:09 +0100238
Yann Colletabb5c652016-04-11 20:42:31 +0200239 if (reset) memset(zc->workSpace, 0, tableSpace ); /* reset only tables */
inikepcc52a972016-02-19 10:09:35 +0100240 zc->hashTable3 = (U32*)(zc->workSpace);
Yann Collete74215e2016-03-19 16:09:09 +0100241 zc->hashTable = zc->hashTable3 + h3Size;
Yann Collet8a57b922016-04-04 13:49:18 +0200242 zc->chainTable = zc->hashTable + hSize;
243 zc->seqStore.buffer = zc->chainTable + chainSize;
Yann Collet863ec402016-01-28 17:56:33 +0100244 zc->hufTable = (HUF_CElt*)zc->seqStore.buffer;
245 zc->flagStaticTables = 0;
Yann Collet597847a2016-03-20 19:14:22 +0100246 zc->seqStore.buffer = ((U32*)(zc->seqStore.buffer)) + 256;
Yann Collet083fcc82015-10-25 14:06:35 +0100247
Yann Colletf48e35c2015-11-07 01:13:31 +0100248 zc->nextToUpdate = 1;
Yann Collet89db5e02015-11-13 11:27:46 +0100249 zc->nextSrc = NULL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100250 zc->base = NULL;
251 zc->dictBase = NULL;
252 zc->dictLimit = 0;
253 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100254 zc->params = params;
Yann Collet120230b2015-12-02 14:00:45 +0100255 zc->blockSize = blockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100256
Yann Collet3b719252016-03-30 19:48:05 +0200257 if (params.cParams.strategy == ZSTD_btopt) {
Yann Collet72d706a2016-03-23 20:44:12 +0100258 zc->seqStore.litFreq = (U32*)(zc->seqStore.buffer);
259 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
260 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
261 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
Yann Collet48537162016-04-07 15:24:29 +0200262 zc->seqStore.matchTable = (ZSTD_match_t*)((void*)(zc->seqStore.offCodeFreq + (MaxOff+1)));
Yann Collet72d706a2016-03-23 20:44:12 +0100263 zc->seqStore.priceTable = (ZSTD_optimal_t*)((void*)(zc->seqStore.matchTable + ZSTD_OPT_NUM+1));
264 zc->seqStore.buffer = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
265 zc->seqStore.litLengthSum = 0;
266 }
inikep87d4f3d2016-03-02 15:56:24 +0100267 zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer);
Yann Collet597847a2016-03-20 19:14:22 +0100268 zc->seqStore.litLengthStart = (U16*) (void*)(zc->seqStore.offsetStart + maxNbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100269 zc->seqStore.matchLengthStart = (U16*) (void*)(zc->seqStore.litLengthStart + maxNbSeq);
270 zc->seqStore.llCodeStart = (BYTE*) (zc->seqStore.matchLengthStart + maxNbSeq);
271 zc->seqStore.mlCodeStart = zc->seqStore.llCodeStart + maxNbSeq;
272 zc->seqStore.offCodeStart = zc->seqStore.mlCodeStart + maxNbSeq;
Yann Colletdd54bbc2016-03-08 02:35:34 +0100273 zc->seqStore.litStart = zc->seqStore.offCodeStart + maxNbSeq;
inikep5cccd772016-03-02 20:37:49 +0100274
Yann Colletecd651b2016-01-07 15:35:18 +0100275 zc->hbSize = 0;
Yann Collet887e7da2016-04-11 20:12:27 +0200276 zc->stage = 1;
Yann Collet2ce49232016-02-02 14:36:49 +0100277 zc->loadedDictEnd = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +0100278
Yann Collet4114f952015-10-30 06:40:22 +0100279 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100280}
281
Yann Collet083fcc82015-10-25 14:06:35 +0100282
Yann Collet370b08e2016-03-08 00:03:59 +0100283/*! ZSTD_copyCCtx() :
284* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet887e7da2016-04-11 20:12:27 +0200285* Only works during stage 1 (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100286* @return : 0, or an error code */
287size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
288{
Yann Collet887e7da2016-04-11 20:12:27 +0200289 if (srcCCtx->stage!=1) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100290
inikep7adceef2016-03-23 15:53:38 +0100291 dstCCtx->hashLog3 = srcCCtx->hashLog3; /* must be before ZSTD_resetCCtx_advanced */
Yann Colletabb5c652016-04-11 20:42:31 +0200292 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, 0);
Yann Collet7b51a292016-01-26 15:58:49 +0100293
294 /* copy tables */
inikep0c7456c2016-04-04 14:54:53 +0200295 { const size_t chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
Yann Collet3b719252016-03-30 19:48:05 +0200296 const size_t hSize = 1 << srcCCtx->params.cParams.hashLog;
inikep7adceef2016-03-23 15:53:38 +0100297 const size_t h3Size = (srcCCtx->hashLog3) ? 1 << srcCCtx->hashLog3 : 0;
inikep0c7456c2016-04-04 14:54:53 +0200298 const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100299 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
300 }
Yann Collet7b51a292016-01-26 15:58:49 +0100301
302 /* copy frame header */
303 dstCCtx->hbSize = srcCCtx->hbSize;
304 memcpy(dstCCtx->headerBuffer , srcCCtx->headerBuffer, srcCCtx->hbSize);
305
306 /* copy dictionary pointers */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100307 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
308 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
309 dstCCtx->nextSrc = srcCCtx->nextSrc;
310 dstCCtx->base = srcCCtx->base;
311 dstCCtx->dictBase = srcCCtx->dictBase;
312 dstCCtx->dictLimit = srcCCtx->dictLimit;
313 dstCCtx->lowLimit = srcCCtx->lowLimit;
314 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Collet7b51a292016-01-26 15:58:49 +0100315
Yann Colletfb810d62016-01-28 00:18:06 +0100316 /* copy entropy tables */
317 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100318 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100319 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100320 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
321 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
322 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
323 }
Yann Collet7b51a292016-01-26 15:58:49 +0100324
325 return 0;
326}
327
328
Yann Colletecabfe32016-03-20 16:20:06 +0100329/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100330* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100331static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100332{
Yann Colletecabfe32016-03-20 16:20:06 +0100333 U32 u;
334 for (u=0 ; u < size ; u++) {
335 if (table[u] < reducerValue) table[u] = 0;
336 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100337 }
338}
339
Yann Colletecabfe32016-03-20 16:20:06 +0100340/*! ZSTD_reduceIndex() :
341* rescale all indexes to avoid future overflow (indexes are U32) */
342static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
343{
Yann Collet3b719252016-03-30 19:48:05 +0200344 { const U32 hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100345 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
346
Yann Collet8a57b922016-04-04 13:49:18 +0200347 { const U32 chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
348 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100349
inikep7adceef2016-03-23 15:53:38 +0100350 { const U32 h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100351 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
352}
353
Yann Collet89db5e02015-11-13 11:27:46 +0100354
Yann Collet863ec402016-01-28 17:56:33 +0100355/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100356* Block entropic compression
357*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100358
Yann Colletfb797352016-03-13 11:08:40 +0100359/* Frame format description
360 Frame Header - [ Block Header - Block ] - Frame End
361 1) Frame Header
362 - 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_static.h)
363 - 1 byte - Frame Descriptor
364 2) Block Header
365 - 3 bytes, starting with a 2-bits descriptor
366 Uncompressed, Compressed, Frame End, unused
367 3) Block
368 See Block Format Description
369 4) Frame End
370 - 3 bytes, compatible with Block Header
371*/
372
373
374/* Frame descriptor
375
376 1 byte, using :
377 bit 0-3 : windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN (see zstd_internal.h)
378 bit 4 : minmatch 4(0) or 3(1)
379 bit 5 : reserved (must be zero)
380 bit 6-7 : Frame content size : unknown, 1 byte, 2 bytes, 8 bytes
381
382 Optional : content size (0, 1, 2 or 8 bytes)
383 0 : unknown
384 1 : 0-255 bytes
385 2 : 256 - 65535+256
386 8 : up to 16 exa
387*/
388
389
Yann Collet59d1f792016-01-23 19:28:41 +0100390/* Block format description
391
392 Block = Literal Section - Sequences Section
393 Prerequisite : size of (compressed) block, maximum size of regenerated data
394
395 1) Literal Section
396
397 1.1) Header : 1-5 bytes
398 flags: 2 bits
399 00 compressed by Huff0
400 01 unused
401 10 is Raw (uncompressed)
402 11 is Rle
403 Note : using 01 => Huff0 with precomputed table ?
404 Note : delta map ? => compressed ?
405
406 1.1.1) Huff0-compressed literal block : 3-5 bytes
Yann Colletafe07092016-01-25 04:10:46 +0100407 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
Yann Collet59d1f792016-01-23 19:28:41 +0100408 srcSize < 1 KB => 3 bytes (2-2-10-10)
Yann Colleta1249dc2016-01-25 04:22:03 +0100409 srcSize < 16KB => 4 bytes (2-2-14-14)
Yann Collet59d1f792016-01-23 19:28:41 +0100410 else => 5 bytes (2-2-18-18)
411 big endian convention
412
413 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
414 size : 5 bits: (IS_RAW<<6) + (0<<4) + size
415 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
416 size&255
417 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
418 size>>8&255
419 size&255
420
421 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
422 size : 5 bits: (IS_RLE<<6) + (0<<4) + size
423 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
424 size&255
425 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
426 size>>8&255
427 size&255
428
Yann Colleta1249dc2016-01-25 04:22:03 +0100429 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
430 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
431 srcSize < 1 KB => 3 bytes (2-2-10-10)
432 srcSize < 16KB => 4 bytes (2-2-14-14)
433 else => 5 bytes (2-2-18-18)
434 big endian convention
435
436 1- CTable available (stored into workspace ?)
Yann Colletb923f652016-01-26 03:14:20 +0100437 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
Yann Colleta1249dc2016-01-25 04:22:03 +0100438
Yann Collet59d1f792016-01-23 19:28:41 +0100439
440 1.2) Literal block content
441
442 1.2.1) Huff0 block, using sizes from header
443 See Huff0 format
444
Yann Colletfb810d62016-01-28 00:18:06 +0100445 1.2.2) Huff0 block, using prepared table
Yann Collet59d1f792016-01-23 19:28:41 +0100446
Yann Colletfb810d62016-01-28 00:18:06 +0100447 1.2.3) Raw content
Yann Collet59d1f792016-01-23 19:28:41 +0100448
Yann Colletfb810d62016-01-28 00:18:06 +0100449 1.2.4) single byte
Yann Collet59d1f792016-01-23 19:28:41 +0100450
451
452 2) Sequences section
Yann Colletfb810d62016-01-28 00:18:06 +0100453
454 - Nb Sequences : 2 bytes, little endian
455 - Control Token : 1 byte (see below)
456 - Dumps Length : 1 or 2 bytes (depending on control token)
457 - Dumps : as stated by dumps length
458 - Literal Lengths FSE table (as needed depending on encoding method)
459 - Offset Codes FSE table (as needed depending on encoding method)
460 - Match Lengths FSE table (as needed depending on encoding method)
461
462 2.1) Control Token
463 8 bits, divided as :
464 0-1 : dumpsLength
465 2-3 : MatchLength, FSE encoding method
466 4-5 : Offset Codes, FSE encoding method
467 6-7 : Literal Lengths, FSE encoding method
468
469 FSE encoding method :
470 FSE_ENCODING_RAW : uncompressed; no header
471 FSE_ENCODING_RLE : single repeated value; header 1 byte
472 FSE_ENCODING_STATIC : use prepared table; no header
473 FSE_ENCODING_DYNAMIC : read NCount
Yann Collet59d1f792016-01-23 19:28:41 +0100474*/
Yann Collet14983e72015-11-11 21:38:21 +0100475
Yann Colletd1b26842016-03-15 01:24:33 +0100476size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100477{
478 BYTE* const ostart = (BYTE* const)dst;
479
Yann Colletd1b26842016-03-15 01:24:33 +0100480 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100481 memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
482
483 /* Build header */
484 ostart[0] = (BYTE)(srcSize>>16);
485 ostart[1] = (BYTE)(srcSize>>8);
486 ostart[2] = (BYTE) srcSize;
487 ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
488
489 return ZSTD_blockHeaderSize+srcSize;
490}
491
492
Yann Colletd1b26842016-03-15 01:24:33 +0100493static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100494{
495 BYTE* const ostart = (BYTE* const)dst;
Yann Colleta910dc82016-03-18 12:37:45 +0100496 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100497
Yann Colletd1b26842016-03-15 01:24:33 +0100498 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100499
Yann Collet59d1f792016-01-23 19:28:41 +0100500 switch(flSize)
501 {
502 case 1: /* 2 - 1 - 5 */
503 ostart[0] = (BYTE)((IS_RAW<<6) + (0<<5) + srcSize);
504 break;
505 case 2: /* 2 - 2 - 12 */
506 ostart[0] = (BYTE)((IS_RAW<<6) + (2<<4) + (srcSize >> 8));
507 ostart[1] = (BYTE)srcSize;
508 break;
509 default: /*note : should not be necessary : flSize is within {1,2,3} */
510 case 3: /* 2 - 2 - 20 */
511 ostart[0] = (BYTE)((IS_RAW<<6) + (3<<4) + (srcSize >> 16));
512 ostart[1] = (BYTE)(srcSize>>8);
513 ostart[2] = (BYTE)srcSize;
514 break;
515 }
516
517 memcpy(ostart + flSize, src, srcSize);
518 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100519}
520
Yann Colletd1b26842016-03-15 01:24:33 +0100521static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100522{
523 BYTE* const ostart = (BYTE* const)dst;
Yann Colleta910dc82016-03-18 12:37:45 +0100524 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100525
Yann Colletd1b26842016-03-15 01:24:33 +0100526 (void)dstCapacity; /* dstCapacity guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100527
528 switch(flSize)
529 {
530 case 1: /* 2 - 1 - 5 */
531 ostart[0] = (BYTE)((IS_RLE<<6) + (0<<5) + srcSize);
532 break;
533 case 2: /* 2 - 2 - 12 */
534 ostart[0] = (BYTE)((IS_RLE<<6) + (2<<4) + (srcSize >> 8));
535 ostart[1] = (BYTE)srcSize;
536 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100537 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100538 case 3: /* 2 - 2 - 20 */
539 ostart[0] = (BYTE)((IS_RLE<<6) + (3<<4) + (srcSize >> 16));
540 ostart[1] = (BYTE)(srcSize>>8);
541 ostart[2] = (BYTE)srcSize;
542 break;
543 }
544
545 ostart[flSize] = *(const BYTE*)src;
546 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100547}
548
Yann Collet59d1f792016-01-23 19:28:41 +0100549
Yann Colleta5c2c082016-03-20 01:09:18 +0100550static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100551
Yann Colletb923f652016-01-26 03:14:20 +0100552static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100553 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100554 const void* src, size_t srcSize)
555{
Yann Colleta910dc82016-03-18 12:37:45 +0100556 size_t const minGain = ZSTD_minGain(srcSize);
557 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet14983e72015-11-11 21:38:21 +0100558 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100559 U32 singleStream = srcSize < 256;
Yann Colletb923f652016-01-26 03:14:20 +0100560 U32 hType = IS_HUF;
Yann Colleta910dc82016-03-18 12:37:45 +0100561 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100562
Yann Collet14983e72015-11-11 21:38:21 +0100563
Yann Colleta5c2c082016-03-20 01:09:18 +0100564 /* small ? don't even attempt compression (speed opt) */
565# define LITERAL_NOENTROPY 63
566 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
567 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
568 }
569
570 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Colletfb810d62016-01-28 00:18:06 +0100571 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletb923f652016-01-26 03:14:20 +0100572 hType = IS_PCH;
573 singleStream = 1;
Yann Colleta910dc82016-03-18 12:37:45 +0100574 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100575 } else {
Yann Colleta910dc82016-03-18 12:37:45 +0100576 cLitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12)
Yann Colletd1b26842016-03-15 01:24:33 +0100577 : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12);
Yann Colletb923f652016-01-26 03:14:20 +0100578 }
Yann Collet14983e72015-11-11 21:38:21 +0100579
Yann Colleta910dc82016-03-18 12:37:45 +0100580 if ((cLitSize==0) || (cLitSize >= srcSize - minGain))
581 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
582 if (cLitSize==1)
583 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100584
585 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100586 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100587 {
Yann Collet59d1f792016-01-23 19:28:41 +0100588 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletb923f652016-01-26 03:14:20 +0100589 ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6));
Yann Colleta910dc82016-03-18 12:37:45 +0100590 ostart[1] = (BYTE)((srcSize<<2) + (cLitSize>>8));
591 ostart[2] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100592 break;
593 case 4: /* 2 - 2 - 14 - 14 */
Yann Colletb923f652016-01-26 03:14:20 +0100594 ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100595 ostart[1] = (BYTE)(srcSize>> 2);
Yann Colleta910dc82016-03-18 12:37:45 +0100596 ostart[2] = (BYTE)((srcSize<<6) + (cLitSize>>8));
597 ostart[3] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100598 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100599 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100600 case 5: /* 2 - 2 - 18 - 18 */
Yann Colletb923f652016-01-26 03:14:20 +0100601 ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100602 ostart[1] = (BYTE)(srcSize>>6);
Yann Colleta910dc82016-03-18 12:37:45 +0100603 ostart[2] = (BYTE)((srcSize<<2) + (cLitSize>>16));
604 ostart[3] = (BYTE)(cLitSize>>8);
605 ostart[4] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100606 break;
Yann Collet14983e72015-11-11 21:38:21 +0100607 }
Yann Colleta910dc82016-03-18 12:37:45 +0100608 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100609}
610
611
Yann Colletb44be742016-03-26 20:52:14 +0100612void ZSTD_seqToCodes(const seqStore_t* seqStorePtr, size_t const nbSeq)
613{
614 /* LL codes */
615 { static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
616 8, 9, 10, 11, 12, 13, 14, 15,
617 16, 16, 17, 17, 18, 18, 19, 19,
618 20, 20, 20, 20, 21, 21, 21, 21,
619 22, 22, 22, 22, 22, 22, 22, 22,
620 23, 23, 23, 23, 23, 23, 23, 23,
621 24, 24, 24, 24, 24, 24, 24, 24,
622 24, 24, 24, 24, 24, 24, 24, 24 };
623 const BYTE LL_deltaCode = 19;
Yann Collet5d393572016-04-07 17:19:00 +0200624 const U16* const llTable = seqStorePtr->litLengthStart;
Yann Colletb44be742016-03-26 20:52:14 +0100625 BYTE* const llCodeTable = seqStorePtr->llCodeStart;
626 size_t u;
627 for (u=0; u<nbSeq; u++) {
Yann Collet5d393572016-04-07 17:19:00 +0200628 U32 const ll = llTable[u];
Yann Colletb44be742016-03-26 20:52:14 +0100629 llCodeTable[u] = (ll>63) ? (BYTE)ZSTD_highbit(ll) + LL_deltaCode : LL_Code[ll];
Yann Collet5d393572016-04-07 17:19:00 +0200630 }
631 if (seqStorePtr->longLengthID==1)
632 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
633 }
Yann Colletb44be742016-03-26 20:52:14 +0100634
635 /* Offset codes */
636 { const U32* const offsetTable = seqStorePtr->offsetStart;
637 BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
638 size_t u;
639 for (u=0; u<nbSeq; u++) ofCodeTable[u] = (BYTE)ZSTD_highbit(offsetTable[u]);
640 }
641
642 /* ML codes */
643 { static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
644 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
645 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
646 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
647 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
648 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
649 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
650 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
651 const BYTE ML_deltaCode = 36;
Yann Collet5d393572016-04-07 17:19:00 +0200652 const U16* const mlTable = seqStorePtr->matchLengthStart;
Yann Colletb44be742016-03-26 20:52:14 +0100653 BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
654 size_t u;
655 for (u=0; u<nbSeq; u++) {
Yann Collet5d393572016-04-07 17:19:00 +0200656 U32 const ml = mlTable[u];
Yann Colletb44be742016-03-26 20:52:14 +0100657 mlCodeTable[u] = (ml>127) ? (BYTE)ZSTD_highbit(ml) + ML_deltaCode : ML_Code[ml];
Yann Collet5d393572016-04-07 17:19:00 +0200658 }
659 if (seqStorePtr->longLengthID==2)
660 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
661 }
Yann Colletb44be742016-03-26 20:52:14 +0100662}
663
664
Yann Colletb923f652016-01-26 03:14:20 +0100665size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100666 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100667 size_t srcSize)
668{
Yann Colletb923f652016-01-26 03:14:20 +0100669 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100670 U32 count[MaxSeq+1];
671 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100672 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
673 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
674 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100675 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletb0aec172016-03-21 13:24:16 +0100676 U16* const llTable = seqStorePtr->litLengthStart;
Yann Colletfadda6c2016-03-22 12:14:26 +0100677 U16* const mlTable = seqStorePtr->matchLengthStart;
Yann Collet14983e72015-11-11 21:38:21 +0100678 const U32* const offsetTable = seqStorePtr->offsetStart;
Yann Colletd64f4352016-03-21 00:07:42 +0100679 const U32* const offsetTableEnd = seqStorePtr->offset;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100680 BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
Yann Collet597847a2016-03-20 19:14:22 +0100681 BYTE* const llCodeTable = seqStorePtr->llCodeStart;
Yann Colletfadda6c2016-03-22 12:14:26 +0100682 BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
Yann Collet5054ee02015-11-23 13:34:21 +0100683 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100684 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100685 BYTE* op = ostart;
Yann Colletd64f4352016-03-21 00:07:42 +0100686 size_t const nbSeq = offsetTableEnd - offsetTable;
Yann Collet14983e72015-11-11 21:38:21 +0100687 BYTE* seqHead;
688
Yann Collet14983e72015-11-11 21:38:21 +0100689 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100690 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100691 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100692 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100693 if (ZSTD_isError(cSize)) return cSize;
694 op += cSize;
695 }
696
697 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100698 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100699 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
700 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
701 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100702 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100703
Yann Colletbe391432016-03-22 23:19:28 +0100704 /* seqHead : flags for FSE encoding type */
705 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100706
Yann Colletfb810d62016-01-28 00:18:06 +0100707#define MIN_SEQ_FOR_DYNAMIC_FSE 64
708#define MAX_SEQ_FOR_STATIC_FSE 1000
709
Yann Colletb44be742016-03-26 20:52:14 +0100710 /* convert length/distances into codes */
711 ZSTD_seqToCodes(seqStorePtr, nbSeq);
Yann Collet597847a2016-03-20 19:14:22 +0100712
Yann Collet14983e72015-11-11 21:38:21 +0100713 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100714 { U32 max = MaxLL;
715 size_t const mostFrequent = FSE_countFast(count, &max, llCodeTable, nbSeq);
716 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
717 *op++ = llCodeTable[0];
718 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
719 LLtype = FSE_ENCODING_RLE;
720 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
721 LLtype = FSE_ENCODING_STATIC;
722 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
723 FSE_buildCTable(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog);
724 LLtype = FSE_ENCODING_RAW;
725 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100726 size_t nbSeq_1 = nbSeq;
727 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
728 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
729 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100730 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
731 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
732 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100733 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
734 LLtype = FSE_ENCODING_DYNAMIC;
735 } }
Yann Collet14983e72015-11-11 21:38:21 +0100736
Yann Colletb44be742016-03-26 20:52:14 +0100737 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100738 { U32 max = MaxOff;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100739 size_t const mostFrequent = FSE_countFast(count, &max, ofCodeTable, nbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100740 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100741 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100742 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
743 Offtype = FSE_ENCODING_RLE;
744 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
745 Offtype = FSE_ENCODING_STATIC;
Yann Collet48537162016-04-07 15:24:29 +0200746 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
747 FSE_buildCTable(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog);
Yann Colletfadda6c2016-03-22 12:14:26 +0100748 Offtype = FSE_ENCODING_RAW;
749 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100750 size_t nbSeq_1 = nbSeq;
751 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100752 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100753 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100754 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
755 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
756 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100757 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
758 Offtype = FSE_ENCODING_DYNAMIC;
759 } }
760
Yann Collet14983e72015-11-11 21:38:21 +0100761 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100762 { U32 max = MaxML;
763 size_t const mostFrequent = FSE_countFast(count, &max, mlCodeTable, nbSeq);
764 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100765 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100766 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
767 MLtype = FSE_ENCODING_RLE;
768 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
769 MLtype = FSE_ENCODING_STATIC;
770 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
771 FSE_buildCTable(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog);
772 MLtype = FSE_ENCODING_RAW;
773 } else {
774 size_t nbSeq_1 = nbSeq;
775 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
776 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
777 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
778 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
779 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
780 op += NCountSize; }
781 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
782 MLtype = FSE_ENCODING_DYNAMIC;
783 } }
Yann Collet14983e72015-11-11 21:38:21 +0100784
Yann Colletbe391432016-03-22 23:19:28 +0100785 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100786 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100787
788 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100789 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100790 FSE_CState_t stateMatchLength;
791 FSE_CState_t stateOffsetBits;
792 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100793
Yann Colleta910dc82016-03-18 12:37:45 +0100794 { size_t const errorCode = BIT_initCStream(&blockStream, op, oend-op);
Yann Collet597847a2016-03-20 19:14:22 +0100795 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100796
Yann Collet597847a2016-03-20 19:14:22 +0100797 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100798 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100799 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100800 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colletb0aec172016-03-21 13:24:16 +0100801 BIT_addBits(&blockStream, llTable[nbSeq-1], LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100802 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Collet25125972016-03-23 14:00:09 +0100803 BIT_addBits(&blockStream, mlTable[nbSeq-1], ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100804 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Collet646693e2016-03-24 02:31:27 +0100805 BIT_addBits(&blockStream, offsetTable[nbSeq-1], ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100806 BIT_flushBits(&blockStream);
807
Yann Colletfadda6c2016-03-22 12:14:26 +0100808 { size_t n;
809 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Colletb9151402016-03-26 17:18:11 +0100810 const BYTE ofCode = ofCodeTable[n];
Yann Collet7cbe79a2016-03-23 22:31:57 +0100811 const BYTE mlCode = mlCodeTable[n];
812 const BYTE llCode = llCodeTable[n];
813 const U32 llBits = LL_bits[llCode];
814 const U32 mlBits = ML_bits[mlCode];
Yann Colletb9151402016-03-26 17:18:11 +0100815 const U32 ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100816 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100817 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
818 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
819 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
820 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200821 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100822 BIT_flushBits(&blockStream); /* (7)*/
Yann Collet7cbe79a2016-03-23 22:31:57 +0100823 BIT_addBits(&blockStream, llTable[n], llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100824 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100825 BIT_addBits(&blockStream, mlTable[n], mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100826 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
827 BIT_addBits(&blockStream, offsetTable[n], ofBits); /* 31 */
828 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100829 } }
Yann Collet14983e72015-11-11 21:38:21 +0100830
831 FSE_flushCState(&blockStream, &stateMatchLength);
832 FSE_flushCState(&blockStream, &stateOffsetBits);
833 FSE_flushCState(&blockStream, &stateLitLength);
834
Yann Colletb9151402016-03-26 17:18:11 +0100835 { size_t const streamSize = BIT_closeCStream(&blockStream);
836 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
837 op += streamSize;
838 } }
Yann Collet14983e72015-11-11 21:38:21 +0100839
840 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100841_check_compressibility:
Yann Colletfadda6c2016-03-22 12:14:26 +0100842 { size_t const minGain = ZSTD_minGain(srcSize);
843 size_t const maxCSize = srcSize - minGain;
844 if ((size_t)(op-ostart) >= maxCSize) return 0; }
Yann Collet14983e72015-11-11 21:38:21 +0100845
Yann Collet5054ee02015-11-23 13:34:21 +0100846 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100847}
848
849
Yann Collet95cd0c22016-03-08 18:24:21 +0100850/*! ZSTD_storeSeq() :
851 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
852 `offsetCode` : distance to match, or 0 == repCode.
853 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100854*/
855MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode)
856{
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100857#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100858 static const BYTE* g_start = NULL;
Yann Colletb0aec172016-03-21 13:24:16 +0100859 const U32 pos = (U32)(literals - g_start);
Yann Collet14983e72015-11-11 21:38:21 +0100860 if (g_start==NULL) g_start = literals;
Yann Collet582933f2016-04-11 16:25:56 +0200861 if ((pos > 5810300) && (pos < 5810500))
Yann Colletb9151402016-03-26 17:18:11 +0100862 printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
Yann Collet433a5cc2016-03-25 11:43:48 +0100863 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +0100864#endif
inikep5cc4efd2016-03-25 10:52:25 +0100865 ZSTD_statsUpdatePrices(&seqStorePtr->stats, litLength, literals, offsetCode, matchCode);
Yann Collet14983e72015-11-11 21:38:21 +0100866
867 /* copy Literals */
868 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
869 seqStorePtr->lit += litLength;
870
871 /* literal Length */
Yann Collet5d393572016-04-07 17:19:00 +0200872 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->litLength - seqStorePtr->litLengthStart); }
873 *seqStorePtr->litLength++ = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100874
875 /* match offset */
Yann Collet646693e2016-03-24 02:31:27 +0100876 *(seqStorePtr->offset++) = (U32)offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100877
878 /* match Length */
Yann Collet5d393572016-04-07 17:19:00 +0200879 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->matchLength - seqStorePtr->matchLengthStart); }
880 *seqStorePtr->matchLength++ = (U16)matchCode;
Yann Collet14983e72015-11-11 21:38:21 +0100881}
882
883
Yann Collet7d360282016-02-12 00:07:30 +0100884/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100885* Match length counter
886***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100887static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100888{
Yann Collet863ec402016-01-28 17:56:33 +0100889 if (MEM_isLittleEndian()) {
890 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100891# if defined(_MSC_VER) && defined(_WIN64)
892 unsigned long r = 0;
893 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100894 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100895# elif defined(__GNUC__) && (__GNUC__ >= 3)
896 return (__builtin_ctzll((U64)val) >> 3);
897# else
898 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 };
899 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
900# endif
Yann Collet863ec402016-01-28 17:56:33 +0100901 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100902# if defined(_MSC_VER)
903 unsigned long r=0;
904 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100905 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100906# elif defined(__GNUC__) && (__GNUC__ >= 3)
907 return (__builtin_ctz((U32)val) >> 3);
908# else
909 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 };
910 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
911# endif
912 }
Yann Collet863ec402016-01-28 17:56:33 +0100913 } else { /* Big Endian CPU */
914 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100915# if defined(_MSC_VER) && defined(_WIN64)
916 unsigned long r = 0;
917 _BitScanReverse64( &r, val );
918 return (unsigned)(r>>3);
919# elif defined(__GNUC__) && (__GNUC__ >= 3)
920 return (__builtin_clzll(val) >> 3);
921# else
922 unsigned r;
923 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
924 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
925 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
926 r += (!val);
927 return r;
928# endif
Yann Collet863ec402016-01-28 17:56:33 +0100929 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100930# if defined(_MSC_VER)
931 unsigned long r = 0;
932 _BitScanReverse( &r, (unsigned long)val );
933 return (unsigned)(r>>3);
934# elif defined(__GNUC__) && (__GNUC__ >= 3)
935 return (__builtin_clz((U32)val) >> 3);
936# else
937 unsigned r;
938 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
939 r += (!val);
940 return r;
941# endif
Yann Collet863ec402016-01-28 17:56:33 +0100942 } }
Yann Collet14983e72015-11-11 21:38:21 +0100943}
944
945
Yann Collet5054ee02015-11-23 13:34:21 +0100946static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100947{
948 const BYTE* const pStart = pIn;
949
Yann Colletfb810d62016-01-28 00:18:06 +0100950 while ((pIn<pInLimit-(sizeof(size_t)-1))) {
Yann Collet7d360282016-02-12 00:07:30 +0100951 size_t diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100952 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
953 pIn += ZSTD_NbCommonBytes(diff);
954 return (size_t)(pIn - pStart);
955 }
Yann Collet14983e72015-11-11 21:38:21 +0100956 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
957 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
958 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
959 return (size_t)(pIn - pStart);
960}
961
Yann Collet04b12d82016-02-11 06:23:24 +0100962/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100963* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100964* convention : on reaching mEnd, match count continue starting from iStart
965*/
966static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
967{
968 size_t matchLength;
969 const BYTE* vEnd = ip + (mEnd - match);
970 if (vEnd > iEnd) vEnd = iEnd;
971 matchLength = ZSTD_count(ip, match, vEnd);
972 if (match + matchLength == mEnd)
973 matchLength += ZSTD_count(ip+matchLength, iStart, iEnd);
974 return matchLength;
975}
976
Yann Collet14983e72015-11-11 21:38:21 +0100977
Yann Collet863ec402016-01-28 17:56:33 +0100978/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100979* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100980***************************************/
inikepcc52a972016-02-19 10:09:35 +0100981static const U32 prime3bytes = 506832829U;
982static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
inikepe2446b02016-03-07 10:07:08 +0100983static size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); }
inikepcc52a972016-02-19 10:09:35 +0100984
Yann Collet4b100f42015-10-30 15:49:48 +0100985static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100986static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100987static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100988
Yann Collet4b100f42015-10-30 15:49:48 +0100989static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100990static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100991static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100992
993static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100994static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100995static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100996
Yann Collet14983e72015-11-11 21:38:21 +0100997static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100998static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100999static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001000
Yann Collet5be2dd22015-11-11 13:43:58 +01001001static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001002{
1003 switch(mls)
1004 {
1005 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001006 case 4: return ZSTD_hash4Ptr(p, hBits);
1007 case 5: return ZSTD_hash5Ptr(p, hBits);
1008 case 6: return ZSTD_hash6Ptr(p, hBits);
1009 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001010 }
1011}
Yann Collet2acb5d32015-10-29 16:49:43 +01001012
Yann Collet863ec402016-01-28 17:56:33 +01001013
Yann Collet2ce49232016-02-02 14:36:49 +01001014/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001015* Fast Scan
1016***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001017static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1018{
1019 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001020 const U32 hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001021 const BYTE* const base = zc->base;
1022 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet2ce49232016-02-02 14:36:49 +01001023 const BYTE* const iend = ((const BYTE*)end) - 8;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001024 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001025
Yann Colletfb810d62016-01-28 00:18:06 +01001026 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001027 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001028 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001029 }
1030}
1031
1032
Yann Collet1f44b3f2015-11-05 17:32:18 +01001033FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001034void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc,
Yann Collet89db5e02015-11-13 11:27:46 +01001035 const void* src, size_t srcSize,
1036 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001037{
Yann Collet417890c2015-12-04 17:16:37 +01001038 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001039 const U32 hBits = zc->params.cParams.hashLog;
Yann Colletc3652152015-11-24 14:06:07 +01001040 seqStore_t* seqStorePtr = &(zc->seqStore);
1041 const BYTE* const base = zc->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001042 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001043 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001044 const BYTE* anchor = istart;
Yann Colletd94efbf2015-12-29 14:29:08 +01001045 const U32 lowIndex = zc->dictLimit;
1046 const BYTE* const lowest = base + lowIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001047 const BYTE* const iend = istart + srcSize;
1048 const BYTE* const ilimit = iend - 8;
Yann Collet89db5e02015-11-13 11:27:46 +01001049 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001050
Yann Collet1f44b3f2015-11-05 17:32:18 +01001051 /* init */
Yann Collet743402c2015-11-20 12:03:53 +01001052 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001053 if (ip < lowest+REPCODE_STARTVALUE) ip = lowest+REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001054
1055 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001056 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Collet5054ee02015-11-23 13:34:21 +01001057 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001058 size_t offset;
Yann Collet5be2dd22015-11-11 13:43:58 +01001059 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Colletd94efbf2015-12-29 14:29:08 +01001060 const U32 matchIndex = hashTable[h];
1061 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001062 const U32 current = (U32)(ip-base);
1063 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001064
Yann Colletfb810d62016-01-28 00:18:06 +01001065 if (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)) { /* note : by construction, offset_1 <= current */
inikep7bc19b62016-04-06 09:46:01 +02001066 mlCode = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
Yann Collet402fdcf2015-11-20 12:46:08 +01001067 ip++;
inikep7bc19b62016-04-06 09:46:01 +02001068 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mlCode-MINMATCH);
inikep59453082016-03-16 15:35:14 +01001069 } else {
Yann Colletd94efbf2015-12-29 14:29:08 +01001070 if ( (matchIndex <= lowIndex) ||
Yann Colletfb810d62016-01-28 00:18:06 +01001071 (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001072 ip += ((ip-anchor) >> g_searchStrength) + 1;
1073 continue;
1074 }
inikep7bc19b62016-04-06 09:46:01 +02001075 mlCode = ZSTD_count(ip+EQUAL_READ32, match+EQUAL_READ32, iend) + EQUAL_READ32;
Yann Collet402fdcf2015-11-20 12:46:08 +01001076 offset = ip-match;
Yann Collet5054ee02015-11-23 13:34:21 +01001077 while ((ip>anchor) && (match>lowest) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001078 offset_2 = offset_1;
1079 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001080
inikep7bc19b62016-04-06 09:46:01 +02001081 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mlCode-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001082 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001083
Yann Collet402fdcf2015-11-20 12:46:08 +01001084 /* match found */
inikep7bc19b62016-04-06 09:46:01 +02001085 ip += mlCode;
Yann Collet402fdcf2015-11-20 12:46:08 +01001086 anchor = ip;
1087
Yann Colletfb810d62016-01-28 00:18:06 +01001088 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001089 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001090 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 +01001091 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1092 /* check immediate repcode */
1093 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001094 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001095 /* store sequence */
inikep7bc19b62016-04-06 09:46:01 +02001096 size_t const rlCode = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
Yann Collet70e45772016-03-19 18:08:32 +01001097 { size_t const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001098 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
inikep7bc19b62016-04-06 09:46:01 +02001099 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rlCode-MINMATCH);
1100 ip += rlCode;
Yann Collet402fdcf2015-11-20 12:46:08 +01001101 anchor = ip;
1102 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001103 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001104
Yann Collet70e45772016-03-19 18:08:32 +01001105 /* Last Literals */
1106 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001107 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1108 seqStorePtr->lit += lastLLSize;
1109 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001110}
1111
1112
Yann Collet82260dd2016-02-11 07:14:25 +01001113static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001114 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001115{
Yann Collet3b719252016-03-30 19:48:05 +02001116 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001117 switch(mls)
1118 {
1119 default:
1120 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001121 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001122 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001123 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001124 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001125 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001126 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001127 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001128 }
1129}
Yann Colletf3eca252015-10-22 15:31:46 +01001130
Yann Colletf3eca252015-10-22 15:31:46 +01001131
Yann Collet82260dd2016-02-11 07:14:25 +01001132static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001133 const void* src, size_t srcSize,
1134 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001135{
1136 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001137 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001138 seqStore_t* seqStorePtr = &(ctx->seqStore);
1139 const BYTE* const base = ctx->base;
1140 const BYTE* const dictBase = ctx->dictBase;
1141 const BYTE* const istart = (const BYTE*)src;
1142 const BYTE* ip = istart;
1143 const BYTE* anchor = istart;
1144 const U32 lowLimit = ctx->lowLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001145 const BYTE* const dictStart = dictBase + lowLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001146 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001147 const BYTE* const lowPrefixPtr = base + dictLimit;
1148 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001149 const BYTE* const iend = istart + srcSize;
1150 const BYTE* const ilimit = iend - 8;
1151
Yann Collet138e89c2015-11-17 14:26:54 +01001152 U32 offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001153
1154
1155 /* init */
1156 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001157 /* skip first position to avoid read overflow during repcode match check */
Yann Colletfb810d62016-01-28 00:18:06 +01001158 hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0);
Yann Collet61e16ce2016-01-31 02:04:15 +01001159 ip += REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001160
1161 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001162 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001163 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001164 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001165 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001166 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001167 const U32 current = (U32)(ip-base);
Yann Collet743402c2015-11-20 12:03:53 +01001168 const U32 repIndex = current + 1 - offset_1;
Yann Collet402fdcf2015-11-20 12:46:08 +01001169 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001170 const BYTE* repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001171 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001172 U32 offset;
Yann Collet89db5e02015-11-13 11:27:46 +01001173 hashTable[h] = current; /* update hash table */
1174
Yann Collet52447382016-03-20 16:00:00 +01001175 if ( ((repIndex >= dictLimit) || (repIndex <= dictLimit-4))
Yann Colletfb810d62016-01-28 00:18:06 +01001176 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001177 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001178 mlCode = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001179 ip++;
inikep7bc19b62016-04-06 09:46:01 +02001180 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mlCode-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001181 } else {
Yann Collet402fdcf2015-11-20 12:46:08 +01001182 if ( (matchIndex < lowLimit) ||
Yann Collet52447382016-03-20 16:00:00 +01001183 (MEM_read32(match) != MEM_read32(ip)) ) {
1184 ip += ((ip-anchor) >> g_searchStrength) + 1;
1185 continue;
1186 }
1187 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001188 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
inikep7bc19b62016-04-06 09:46:01 +02001189 mlCode = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Colletfb810d62016-01-28 00:18:06 +01001190 while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001191 offset = current - matchIndex;
1192 offset_2 = offset_1;
1193 offset_1 = offset;
inikep7bc19b62016-04-06 09:46:01 +02001194 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mlCode-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001195 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001196
Yann Collet5054ee02015-11-23 13:34:21 +01001197 /* found a match : store it */
inikep7bc19b62016-04-06 09:46:01 +02001198 ip += mlCode;
Yann Collet402fdcf2015-11-20 12:46:08 +01001199 anchor = ip;
1200
Yann Colletfb810d62016-01-28 00:18:06 +01001201 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001202 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001203 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001204 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1205 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001206 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001207 U32 const current2 = (U32)(ip-base);
1208 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001209 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet743402c2015-11-20 12:03:53 +01001210 if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001211 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001212 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001213 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001214 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001215 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001216 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001217 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001218 anchor = ip;
1219 continue;
1220 }
Yann Collet743402c2015-11-20 12:03:53 +01001221 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001222 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001223
1224 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001225 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001226 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1227 seqStorePtr->lit += lastLLSize;
1228 }
Yann Collet89db5e02015-11-13 11:27:46 +01001229}
1230
1231
Yann Collet82260dd2016-02-11 07:14:25 +01001232static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001233 const void* src, size_t srcSize)
1234{
Yann Collet3b719252016-03-30 19:48:05 +02001235 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001236 switch(mls)
1237 {
1238 default:
1239 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001240 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001241 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001242 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001243 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001244 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001245 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001246 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001247 }
1248}
1249
1250
inikep75716852016-04-06 12:34:42 +02001251
inikep2db1eb72016-04-06 17:14:19 +02001252
Yann Collet04b12d82016-02-11 06:23:24 +01001253/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001254* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001255***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001256/** ZSTD_insertBt1() : add one or multiple positions to tree.
1257* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001258* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001259static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1260 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001261{
1262 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001263 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet5be2dd22015-11-11 13:43:58 +01001264 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet8a57b922016-04-04 13:49:18 +02001265 U32* const bt = zc->chainTable;
1266 const U32 btLog = zc->params.cParams.chainLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001267 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;
Yann Collet1358f912016-01-01 07:29:39 +01001271 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;
Yann Colletf48e35c2015-11-07 01:13:31 +01001275 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001276 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001277 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001278 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001279 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001280 U32 dummy32; /* to be nullified at the end */
Yann Collet03526e12015-11-23 15:29:15 +01001281 const U32 windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001282 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001283 size_t bestLength = 8;
Yann Collet7beaa052016-01-21 11:57:45 +01001284 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1285 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1286 predictedSmall += (predictedSmall>0);
1287 predictedLarge += (predictedLarge>0);
Yann Colletf48e35c2015-11-07 01:13:31 +01001288
Yann Collet6c3e2e72015-12-11 10:44:07 +01001289 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001290
Yann Colletfb810d62016-01-28 00:18:06 +01001291 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001292 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001293 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet793c6492016-04-09 20:32:00 +02001294#if 0 /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001295 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001296 if (matchIndex == predictedSmall) {
1297 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001298 *smallerPtr = matchIndex;
1299 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1300 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1301 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001302 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001303 continue;
1304 }
Yann Colletfb810d62016-01-28 00:18:06 +01001305 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001306 *largerPtr = matchIndex;
1307 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1308 largerPtr = nextPtr;
1309 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001310 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001311 continue;
1312 }
Yann Collet04b12d82016-02-11 06:23:24 +01001313#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001314 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001315 match = base + matchIndex;
1316 if (match[matchLength] == ip[matchLength])
1317 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001318 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001319 match = dictBase + matchIndex;
1320 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1321 if (matchIndex+matchLength >= dictLimit)
1322 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1323 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001324
Yann Colletb8a6f682016-02-15 17:06:29 +01001325 if (matchLength > bestLength) {
1326 bestLength = matchLength;
1327 if (matchLength > matchEndIdx - matchIndex)
1328 matchEndIdx = matchIndex + (U32)matchLength;
1329 }
Yann Colletee3f4512015-12-29 22:26:09 +01001330
Yann Collet59d70632015-11-04 12:05:27 +01001331 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001332 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001333
Yann Colletfb810d62016-01-28 00:18:06 +01001334 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001335 /* match is smaller than current */
1336 *smallerPtr = matchIndex; /* update smaller idx */
1337 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001338 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001339 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001340 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001341 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001342 /* match is larger than current */
1343 *largerPtr = matchIndex;
1344 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001345 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001346 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001347 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001348 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001349
Yann Collet59d70632015-11-04 12:05:27 +01001350 *smallerPtr = *largerPtr = 0;
Yann Colletb8a6f682016-02-15 17:06:29 +01001351 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384));
1352 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1353 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001354}
1355
1356
Yann Collet82260dd2016-02-11 07:14:25 +01001357static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001358 ZSTD_CCtx* zc,
1359 const BYTE* const ip, const BYTE* const iend,
1360 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001361 U32 nbCompares, const U32 mls,
1362 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001363{
1364 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001365 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet03526e12015-11-23 15:29:15 +01001366 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet8a57b922016-04-04 13:49:18 +02001367 U32* const bt = zc->chainTable;
1368 const U32 btLog = zc->params.cParams.chainLog - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001369 const U32 btMask= (1 << btLog) - 1;
1370 U32 matchIndex = hashTable[h];
1371 size_t commonLengthSmaller=0, commonLengthLarger=0;
1372 const BYTE* const base = zc->base;
1373 const BYTE* const dictBase = zc->dictBase;
1374 const U32 dictLimit = zc->dictLimit;
1375 const BYTE* const dictEnd = dictBase + dictLimit;
1376 const BYTE* const prefixStart = base + dictLimit;
1377 const U32 current = (U32)(ip-base);
1378 const U32 btLow = btMask >= current ? 0 : current - btMask;
1379 const U32 windowLow = zc->lowLimit;
1380 U32* smallerPtr = bt + 2*(current&btMask);
1381 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001382 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001383 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001384 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001385
Yann Collet6c3e2e72015-12-11 10:44:07 +01001386 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001387
Yann Colletfb810d62016-01-28 00:18:06 +01001388 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001389 U32* nextPtr = bt + 2*(matchIndex & btMask);
1390 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1391 const BYTE* match;
1392
Yann Colletfb810d62016-01-28 00:18:06 +01001393 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001394 match = base + matchIndex;
1395 if (match[matchLength] == ip[matchLength])
1396 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001397 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001398 match = dictBase + matchIndex;
1399 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001400 if (matchIndex+matchLength >= dictLimit)
1401 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001402 }
1403
Yann Colletfb810d62016-01-28 00:18:06 +01001404 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001405 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001406 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet03526e12015-11-23 15:29:15 +01001407 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001408 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001409 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1410 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1411 }
1412
Yann Colletfb810d62016-01-28 00:18:06 +01001413 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001414 /* match is smaller than current */
1415 *smallerPtr = matchIndex; /* update smaller idx */
1416 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1417 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1418 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1419 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001420 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001421 /* match is larger than current */
1422 *largerPtr = matchIndex;
1423 commonLengthLarger = matchLength;
1424 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1425 largerPtr = nextPtr;
1426 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001427 } }
Yann Collet03526e12015-11-23 15:29:15 +01001428
1429 *smallerPtr = *largerPtr = 0;
1430
Yann Collet72e84cf2015-12-31 19:08:44 +01001431 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001432 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001433}
1434
Yann Collet2cc12cb2016-01-01 07:47:58 +01001435
Yann Colletb8a6f682016-02-15 17:06:29 +01001436static 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 +01001437{
1438 const BYTE* const base = zc->base;
1439 const U32 target = (U32)(ip - base);
1440 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001441
1442 while(idx < target)
1443 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001444}
1445
Yann Collet52447382016-03-20 16:00:00 +01001446/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001447static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001448 ZSTD_CCtx* zc,
1449 const BYTE* const ip, const BYTE* const iLimit,
1450 size_t* offsetPtr,
1451 const U32 maxNbAttempts, const U32 mls)
1452{
1453 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001454 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001455 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1456}
1457
1458
Yann Collet768c6bc2016-02-10 14:01:49 +01001459static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001460 ZSTD_CCtx* zc, /* Index table will be updated */
1461 const BYTE* ip, const BYTE* const iLimit,
1462 size_t* offsetPtr,
1463 const U32 maxNbAttempts, const U32 matchLengthSearch)
1464{
1465 switch(matchLengthSearch)
1466 {
1467 default :
1468 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1469 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1470 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1471 }
1472}
1473
1474
Yann Colletb8a6f682016-02-15 17:06:29 +01001475static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1476{
1477 const BYTE* const base = zc->base;
1478 const U32 target = (U32)(ip - base);
1479 U32 idx = zc->nextToUpdate;
1480
1481 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1482}
1483
inikep64d7bcb2016-04-07 19:14:09 +02001484
1485
Yann Collet03526e12015-11-23 15:29:15 +01001486/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001487static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001488 ZSTD_CCtx* zc,
1489 const BYTE* const ip, const BYTE* const iLimit,
1490 size_t* offsetPtr,
1491 const U32 maxNbAttempts, const U32 mls)
1492{
Yann Colletee3f4512015-12-29 22:26:09 +01001493 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001494 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001495 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001496}
1497
1498
Yann Collet82260dd2016-02-11 07:14:25 +01001499static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001500 ZSTD_CCtx* zc, /* Index table will be updated */
1501 const BYTE* ip, const BYTE* const iLimit,
1502 size_t* offsetPtr,
1503 const U32 maxNbAttempts, const U32 matchLengthSearch)
1504{
1505 switch(matchLengthSearch)
1506 {
1507 default :
1508 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1509 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1510 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1511 }
1512}
1513
1514
Yann Collet5106a762015-11-05 15:00:24 +01001515
inikep64d7bcb2016-04-07 19:14:09 +02001516/* ***********************
1517* Hash Chain
1518*************************/
1519
1520#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1521
inikepafe1f792016-04-07 19:50:03 +02001522
inikep64d7bcb2016-04-07 19:14:09 +02001523/* Update chains up to ip (excluded)
1524 Assumption : always within prefix (ie. not within extDict) */
1525FORCE_INLINE
1526U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1527{
1528 U32* const hashTable = zc->hashTable;
1529 const U32 hashLog = zc->params.cParams.hashLog;
1530 U32* const chainTable = zc->chainTable;
1531 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1532 const BYTE* const base = zc->base;
1533 const U32 target = (U32)(ip - base);
1534 U32 idx = zc->nextToUpdate;
1535
1536 while(idx < target) {
1537 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1538 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1539 hashTable[h] = idx;
1540 idx++;
1541 }
1542
1543 zc->nextToUpdate = target;
1544 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1545}
1546
1547
1548
1549FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1550size_t ZSTD_HcFindBestMatch_generic (
1551 ZSTD_CCtx* zc, /* Index table will be updated */
1552 const BYTE* const ip, const BYTE* const iLimit,
1553 size_t* offsetPtr,
1554 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1555{
1556 U32* const chainTable = zc->chainTable;
1557 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1558 const U32 chainMask = chainSize-1;
1559 const BYTE* const base = zc->base;
1560 const BYTE* const dictBase = zc->dictBase;
1561 const U32 dictLimit = zc->dictLimit;
1562 const BYTE* const prefixStart = base + dictLimit;
1563 const BYTE* const dictEnd = dictBase + dictLimit;
1564 const U32 lowLimit = zc->lowLimit;
1565 const U32 current = (U32)(ip-base);
1566 const U32 minChain = current > chainSize ? current - chainSize : 0;
1567 int nbAttempts=maxNbAttempts;
1568 size_t ml=EQUAL_READ32-1;
1569
1570 /* HC4 match finder */
1571 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1572
1573 for ( ; (matchIndex>lowLimit) && (nbAttempts) ; nbAttempts--) {
1574 const BYTE* match;
1575 size_t currentMl=0;
1576 if ((!extDict) || matchIndex >= dictLimit) {
1577 match = base + matchIndex;
1578 if (match[ml] == ip[ml]) /* potentially better */
1579 currentMl = ZSTD_count(ip, match, iLimit);
1580 } else {
1581 match = dictBase + matchIndex;
1582 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1583 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1584 }
1585
1586 /* save best solution */
1587 if (currentMl > ml) { ml = currentMl; *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }
1588
1589 if (matchIndex <= minChain) break;
1590 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1591 }
1592
1593 return ml;
1594}
1595
1596
1597FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1598 ZSTD_CCtx* zc,
1599 const BYTE* ip, const BYTE* const iLimit,
1600 size_t* offsetPtr,
1601 const U32 maxNbAttempts, const U32 matchLengthSearch)
1602{
1603 switch(matchLengthSearch)
1604 {
1605 default :
1606 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1607 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1608 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1609 }
1610}
1611
1612
1613FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1614 ZSTD_CCtx* zc,
1615 const BYTE* ip, const BYTE* const iLimit,
1616 size_t* offsetPtr,
1617 const U32 maxNbAttempts, const U32 matchLengthSearch)
1618{
1619 switch(matchLengthSearch)
1620 {
1621 default :
1622 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1623 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1624 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1625 }
1626}
1627
1628/* The optimal parser */
1629#include "zstd_opt.h"
1630
1631
Yann Collet287b7d92015-11-22 13:24:05 +01001632/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001633* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001634*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001635FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001636void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1637 const void* src, size_t srcSize,
1638 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001639{
inikepfaa8d8a2016-04-05 19:01:10 +02001640 seqStore_t* seqStorePtr = &(ctx->seqStore);
1641 const BYTE* const istart = (const BYTE*)src;
1642 const BYTE* ip = istart;
1643 const BYTE* anchor = istart;
1644 const BYTE* const iend = istart + srcSize;
1645 const BYTE* const ilimit = iend - 8;
1646 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001647
Yann Collet793c6492016-04-09 20:32:00 +02001648 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1649 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001650
inikep64d7bcb2016-04-07 19:14:09 +02001651 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1652 size_t* offsetPtr,
1653 U32 maxNbAttempts, U32 matchLengthSearch);
1654 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
1655
inikepfaa8d8a2016-04-05 19:01:10 +02001656 /* init */
1657 U32 rep[ZSTD_REP_INIT];
Yann Colletea63bb72016-04-08 15:25:32 +02001658 { U32 i ; for (i=0; i<ZSTD_REP_INIT; i++) rep[i]=REPCODE_STARTVALUE; }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001659
inikep64d7bcb2016-04-07 19:14:09 +02001660 ctx->nextToUpdate3 = ctx->nextToUpdate;
inikepfaa8d8a2016-04-05 19:01:10 +02001661 ZSTD_resetSeqStore(seqStorePtr);
1662 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001663
inikepfaa8d8a2016-04-05 19:01:10 +02001664 /* Match Loop */
1665 while (ip < ilimit) {
1666 size_t matchLength=0;
1667 size_t offset=0;
1668 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001669
inikepfaa8d8a2016-04-05 19:01:10 +02001670 /* check repCode */
inikep64d7bcb2016-04-07 19:14:09 +02001671 if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep[0])) {
inikepfaa8d8a2016-04-05 19:01:10 +02001672 /* repcode : we take it */
inikep64d7bcb2016-04-07 19:14:09 +02001673 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-rep[0], iend) + EQUAL_READ32;
1674 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001675 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001676
inikepfaa8d8a2016-04-05 19:01:10 +02001677 /* first search (depth 0) */
1678 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001679 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001680 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001681 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001682 }
Yann Collet5106a762015-11-05 15:00:24 +01001683
inikep7bc19b62016-04-06 09:46:01 +02001684 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001685 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1686 continue;
1687 }
1688
inikep64d7bcb2016-04-07 19:14:09 +02001689 /* let's try to find a better solution */
1690 if (depth>=1)
1691 while (ip<ilimit) {
1692 ip ++;
1693 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - rep[0]))) {
1694 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-rep[0], iend) + EQUAL_READ32;
1695 int const gain2 = (int)(mlRep * 3);
1696 int const gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1697 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1698 matchLength = mlRep, offset = 0, start = ip;
1699 }
1700 { size_t offset2=99999999;
1701 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1702 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1703 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
1704 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1705 matchLength = ml2, offset = offset2, start = ip;
1706 continue; /* search a better one */
1707 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001708
inikep64d7bcb2016-04-07 19:14:09 +02001709 /* let's find an even better one */
1710 if ((depth==2) && (ip<ilimit)) {
1711 ip ++;
1712 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - rep[0]))) {
1713 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-rep[0], iend) + EQUAL_READ32;
1714 int const gain2 = (int)(ml2 * 4);
1715 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1716 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1717 matchLength = ml2, offset = 0, start = ip;
1718 }
1719 { size_t offset2=99999999;
1720 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1721 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1722 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
1723 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1724 matchLength = ml2, offset = offset2, start = ip;
1725 continue;
1726 } } }
1727 break; /* nothing found : store previous solution */
1728 }
1729
1730 /* catch up */
1731 if (offset) {
1732 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1733 { start--; matchLength++; }
1734 rep[1] = rep[0]; rep[0] = (U32)(offset - ZSTD_REP_MOVE);
1735 }
1736
inikepfaa8d8a2016-04-05 19:01:10 +02001737 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001738_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001739 { size_t const litLength = start - anchor;
1740 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1741 anchor = ip = start + matchLength;
1742 }
Yann Collet48537162016-04-07 15:24:29 +02001743
inikepfaa8d8a2016-04-05 19:01:10 +02001744 /* check immediate repcode */
1745 while ( (ip <= ilimit)
1746 && (MEM_read32(ip) == MEM_read32(ip - rep[1])) ) {
1747 /* store sequence */
inikep7bc19b62016-04-06 09:46:01 +02001748 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-rep[1], iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001749 offset = rep[1]; rep[1] = rep[0]; rep[0] = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02001750 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1751 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02001752 anchor = ip;
1753 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02001754 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001755
1756 /* Last Literals */
1757 { size_t const lastLLSize = iend - anchor;
1758 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1759 seqStorePtr->lit += lastLLSize;
1760 ZSTD_statsUpdatePrices(&seqStorePtr->stats, lastLLSize, anchor, 0, 0);
Yann Collet5106a762015-11-05 15:00:24 +01001761 }
Yann Collet5106a762015-11-05 15:00:24 +01001762}
1763
Yann Collet5be2dd22015-11-11 13:43:58 +01001764
inikep64d7bcb2016-04-07 19:14:09 +02001765
1766static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1767{
1768 ZSTD_compressBlock_opt_generic(ctx, src, srcSize);
1769}
1770
1771static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1772{
1773 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
1774}
1775
1776static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1777{
1778 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
1779}
1780
1781static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1782{
1783 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
1784}
1785
1786static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1787{
1788 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
1789}
1790
1791
inikepfaa8d8a2016-04-05 19:01:10 +02001792FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001793void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1794 const void* src, size_t srcSize,
1795 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01001796{
inikepfaa8d8a2016-04-05 19:01:10 +02001797 seqStore_t* seqStorePtr = &(ctx->seqStore);
1798 const BYTE* const istart = (const BYTE*)src;
1799 const BYTE* ip = istart;
1800 const BYTE* anchor = istart;
1801 const BYTE* const iend = istart + srcSize;
1802 const BYTE* const ilimit = iend - 8;
1803 const BYTE* const base = ctx->base;
1804 const U32 dictLimit = ctx->dictLimit;
1805 const BYTE* const prefixStart = base + dictLimit;
1806 const BYTE* const dictBase = ctx->dictBase;
1807 const BYTE* const dictEnd = dictBase + dictLimit;
1808 const BYTE* const dictStart = dictBase + ctx->lowLimit;
1809
1810 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
1811 const U32 mls = ctx->params.cParams.searchLength;
1812
inikep64d7bcb2016-04-07 19:14:09 +02001813 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1814 size_t* offsetPtr,
1815 U32 maxNbAttempts, U32 matchLengthSearch);
1816 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
1817
inikepfaa8d8a2016-04-05 19:01:10 +02001818 /* init */
1819 U32 rep[ZSTD_REP_INIT];
Yann Colletea63bb72016-04-08 15:25:32 +02001820 { U32 i; for (i=0; i<ZSTD_REP_INIT; i++) rep[i]=REPCODE_STARTVALUE; }
inikepfaa8d8a2016-04-05 19:01:10 +02001821
inikep64d7bcb2016-04-07 19:14:09 +02001822 ctx->nextToUpdate3 = ctx->nextToUpdate;
inikepfaa8d8a2016-04-05 19:01:10 +02001823 ZSTD_resetSeqStore(seqStorePtr);
1824 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
1825
1826 /* Match Loop */
1827 while (ip < ilimit) {
1828 size_t matchLength=0;
1829 size_t offset=0;
1830 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02001831 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02001832
1833 /* check repCode */
1834 {
inikep64d7bcb2016-04-07 19:14:09 +02001835 const U32 repIndex = (U32)(current+1 - rep[0]);
inikepfaa8d8a2016-04-05 19:01:10 +02001836 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1837 const BYTE* const repMatch = repBase + repIndex;
1838 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02001839 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02001840 /* repcode detected we should take it */
1841 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02001842 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1843 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02001844 } }
1845
1846 /* first search (depth 0) */
1847 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001848 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001849 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001850 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001851 }
1852
inikep7bc19b62016-04-06 09:46:01 +02001853 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001854 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1855 continue;
1856 }
1857
inikep64d7bcb2016-04-07 19:14:09 +02001858 /* let's try to find a better solution */
1859 if (depth>=1)
1860 while (ip<ilimit) {
1861 ip ++;
1862 current++;
1863 /* check repCode */
1864 if (offset) {
1865 const U32 repIndex = (U32)(current - rep[0]);
1866 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1867 const BYTE* const repMatch = repBase + repIndex;
1868 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
1869 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1870 /* repcode detected */
1871 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
1872 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1873 int const gain2 = (int)(repLength * 3);
1874 int const gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1875 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
1876 matchLength = repLength, offset = 0, start = ip;
1877 } }
1878
1879 /* search match, depth 1 */
1880 { size_t offset2=99999999;
1881 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1882 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1883 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
1884 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1885 matchLength = ml2, offset = offset2, start = ip;
1886 continue; /* search a better one */
1887 } }
1888
1889 /* let's find an even better one */
1890 if ((depth==2) && (ip<ilimit)) {
1891 ip ++;
1892 current++;
1893 /* check repCode */
1894 if (offset) {
1895 const U32 repIndex = (U32)(current - rep[0]);
1896 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1897 const BYTE* const repMatch = repBase + repIndex;
1898 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
1899 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1900 /* repcode detected */
1901 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
1902 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1903 int gain2 = (int)(repLength * 4);
1904 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1905 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
1906 matchLength = repLength, offset = 0, start = ip;
1907 } }
1908
1909 /* search match, depth 2 */
1910 { size_t offset2=99999999;
1911 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1912 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1913 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
1914 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1915 matchLength = ml2, offset = offset2, start = ip;
1916 continue;
1917 } } }
1918 break; /* nothing found : store previous solution */
1919 }
1920
inikepfaa8d8a2016-04-05 19:01:10 +02001921 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001922 if (offset) {
inikepfaa8d8a2016-04-05 19:01:10 +02001923 U32 matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
1924 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1925 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02001926 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
inikep5ce00ae2016-04-05 21:03:43 +02001927 rep[1] = rep[0]; rep[0] = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02001928 }
inikepfaa8d8a2016-04-05 19:01:10 +02001929
inikepfaa8d8a2016-04-05 19:01:10 +02001930 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001931_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001932 { size_t const litLength = start - anchor;
1933 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1934 anchor = ip = start + matchLength;
1935 }
1936
1937 /* check immediate repcode */
1938 while (ip <= ilimit) {
1939 const U32 repIndex = (U32)((ip-base) - rep[1]);
1940 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1941 const BYTE* const repMatch = repBase + repIndex;
1942 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
1943 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1944 /* repcode detected we should take it */
1945 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001946 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
inikep5ce00ae2016-04-05 21:03:43 +02001947 offset = rep[1]; rep[1] = rep[0]; rep[0] = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02001948 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1949 ip += matchLength;
1950 anchor = ip;
1951 continue; /* faster when present ... (?) */
1952 }
1953 break;
1954 } }
1955
1956 /* Last Literals */
1957 { size_t const lastLLSize = iend - anchor;
1958 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1959 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01001960 }
1961}
1962
1963
Yann Collet59d1f792016-01-23 19:28:41 +01001964void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01001965{
inikep64d7bcb2016-04-07 19:14:09 +02001966 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01001967}
1968
Yann Collet59d1f792016-01-23 19:28:41 +01001969static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01001970{
Yann Colleta1249dc2016-01-25 04:22:03 +01001971 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01001972}
Yann Collet9a24e592015-11-22 02:53:43 +01001973
Yann Collet59d1f792016-01-23 19:28:41 +01001974static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01001975{
Yann Colleta1249dc2016-01-25 04:22:03 +01001976 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01001977}
1978
Yann Collet59d1f792016-01-23 19:28:41 +01001979static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01001980{
Yann Colleta1249dc2016-01-25 04:22:03 +01001981 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001982}
1983
inikepd3b8d7a2016-02-22 10:06:17 +01001984static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01001985{
inikep5ce00ae2016-04-05 21:03:43 +02001986 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize);
inikepe2bfe242016-01-31 11:25:48 +01001987}
1988
Yann Collet7a231792015-11-21 15:27:35 +01001989
Yann Collet59d1f792016-01-23 19:28:41 +01001990typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01001991
Yann Colletb923f652016-01-26 03:14:20 +01001992static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01001993{
inikepd3b8d7a2016-02-22 10:06:17 +01001994 static const ZSTD_blockCompressor blockCompressor[2][6] = {
inikepf8a339d2016-04-05 23:58:51 +02001995#if 1
inikepd3b8d7a2016-02-22 10:06:17 +01001996 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt },
inikep908fcb32016-04-05 18:16:38 +02001997#else
1998 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict },
1999#endif
inikepd3b8d7a2016-02-22 10:06:17 +01002000 { 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 +01002001 };
2002
2003 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002004}
2005
2006
Yann Colletd1b26842016-03-15 01:24:33 +01002007static size_t ZSTD_compressBlock_internal(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Colletbe2010e2015-10-31 12:57:14 +01002008{
Yann Collet3b719252016-03-30 19:48:05 +02002009 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01002010 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 +01002011 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002012 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002013}
2014
2015
inikep5cc4efd2016-03-25 10:52:25 +01002016
2017
Yann Collet2ce49232016-02-02 14:36:49 +01002018static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +01002019 void* dst, size_t dstCapacity,
Yann Colletf3eca252015-10-22 15:31:46 +01002020 const void* src, size_t srcSize)
2021{
Yann Collet2ce49232016-02-02 14:36:49 +01002022 size_t blockSize = zc->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002023 size_t remaining = srcSize;
2024 const BYTE* ip = (const BYTE*)src;
2025 BYTE* const ostart = (BYTE*)dst;
2026 BYTE* op = ostart;
Yann Collet3b719252016-03-30 19:48:05 +02002027 const U32 maxDist = 1 << zc->params.cParams.windowLog;
inikep5cc4efd2016-03-25 10:52:25 +01002028 ZSTD_stats_t* stats = &zc->seqStore.stats;
2029
2030 ZSTD_statsInit(stats);
Yann Collet9b11b462015-11-01 12:40:22 +01002031
Yann Collet2ce49232016-02-02 14:36:49 +01002032 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01002033 size_t cSize;
inikep5cc4efd2016-03-25 10:52:25 +01002034 ZSTD_statsResetFreqs(stats);
Yann Collet3e358272015-11-04 18:19:39 +01002035
Yann Colletd1b26842016-03-15 01:24:33 +01002036 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01002037 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002038
Yann Collet70e45772016-03-19 18:08:32 +01002039 if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) {
2040 /* enforce maxDist */
2041 U32 const newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist;
Yann Collet7a6343f2016-02-02 16:00:50 +01002042 if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002043 if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002044 }
Yann Collet89db5e02015-11-13 11:27:46 +01002045
Yann Colletd1b26842016-03-15 01:24:33 +01002046 cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
Yann Collet3e358272015-11-04 18:19:39 +01002047 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002048
Yann Collet2ce49232016-02-02 14:36:49 +01002049 if (cSize == 0) { /* block is not compressible */
Yann Colletd1b26842016-03-15 01:24:33 +01002050 cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize);
Yann Collet523b5942016-01-09 02:10:40 +01002051 if (ZSTD_isError(cSize)) return cSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002052 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01002053 op[0] = (BYTE)(cSize>>16);
2054 op[1] = (BYTE)(cSize>>8);
2055 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01002056 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01002057 cSize += 3;
2058 }
2059
2060 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002061 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002062 ip += blockSize;
2063 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002064 }
2065
inikep19bd48f2016-04-04 12:10:00 +02002066 ZSTD_statsPrint(stats, zc->params.cParams.searchLength);
Yann Colletf3eca252015-10-22 15:31:46 +01002067 return op-ostart;
2068}
2069
2070
Yann Colletbf42c8e2016-01-09 01:08:23 +01002071static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002072 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002073 const void* src, size_t srcSize,
2074 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01002075{
Yann Collet2acb5d32015-10-29 16:49:43 +01002076 const BYTE* const ip = (const BYTE*) src;
Yann Colletecd651b2016-01-07 15:35:18 +01002077 size_t hbSize = 0;
2078
Yann Collet887e7da2016-04-11 20:12:27 +02002079 if (zc->stage==0) return ERROR(stage_wrong);
2080 if (frame && (zc->stage==1)) { /* copy saved header */
Yann Colletecd651b2016-01-07 15:35:18 +01002081 hbSize = zc->hbSize;
Yann Collet7cbe79a2016-03-23 22:31:57 +01002082 if (dstCapacity <= hbSize) return ERROR(dstSize_tooSmall);
Yann Collet887e7da2016-04-11 20:12:27 +02002083 zc->stage = 2;
Yann Colletecd651b2016-01-07 15:35:18 +01002084 memcpy(dst, zc->headerBuffer, hbSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002085 dstCapacity -= hbSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002086 dst = (char*)dst + hbSize;
2087 }
Yann Colletf3eca252015-10-22 15:31:46 +01002088
Yann Collet417890c2015-12-04 17:16:37 +01002089 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01002090 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002091 /* not contiguous */
Yann Collet70e45772016-03-19 18:08:32 +01002092 size_t const delta = zc->nextSrc - ip;
Yann Collet417890c2015-12-04 17:16:37 +01002093 zc->lowLimit = zc->dictLimit;
2094 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2095 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01002096 zc->base -= delta;
2097 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01002098 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002099 }
2100
Yann Collet89db5e02015-11-13 11:27:46 +01002101 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01002102 if (zc->lowLimit > (1<<30)) {
Yann Collet3b719252016-03-30 19:48:05 +02002103 U32 const btplus = (zc->params.cParams.strategy == ZSTD_btlazy2) || (zc->params.cParams.strategy == ZSTD_btopt);
Yann Collet8a57b922016-04-04 13:49:18 +02002104 U32 const chainMask = (1 << (zc->params.cParams.chainLog - btplus)) - 1;
2105 U32 const newLowLimit = zc->lowLimit & chainMask; /* preserve position % chainSize */
Yann Collet70e45772016-03-19 18:08:32 +01002106 U32 const correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002107 ZSTD_reduceIndex(zc, correction);
2108 zc->base += correction;
2109 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002110 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002111 zc->dictLimit -= correction;
2112 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2113 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01002114 }
2115
Yann Colletbf42c8e2016-01-09 01:08:23 +01002116 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01002117 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01002118 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2119 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002120 }
2121
Yann Colletc3652152015-11-24 14:06:07 +01002122 zc->nextSrc = ip + srcSize;
Yann Collet70e45772016-03-19 18:08:32 +01002123 { size_t const cSize = frame ?
Yann Collet7cbe79a2016-03-23 22:31:57 +01002124 ZSTD_compress_generic (zc, dst, dstCapacity, src, srcSize) :
2125 ZSTD_compressBlock_internal (zc, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002126 if (ZSTD_isError(cSize)) return cSize;
2127 return cSize + hbSize;
2128 }
Yann Colletf3eca252015-10-22 15:31:46 +01002129}
2130
Yann Colletbf42c8e2016-01-09 01:08:23 +01002131
2132size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002133 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002134 const void* src, size_t srcSize)
2135{
Yann Collet7cbe79a2016-03-23 22:31:57 +01002136 return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 1);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002137}
2138
2139
Yann Colletd1b26842016-03-15 01:24:33 +01002140size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002141{
Yann Collet569b81a2016-03-16 15:26:51 +01002142 if (srcSize > ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
inikepd6f208b2016-04-04 21:15:23 +02002143 ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.cParams.searchLength);
Yann Colletd1b26842016-03-15 01:24:33 +01002144 return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002145}
2146
2147
Yann Colletb923f652016-01-26 03:14:20 +01002148static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002149{
2150 const BYTE* const ip = (const BYTE*) src;
2151 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002152
Yann Collet417890c2015-12-04 17:16:37 +01002153 /* input becomes current prefix */
2154 zc->lowLimit = zc->dictLimit;
2155 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2156 zc->dictBase = zc->base;
2157 zc->base += ip - zc->nextSrc;
2158 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002159 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002160
2161 zc->nextSrc = iend;
2162 if (srcSize <= 8) return 0;
2163
Yann Collet3b719252016-03-30 19:48:05 +02002164 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002165 {
2166 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002167 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002168 break;
2169
2170 case ZSTD_greedy:
2171 case ZSTD_lazy:
2172 case ZSTD_lazy2:
Yann Collet3b719252016-03-30 19:48:05 +02002173 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002174 break;
2175
2176 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002177 case ZSTD_btopt:
Yann Collet3b719252016-03-30 19:48:05 +02002178 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002179 break;
2180
2181 default:
2182 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2183 }
2184
Yann Collet2ce49232016-02-02 14:36:49 +01002185 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002186 return 0;
2187}
2188
2189
Yann Colletb923f652016-01-26 03:14:20 +01002190/* Dictionary format :
2191 Magic == ZSTD_DICT_MAGIC (4 bytes)
Yann Colletfb797352016-03-13 11:08:40 +01002192 HUF_writeCTable(256)
Yann Colletb923f652016-01-26 03:14:20 +01002193 Dictionary content
2194*/
Yann Colletfb797352016-03-13 11:08:40 +01002195/*! ZSTD_loadDictEntropyStats() :
Yann Colletb923f652016-01-26 03:14:20 +01002196 @return : size read from dictionary */
2197static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2198{
2199 /* note : magic number already checked */
Yann Colletfb810d62016-01-28 00:18:06 +01002200 size_t offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize, errorCode;
2201 short offcodeNCount[MaxOff+1];
2202 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2203 short matchlengthNCount[MaxML+1];
2204 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2205 short litlengthNCount[MaxLL+1];
2206 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2207
Yann Collet70e45772016-03-19 18:08:32 +01002208 size_t const hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize);
Yann Colletb923f652016-01-26 03:14:20 +01002209 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Colletfb810d62016-01-28 00:18:06 +01002210 zc->flagStaticTables = 1;
2211 dict = (const char*)dict + hufHeaderSize;
2212 dictSize -= hufHeaderSize;
2213
2214 offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
2215 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2216 errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2217 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2218 dict = (const char*)dict + offcodeHeaderSize;
2219 dictSize -= offcodeHeaderSize;
2220
2221 matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
2222 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2223 errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2224 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2225 dict = (const char*)dict + matchlengthHeaderSize;
2226 dictSize -= matchlengthHeaderSize;
2227
2228 litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
2229 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2230 errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2231 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2232
2233 return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
Yann Colletb923f652016-01-26 03:14:20 +01002234}
2235
Yann Colletd1b26842016-03-15 01:24:33 +01002236/** ZSTD_compress_insertDictionary() :
2237* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002238static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002239{
Yann Colletd1b26842016-03-15 01:24:33 +01002240 if ((dict==NULL) || (dictSize<=4)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002241
Yann Colletd1b26842016-03-15 01:24:33 +01002242 /* default : dict is pure content */
2243 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
2244
2245 /* known magic number : dict is parsed for entropy stats and content */
Yann Collet21588e32016-03-30 16:50:44 +02002246 { size_t const eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4 /* skip magic */, dictSize-4) + 4;
2247 if (ZSTD_isError(eSize)) return eSize;
2248 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002249 }
Yann Colletecd651b2016-01-07 15:35:18 +01002250}
2251
Yann Collet27caf2a2016-04-01 15:48:48 +02002252/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002253* @return : 0, or an error code */
Yann Collet27caf2a2016-04-01 15:48:48 +02002254static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* zc,
Yann Collet1c8e1942016-01-26 16:31:22 +01002255 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002256 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002257{
Yann Collet48537162016-04-07 15:24:29 +02002258 U32 hashLog3 = (pledgedSrcSize || pledgedSrcSize >= 8192) ? ZSTD_HASHLOG3_MAX : ((pledgedSrcSize >= 2048) ? ZSTD_HASHLOG3_MIN + 1 : ZSTD_HASHLOG3_MIN);
inikep19bd48f2016-04-04 12:10:00 +02002259 zc->hashLog3 = (params.cParams.searchLength==3) ? hashLog3 : 0;
inikep7adceef2016-03-23 15:53:38 +01002260// printf("windowLog=%d hashLog=%d hashLog3=%d \n", params.windowLog, params.hashLog, zc->hashLog3);
Yann Collet88fcd292015-11-25 14:42:45 +01002261
Yann Colletabb5c652016-04-11 20:42:31 +02002262 { size_t const resetError = ZSTD_resetCCtx_advanced(zc, params, 1);
2263 if (ZSTD_isError(resetError)) return resetError; }
Yann Collet89db5e02015-11-13 11:27:46 +01002264
Yann Colletd1b26842016-03-15 01:24:33 +01002265 /* Write Frame Header into ctx headerBuffer */
2266 MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER);
Yann Collet37f3d1b2016-03-19 15:11:42 +01002267 { BYTE* const op = (BYTE*)zc->headerBuffer;
Yann Collet3b719252016-03-30 19:48:05 +02002268 U32 const fcsId = (pledgedSrcSize>0) + (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256); /* 0-3 */
2269 BYTE fdescriptor = (BYTE)(params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN); /* windowLog : 4 KB - 128 MB */
Yann Colletd1b26842016-03-15 01:24:33 +01002270 fdescriptor |= (BYTE)(fcsId << 6);
Yann Collet1c2c2bc2016-03-15 01:33:36 +01002271 op[4] = fdescriptor;
Yann Colletd1b26842016-03-15 01:24:33 +01002272 switch(fcsId)
2273 {
2274 default: /* impossible */
2275 case 0 : break;
Yann Collet3b719252016-03-30 19:48:05 +02002276 case 1 : op[5] = (BYTE)(pledgedSrcSize); break;
2277 case 2 : MEM_writeLE16(op+5, (U16)(pledgedSrcSize-256)); break;
2278 case 3 : MEM_writeLE64(op+5, (U64)(pledgedSrcSize)); break;
Yann Colletd1b26842016-03-15 01:24:33 +01002279 }
Yann Collet37f3d1b2016-03-19 15:11:42 +01002280 zc->hbSize = ZSTD_frameHeaderSize_min + ZSTD_fcs_fieldSize[fcsId];
Yann Colletd1b26842016-03-15 01:24:33 +01002281 }
2282
Yann Collet1c8e1942016-01-26 16:31:22 +01002283 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002284}
2285
2286
Yann Collet27caf2a2016-04-01 15:48:48 +02002287/*! ZSTD_compressBegin_advanced() :
2288* @return : 0, or an error code */
2289size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
2290 const void* dict, size_t dictSize,
2291 ZSTD_parameters params, U64 pledgedSrcSize)
2292{
2293 /* compression parameters verification and optimization */
2294 { size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize);
2295 if (ZSTD_isError(errorCode)) return errorCode; }
2296
2297 return ZSTD_compressBegin_internal(zc, dict, dictSize, params, pledgedSrcSize);
2298}
2299
2300
Yann Collet1c8e1942016-01-26 16:31:22 +01002301size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002302{
Yann Collet3b719252016-03-30 19:48:05 +02002303 ZSTD_parameters params;
2304 params.cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
2305 params.fParams.contentSizeFlag = 0;
Yann Collet27caf2a2016-04-01 15:48:48 +02002306 ZSTD_adjustCParams(&params.cParams, 0, dictSize);
inikepa4dde252016-03-01 14:14:35 +01002307 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet27caf2a2016-04-01 15:48:48 +02002308 return ZSTD_compressBegin_internal(zc, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002309}
Yann Collet083fcc82015-10-25 14:06:35 +01002310
inikep19bd48f2016-04-04 12:10:00 +02002311
2312size_t ZSTD_compressBegin_targetSrcSize(ZSTD_CCtx* zc, const void* dict, size_t dictSize, size_t targetSrcSize, int compressionLevel)
2313{
2314 ZSTD_parameters params;
2315 params.cParams = ZSTD_getCParams(compressionLevel, targetSrcSize, dictSize);
2316 params.fParams.contentSizeFlag = 1;
2317 ZSTD_adjustCParams(&params.cParams, targetSrcSize, dictSize);
2318 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_targetSrcSize compressionLevel=%d\n", zc->base, compressionLevel);
2319 return ZSTD_compressBegin_internal(zc, dict, dictSize, params, targetSrcSize);
2320}
2321
2322
Yann Collet1c8e1942016-01-26 16:31:22 +01002323size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002324{
inikepa4dde252016-03-01 14:14:35 +01002325 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet3b719252016-03-30 19:48:05 +02002326 return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002327}
2328
2329
Yann Colletfb797352016-03-13 11:08:40 +01002330/*! ZSTD_compressEnd() :
2331* Write frame epilogue.
Yann Collet88fcd292015-11-25 14:42:45 +01002332* @return : nb of bytes written into dst (or an error code) */
Yann Colletd1b26842016-03-15 01:24:33 +01002333size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002334{
2335 BYTE* op = (BYTE*)dst;
Yann Colletecd651b2016-01-07 15:35:18 +01002336 size_t hbSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002337
Yann Collet887e7da2016-04-11 20:12:27 +02002338 /* not even init ! */
2339 if (zc->stage==0) return ERROR(stage_wrong);
2340
2341 /* special case : empty frame */
2342 if (zc->stage==1) {
Yann Colletecd651b2016-01-07 15:35:18 +01002343 hbSize = zc->hbSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002344 if (dstCapacity <= hbSize) return ERROR(dstSize_tooSmall);
Yann Collet887e7da2016-04-11 20:12:27 +02002345 zc->stage = 2;
Yann Colletecd651b2016-01-07 15:35:18 +01002346 memcpy(dst, zc->headerBuffer, hbSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002347 dstCapacity -= hbSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002348 op += hbSize;
2349 }
2350
2351 /* frame epilogue */
Yann Colletd1b26842016-03-15 01:24:33 +01002352 if (dstCapacity < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002353 op[0] = (BYTE)(bt_end << 6);
2354 op[1] = 0;
2355 op[2] = 0;
2356
Yann Collet887e7da2016-04-11 20:12:27 +02002357 zc->stage = 0; /* return to "created by not init" status */
Yann Colletecd651b2016-01-07 15:35:18 +01002358 return 3+hbSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002359}
2360
Yann Colletfd416f12016-01-30 03:14:15 +01002361
2362size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
Yann Colletd1b26842016-03-15 01:24:33 +01002363 void* dst, size_t dstCapacity,
Yann Colletfd416f12016-01-30 03:14:15 +01002364 const void* src, size_t srcSize)
2365{
Yann Collet70e45772016-03-19 18:08:32 +01002366 { size_t const errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2367 if (ZSTD_isError(errorCode)) return errorCode;
2368 }
2369 { size_t const cSize = ZSTD_compressContinue(cctx, dst, dstCapacity, src, srcSize);
2370 if (ZSTD_isError(cSize)) return cSize;
Yann Collet0dbf2872016-04-08 02:02:12 +02002371
Yann Collet70e45772016-03-19 18:08:32 +01002372 { size_t const endSize = ZSTD_compressEnd(cctx, (char*)dst+cSize, dstCapacity-cSize);
2373 if (ZSTD_isError(endSize)) return endSize;
2374 return cSize + endSize;
2375 } }
Yann Colletfd416f12016-01-30 03:14:15 +01002376}
2377
2378
Yann Collet21588e32016-03-30 16:50:44 +02002379static size_t ZSTD_compress_internal (ZSTD_CCtx* ctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002380 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002381 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002382 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002383 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002384{
2385 BYTE* const ostart = (BYTE*)dst;
2386 BYTE* op = ostart;
2387
Yann Collet1c8e1942016-01-26 16:31:22 +01002388 /* Init */
Yann Collet27caf2a2016-04-01 15:48:48 +02002389 { size_t const errorCode = ZSTD_compressBegin_internal(ctx, dict, dictSize, params, srcSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002390 if(ZSTD_isError(errorCode)) return errorCode; }
Yann Colletf3eca252015-10-22 15:31:46 +01002391
2392 /* body (compression) */
Yann Colletd1b26842016-03-15 01:24:33 +01002393 { size_t const oSize = ZSTD_compressContinue (ctx, op, dstCapacity, src, srcSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002394 if(ZSTD_isError(oSize)) return oSize;
2395 op += oSize;
2396 dstCapacity -= oSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002397
2398 /* Close frame */
Yann Colletd1b26842016-03-15 01:24:33 +01002399 { size_t const oSize = ZSTD_compressEnd(ctx, op, dstCapacity);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002400 if(ZSTD_isError(oSize)) return oSize;
2401 op += oSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002402
2403 return (op - ostart);
2404}
2405
Yann Collet21588e32016-03-30 16:50:44 +02002406size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2407 void* dst, size_t dstCapacity,
2408 const void* src, size_t srcSize,
2409 const void* dict,size_t dictSize,
2410 ZSTD_parameters params)
2411{
Yann Collet3b719252016-03-30 19:48:05 +02002412 size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, srcSize);
Yann Collet21588e32016-03-30 16:50:44 +02002413 if (ZSTD_isError(errorCode)) return errorCode;
2414 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2415}
2416
Yann Colletd1b26842016-03-15 01:24:33 +01002417size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, int compressionLevel)
Yann Collet31683c02015-12-18 01:26:48 +01002418{
Yann Collet3b719252016-03-30 19:48:05 +02002419 ZSTD_parameters params;
inikepa4dde252016-03-01 14:14:35 +01002420 ZSTD_LOG_BLOCK("%p: ZSTD_compress_usingDict srcSize=%d dictSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, (int)dictSize, compressionLevel);
Yann Collet3b719252016-03-30 19:48:05 +02002421 params.cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
2422 params.fParams.contentSizeFlag = 1;
2423 ZSTD_adjustCParams(&params.cParams, srcSize, dictSize);
Yann Collet21588e32016-03-30 16:50:44 +02002424 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002425}
2426
Yann Colletd1b26842016-03-15 01:24:33 +01002427size_t ZSTD_compressCCtx (ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002428{
inikepa4dde252016-03-01 14:14:35 +01002429 ZSTD_LOG_BLOCK("%p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, compressionLevel);
Yann Collet21588e32016-03-30 16:50:44 +02002430 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002431}
2432
Yann Colletd1b26842016-03-15 01:24:33 +01002433size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002434{
Yann Collet44fe9912015-10-29 22:02:40 +01002435 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002436 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002437 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Colletd1b26842016-03-15 01:24:33 +01002438 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Colletecd651b2016-01-07 15:35:18 +01002439 free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002440 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002441}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002442
Yann Colletfd416f12016-01-30 03:14:15 +01002443
Yann Collet70e8c382016-02-10 13:37:52 +01002444/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01002445
Yann Collete3193c42016-03-09 16:57:09 +01002446#define ZSTD_MAX_CLEVEL 22
Yann Collet7d968c72016-02-03 02:11:32 +01002447unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2448
Yann Collet3b719252016-03-30 19:48:05 +02002449static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01002450{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02002451 /* W, C, H, S, L, TL, strat */
Yann Collet3b719252016-03-30 19:48:05 +02002452 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2453 { 19, 13, 14, 1, 7, 4, ZSTD_fast }, /* level 1 */
2454 { 19, 15, 16, 1, 6, 4, ZSTD_fast }, /* level 2 */
2455 { 20, 18, 20, 1, 6, 4, ZSTD_fast }, /* level 3 */
2456 { 20, 13, 17, 2, 5, 4, ZSTD_greedy }, /* level 4.*/
2457 { 20, 15, 18, 3, 5, 4, ZSTD_greedy }, /* level 5 */
2458 { 21, 16, 19, 2, 5, 4, ZSTD_lazy }, /* level 6 */
2459 { 21, 17, 20, 3, 5, 4, ZSTD_lazy }, /* level 7 */
2460 { 21, 18, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 8.*/
2461 { 21, 20, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 9 */
2462 { 21, 19, 21, 4, 5, 4, ZSTD_lazy2 }, /* level 10 */
2463 { 22, 20, 22, 4, 5, 4, ZSTD_lazy2 }, /* level 11 */
2464 { 22, 20, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 12 */
2465 { 22, 21, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 13 */
2466 { 22, 21, 22, 6, 5, 4, ZSTD_lazy2 }, /* level 14 */
2467 { 22, 21, 21, 5, 5, 4, ZSTD_btlazy2 }, /* level 15 */
2468 { 23, 22, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */
Yann Collet793c6492016-04-09 20:32:00 +02002469 { 23, 23, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 17.*/
2470 { 23, 23, 22, 6, 5, 24, ZSTD_btopt }, /* level 18.*/
2471 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19.*/
2472 { 25, 26, 23, 7, 3, 64, ZSTD_btopt }, /* level 20.*/
2473 { 26, 26, 23, 7, 3,256, ZSTD_btopt }, /* level 21.*/
2474 { 27, 27, 25, 9, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002475},
2476{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002477 /* W, C, H, S, L, T, strat */
2478 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 */
Yann Collet0dbf2872016-04-08 02:02:12 +02002479 { 18, 13, 14, 1, 6, 4, ZSTD_fast }, /* level 1 */
Yann Collet78267d12016-04-08 12:36:19 +02002480 { 18, 15, 17, 1, 5, 4, ZSTD_fast }, /* level 2 */
2481 { 18, 13, 15, 1, 5, 4, ZSTD_greedy }, /* level 3.*/
2482 { 18, 15, 17, 1, 5, 4, ZSTD_greedy }, /* level 4.*/
2483 { 18, 16, 17, 4, 5, 4, ZSTD_greedy }, /* level 5 */
2484 { 18, 17, 17, 5, 5, 4, ZSTD_greedy }, /* level 6 */
Yann Collet3b719252016-03-30 19:48:05 +02002485 { 18, 17, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */
2486 { 18, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2487 { 18, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2488 { 18, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
Yann Collet78267d12016-04-08 12:36:19 +02002489 { 18, 18, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 11.*/
2490 { 18, 18, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 12.*/
2491 { 18, 19, 17, 7, 4, 4, ZSTD_btlazy2 }, /* level 13 */
2492 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
2493 { 18, 18, 18, 8, 4, 24, ZSTD_btopt }, /* level 15.*/
2494 { 18, 19, 18, 8, 3, 48, ZSTD_btopt }, /* level 16.*/
2495 { 18, 19, 18, 8, 3, 96, ZSTD_btopt }, /* level 17.*/
2496 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
2497 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
2498 { 18, 19, 18, 11, 3,512, ZSTD_btopt }, /* level 20.*/
2499 { 18, 19, 18, 12, 3,512, ZSTD_btopt }, /* level 21.*/
2500 { 18, 19, 18, 13, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002501},
2502{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002503 /* W, C, H, S, L, T, strat */
2504 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2505 { 17, 12, 13, 1, 6, 4, ZSTD_fast }, /* level 1 */
2506 { 17, 13, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */
2507 { 17, 13, 14, 2, 5, 4, ZSTD_greedy }, /* level 3 */
2508 { 17, 13, 15, 3, 4, 4, ZSTD_greedy }, /* level 4 */
2509 { 17, 15, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */
2510 { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
2511 { 17, 15, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 7 */
2512 { 17, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2513 { 17, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2514 { 17, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
2515 { 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */
2516 { 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */
2517 { 17, 18, 17, 6, 4, 4, ZSTD_btlazy2 }, /* level 13.*/
2518 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
2519 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
2520 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
2521 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
2522 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
2523 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
2524 { 17, 18, 17, 9, 3,256, ZSTD_btopt }, /* level 20.*/
2525 { 17, 18, 17, 10, 3,256, ZSTD_btopt }, /* level 21.*/
2526 { 17, 18, 17, 11, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002527},
2528{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002529 /* W, C, H, S, L, T, strat */
2530 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 -- never used */
2531 { 14, 14, 14, 1, 4, 4, ZSTD_fast }, /* level 1 */
2532 { 14, 14, 15, 1, 4, 4, ZSTD_fast }, /* level 2 */
2533 { 14, 14, 14, 4, 4, 4, ZSTD_greedy }, /* level 3.*/
2534 { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 4.*/
2535 { 14, 14, 14, 4, 4, 4, ZSTD_lazy2 }, /* level 5 */
2536 { 14, 14, 14, 5, 4, 4, ZSTD_lazy2 }, /* level 6 */
2537 { 14, 14, 14, 6, 4, 4, ZSTD_lazy2 }, /* level 7.*/
2538 { 14, 14, 14, 7, 4, 4, ZSTD_lazy2 }, /* level 8.*/
2539 { 14, 15, 14, 6, 4, 4, ZSTD_btlazy2 }, /* level 9.*/
2540 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
2541 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
2542 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
2543 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
2544 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
2545 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
2546 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
2547 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
2548 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
2549 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
2550 { 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 20.*/
2551 { 14, 15, 15, 9, 3,256, ZSTD_btopt }, /* level 21.*/
2552 { 14, 15, 15, 10, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002553},
2554};
2555
Yann Collet1df25942016-03-05 18:43:21 +01002556/*! ZSTD_getParams() :
Yann Colletfd416f12016-01-30 03:14:15 +01002557* @return ZSTD_parameters structure for a selected compression level and srcSize.
Yann Colletde406ee2016-03-20 15:46:10 +01002558* `srcSize` value is optional, select 0 if not known */
Yann Collet3b719252016-03-30 19:48:05 +02002559ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, U64 srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01002560{
Yann Collet15354142016-04-04 04:22:53 +02002561 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02002562 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02002563 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02002564 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Colletfd416f12016-01-30 03:14:15 +01002565 if (compressionLevel<=0) compressionLevel = 1;
2566 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02002567 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02002568 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
2569 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02002570 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02002571 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
2572 }
Yann Collet15354142016-04-04 04:22:53 +02002573 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01002574}