blob: 7898cf3fce3916348b2f704b3238242c1d89548e [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***************************************/
Yann Colletd3b7f8d2016-06-04 19:47:02 +020054#include <string.h> /* memset */
Yann Collet14983e72015-11-11 21:38:21 +010055#include "mem.h"
Yann Colletf2a3b6e2016-05-31 18:13:56 +020056#define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
Yann Colletd3b7f8d2016-06-04 19:47:02 +020057#include "xxhash.h" /* XXH_reset, update, digest */
Yann Collet14983e72015-11-11 21:38:21 +010058#include "fse_static.h"
Yann Collet130fe112016-06-05 00:42:28 +020059#define HUF_STATIC_LINKING_ONLY
60#include "huf.h"
Yann Colletd3b7f8d2016-06-04 19:47:02 +020061#include "zstd_internal.h" /* includes zstd.h */
Yann Colletf3eca252015-10-22 15:31:46 +010062
63
Yann Collet7d360282016-02-12 00:07:30 +010064/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010065* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010066***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010067static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Colletf3eca252015-10-22 15:31:46 +010068
Yann Colletf3eca252015-10-22 15:31:46 +010069
Yann Collet7d360282016-02-12 00:07:30 +010070/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010071* Helper functions
72***************************************/
Yann Collet59d1f792016-01-23 19:28:41 +010073size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
74
Yann Collet49bb0042016-06-04 20:17:38 +020075static U32 ZSTD_highbit32(U32 val)
76{
77# if defined(_MSC_VER) /* Visual */
78 unsigned long r=0;
79 _BitScanReverse(&r, val);
80 return (unsigned)r;
81# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
82 return 31 - __builtin_clz(val);
83# else /* Software version */
84 static const int DeBruijnClz[32] = { 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30, 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31 };
85 U32 v = val;
86 int r;
87 v |= v >> 1;
88 v |= v >> 2;
89 v |= v >> 4;
90 v |= v >> 8;
91 v |= v >> 16;
92 r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];
93 return r;
94# endif
95}
Yann Collet59d1f792016-01-23 19:28:41 +010096
Yann Collet7d360282016-02-12 00:07:30 +010097/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010098* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010099***************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100100static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
101{
102 ssPtr->offset = ssPtr->offsetStart;
103 ssPtr->lit = ssPtr->litStart;
104 ssPtr->litLength = ssPtr->litLengthStart;
105 ssPtr->matchLength = ssPtr->matchLengthStart;
Yann Collet5d393572016-04-07 17:19:00 +0200106 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100107}
108
109
Yann Collet7d360282016-02-12 00:07:30 +0100110/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100111* Context memory management
112***************************************/
Yann Collet5be2dd22015-11-11 13:43:58 +0100113struct ZSTD_CCtx_s
Yann Colletf3eca252015-10-22 15:31:46 +0100114{
Yann Collet89db5e02015-11-13 11:27:46 +0100115 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100116 const BYTE* base; /* All regular indexes relative to this position */
117 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +0100118 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100119 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +0100120 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +0100121 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +0100122 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Collet2ce49232016-02-02 14:36:49 +0100123 U32 loadedDictEnd;
Yann Collet887e7da2016-04-11 20:12:27 +0200124 U32 stage; /* 0: created; 1: init,dictLoad; 2:started */
Yann Colletc46fb922016-05-29 05:01:04 +0200125 U32 dictID;
Yann Collet5be2dd22015-11-11 13:43:58 +0100126 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +0100127 void* workSpace;
128 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100129 size_t blockSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200130 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +0200131 ZSTD_customMem customMem;
Yann Colletecd651b2016-01-07 15:35:18 +0100132
Yann Collet712def92015-10-29 18:41:45 +0100133 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100134 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +0100135 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +0200136 U32* chainTable;
Yann Colletb923f652016-01-26 03:14:20 +0100137 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +0100138 U32 flagStaticTables;
139 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
140 FSE_CTable matchlengthCTable [FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
141 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Colletf3eca252015-10-22 15:31:46 +0100142};
143
Yann Collet5be2dd22015-11-11 13:43:58 +0100144ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100145{
inikep3763c772016-06-03 13:28:20 +0200146 return ZSTD_createCCtx_advanced(defaultCustomMem);
inikep50e82c02016-05-23 15:49:09 +0200147}
148
149ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
150{
inikep107e2432016-05-23 16:24:52 +0200151 ZSTD_CCtx* ctx;
inikep50e82c02016-05-23 15:49:09 +0200152
inikep13ba8802016-05-23 17:04:23 +0200153 if (!customMem.customAlloc && !customMem.customFree)
inikep36fac002016-06-03 13:23:04 +0200154 customMem = defaultCustomMem;
inikep107e2432016-05-23 16:24:52 +0200155
inikep13ba8802016-05-23 17:04:23 +0200156 if (!customMem.customAlloc || !customMem.customFree)
157 return NULL;
158
inikep28669512016-06-02 13:04:18 +0200159 ctx = (ZSTD_CCtx*) customMem.customAlloc(customMem.opaque, sizeof(ZSTD_CCtx));
inikep50e82c02016-05-23 15:49:09 +0200160 if (!ctx) return NULL;
inikep50e82c02016-05-23 15:49:09 +0200161 memset(ctx, 0, sizeof(ZSTD_CCtx));
inikep28669512016-06-02 13:04:18 +0200162 memcpy(&ctx->customMem, &customMem, sizeof(ZSTD_customMem));
inikep50e82c02016-05-23 15:49:09 +0200163 return ctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100164}
165
Yann Collet5be2dd22015-11-11 13:43:58 +0100166size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100167{
inikep36403962016-06-03 16:36:50 +0200168 if (cctx==NULL) return 0; /* support free on NULL */
169 if (cctx->workSpace) cctx->customMem.customFree(cctx->customMem.opaque, cctx->workSpace);
inikep28669512016-06-02 13:04:18 +0200170 cctx->customMem.customFree(cctx->customMem.opaque, cctx);
Yann Collet982ffc72016-02-05 02:33:10 +0100171 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100172}
173
Yann Colletb44be742016-03-26 20:52:14 +0100174const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100175{
Yann Colletb44be742016-03-26 20:52:14 +0100176 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100177}
178
Yann Collet59d70632015-11-04 12:05:27 +0100179
Yann Collet21588e32016-03-30 16:50:44 +0200180#define CLAMP(val,min,max) { if (val<min) val=min; else if (val>max) val=max; }
181#define CLAMPCHECK(val,min,max) { if ((val<min) || (val>max)) return ERROR(compressionParameter_unsupported); }
182
183/** ZSTD_checkParams() :
184 ensure param values remain within authorized range.
185 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200186size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200187{
Yann Collet15354142016-04-04 04:22:53 +0200188 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200189 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200190 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
191 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
inikep75716852016-04-06 12:34:42 +0200192 { 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 +0200193 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
194 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
195 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Collet9bb87e52016-03-30 21:28:15 +0200196 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200197 return 0;
198}
199
200
Yann Collet3b719252016-03-30 19:48:05 +0200201/** ZSTD_checkCParams_advanced() :
202 temporary work-around, while the compressor compatibility remains limited regarding windowLog < 18 */
203size_t ZSTD_checkCParams_advanced(ZSTD_compressionParameters cParams, U64 srcSize)
204{
Yann Colletefb18302016-04-01 18:54:13 +0200205 if (srcSize > (1ULL << ZSTD_WINDOWLOG_MIN)) return ZSTD_checkCParams(cParams);
Yann Collet3b719252016-03-30 19:48:05 +0200206 if (cParams.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) return ERROR(compressionParameter_unsupported);
Yann Collet8a57b922016-04-04 13:49:18 +0200207 if (srcSize <= (1ULL << cParams.windowLog)) cParams.windowLog = ZSTD_WINDOWLOG_MIN; /* fake value - temporary work around */
208 if (srcSize <= (1ULL << cParams.chainLog)) cParams.chainLog = ZSTD_CHAINLOG_MIN; /* fake value - temporary work around */
Yann Colletef363902016-04-02 00:46:40 +0200209 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 +0200210 return ZSTD_checkCParams(cParams);
211}
212
213
Yann Collet70d13012016-06-01 18:45:34 +0200214/** ZSTD_adjustCParams() :
215 optimize cPar for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200216 mostly downsizing to reduce memory consumption and initialization.
217 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
218 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200219 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
220ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, U64 srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100221{
Yann Collet70d13012016-06-01 18:45:34 +0200222 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100223
Yann Collet70e45772016-03-19 18:08:32 +0100224 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200225 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
226 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200227 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Collet49bb0042016-06-04 20:17:38 +0200228 U32 const srcLog = ZSTD_highbit32((U32)(rSize)-1) + 1;
Yann Collet70d13012016-06-01 18:45:34 +0200229 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200230 } }
Yann Collet70d13012016-06-01 18:45:34 +0200231 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
232 { U32 const btPlus = (cPar.strategy == ZSTD_btlazy2) || (cPar.strategy == ZSTD_btopt);
233 U32 const maxChainLog = cPar.windowLog+btPlus;
234 if (cPar.chainLog > maxChainLog) cPar.chainLog = maxChainLog; } /* <= ZSTD_CHAINLOG_MAX */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100235
Yann Collet70d13012016-06-01 18:45:34 +0200236 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
237 if ((cPar.hashLog < ZSTD_HASHLOG_MIN) && ( (U32)cPar.strategy >= (U32)ZSTD_btlazy2)) cPar.hashLog = ZSTD_HASHLOG_MIN; /* required to ensure collision resistance in bt */
238
239 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100240}
241
242
Yann Collet51d50042016-03-30 20:42:19 +0200243size_t ZSTD_sizeofCCtx(ZSTD_compressionParameters cParams) /* hidden interface, for paramagrill */
Yann Collete74215e2016-03-19 16:09:09 +0100244{
245 ZSTD_CCtx* zc = ZSTD_createCCtx();
Yann Collet51d50042016-03-30 20:42:19 +0200246 ZSTD_parameters params;
Yann Colletc46fb922016-05-29 05:01:04 +0200247 memset(&params, 0, sizeof(params));
Yann Collet51d50042016-03-30 20:42:19 +0200248 params.cParams = cParams;
249 params.fParams.contentSizeFlag = 1;
Yann Collet3b719252016-03-30 19:48:05 +0200250 ZSTD_compressBegin_advanced(zc, NULL, 0, params, 0);
Yann Colletd64f4352016-03-21 00:07:42 +0100251 { size_t const ccsize = sizeof(*zc) + zc->workSpaceSize;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100252 ZSTD_freeCCtx(zc);
Yann Colletd64f4352016-03-21 00:07:42 +0100253 return ccsize; }
Yann Collet2e91dde2016-03-08 12:22:11 +0100254}
255
Yann Collet27caf2a2016-04-01 15:48:48 +0200256/*! ZSTD_resetCCtx_advanced() :
257 note : 'params' is expected to be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100258static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Colletabb5c652016-04-11 20:42:31 +0200259 ZSTD_parameters params, U32 reset)
Yann Collet863ec402016-01-28 17:56:33 +0100260{ /* note : params considered validated here */
Yann Collet3b719252016-03-30 19:48:05 +0200261 const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
262 const U32 divider = (params.cParams.searchLength==3) ? 3 : 4;
Yann Colletdd54bbc2016-03-08 02:35:34 +0100263 const size_t maxNbSeq = blockSize / divider;
Yann Colletbe391432016-03-22 23:19:28 +0100264 const size_t tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet8a57b922016-04-04 13:49:18 +0200265 const size_t chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
inikep1007a1f2016-04-25 15:23:09 +0200266 const size_t hSize = ((size_t)1) << params.cParams.hashLog;
inikep7adceef2016-03-23 15:53:38 +0100267 const size_t h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Collet8a57b922016-04-04 13:49:18 +0200268 const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
inikep87d4f3d2016-03-02 15:56:24 +0100269
Yann Collete74215e2016-03-19 16:09:09 +0100270 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Collet48537162016-04-07 15:24:29 +0200271 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
Yann Collete74215e2016-03-19 16:09:09 +0100272 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
273 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Yann Collet1005fc12016-04-04 13:28:28 +0200274 + ((params.cParams.strategy == ZSTD_btopt) ? optSpace : 0);
Yann Collete74215e2016-03-19 16:09:09 +0100275 if (zc->workSpaceSize < neededSpace) {
inikep28669512016-06-02 13:04:18 +0200276 zc->customMem.customFree(zc->customMem.opaque, zc->workSpace);
277 zc->workSpace = zc->customMem.customAlloc(zc->customMem.opaque, neededSpace);
Yann Collete74215e2016-03-19 16:09:09 +0100278 if (zc->workSpace == NULL) return ERROR(memory_allocation);
279 zc->workSpaceSize = neededSpace;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100280 } }
Yann Collete74215e2016-03-19 16:09:09 +0100281
Yann Colletabb5c652016-04-11 20:42:31 +0200282 if (reset) memset(zc->workSpace, 0, tableSpace ); /* reset only tables */
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200283 XXH64_reset(&zc->xxhState, 0);
inikepcc52a972016-02-19 10:09:35 +0100284 zc->hashTable3 = (U32*)(zc->workSpace);
Yann Collete74215e2016-03-19 16:09:09 +0100285 zc->hashTable = zc->hashTable3 + h3Size;
Yann Collet8a57b922016-04-04 13:49:18 +0200286 zc->chainTable = zc->hashTable + hSize;
287 zc->seqStore.buffer = zc->chainTable + chainSize;
Yann Collet863ec402016-01-28 17:56:33 +0100288 zc->hufTable = (HUF_CElt*)zc->seqStore.buffer;
289 zc->flagStaticTables = 0;
Yann Collet597847a2016-03-20 19:14:22 +0100290 zc->seqStore.buffer = ((U32*)(zc->seqStore.buffer)) + 256;
Yann Collet083fcc82015-10-25 14:06:35 +0100291
Yann Colletf48e35c2015-11-07 01:13:31 +0100292 zc->nextToUpdate = 1;
Yann Collet89db5e02015-11-13 11:27:46 +0100293 zc->nextSrc = NULL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100294 zc->base = NULL;
295 zc->dictBase = NULL;
296 zc->dictLimit = 0;
297 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100298 zc->params = params;
Yann Collet120230b2015-12-02 14:00:45 +0100299 zc->blockSize = blockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100300
Yann Collet3b719252016-03-30 19:48:05 +0200301 if (params.cParams.strategy == ZSTD_btopt) {
Yann Collet72d706a2016-03-23 20:44:12 +0100302 zc->seqStore.litFreq = (U32*)(zc->seqStore.buffer);
303 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
304 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
305 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
Yann Collet48537162016-04-07 15:24:29 +0200306 zc->seqStore.matchTable = (ZSTD_match_t*)((void*)(zc->seqStore.offCodeFreq + (MaxOff+1)));
Yann Collet72d706a2016-03-23 20:44:12 +0100307 zc->seqStore.priceTable = (ZSTD_optimal_t*)((void*)(zc->seqStore.matchTable + ZSTD_OPT_NUM+1));
308 zc->seqStore.buffer = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
309 zc->seqStore.litLengthSum = 0;
310 }
inikep87d4f3d2016-03-02 15:56:24 +0100311 zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer);
Yann Collet597847a2016-03-20 19:14:22 +0100312 zc->seqStore.litLengthStart = (U16*) (void*)(zc->seqStore.offsetStart + maxNbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100313 zc->seqStore.matchLengthStart = (U16*) (void*)(zc->seqStore.litLengthStart + maxNbSeq);
314 zc->seqStore.llCodeStart = (BYTE*) (zc->seqStore.matchLengthStart + maxNbSeq);
315 zc->seqStore.mlCodeStart = zc->seqStore.llCodeStart + maxNbSeq;
316 zc->seqStore.offCodeStart = zc->seqStore.mlCodeStart + maxNbSeq;
Yann Colletdd54bbc2016-03-08 02:35:34 +0100317 zc->seqStore.litStart = zc->seqStore.offCodeStart + maxNbSeq;
inikep5cccd772016-03-02 20:37:49 +0100318
Yann Collet887e7da2016-04-11 20:12:27 +0200319 zc->stage = 1;
Yann Colletc46fb922016-05-29 05:01:04 +0200320 zc->dictID = 0;
Yann Collet2ce49232016-02-02 14:36:49 +0100321 zc->loadedDictEnd = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +0100322
Yann Collet4114f952015-10-30 06:40:22 +0100323 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100324}
325
Yann Collet083fcc82015-10-25 14:06:35 +0100326
Yann Collet370b08e2016-03-08 00:03:59 +0100327/*! ZSTD_copyCCtx() :
328* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet887e7da2016-04-11 20:12:27 +0200329* Only works during stage 1 (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100330* @return : 0, or an error code */
331size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
332{
Yann Collet887e7da2016-04-11 20:12:27 +0200333 if (srcCCtx->stage!=1) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100334
inikep107e2432016-05-23 16:24:52 +0200335 dstCCtx->hashLog3 = srcCCtx->hashLog3; /* must be before ZSTD_resetCCtx_advanced */
inikep28669512016-06-02 13:04:18 +0200336 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Yann Colletabb5c652016-04-11 20:42:31 +0200337 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, 0);
Yann Collet389648c2016-04-12 19:13:08 +0200338 dstCCtx->params.fParams.contentSizeFlag = 0; /* content size different from the one set during srcCCtx init */
Yann Collet7b51a292016-01-26 15:58:49 +0100339
340 /* copy tables */
inikep0c7456c2016-04-04 14:54:53 +0200341 { const size_t chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
inikep1007a1f2016-04-25 15:23:09 +0200342 const size_t hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
inikep7adceef2016-03-23 15:53:38 +0100343 const size_t h3Size = (srcCCtx->hashLog3) ? 1 << srcCCtx->hashLog3 : 0;
inikep0c7456c2016-04-04 14:54:53 +0200344 const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100345 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
346 }
Yann Collet7b51a292016-01-26 15:58:49 +0100347
Yann Colletc46fb922016-05-29 05:01:04 +0200348 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100349 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
350 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
351 dstCCtx->nextSrc = srcCCtx->nextSrc;
352 dstCCtx->base = srcCCtx->base;
353 dstCCtx->dictBase = srcCCtx->dictBase;
354 dstCCtx->dictLimit = srcCCtx->dictLimit;
355 dstCCtx->lowLimit = srcCCtx->lowLimit;
356 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200357 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100358
Yann Colletfb810d62016-01-28 00:18:06 +0100359 /* copy entropy tables */
360 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100361 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100362 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100363 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
364 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
365 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
366 }
Yann Collet7b51a292016-01-26 15:58:49 +0100367
368 return 0;
369}
370
371
Yann Colletecabfe32016-03-20 16:20:06 +0100372/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100373* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100374static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100375{
Yann Colletecabfe32016-03-20 16:20:06 +0100376 U32 u;
377 for (u=0 ; u < size ; u++) {
378 if (table[u] < reducerValue) table[u] = 0;
379 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100380 }
381}
382
Yann Colletecabfe32016-03-20 16:20:06 +0100383/*! ZSTD_reduceIndex() :
384* rescale all indexes to avoid future overflow (indexes are U32) */
385static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
386{
Yann Collet3b719252016-03-30 19:48:05 +0200387 { const U32 hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100388 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
389
Yann Collet8a57b922016-04-04 13:49:18 +0200390 { const U32 chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
391 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100392
inikep7adceef2016-03-23 15:53:38 +0100393 { const U32 h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100394 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
395}
396
Yann Collet89db5e02015-11-13 11:27:46 +0100397
Yann Collet863ec402016-01-28 17:56:33 +0100398/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100399* Block entropic compression
400*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100401
Yann Colletfb797352016-03-13 11:08:40 +0100402/* Frame format description
403 Frame Header - [ Block Header - Block ] - Frame End
404 1) Frame Header
405 - 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_static.h)
406 - 1 byte - Frame Descriptor
407 2) Block Header
408 - 3 bytes, starting with a 2-bits descriptor
409 Uncompressed, Compressed, Frame End, unused
410 3) Block
411 See Block Format Description
412 4) Frame End
413 - 3 bytes, compatible with Block Header
414*/
415
416
417/* Frame descriptor
418
419 1 byte, using :
420 bit 0-3 : windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN (see zstd_internal.h)
421 bit 4 : minmatch 4(0) or 3(1)
422 bit 5 : reserved (must be zero)
423 bit 6-7 : Frame content size : unknown, 1 byte, 2 bytes, 8 bytes
424
425 Optional : content size (0, 1, 2 or 8 bytes)
426 0 : unknown
427 1 : 0-255 bytes
428 2 : 256 - 65535+256
429 8 : up to 16 exa
430*/
431
432
Yann Collet59d1f792016-01-23 19:28:41 +0100433/* Block format description
434
435 Block = Literal Section - Sequences Section
436 Prerequisite : size of (compressed) block, maximum size of regenerated data
437
438 1) Literal Section
439
440 1.1) Header : 1-5 bytes
441 flags: 2 bits
442 00 compressed by Huff0
443 01 unused
444 10 is Raw (uncompressed)
445 11 is Rle
446 Note : using 01 => Huff0 with precomputed table ?
447 Note : delta map ? => compressed ?
448
449 1.1.1) Huff0-compressed literal block : 3-5 bytes
Yann Colletafe07092016-01-25 04:10:46 +0100450 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
Yann Collet59d1f792016-01-23 19:28:41 +0100451 srcSize < 1 KB => 3 bytes (2-2-10-10)
Yann Colleta1249dc2016-01-25 04:22:03 +0100452 srcSize < 16KB => 4 bytes (2-2-14-14)
Yann Collet59d1f792016-01-23 19:28:41 +0100453 else => 5 bytes (2-2-18-18)
454 big endian convention
455
456 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
457 size : 5 bits: (IS_RAW<<6) + (0<<4) + size
458 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
459 size&255
460 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
461 size>>8&255
462 size&255
463
464 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
465 size : 5 bits: (IS_RLE<<6) + (0<<4) + size
466 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
467 size&255
468 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
469 size>>8&255
470 size&255
471
Yann Colleta1249dc2016-01-25 04:22:03 +0100472 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
473 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
474 srcSize < 1 KB => 3 bytes (2-2-10-10)
475 srcSize < 16KB => 4 bytes (2-2-14-14)
476 else => 5 bytes (2-2-18-18)
477 big endian convention
478
479 1- CTable available (stored into workspace ?)
Yann Colletb923f652016-01-26 03:14:20 +0100480 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
Yann Colleta1249dc2016-01-25 04:22:03 +0100481
Yann Collet59d1f792016-01-23 19:28:41 +0100482
483 1.2) Literal block content
484
485 1.2.1) Huff0 block, using sizes from header
486 See Huff0 format
487
Yann Colletfb810d62016-01-28 00:18:06 +0100488 1.2.2) Huff0 block, using prepared table
Yann Collet59d1f792016-01-23 19:28:41 +0100489
Yann Colletfb810d62016-01-28 00:18:06 +0100490 1.2.3) Raw content
Yann Collet59d1f792016-01-23 19:28:41 +0100491
Yann Colletfb810d62016-01-28 00:18:06 +0100492 1.2.4) single byte
Yann Collet59d1f792016-01-23 19:28:41 +0100493
494
495 2) Sequences section
Yann Colletfb810d62016-01-28 00:18:06 +0100496
497 - Nb Sequences : 2 bytes, little endian
498 - Control Token : 1 byte (see below)
499 - Dumps Length : 1 or 2 bytes (depending on control token)
500 - Dumps : as stated by dumps length
501 - Literal Lengths FSE table (as needed depending on encoding method)
502 - Offset Codes FSE table (as needed depending on encoding method)
503 - Match Lengths FSE table (as needed depending on encoding method)
504
505 2.1) Control Token
506 8 bits, divided as :
507 0-1 : dumpsLength
508 2-3 : MatchLength, FSE encoding method
509 4-5 : Offset Codes, FSE encoding method
510 6-7 : Literal Lengths, FSE encoding method
511
512 FSE encoding method :
513 FSE_ENCODING_RAW : uncompressed; no header
514 FSE_ENCODING_RLE : single repeated value; header 1 byte
515 FSE_ENCODING_STATIC : use prepared table; no header
516 FSE_ENCODING_DYNAMIC : read NCount
Yann Collet59d1f792016-01-23 19:28:41 +0100517*/
Yann Collet14983e72015-11-11 21:38:21 +0100518
Yann Colletd1b26842016-03-15 01:24:33 +0100519size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100520{
521 BYTE* const ostart = (BYTE* const)dst;
522
Yann Colletd1b26842016-03-15 01:24:33 +0100523 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100524 memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
525
526 /* Build header */
527 ostart[0] = (BYTE)(srcSize>>16);
528 ostart[1] = (BYTE)(srcSize>>8);
529 ostart[2] = (BYTE) srcSize;
530 ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
531
532 return ZSTD_blockHeaderSize+srcSize;
533}
534
535
Yann Colletd1b26842016-03-15 01:24:33 +0100536static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100537{
538 BYTE* const ostart = (BYTE* const)dst;
Yann Colleta910dc82016-03-18 12:37:45 +0100539 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100540
Yann Colletd1b26842016-03-15 01:24:33 +0100541 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100542
Yann Collet59d1f792016-01-23 19:28:41 +0100543 switch(flSize)
544 {
545 case 1: /* 2 - 1 - 5 */
546 ostart[0] = (BYTE)((IS_RAW<<6) + (0<<5) + srcSize);
547 break;
548 case 2: /* 2 - 2 - 12 */
549 ostart[0] = (BYTE)((IS_RAW<<6) + (2<<4) + (srcSize >> 8));
550 ostart[1] = (BYTE)srcSize;
551 break;
552 default: /*note : should not be necessary : flSize is within {1,2,3} */
553 case 3: /* 2 - 2 - 20 */
554 ostart[0] = (BYTE)((IS_RAW<<6) + (3<<4) + (srcSize >> 16));
555 ostart[1] = (BYTE)(srcSize>>8);
556 ostart[2] = (BYTE)srcSize;
557 break;
558 }
559
560 memcpy(ostart + flSize, src, srcSize);
561 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100562}
563
Yann Colletd1b26842016-03-15 01:24:33 +0100564static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100565{
566 BYTE* const ostart = (BYTE* const)dst;
Yann Colleta910dc82016-03-18 12:37:45 +0100567 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100568
Yann Colletd1b26842016-03-15 01:24:33 +0100569 (void)dstCapacity; /* dstCapacity guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100570
571 switch(flSize)
572 {
573 case 1: /* 2 - 1 - 5 */
574 ostart[0] = (BYTE)((IS_RLE<<6) + (0<<5) + srcSize);
575 break;
576 case 2: /* 2 - 2 - 12 */
577 ostart[0] = (BYTE)((IS_RLE<<6) + (2<<4) + (srcSize >> 8));
578 ostart[1] = (BYTE)srcSize;
579 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100580 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100581 case 3: /* 2 - 2 - 20 */
582 ostart[0] = (BYTE)((IS_RLE<<6) + (3<<4) + (srcSize >> 16));
583 ostart[1] = (BYTE)(srcSize>>8);
584 ostart[2] = (BYTE)srcSize;
585 break;
586 }
587
588 ostart[flSize] = *(const BYTE*)src;
589 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100590}
591
Yann Collet59d1f792016-01-23 19:28:41 +0100592
Yann Colleta5c2c082016-03-20 01:09:18 +0100593static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100594
Yann Colletb923f652016-01-26 03:14:20 +0100595static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100596 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100597 const void* src, size_t srcSize)
598{
Yann Colleta910dc82016-03-18 12:37:45 +0100599 size_t const minGain = ZSTD_minGain(srcSize);
600 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet14983e72015-11-11 21:38:21 +0100601 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100602 U32 singleStream = srcSize < 256;
Yann Colletb923f652016-01-26 03:14:20 +0100603 U32 hType = IS_HUF;
Yann Colleta910dc82016-03-18 12:37:45 +0100604 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100605
Yann Collet14983e72015-11-11 21:38:21 +0100606
Yann Colleta5c2c082016-03-20 01:09:18 +0100607 /* small ? don't even attempt compression (speed opt) */
608# define LITERAL_NOENTROPY 63
609 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
610 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
611 }
612
613 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Colletfb810d62016-01-28 00:18:06 +0100614 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletb923f652016-01-26 03:14:20 +0100615 hType = IS_PCH;
616 singleStream = 1;
Yann Colleta910dc82016-03-18 12:37:45 +0100617 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100618 } else {
Yann Colleta910dc82016-03-18 12:37:45 +0100619 cLitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12)
Yann Colletd1b26842016-03-15 01:24:33 +0100620 : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12);
Yann Colletb923f652016-01-26 03:14:20 +0100621 }
Yann Collet14983e72015-11-11 21:38:21 +0100622
Yann Colleta910dc82016-03-18 12:37:45 +0100623 if ((cLitSize==0) || (cLitSize >= srcSize - minGain))
624 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
625 if (cLitSize==1)
626 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100627
628 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100629 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100630 {
Yann Collet59d1f792016-01-23 19:28:41 +0100631 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletb923f652016-01-26 03:14:20 +0100632 ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6));
Yann Colleta910dc82016-03-18 12:37:45 +0100633 ostart[1] = (BYTE)((srcSize<<2) + (cLitSize>>8));
634 ostart[2] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100635 break;
636 case 4: /* 2 - 2 - 14 - 14 */
Yann Colletb923f652016-01-26 03:14:20 +0100637 ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100638 ostart[1] = (BYTE)(srcSize>> 2);
Yann Colleta910dc82016-03-18 12:37:45 +0100639 ostart[2] = (BYTE)((srcSize<<6) + (cLitSize>>8));
640 ostart[3] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100641 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100642 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100643 case 5: /* 2 - 2 - 18 - 18 */
Yann Colletb923f652016-01-26 03:14:20 +0100644 ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100645 ostart[1] = (BYTE)(srcSize>>6);
Yann Colleta910dc82016-03-18 12:37:45 +0100646 ostart[2] = (BYTE)((srcSize<<2) + (cLitSize>>16));
647 ostart[3] = (BYTE)(cLitSize>>8);
648 ostart[4] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100649 break;
Yann Collet14983e72015-11-11 21:38:21 +0100650 }
Yann Colleta910dc82016-03-18 12:37:45 +0100651 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100652}
653
654
Yann Colletb44be742016-03-26 20:52:14 +0100655void ZSTD_seqToCodes(const seqStore_t* seqStorePtr, size_t const nbSeq)
656{
657 /* LL codes */
658 { static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
659 8, 9, 10, 11, 12, 13, 14, 15,
660 16, 16, 17, 17, 18, 18, 19, 19,
661 20, 20, 20, 20, 21, 21, 21, 21,
662 22, 22, 22, 22, 22, 22, 22, 22,
663 23, 23, 23, 23, 23, 23, 23, 23,
664 24, 24, 24, 24, 24, 24, 24, 24,
665 24, 24, 24, 24, 24, 24, 24, 24 };
666 const BYTE LL_deltaCode = 19;
Yann Collet5d393572016-04-07 17:19:00 +0200667 const U16* const llTable = seqStorePtr->litLengthStart;
Yann Colletb44be742016-03-26 20:52:14 +0100668 BYTE* const llCodeTable = seqStorePtr->llCodeStart;
669 size_t u;
670 for (u=0; u<nbSeq; u++) {
Yann Collet5d393572016-04-07 17:19:00 +0200671 U32 const ll = llTable[u];
Yann Collet49bb0042016-06-04 20:17:38 +0200672 llCodeTable[u] = (ll>63) ? (BYTE)ZSTD_highbit32(ll) + LL_deltaCode : LL_Code[ll];
Yann Collet5d393572016-04-07 17:19:00 +0200673 }
674 if (seqStorePtr->longLengthID==1)
675 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
676 }
Yann Colletb44be742016-03-26 20:52:14 +0100677
678 /* Offset codes */
679 { const U32* const offsetTable = seqStorePtr->offsetStart;
680 BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
681 size_t u;
Yann Collet49bb0042016-06-04 20:17:38 +0200682 for (u=0; u<nbSeq; u++) ofCodeTable[u] = (BYTE)ZSTD_highbit32(offsetTable[u]);
Yann Colletb44be742016-03-26 20:52:14 +0100683 }
684
685 /* ML codes */
686 { static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
687 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
688 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
689 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
690 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
691 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
692 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
693 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
694 const BYTE ML_deltaCode = 36;
Yann Collet5d393572016-04-07 17:19:00 +0200695 const U16* const mlTable = seqStorePtr->matchLengthStart;
Yann Colletb44be742016-03-26 20:52:14 +0100696 BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
697 size_t u;
698 for (u=0; u<nbSeq; u++) {
Yann Collet5d393572016-04-07 17:19:00 +0200699 U32 const ml = mlTable[u];
Yann Collet49bb0042016-06-04 20:17:38 +0200700 mlCodeTable[u] = (ml>127) ? (BYTE)ZSTD_highbit32(ml) + ML_deltaCode : ML_Code[ml];
Yann Collet5d393572016-04-07 17:19:00 +0200701 }
702 if (seqStorePtr->longLengthID==2)
703 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
704 }
Yann Colletb44be742016-03-26 20:52:14 +0100705}
706
707
Yann Colletb923f652016-01-26 03:14:20 +0100708size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100709 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100710 size_t srcSize)
711{
Yann Colletb923f652016-01-26 03:14:20 +0100712 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100713 U32 count[MaxSeq+1];
714 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100715 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
716 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
717 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100718 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletb0aec172016-03-21 13:24:16 +0100719 U16* const llTable = seqStorePtr->litLengthStart;
Yann Colletfadda6c2016-03-22 12:14:26 +0100720 U16* const mlTable = seqStorePtr->matchLengthStart;
Yann Collet14983e72015-11-11 21:38:21 +0100721 const U32* const offsetTable = seqStorePtr->offsetStart;
Yann Colletd64f4352016-03-21 00:07:42 +0100722 const U32* const offsetTableEnd = seqStorePtr->offset;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100723 BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
Yann Collet597847a2016-03-20 19:14:22 +0100724 BYTE* const llCodeTable = seqStorePtr->llCodeStart;
Yann Colletfadda6c2016-03-22 12:14:26 +0100725 BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
Yann Collet5054ee02015-11-23 13:34:21 +0100726 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100727 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100728 BYTE* op = ostart;
Yann Colletd64f4352016-03-21 00:07:42 +0100729 size_t const nbSeq = offsetTableEnd - offsetTable;
Yann Collet14983e72015-11-11 21:38:21 +0100730 BYTE* seqHead;
731
Yann Collet14983e72015-11-11 21:38:21 +0100732 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100733 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100734 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100735 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100736 if (ZSTD_isError(cSize)) return cSize;
737 op += cSize;
738 }
739
740 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100741 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100742 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
743 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
744 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100745 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100746
Yann Colletbe391432016-03-22 23:19:28 +0100747 /* seqHead : flags for FSE encoding type */
748 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100749
Yann Colletfb810d62016-01-28 00:18:06 +0100750#define MIN_SEQ_FOR_DYNAMIC_FSE 64
751#define MAX_SEQ_FOR_STATIC_FSE 1000
752
Yann Colletb44be742016-03-26 20:52:14 +0100753 /* convert length/distances into codes */
754 ZSTD_seqToCodes(seqStorePtr, nbSeq);
Yann Collet597847a2016-03-20 19:14:22 +0100755
Yann Collet14983e72015-11-11 21:38:21 +0100756 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100757 { U32 max = MaxLL;
758 size_t const mostFrequent = FSE_countFast(count, &max, llCodeTable, nbSeq);
759 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
760 *op++ = llCodeTable[0];
761 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
762 LLtype = FSE_ENCODING_RLE;
763 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
764 LLtype = FSE_ENCODING_STATIC;
765 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
766 FSE_buildCTable(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog);
767 LLtype = FSE_ENCODING_RAW;
768 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100769 size_t nbSeq_1 = nbSeq;
770 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
771 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
772 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100773 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
774 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
775 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100776 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
777 LLtype = FSE_ENCODING_DYNAMIC;
778 } }
Yann Collet14983e72015-11-11 21:38:21 +0100779
Yann Colletb44be742016-03-26 20:52:14 +0100780 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100781 { U32 max = MaxOff;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100782 size_t const mostFrequent = FSE_countFast(count, &max, ofCodeTable, nbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100783 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100784 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100785 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
786 Offtype = FSE_ENCODING_RLE;
787 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
788 Offtype = FSE_ENCODING_STATIC;
Yann Collet48537162016-04-07 15:24:29 +0200789 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
790 FSE_buildCTable(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog);
Yann Colletfadda6c2016-03-22 12:14:26 +0100791 Offtype = FSE_ENCODING_RAW;
792 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100793 size_t nbSeq_1 = nbSeq;
794 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100795 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100796 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100797 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
798 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
799 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100800 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
801 Offtype = FSE_ENCODING_DYNAMIC;
802 } }
803
Yann Collet14983e72015-11-11 21:38:21 +0100804 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100805 { U32 max = MaxML;
806 size_t const mostFrequent = FSE_countFast(count, &max, mlCodeTable, nbSeq);
807 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100808 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100809 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
810 MLtype = FSE_ENCODING_RLE;
811 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
812 MLtype = FSE_ENCODING_STATIC;
813 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
814 FSE_buildCTable(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog);
815 MLtype = FSE_ENCODING_RAW;
816 } else {
817 size_t nbSeq_1 = nbSeq;
818 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
819 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
820 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
821 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
822 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
823 op += NCountSize; }
824 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
825 MLtype = FSE_ENCODING_DYNAMIC;
826 } }
Yann Collet14983e72015-11-11 21:38:21 +0100827
Yann Colletbe391432016-03-22 23:19:28 +0100828 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100829 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100830
831 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100832 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100833 FSE_CState_t stateMatchLength;
834 FSE_CState_t stateOffsetBits;
835 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100836
Yann Colleta910dc82016-03-18 12:37:45 +0100837 { size_t const errorCode = BIT_initCStream(&blockStream, op, oend-op);
Yann Collet597847a2016-03-20 19:14:22 +0100838 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100839
Yann Collet597847a2016-03-20 19:14:22 +0100840 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100841 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100842 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100843 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colletb0aec172016-03-21 13:24:16 +0100844 BIT_addBits(&blockStream, llTable[nbSeq-1], LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100845 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Collet25125972016-03-23 14:00:09 +0100846 BIT_addBits(&blockStream, mlTable[nbSeq-1], ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100847 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Collet646693e2016-03-24 02:31:27 +0100848 BIT_addBits(&blockStream, offsetTable[nbSeq-1], ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100849 BIT_flushBits(&blockStream);
850
Yann Colletfadda6c2016-03-22 12:14:26 +0100851 { size_t n;
852 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Colletb9151402016-03-26 17:18:11 +0100853 const BYTE ofCode = ofCodeTable[n];
Yann Collet7cbe79a2016-03-23 22:31:57 +0100854 const BYTE mlCode = mlCodeTable[n];
855 const BYTE llCode = llCodeTable[n];
856 const U32 llBits = LL_bits[llCode];
857 const U32 mlBits = ML_bits[mlCode];
Yann Colletb9151402016-03-26 17:18:11 +0100858 const U32 ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100859 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100860 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
861 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
862 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
863 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200864 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100865 BIT_flushBits(&blockStream); /* (7)*/
Yann Collet7cbe79a2016-03-23 22:31:57 +0100866 BIT_addBits(&blockStream, llTable[n], llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100867 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100868 BIT_addBits(&blockStream, mlTable[n], mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100869 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
870 BIT_addBits(&blockStream, offsetTable[n], ofBits); /* 31 */
871 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100872 } }
Yann Collet14983e72015-11-11 21:38:21 +0100873
874 FSE_flushCState(&blockStream, &stateMatchLength);
875 FSE_flushCState(&blockStream, &stateOffsetBits);
876 FSE_flushCState(&blockStream, &stateLitLength);
877
Yann Colletb9151402016-03-26 17:18:11 +0100878 { size_t const streamSize = BIT_closeCStream(&blockStream);
879 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
880 op += streamSize;
881 } }
Yann Collet14983e72015-11-11 21:38:21 +0100882
883 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100884_check_compressibility:
Yann Colletfadda6c2016-03-22 12:14:26 +0100885 { size_t const minGain = ZSTD_minGain(srcSize);
886 size_t const maxCSize = srcSize - minGain;
887 if ((size_t)(op-ostart) >= maxCSize) return 0; }
Yann Collet14983e72015-11-11 21:38:21 +0100888
Yann Collet5054ee02015-11-23 13:34:21 +0100889 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100890}
891
892
Yann Collet95cd0c22016-03-08 18:24:21 +0100893/*! ZSTD_storeSeq() :
894 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
895 `offsetCode` : distance to match, or 0 == repCode.
896 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100897*/
898MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode)
899{
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100900#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100901 static const BYTE* g_start = NULL;
Yann Colletb0aec172016-03-21 13:24:16 +0100902 const U32 pos = (U32)(literals - g_start);
Yann Collet14983e72015-11-11 21:38:21 +0100903 if (g_start==NULL) g_start = literals;
Yann Collet3f8ed502016-05-05 03:01:13 +0200904 if ((pos > 2587900) && (pos < 2588050))
Yann Colletb9151402016-03-26 17:18:11 +0100905 printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
Yann Collet433a5cc2016-03-25 11:43:48 +0100906 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +0100907#endif
inikepfb5df612016-05-24 15:36:37 +0200908 ZSTD_statsUpdatePrices(&seqStorePtr->stats, litLength, literals, offsetCode, matchCode);
Yann Collet14983e72015-11-11 21:38:21 +0100909
910 /* copy Literals */
911 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
912 seqStorePtr->lit += litLength;
913
914 /* literal Length */
Yann Collet5d393572016-04-07 17:19:00 +0200915 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->litLength - seqStorePtr->litLengthStart); }
916 *seqStorePtr->litLength++ = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100917
918 /* match offset */
Yann Collet646693e2016-03-24 02:31:27 +0100919 *(seqStorePtr->offset++) = (U32)offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100920
921 /* match Length */
Yann Collet5d393572016-04-07 17:19:00 +0200922 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->matchLength - seqStorePtr->matchLengthStart); }
923 *seqStorePtr->matchLength++ = (U16)matchCode;
Yann Collet14983e72015-11-11 21:38:21 +0100924}
925
926
Yann Collet7d360282016-02-12 00:07:30 +0100927/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100928* Match length counter
929***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100930static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100931{
Yann Collet863ec402016-01-28 17:56:33 +0100932 if (MEM_isLittleEndian()) {
933 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100934# if defined(_MSC_VER) && defined(_WIN64)
935 unsigned long r = 0;
936 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100937 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100938# elif defined(__GNUC__) && (__GNUC__ >= 3)
939 return (__builtin_ctzll((U64)val) >> 3);
940# else
941 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 };
942 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
943# endif
Yann Collet863ec402016-01-28 17:56:33 +0100944 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100945# if defined(_MSC_VER)
946 unsigned long r=0;
947 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100948 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100949# elif defined(__GNUC__) && (__GNUC__ >= 3)
950 return (__builtin_ctz((U32)val) >> 3);
951# else
952 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 };
953 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
954# endif
955 }
Yann Collet863ec402016-01-28 17:56:33 +0100956 } else { /* Big Endian CPU */
957 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100958# if defined(_MSC_VER) && defined(_WIN64)
959 unsigned long r = 0;
960 _BitScanReverse64( &r, val );
961 return (unsigned)(r>>3);
962# elif defined(__GNUC__) && (__GNUC__ >= 3)
963 return (__builtin_clzll(val) >> 3);
964# else
965 unsigned r;
966 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
967 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
968 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
969 r += (!val);
970 return r;
971# endif
Yann Collet863ec402016-01-28 17:56:33 +0100972 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100973# if defined(_MSC_VER)
974 unsigned long r = 0;
975 _BitScanReverse( &r, (unsigned long)val );
976 return (unsigned)(r>>3);
977# elif defined(__GNUC__) && (__GNUC__ >= 3)
978 return (__builtin_clz((U32)val) >> 3);
979# else
980 unsigned r;
981 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
982 r += (!val);
983 return r;
984# endif
Yann Collet863ec402016-01-28 17:56:33 +0100985 } }
Yann Collet14983e72015-11-11 21:38:21 +0100986}
987
988
Yann Collet5054ee02015-11-23 13:34:21 +0100989static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100990{
991 const BYTE* const pStart = pIn;
992
Yann Colletfb810d62016-01-28 00:18:06 +0100993 while ((pIn<pInLimit-(sizeof(size_t)-1))) {
Yann Collet7591a7f2016-05-20 11:44:43 +0200994 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100995 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
996 pIn += ZSTD_NbCommonBytes(diff);
997 return (size_t)(pIn - pStart);
998 }
Yann Collet14983e72015-11-11 21:38:21 +0100999 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
1000 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
1001 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
1002 return (size_t)(pIn - pStart);
1003}
1004
Yann Collet04b12d82016-02-11 06:23:24 +01001005/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +01001006* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +01001007* convention : on reaching mEnd, match count continue starting from iStart
1008*/
1009static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
1010{
Yann Collet7591a7f2016-05-20 11:44:43 +02001011 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
1012 size_t matchLength = ZSTD_count(ip, match, vEnd);
Yann Collet5054ee02015-11-23 13:34:21 +01001013 if (match + matchLength == mEnd)
1014 matchLength += ZSTD_count(ip+matchLength, iStart, iEnd);
1015 return matchLength;
1016}
1017
Yann Collet14983e72015-11-11 21:38:21 +01001018
Yann Collet863ec402016-01-28 17:56:33 +01001019/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001020* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +01001021***************************************/
inikepcc52a972016-02-19 10:09:35 +01001022static const U32 prime3bytes = 506832829U;
1023static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
inikepe2446b02016-03-07 10:07:08 +01001024static size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); }
inikepcc52a972016-02-19 10:09:35 +01001025
Yann Collet4b100f42015-10-30 15:49:48 +01001026static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +01001027static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +01001028static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +01001029
Yann Collet4b100f42015-10-30 15:49:48 +01001030static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001031static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001032static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001033
1034static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001035static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001036static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001037
Yann Collet14983e72015-11-11 21:38:21 +01001038static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001039static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001040static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001041
Yann Collet5be2dd22015-11-11 13:43:58 +01001042static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001043{
1044 switch(mls)
1045 {
1046 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001047 case 4: return ZSTD_hash4Ptr(p, hBits);
1048 case 5: return ZSTD_hash5Ptr(p, hBits);
1049 case 6: return ZSTD_hash6Ptr(p, hBits);
1050 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001051 }
1052}
Yann Collet2acb5d32015-10-29 16:49:43 +01001053
Yann Collet863ec402016-01-28 17:56:33 +01001054
Yann Collet2ce49232016-02-02 14:36:49 +01001055/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001056* Fast Scan
1057***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001058static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1059{
1060 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001061 const U32 hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001062 const BYTE* const base = zc->base;
1063 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet2ce49232016-02-02 14:36:49 +01001064 const BYTE* const iend = ((const BYTE*)end) - 8;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001065 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001066
Yann Colletfb810d62016-01-28 00:18:06 +01001067 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001068 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001069 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001070 }
1071}
1072
1073
Yann Collet1f44b3f2015-11-05 17:32:18 +01001074FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001075void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc,
Yann Collet89db5e02015-11-13 11:27:46 +01001076 const void* src, size_t srcSize,
1077 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001078{
Yann Collet417890c2015-12-04 17:16:37 +01001079 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001080 const U32 hBits = zc->params.cParams.hashLog;
Yann Colletc3652152015-11-24 14:06:07 +01001081 seqStore_t* seqStorePtr = &(zc->seqStore);
1082 const BYTE* const base = zc->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001083 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001084 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001085 const BYTE* anchor = istart;
Yann Colletd94efbf2015-12-29 14:29:08 +01001086 const U32 lowIndex = zc->dictLimit;
1087 const BYTE* const lowest = base + lowIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001088 const BYTE* const iend = istart + srcSize;
1089 const BYTE* const ilimit = iend - 8;
Yann Collet89db5e02015-11-13 11:27:46 +01001090 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001091
Yann Collet1f44b3f2015-11-05 17:32:18 +01001092 /* init */
Yann Collet743402c2015-11-20 12:03:53 +01001093 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001094 if (ip < lowest+REPCODE_STARTVALUE) ip = lowest+REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001095
1096 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001097 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Collet5054ee02015-11-23 13:34:21 +01001098 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001099 size_t offset;
Yann Collet5be2dd22015-11-11 13:43:58 +01001100 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Colletd94efbf2015-12-29 14:29:08 +01001101 const U32 matchIndex = hashTable[h];
1102 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001103 const U32 current = (U32)(ip-base);
1104 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001105
Yann Colletfb810d62016-01-28 00:18:06 +01001106 if (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)) { /* note : by construction, offset_1 <= current */
inikep7bc19b62016-04-06 09:46:01 +02001107 mlCode = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
Yann Collet402fdcf2015-11-20 12:46:08 +01001108 ip++;
inikep7bc19b62016-04-06 09:46:01 +02001109 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mlCode-MINMATCH);
inikep59453082016-03-16 15:35:14 +01001110 } else {
Yann Colletd94efbf2015-12-29 14:29:08 +01001111 if ( (matchIndex <= lowIndex) ||
Yann Colletfb810d62016-01-28 00:18:06 +01001112 (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001113 ip += ((ip-anchor) >> g_searchStrength) + 1;
1114 continue;
1115 }
inikep7bc19b62016-04-06 09:46:01 +02001116 mlCode = ZSTD_count(ip+EQUAL_READ32, match+EQUAL_READ32, iend) + EQUAL_READ32;
Yann Collet402fdcf2015-11-20 12:46:08 +01001117 offset = ip-match;
Yann Collet5054ee02015-11-23 13:34:21 +01001118 while ((ip>anchor) && (match>lowest) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001119 offset_2 = offset_1;
1120 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001121
inikep7bc19b62016-04-06 09:46:01 +02001122 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mlCode-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001123 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001124
Yann Collet402fdcf2015-11-20 12:46:08 +01001125 /* match found */
inikep7bc19b62016-04-06 09:46:01 +02001126 ip += mlCode;
Yann Collet402fdcf2015-11-20 12:46:08 +01001127 anchor = ip;
1128
Yann Colletfb810d62016-01-28 00:18:06 +01001129 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001130 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001131 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 +01001132 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1133 /* check immediate repcode */
1134 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001135 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001136 /* store sequence */
inikep7bc19b62016-04-06 09:46:01 +02001137 size_t const rlCode = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
Yann Collet70e45772016-03-19 18:08:32 +01001138 { 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 +01001139 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
inikep7bc19b62016-04-06 09:46:01 +02001140 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rlCode-MINMATCH);
1141 ip += rlCode;
Yann Collet402fdcf2015-11-20 12:46:08 +01001142 anchor = ip;
1143 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001144 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001145
Yann Collet70e45772016-03-19 18:08:32 +01001146 /* Last Literals */
1147 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001148 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1149 seqStorePtr->lit += lastLLSize;
1150 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001151}
1152
1153
Yann Collet82260dd2016-02-11 07:14:25 +01001154static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001155 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001156{
Yann Collet3b719252016-03-30 19:48:05 +02001157 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001158 switch(mls)
1159 {
1160 default:
1161 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001162 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001163 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001164 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001165 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001166 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001167 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001168 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001169 }
1170}
Yann Colletf3eca252015-10-22 15:31:46 +01001171
Yann Colletf3eca252015-10-22 15:31:46 +01001172
Yann Collet82260dd2016-02-11 07:14:25 +01001173static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001174 const void* src, size_t srcSize,
1175 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001176{
1177 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001178 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001179 seqStore_t* seqStorePtr = &(ctx->seqStore);
1180 const BYTE* const base = ctx->base;
1181 const BYTE* const dictBase = ctx->dictBase;
1182 const BYTE* const istart = (const BYTE*)src;
1183 const BYTE* ip = istart;
1184 const BYTE* anchor = istart;
1185 const U32 lowLimit = ctx->lowLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001186 const BYTE* const dictStart = dictBase + lowLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001187 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001188 const BYTE* const lowPrefixPtr = base + dictLimit;
1189 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001190 const BYTE* const iend = istart + srcSize;
1191 const BYTE* const ilimit = iend - 8;
1192
Yann Collet138e89c2015-11-17 14:26:54 +01001193 U32 offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001194
1195
1196 /* init */
1197 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001198 /* skip first position to avoid read overflow during repcode match check */
Yann Colletfb810d62016-01-28 00:18:06 +01001199 hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0);
Yann Collet61e16ce2016-01-31 02:04:15 +01001200 ip += REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001201
1202 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001203 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001204 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001205 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001206 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001207 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001208 const U32 current = (U32)(ip-base);
Yann Collet743402c2015-11-20 12:03:53 +01001209 const U32 repIndex = current + 1 - offset_1;
Yann Collet402fdcf2015-11-20 12:46:08 +01001210 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001211 const BYTE* repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001212 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001213 U32 offset;
Yann Collet89db5e02015-11-13 11:27:46 +01001214 hashTable[h] = current; /* update hash table */
1215
Yann Collet52447382016-03-20 16:00:00 +01001216 if ( ((repIndex >= dictLimit) || (repIndex <= dictLimit-4))
Yann Colletfb810d62016-01-28 00:18:06 +01001217 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001218 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001219 mlCode = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001220 ip++;
inikep7bc19b62016-04-06 09:46:01 +02001221 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mlCode-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001222 } else {
Yann Collet402fdcf2015-11-20 12:46:08 +01001223 if ( (matchIndex < lowLimit) ||
Yann Collet52447382016-03-20 16:00:00 +01001224 (MEM_read32(match) != MEM_read32(ip)) ) {
1225 ip += ((ip-anchor) >> g_searchStrength) + 1;
1226 continue;
1227 }
1228 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001229 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
inikep7bc19b62016-04-06 09:46:01 +02001230 mlCode = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Colletfb810d62016-01-28 00:18:06 +01001231 while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001232 offset = current - matchIndex;
1233 offset_2 = offset_1;
1234 offset_1 = offset;
inikep7bc19b62016-04-06 09:46:01 +02001235 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mlCode-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001236 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001237
Yann Collet5054ee02015-11-23 13:34:21 +01001238 /* found a match : store it */
inikep7bc19b62016-04-06 09:46:01 +02001239 ip += mlCode;
Yann Collet402fdcf2015-11-20 12:46:08 +01001240 anchor = ip;
1241
Yann Colletfb810d62016-01-28 00:18:06 +01001242 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001243 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001244 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001245 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1246 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001247 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001248 U32 const current2 = (U32)(ip-base);
1249 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001250 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet743402c2015-11-20 12:03:53 +01001251 if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001252 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001253 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001254 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001255 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001256 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001257 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001258 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001259 anchor = ip;
1260 continue;
1261 }
Yann Collet743402c2015-11-20 12:03:53 +01001262 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001263 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001264
1265 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001266 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001267 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1268 seqStorePtr->lit += lastLLSize;
1269 }
Yann Collet89db5e02015-11-13 11:27:46 +01001270}
1271
1272
Yann Collet82260dd2016-02-11 07:14:25 +01001273static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001274 const void* src, size_t srcSize)
1275{
Yann Collet3b719252016-03-30 19:48:05 +02001276 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001277 switch(mls)
1278 {
1279 default:
1280 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001281 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001282 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001283 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001284 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001285 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001286 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001287 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001288 }
1289}
1290
1291
inikep75716852016-04-06 12:34:42 +02001292
inikep2db1eb72016-04-06 17:14:19 +02001293
Yann Collet04b12d82016-02-11 06:23:24 +01001294/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001295* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001296***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001297/** ZSTD_insertBt1() : add one or multiple positions to tree.
1298* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001299* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001300static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1301 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001302{
1303 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001304 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet5be2dd22015-11-11 13:43:58 +01001305 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet8a57b922016-04-04 13:49:18 +02001306 U32* const bt = zc->chainTable;
1307 const U32 btLog = zc->params.cParams.chainLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001308 const U32 btMask= (1 << btLog) - 1;
1309 U32 matchIndex = hashTable[h];
1310 size_t commonLengthSmaller=0, commonLengthLarger=0;
1311 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001312 const BYTE* const dictBase = zc->dictBase;
1313 const U32 dictLimit = zc->dictLimit;
1314 const BYTE* const dictEnd = dictBase + dictLimit;
1315 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001316 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001317 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001318 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001319 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001320 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001321 U32 dummy32; /* to be nullified at the end */
Yann Collet03526e12015-11-23 15:29:15 +01001322 const U32 windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001323 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001324 size_t bestLength = 8;
Yann Collet7beaa052016-01-21 11:57:45 +01001325 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1326 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1327 predictedSmall += (predictedSmall>0);
1328 predictedLarge += (predictedLarge>0);
Yann Colletf48e35c2015-11-07 01:13:31 +01001329
Yann Collet6c3e2e72015-12-11 10:44:07 +01001330 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001331
Yann Colletfb810d62016-01-28 00:18:06 +01001332 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001333 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001334 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet793c6492016-04-09 20:32:00 +02001335#if 0 /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001336 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001337 if (matchIndex == predictedSmall) {
1338 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001339 *smallerPtr = matchIndex;
1340 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1341 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1342 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001343 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001344 continue;
1345 }
Yann Colletfb810d62016-01-28 00:18:06 +01001346 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001347 *largerPtr = matchIndex;
1348 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1349 largerPtr = nextPtr;
1350 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001351 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001352 continue;
1353 }
Yann Collet04b12d82016-02-11 06:23:24 +01001354#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001355 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001356 match = base + matchIndex;
1357 if (match[matchLength] == ip[matchLength])
1358 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001359 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001360 match = dictBase + matchIndex;
1361 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1362 if (matchIndex+matchLength >= dictLimit)
1363 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1364 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001365
Yann Colletb8a6f682016-02-15 17:06:29 +01001366 if (matchLength > bestLength) {
1367 bestLength = matchLength;
1368 if (matchLength > matchEndIdx - matchIndex)
1369 matchEndIdx = matchIndex + (U32)matchLength;
1370 }
Yann Colletee3f4512015-12-29 22:26:09 +01001371
Yann Collet59d70632015-11-04 12:05:27 +01001372 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001373 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001374
Yann Colletfb810d62016-01-28 00:18:06 +01001375 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001376 /* match is smaller than current */
1377 *smallerPtr = matchIndex; /* update smaller idx */
1378 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001379 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001380 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001381 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001382 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001383 /* match is larger than current */
1384 *largerPtr = matchIndex;
1385 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001386 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001387 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001388 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001389 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001390
Yann Collet59d70632015-11-04 12:05:27 +01001391 *smallerPtr = *largerPtr = 0;
Yann Colletb8a6f682016-02-15 17:06:29 +01001392 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384));
1393 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1394 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001395}
1396
1397
Yann Collet82260dd2016-02-11 07:14:25 +01001398static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001399 ZSTD_CCtx* zc,
1400 const BYTE* const ip, const BYTE* const iend,
1401 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001402 U32 nbCompares, const U32 mls,
1403 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001404{
1405 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001406 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet03526e12015-11-23 15:29:15 +01001407 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet8a57b922016-04-04 13:49:18 +02001408 U32* const bt = zc->chainTable;
1409 const U32 btLog = zc->params.cParams.chainLog - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001410 const U32 btMask= (1 << btLog) - 1;
1411 U32 matchIndex = hashTable[h];
1412 size_t commonLengthSmaller=0, commonLengthLarger=0;
1413 const BYTE* const base = zc->base;
1414 const BYTE* const dictBase = zc->dictBase;
1415 const U32 dictLimit = zc->dictLimit;
1416 const BYTE* const dictEnd = dictBase + dictLimit;
1417 const BYTE* const prefixStart = base + dictLimit;
1418 const U32 current = (U32)(ip-base);
1419 const U32 btLow = btMask >= current ? 0 : current - btMask;
1420 const U32 windowLow = zc->lowLimit;
1421 U32* smallerPtr = bt + 2*(current&btMask);
1422 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001423 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001424 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001425 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001426
Yann Collet6c3e2e72015-12-11 10:44:07 +01001427 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001428
Yann Colletfb810d62016-01-28 00:18:06 +01001429 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001430 U32* nextPtr = bt + 2*(matchIndex & btMask);
1431 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1432 const BYTE* match;
1433
Yann Colletfb810d62016-01-28 00:18:06 +01001434 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001435 match = base + matchIndex;
1436 if (match[matchLength] == ip[matchLength])
1437 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001438 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001439 match = dictBase + matchIndex;
1440 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001441 if (matchIndex+matchLength >= dictLimit)
1442 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001443 }
1444
Yann Colletfb810d62016-01-28 00:18:06 +01001445 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001446 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001447 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02001448 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001449 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001450 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1451 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1452 }
1453
Yann Colletfb810d62016-01-28 00:18:06 +01001454 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001455 /* match is smaller than current */
1456 *smallerPtr = matchIndex; /* update smaller idx */
1457 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1458 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1459 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1460 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001461 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001462 /* match is larger than current */
1463 *largerPtr = matchIndex;
1464 commonLengthLarger = matchLength;
1465 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1466 largerPtr = nextPtr;
1467 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001468 } }
Yann Collet03526e12015-11-23 15:29:15 +01001469
1470 *smallerPtr = *largerPtr = 0;
1471
Yann Collet72e84cf2015-12-31 19:08:44 +01001472 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001473 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001474}
1475
Yann Collet2cc12cb2016-01-01 07:47:58 +01001476
Yann Colletb8a6f682016-02-15 17:06:29 +01001477static 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 +01001478{
1479 const BYTE* const base = zc->base;
1480 const U32 target = (U32)(ip - base);
1481 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001482
1483 while(idx < target)
1484 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001485}
1486
Yann Collet52447382016-03-20 16:00:00 +01001487/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001488static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001489 ZSTD_CCtx* zc,
1490 const BYTE* const ip, const BYTE* const iLimit,
1491 size_t* offsetPtr,
1492 const U32 maxNbAttempts, const U32 mls)
1493{
1494 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001495 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001496 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1497}
1498
1499
Yann Collet768c6bc2016-02-10 14:01:49 +01001500static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001501 ZSTD_CCtx* zc, /* Index table will be updated */
1502 const BYTE* ip, const BYTE* const iLimit,
1503 size_t* offsetPtr,
1504 const U32 maxNbAttempts, const U32 matchLengthSearch)
1505{
1506 switch(matchLengthSearch)
1507 {
1508 default :
1509 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1510 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1511 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1512 }
1513}
1514
1515
Yann Colletb8a6f682016-02-15 17:06:29 +01001516static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1517{
1518 const BYTE* const base = zc->base;
1519 const U32 target = (U32)(ip - base);
1520 U32 idx = zc->nextToUpdate;
1521
1522 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1523}
1524
inikep64d7bcb2016-04-07 19:14:09 +02001525
1526
Yann Collet03526e12015-11-23 15:29:15 +01001527/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001528static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001529 ZSTD_CCtx* zc,
1530 const BYTE* const ip, const BYTE* const iLimit,
1531 size_t* offsetPtr,
1532 const U32 maxNbAttempts, const U32 mls)
1533{
Yann Colletee3f4512015-12-29 22:26:09 +01001534 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001535 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001536 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001537}
1538
1539
Yann Collet82260dd2016-02-11 07:14:25 +01001540static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001541 ZSTD_CCtx* zc, /* Index table will be updated */
1542 const BYTE* ip, const BYTE* const iLimit,
1543 size_t* offsetPtr,
1544 const U32 maxNbAttempts, const U32 matchLengthSearch)
1545{
1546 switch(matchLengthSearch)
1547 {
1548 default :
1549 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1550 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1551 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1552 }
1553}
1554
1555
Yann Collet5106a762015-11-05 15:00:24 +01001556
inikep64d7bcb2016-04-07 19:14:09 +02001557/* ***********************
1558* Hash Chain
1559*************************/
1560
1561#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1562
inikepafe1f792016-04-07 19:50:03 +02001563
inikep64d7bcb2016-04-07 19:14:09 +02001564/* Update chains up to ip (excluded)
1565 Assumption : always within prefix (ie. not within extDict) */
1566FORCE_INLINE
1567U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1568{
1569 U32* const hashTable = zc->hashTable;
1570 const U32 hashLog = zc->params.cParams.hashLog;
1571 U32* const chainTable = zc->chainTable;
1572 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1573 const BYTE* const base = zc->base;
1574 const U32 target = (U32)(ip - base);
1575 U32 idx = zc->nextToUpdate;
1576
1577 while(idx < target) {
1578 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1579 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1580 hashTable[h] = idx;
1581 idx++;
1582 }
1583
1584 zc->nextToUpdate = target;
1585 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1586}
1587
1588
1589
1590FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1591size_t ZSTD_HcFindBestMatch_generic (
1592 ZSTD_CCtx* zc, /* Index table will be updated */
1593 const BYTE* const ip, const BYTE* const iLimit,
1594 size_t* offsetPtr,
1595 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1596{
1597 U32* const chainTable = zc->chainTable;
1598 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1599 const U32 chainMask = chainSize-1;
1600 const BYTE* const base = zc->base;
1601 const BYTE* const dictBase = zc->dictBase;
1602 const U32 dictLimit = zc->dictLimit;
1603 const BYTE* const prefixStart = base + dictLimit;
1604 const BYTE* const dictEnd = dictBase + dictLimit;
1605 const U32 lowLimit = zc->lowLimit;
1606 const U32 current = (U32)(ip-base);
1607 const U32 minChain = current > chainSize ? current - chainSize : 0;
1608 int nbAttempts=maxNbAttempts;
1609 size_t ml=EQUAL_READ32-1;
1610
1611 /* HC4 match finder */
1612 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1613
1614 for ( ; (matchIndex>lowLimit) && (nbAttempts) ; nbAttempts--) {
1615 const BYTE* match;
1616 size_t currentMl=0;
1617 if ((!extDict) || matchIndex >= dictLimit) {
1618 match = base + matchIndex;
1619 if (match[ml] == ip[ml]) /* potentially better */
1620 currentMl = ZSTD_count(ip, match, iLimit);
1621 } else {
1622 match = dictBase + matchIndex;
1623 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1624 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1625 }
1626
1627 /* save best solution */
1628 if (currentMl > ml) { ml = currentMl; *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }
1629
1630 if (matchIndex <= minChain) break;
1631 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1632 }
1633
1634 return ml;
1635}
1636
1637
1638FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1639 ZSTD_CCtx* zc,
1640 const BYTE* ip, const BYTE* const iLimit,
1641 size_t* offsetPtr,
1642 const U32 maxNbAttempts, const U32 matchLengthSearch)
1643{
1644 switch(matchLengthSearch)
1645 {
1646 default :
1647 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1648 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1649 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1650 }
1651}
1652
1653
1654FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1655 ZSTD_CCtx* zc,
1656 const BYTE* ip, const BYTE* const iLimit,
1657 size_t* offsetPtr,
1658 const U32 maxNbAttempts, const U32 matchLengthSearch)
1659{
1660 switch(matchLengthSearch)
1661 {
1662 default :
1663 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1664 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1665 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1666 }
1667}
1668
inikep64d7bcb2016-04-07 19:14:09 +02001669
Yann Collet287b7d92015-11-22 13:24:05 +01001670/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001671* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001672*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001673FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001674void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1675 const void* src, size_t srcSize,
1676 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001677{
inikepfaa8d8a2016-04-05 19:01:10 +02001678 seqStore_t* seqStorePtr = &(ctx->seqStore);
1679 const BYTE* const istart = (const BYTE*)src;
1680 const BYTE* ip = istart;
1681 const BYTE* anchor = istart;
1682 const BYTE* const iend = istart + srcSize;
1683 const BYTE* const ilimit = iend - 8;
1684 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001685
Yann Collet793c6492016-04-09 20:32:00 +02001686 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1687 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001688
inikep64d7bcb2016-04-07 19:14:09 +02001689 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1690 size_t* offsetPtr,
1691 U32 maxNbAttempts, U32 matchLengthSearch);
1692 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
1693
inikepfaa8d8a2016-04-05 19:01:10 +02001694 /* init */
1695 U32 rep[ZSTD_REP_INIT];
Yann Colletea63bb72016-04-08 15:25:32 +02001696 { U32 i ; for (i=0; i<ZSTD_REP_INIT; i++) rep[i]=REPCODE_STARTVALUE; }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001697
inikep64d7bcb2016-04-07 19:14:09 +02001698 ctx->nextToUpdate3 = ctx->nextToUpdate;
inikepfaa8d8a2016-04-05 19:01:10 +02001699 ZSTD_resetSeqStore(seqStorePtr);
1700 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001701
inikepfaa8d8a2016-04-05 19:01:10 +02001702 /* Match Loop */
1703 while (ip < ilimit) {
1704 size_t matchLength=0;
1705 size_t offset=0;
1706 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001707
inikepfaa8d8a2016-04-05 19:01:10 +02001708 /* check repCode */
inikep64d7bcb2016-04-07 19:14:09 +02001709 if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep[0])) {
inikepfaa8d8a2016-04-05 19:01:10 +02001710 /* repcode : we take it */
inikep64d7bcb2016-04-07 19:14:09 +02001711 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-rep[0], iend) + EQUAL_READ32;
1712 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001713 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001714
inikepfaa8d8a2016-04-05 19:01:10 +02001715 /* first search (depth 0) */
1716 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001717 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001718 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001719 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001720 }
Yann Collet5106a762015-11-05 15:00:24 +01001721
inikep7bc19b62016-04-06 09:46:01 +02001722 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001723 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1724 continue;
1725 }
1726
inikep64d7bcb2016-04-07 19:14:09 +02001727 /* let's try to find a better solution */
1728 if (depth>=1)
1729 while (ip<ilimit) {
1730 ip ++;
1731 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - rep[0]))) {
1732 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-rep[0], iend) + EQUAL_READ32;
1733 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02001734 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001735 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1736 matchLength = mlRep, offset = 0, start = ip;
1737 }
1738 { size_t offset2=99999999;
1739 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001740 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1741 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02001742 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1743 matchLength = ml2, offset = offset2, start = ip;
1744 continue; /* search a better one */
1745 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001746
inikep64d7bcb2016-04-07 19:14:09 +02001747 /* let's find an even better one */
1748 if ((depth==2) && (ip<ilimit)) {
1749 ip ++;
1750 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - rep[0]))) {
1751 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-rep[0], iend) + EQUAL_READ32;
1752 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02001753 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001754 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1755 matchLength = ml2, offset = 0, start = ip;
1756 }
1757 { size_t offset2=99999999;
1758 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001759 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1760 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02001761 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1762 matchLength = ml2, offset = offset2, start = ip;
1763 continue;
1764 } } }
1765 break; /* nothing found : store previous solution */
1766 }
1767
1768 /* catch up */
1769 if (offset) {
1770 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1771 { start--; matchLength++; }
1772 rep[1] = rep[0]; rep[0] = (U32)(offset - ZSTD_REP_MOVE);
1773 }
1774
inikepfaa8d8a2016-04-05 19:01:10 +02001775 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001776_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001777 { size_t const litLength = start - anchor;
1778 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1779 anchor = ip = start + matchLength;
1780 }
Yann Collet48537162016-04-07 15:24:29 +02001781
inikepfaa8d8a2016-04-05 19:01:10 +02001782 /* check immediate repcode */
1783 while ( (ip <= ilimit)
1784 && (MEM_read32(ip) == MEM_read32(ip - rep[1])) ) {
1785 /* store sequence */
inikep7bc19b62016-04-06 09:46:01 +02001786 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-rep[1], iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001787 offset = rep[1]; rep[1] = rep[0]; rep[0] = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02001788 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1789 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02001790 anchor = ip;
1791 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02001792 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001793
1794 /* Last Literals */
1795 { size_t const lastLLSize = iend - anchor;
1796 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1797 seqStorePtr->lit += lastLLSize;
inikepfb5df612016-05-24 15:36:37 +02001798 ZSTD_statsUpdatePrices(&seqStorePtr->stats, lastLLSize, anchor, 0, 0);
Yann Collet5106a762015-11-05 15:00:24 +01001799 }
Yann Collet5106a762015-11-05 15:00:24 +01001800}
1801
Yann Collet5be2dd22015-11-11 13:43:58 +01001802
inikep64d7bcb2016-04-07 19:14:09 +02001803static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1804{
1805 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
1806}
1807
1808static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1809{
1810 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
1811}
1812
1813static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1814{
1815 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
1816}
1817
1818static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1819{
1820 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
1821}
1822
1823
inikepfaa8d8a2016-04-05 19:01:10 +02001824FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001825void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1826 const void* src, size_t srcSize,
1827 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01001828{
inikepfaa8d8a2016-04-05 19:01:10 +02001829 seqStore_t* seqStorePtr = &(ctx->seqStore);
1830 const BYTE* const istart = (const BYTE*)src;
1831 const BYTE* ip = istart;
1832 const BYTE* anchor = istart;
1833 const BYTE* const iend = istart + srcSize;
1834 const BYTE* const ilimit = iend - 8;
1835 const BYTE* const base = ctx->base;
1836 const U32 dictLimit = ctx->dictLimit;
1837 const BYTE* const prefixStart = base + dictLimit;
1838 const BYTE* const dictBase = ctx->dictBase;
1839 const BYTE* const dictEnd = dictBase + dictLimit;
1840 const BYTE* const dictStart = dictBase + ctx->lowLimit;
1841
1842 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
1843 const U32 mls = ctx->params.cParams.searchLength;
1844
inikep64d7bcb2016-04-07 19:14:09 +02001845 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1846 size_t* offsetPtr,
1847 U32 maxNbAttempts, U32 matchLengthSearch);
1848 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
1849
inikepfaa8d8a2016-04-05 19:01:10 +02001850 /* init */
1851 U32 rep[ZSTD_REP_INIT];
Yann Colletea63bb72016-04-08 15:25:32 +02001852 { U32 i; for (i=0; i<ZSTD_REP_INIT; i++) rep[i]=REPCODE_STARTVALUE; }
inikepfaa8d8a2016-04-05 19:01:10 +02001853
inikep64d7bcb2016-04-07 19:14:09 +02001854 ctx->nextToUpdate3 = ctx->nextToUpdate;
inikepfaa8d8a2016-04-05 19:01:10 +02001855 ZSTD_resetSeqStore(seqStorePtr);
1856 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
1857
1858 /* Match Loop */
1859 while (ip < ilimit) {
1860 size_t matchLength=0;
1861 size_t offset=0;
1862 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02001863 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02001864
1865 /* check repCode */
1866 {
inikep64d7bcb2016-04-07 19:14:09 +02001867 const U32 repIndex = (U32)(current+1 - rep[0]);
inikepfaa8d8a2016-04-05 19:01:10 +02001868 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1869 const BYTE* const repMatch = repBase + repIndex;
1870 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02001871 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02001872 /* repcode detected we should take it */
1873 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02001874 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1875 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02001876 } }
1877
1878 /* first search (depth 0) */
1879 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001880 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001881 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001882 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001883 }
1884
inikep7bc19b62016-04-06 09:46:01 +02001885 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001886 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1887 continue;
1888 }
1889
inikep64d7bcb2016-04-07 19:14:09 +02001890 /* let's try to find a better solution */
1891 if (depth>=1)
1892 while (ip<ilimit) {
1893 ip ++;
1894 current++;
1895 /* check repCode */
1896 if (offset) {
1897 const U32 repIndex = (U32)(current - rep[0]);
1898 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1899 const BYTE* const repMatch = repBase + repIndex;
1900 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
1901 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1902 /* repcode detected */
1903 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
1904 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1905 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02001906 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001907 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
1908 matchLength = repLength, offset = 0, start = ip;
1909 } }
1910
1911 /* search match, depth 1 */
1912 { size_t offset2=99999999;
1913 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001914 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1915 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02001916 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1917 matchLength = ml2, offset = offset2, start = ip;
1918 continue; /* search a better one */
1919 } }
1920
1921 /* let's find an even better one */
1922 if ((depth==2) && (ip<ilimit)) {
1923 ip ++;
1924 current++;
1925 /* check repCode */
1926 if (offset) {
1927 const U32 repIndex = (U32)(current - rep[0]);
1928 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1929 const BYTE* const repMatch = repBase + repIndex;
1930 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
1931 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1932 /* repcode detected */
1933 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
1934 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1935 int gain2 = (int)(repLength * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02001936 int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001937 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
1938 matchLength = repLength, offset = 0, start = ip;
1939 } }
1940
1941 /* search match, depth 2 */
1942 { size_t offset2=99999999;
1943 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001944 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1945 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02001946 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1947 matchLength = ml2, offset = offset2, start = ip;
1948 continue;
1949 } } }
1950 break; /* nothing found : store previous solution */
1951 }
1952
inikepfaa8d8a2016-04-05 19:01:10 +02001953 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001954 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001955 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02001956 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1957 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02001958 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
inikep5ce00ae2016-04-05 21:03:43 +02001959 rep[1] = rep[0]; rep[0] = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02001960 }
inikepfaa8d8a2016-04-05 19:01:10 +02001961
inikepfaa8d8a2016-04-05 19:01:10 +02001962 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001963_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001964 { size_t const litLength = start - anchor;
1965 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1966 anchor = ip = start + matchLength;
1967 }
1968
1969 /* check immediate repcode */
1970 while (ip <= ilimit) {
1971 const U32 repIndex = (U32)((ip-base) - rep[1]);
1972 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1973 const BYTE* const repMatch = repBase + repIndex;
1974 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
1975 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1976 /* repcode detected we should take it */
1977 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001978 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
inikep5ce00ae2016-04-05 21:03:43 +02001979 offset = rep[1]; rep[1] = rep[0]; rep[0] = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02001980 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1981 ip += matchLength;
1982 anchor = ip;
1983 continue; /* faster when present ... (?) */
1984 }
1985 break;
1986 } }
1987
1988 /* Last Literals */
1989 { size_t const lastLLSize = iend - anchor;
1990 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1991 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01001992 }
1993}
1994
1995
Yann Collet59d1f792016-01-23 19:28:41 +01001996void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01001997{
inikep64d7bcb2016-04-07 19:14:09 +02001998 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01001999}
2000
Yann Collet59d1f792016-01-23 19:28:41 +01002001static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002002{
Yann Colleta1249dc2016-01-25 04:22:03 +01002003 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002004}
Yann Collet9a24e592015-11-22 02:53:43 +01002005
Yann Collet59d1f792016-01-23 19:28:41 +01002006static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002007{
Yann Colleta1249dc2016-01-25 04:22:03 +01002008 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002009}
2010
Yann Collet59d1f792016-01-23 19:28:41 +01002011static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002012{
Yann Colleta1249dc2016-01-25 04:22:03 +01002013 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002014}
2015
inikepef519412016-04-21 11:08:43 +02002016
2017
2018/* The optimal parser */
2019#include "zstd_opt.h"
2020
2021static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2022{
2023 ZSTD_compressBlock_opt_generic(ctx, src, srcSize);
2024}
2025
inikepd3b8d7a2016-02-22 10:06:17 +01002026static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002027{
inikep5ce00ae2016-04-05 21:03:43 +02002028 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize);
inikepe2bfe242016-01-31 11:25:48 +01002029}
2030
Yann Collet7a231792015-11-21 15:27:35 +01002031
Yann Collet59d1f792016-01-23 19:28:41 +01002032typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002033
Yann Colletb923f652016-01-26 03:14:20 +01002034static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002035{
inikepd3b8d7a2016-02-22 10:06:17 +01002036 static const ZSTD_blockCompressor blockCompressor[2][6] = {
inikepf8a339d2016-04-05 23:58:51 +02002037#if 1
inikepd3b8d7a2016-02-22 10:06:17 +01002038 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt },
inikep908fcb32016-04-05 18:16:38 +02002039#else
2040 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict },
2041#endif
inikepd3b8d7a2016-02-22 10:06:17 +01002042 { 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 +01002043 };
2044
2045 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002046}
2047
2048
Yann Colletd1b26842016-03-15 01:24:33 +01002049static 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 +01002050{
Yann Collet3b719252016-03-30 19:48:05 +02002051 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01002052 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 +01002053 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002054 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002055}
2056
2057
inikep5cc4efd2016-03-25 10:52:25 +01002058
2059
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002060static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2061 void* dst, size_t dstCapacity,
2062 const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002063{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002064 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002065 size_t remaining = srcSize;
2066 const BYTE* ip = (const BYTE*)src;
2067 BYTE* const ostart = (BYTE*)dst;
2068 BYTE* op = ostart;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002069 const U32 maxDist = 1 << cctx->params.cParams.windowLog;
2070 ZSTD_stats_t* stats = &cctx->seqStore.stats;
inikep5cc4efd2016-03-25 10:52:25 +01002071 ZSTD_statsInit(stats);
Yann Collet9b11b462015-11-01 12:40:22 +01002072
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002073 if (cctx->params.fParams.checksumFlag)
2074 XXH64_update(&cctx->xxhState, src, srcSize);
2075
Yann Collet2ce49232016-02-02 14:36:49 +01002076 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01002077 size_t cSize;
inikep5cc4efd2016-03-25 10:52:25 +01002078 ZSTD_statsResetFreqs(stats);
Yann Collet3e358272015-11-04 18:19:39 +01002079
inikepfb5df612016-05-24 15:36:37 +02002080 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 +01002081 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002082
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002083 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002084 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002085 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2086 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2087 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002088 }
Yann Collet89db5e02015-11-13 11:27:46 +01002089
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002090 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002091 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002092
Yann Collet2ce49232016-02-02 14:36:49 +01002093 if (cSize == 0) { /* block is not compressible */
Yann Colletd1b26842016-03-15 01:24:33 +01002094 cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002095 if (ZSTD_isError(cSize)) return cSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002096 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01002097 op[0] = (BYTE)(cSize>>16);
2098 op[1] = (BYTE)(cSize>>8);
2099 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01002100 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01002101 cSize += 3;
2102 }
2103
2104 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002105 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002106 ip += blockSize;
2107 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002108 }
2109
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002110 ZSTD_statsPrint(stats, cctx->params.cParams.searchLength);
Yann Colletf3eca252015-10-22 15:31:46 +01002111 return op-ostart;
2112}
2113
2114
Yann Collet6236eba2016-04-12 15:52:33 +02002115static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002116 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002117{ BYTE* const op = (BYTE*)dst;
2118 U32 const fcsId = params.fParams.contentSizeFlag ?
2119 (pledgedSrcSize>0) + (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) : /* 0-3 */
2120 0;
Yann Colletc46fb922016-05-29 05:01:04 +02002121 BYTE const fAllocByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) /* windowLog : 4 KB - 128 MB */
Yann Collet6236eba2016-04-12 15:52:33 +02002122 | (fcsId << 6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002123 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002124 BYTE const fCheckByte = (BYTE)((dictIDSizeCode&3) + (params.fParams.checksumFlag<<4));
Yann Colletc46fb922016-05-29 05:01:04 +02002125 size_t pos;
2126
2127 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet6236eba2016-04-12 15:52:33 +02002128
2129 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Colletc46fb922016-05-29 05:01:04 +02002130 op[4] = fAllocByte;
2131 op[5] = fCheckByte;
2132 pos = 6;
2133 switch(dictIDSizeCode)
2134 {
2135 default: /* impossible */
2136 case 0 : break;
2137 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
2138 case 2 : MEM_writeLE16(op+pos, (U16)(dictID)); pos+=2; break;
2139 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2140 }
Yann Collet6236eba2016-04-12 15:52:33 +02002141 switch(fcsId)
2142 {
2143 default: /* impossible */
2144 case 0 : break;
Yann Colletc46fb922016-05-29 05:01:04 +02002145 case 1 : op[pos] = (BYTE)(pledgedSrcSize); pos++; break;
2146 case 2 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2147 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002148 }
Yann Colletc46fb922016-05-29 05:01:04 +02002149 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002150}
2151
2152
Yann Colletbf42c8e2016-01-09 01:08:23 +01002153static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002154 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002155 const void* src, size_t srcSize,
2156 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01002157{
Yann Collet2acb5d32015-10-29 16:49:43 +01002158 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002159 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002160
Yann Collet887e7da2016-04-11 20:12:27 +02002161 if (zc->stage==0) return ERROR(stage_wrong);
2162 if (frame && (zc->stage==1)) { /* copy saved header */
Yann Colletc46fb922016-05-29 05:01:04 +02002163 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, zc->params, srcSize, zc->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002164 if (ZSTD_isError(fhSize)) return fhSize;
2165 dstCapacity -= fhSize;
2166 dst = (char*)dst + fhSize;
Yann Collet887e7da2016-04-11 20:12:27 +02002167 zc->stage = 2;
Yann Colletecd651b2016-01-07 15:35:18 +01002168 }
Yann Colletf3eca252015-10-22 15:31:46 +01002169
Yann Collet417890c2015-12-04 17:16:37 +01002170 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01002171 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002172 /* not contiguous */
Yann Collet70e45772016-03-19 18:08:32 +01002173 size_t const delta = zc->nextSrc - ip;
Yann Collet417890c2015-12-04 17:16:37 +01002174 zc->lowLimit = zc->dictLimit;
2175 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2176 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01002177 zc->base -= delta;
2178 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01002179 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002180 }
2181
Yann Collet89db5e02015-11-13 11:27:46 +01002182 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01002183 if (zc->lowLimit > (1<<30)) {
Yann Collet3b719252016-03-30 19:48:05 +02002184 U32 const btplus = (zc->params.cParams.strategy == ZSTD_btlazy2) || (zc->params.cParams.strategy == ZSTD_btopt);
Yann Collet8a57b922016-04-04 13:49:18 +02002185 U32 const chainMask = (1 << (zc->params.cParams.chainLog - btplus)) - 1;
2186 U32 const newLowLimit = zc->lowLimit & chainMask; /* preserve position % chainSize */
Yann Collet70e45772016-03-19 18:08:32 +01002187 U32 const correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002188 ZSTD_reduceIndex(zc, correction);
2189 zc->base += correction;
2190 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002191 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002192 zc->dictLimit -= correction;
2193 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2194 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01002195 }
2196
Yann Colletbf42c8e2016-01-09 01:08:23 +01002197 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01002198 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01002199 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2200 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002201 }
2202
Yann Colletc3652152015-11-24 14:06:07 +01002203 zc->nextSrc = ip + srcSize;
Yann Collet70e45772016-03-19 18:08:32 +01002204 { size_t const cSize = frame ?
Yann Collet7cbe79a2016-03-23 22:31:57 +01002205 ZSTD_compress_generic (zc, dst, dstCapacity, src, srcSize) :
2206 ZSTD_compressBlock_internal (zc, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002207 if (ZSTD_isError(cSize)) return cSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002208 return cSize + fhSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002209 }
Yann Colletf3eca252015-10-22 15:31:46 +01002210}
2211
Yann Colletbf42c8e2016-01-09 01:08:23 +01002212
2213size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002214 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002215 const void* src, size_t srcSize)
2216{
Yann Collet7cbe79a2016-03-23 22:31:57 +01002217 return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 1);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002218}
2219
2220
Yann Colletd1b26842016-03-15 01:24:33 +01002221size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002222{
Yann Collet569b81a2016-03-16 15:26:51 +01002223 if (srcSize > ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
inikepd6f208b2016-04-04 21:15:23 +02002224 ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.cParams.searchLength);
Yann Colletd1b26842016-03-15 01:24:33 +01002225 return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002226}
2227
2228
Yann Colletb923f652016-01-26 03:14:20 +01002229static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002230{
2231 const BYTE* const ip = (const BYTE*) src;
2232 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002233
Yann Collet417890c2015-12-04 17:16:37 +01002234 /* input becomes current prefix */
2235 zc->lowLimit = zc->dictLimit;
2236 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2237 zc->dictBase = zc->base;
2238 zc->base += ip - zc->nextSrc;
2239 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002240 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002241
2242 zc->nextSrc = iend;
2243 if (srcSize <= 8) return 0;
2244
Yann Collet3b719252016-03-30 19:48:05 +02002245 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002246 {
2247 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002248 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002249 break;
2250
2251 case ZSTD_greedy:
2252 case ZSTD_lazy:
2253 case ZSTD_lazy2:
Yann Collet3b719252016-03-30 19:48:05 +02002254 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002255 break;
2256
2257 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002258 case ZSTD_btopt:
Yann Collet3b719252016-03-30 19:48:05 +02002259 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002260 break;
2261
2262 default:
2263 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2264 }
2265
Yann Collet2ce49232016-02-02 14:36:49 +01002266 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002267 return 0;
2268}
2269
2270
Yann Colletb923f652016-01-26 03:14:20 +01002271/* Dictionary format :
2272 Magic == ZSTD_DICT_MAGIC (4 bytes)
Yann Colletfb797352016-03-13 11:08:40 +01002273 HUF_writeCTable(256)
Yann Colletb923f652016-01-26 03:14:20 +01002274 Dictionary content
2275*/
Yann Colletfb797352016-03-13 11:08:40 +01002276/*! ZSTD_loadDictEntropyStats() :
Yann Colletb923f652016-01-26 03:14:20 +01002277 @return : size read from dictionary */
2278static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2279{
2280 /* note : magic number already checked */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002281 size_t const dictSizeStart = dictSize;
Yann Colletfb810d62016-01-28 00:18:06 +01002282
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002283 { size_t const hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize);
2284 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
2285 zc->flagStaticTables = 1;
2286 dict = (const char*)dict + hufHeaderSize;
2287 dictSize -= hufHeaderSize;
2288 }
Yann Colletfb810d62016-01-28 00:18:06 +01002289
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002290 { short offcodeNCount[MaxOff+1];
2291 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2292 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
2293 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2294 { size_t const errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2295 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
2296 dict = (const char*)dict + offcodeHeaderSize;
2297 dictSize -= offcodeHeaderSize;
2298 }
Yann Colletfb810d62016-01-28 00:18:06 +01002299
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002300 { short matchlengthNCount[MaxML+1];
2301 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2302 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
2303 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2304 { size_t const errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2305 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
2306 dict = (const char*)dict + matchlengthHeaderSize;
2307 dictSize -= matchlengthHeaderSize;
2308 }
Yann Colletfb810d62016-01-28 00:18:06 +01002309
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002310 { short litlengthNCount[MaxLL+1];
2311 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2312 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
2313 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2314 { size_t const errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2315 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
2316 dictSize -= litlengthHeaderSize;
2317 }
Yann Colletfb810d62016-01-28 00:18:06 +01002318
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002319 return (dictSizeStart-dictSize);
Yann Colletb923f652016-01-26 03:14:20 +01002320}
2321
Yann Colletd1b26842016-03-15 01:24:33 +01002322/** ZSTD_compress_insertDictionary() :
2323* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002324static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002325{
Yann Colletc46fb922016-05-29 05:01:04 +02002326 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002327
Yann Colletd1b26842016-03-15 01:24:33 +01002328 /* default : dict is pure content */
2329 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletc46fb922016-05-29 05:01:04 +02002330 zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4);
Yann Colletd1b26842016-03-15 01:24:33 +01002331
2332 /* known magic number : dict is parsed for entropy stats and content */
Yann Colletc46fb922016-05-29 05:01:04 +02002333 { size_t const eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8) + 8;
Yann Collet21588e32016-03-30 16:50:44 +02002334 if (ZSTD_isError(eSize)) return eSize;
2335 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002336 }
Yann Colletecd651b2016-01-07 15:35:18 +01002337}
2338
Yann Collet0085cd32016-04-12 14:14:10 +02002339
Yann Collet27caf2a2016-04-01 15:48:48 +02002340/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002341* @return : 0, or an error code */
Yann Collet27caf2a2016-04-01 15:48:48 +02002342static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* zc,
Yann Collet1c8e1942016-01-26 16:31:22 +01002343 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002344 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002345{
Yann Colletc46fb922016-05-29 05:01:04 +02002346 { U32 const hashLog3 = (!pledgedSrcSize || pledgedSrcSize >= 8192) ? ZSTD_HASHLOG3_MAX : ((pledgedSrcSize >= 2048) ? ZSTD_HASHLOG3_MIN + 1 : ZSTD_HASHLOG3_MIN);
Yann Collet6236eba2016-04-12 15:52:33 +02002347 zc->hashLog3 = (params.cParams.searchLength==3) ? hashLog3 : 0; }
Yann Collet88fcd292015-11-25 14:42:45 +01002348
Yann Colletabb5c652016-04-11 20:42:31 +02002349 { size_t const resetError = ZSTD_resetCCtx_advanced(zc, params, 1);
2350 if (ZSTD_isError(resetError)) return resetError; }
Yann Collet89db5e02015-11-13 11:27:46 +01002351
Yann Collet1c8e1942016-01-26 16:31:22 +01002352 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002353}
2354
2355
Yann Collet27caf2a2016-04-01 15:48:48 +02002356/*! ZSTD_compressBegin_advanced() :
2357* @return : 0, or an error code */
2358size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
2359 const void* dict, size_t dictSize,
2360 ZSTD_parameters params, U64 pledgedSrcSize)
2361{
2362 /* compression parameters verification and optimization */
2363 { size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize);
2364 if (ZSTD_isError(errorCode)) return errorCode; }
2365
2366 return ZSTD_compressBegin_internal(zc, dict, dictSize, params, pledgedSrcSize);
2367}
2368
2369
Yann Collet1c8e1942016-01-26 16:31:22 +01002370size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002371{
Yann Collet3b719252016-03-30 19:48:05 +02002372 ZSTD_parameters params;
Yann Colletc46fb922016-05-29 05:01:04 +02002373 memset(&params, 0, sizeof(params));
Yann Collet3b719252016-03-30 19:48:05 +02002374 params.cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
inikepa4dde252016-03-01 14:14:35 +01002375 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet27caf2a2016-04-01 15:48:48 +02002376 return ZSTD_compressBegin_internal(zc, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002377}
Yann Collet083fcc82015-10-25 14:06:35 +01002378
inikep19bd48f2016-04-04 12:10:00 +02002379
Yann Collet1c8e1942016-01-26 16:31:22 +01002380size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002381{
inikepa4dde252016-03-01 14:14:35 +01002382 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet3b719252016-03-30 19:48:05 +02002383 return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002384}
2385
2386
Yann Colletfb797352016-03-13 11:08:40 +01002387/*! ZSTD_compressEnd() :
2388* Write frame epilogue.
Yann Collet88fcd292015-11-25 14:42:45 +01002389* @return : nb of bytes written into dst (or an error code) */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002390size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002391{
2392 BYTE* op = (BYTE*)dst;
Yann Collet6236eba2016-04-12 15:52:33 +02002393 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002394
Yann Collet887e7da2016-04-11 20:12:27 +02002395 /* not even init ! */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002396 if (cctx->stage==0) return ERROR(stage_wrong);
Yann Collet887e7da2016-04-11 20:12:27 +02002397
2398 /* special case : empty frame */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002399 if (cctx->stage==1) {
2400 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002401 if (ZSTD_isError(fhSize)) return fhSize;
2402 dstCapacity -= fhSize;
2403 op += fhSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002404 cctx->stage = 2;
Yann Colletecd651b2016-01-07 15:35:18 +01002405 }
2406
2407 /* frame epilogue */
Yann Colletd1b26842016-03-15 01:24:33 +01002408 if (dstCapacity < 3) return ERROR(dstSize_tooSmall);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002409 { U32 const checksum = cctx->params.fParams.checksumFlag ?
2410 (U32)((XXH64_digest(&cctx->xxhState) >> 11) & ((1<<22)-1)) :
2411 0;
2412 op[0] = (BYTE)((bt_end<<6) + (checksum>>16));
2413 op[1] = (BYTE)(checksum>>8);
2414 op[2] = (BYTE)checksum;
2415 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002416
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002417 cctx->stage = 0; /* return to "created but not init" status */
Yann Collet6236eba2016-04-12 15:52:33 +02002418 return 3+fhSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002419}
2420
Yann Colletfd416f12016-01-30 03:14:15 +01002421
2422size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
Yann Colletd1b26842016-03-15 01:24:33 +01002423 void* dst, size_t dstCapacity,
Yann Colletfd416f12016-01-30 03:14:15 +01002424 const void* src, size_t srcSize)
2425{
Yann Collet70e45772016-03-19 18:08:32 +01002426 { size_t const errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2427 if (ZSTD_isError(errorCode)) return errorCode;
2428 }
2429 { size_t const cSize = ZSTD_compressContinue(cctx, dst, dstCapacity, src, srcSize);
2430 if (ZSTD_isError(cSize)) return cSize;
Yann Collet0dbf2872016-04-08 02:02:12 +02002431
Yann Collet70e45772016-03-19 18:08:32 +01002432 { size_t const endSize = ZSTD_compressEnd(cctx, (char*)dst+cSize, dstCapacity-cSize);
2433 if (ZSTD_isError(endSize)) return endSize;
2434 return cSize + endSize;
2435 } }
Yann Colletfd416f12016-01-30 03:14:15 +01002436}
2437
2438
Yann Collet21588e32016-03-30 16:50:44 +02002439static size_t ZSTD_compress_internal (ZSTD_CCtx* ctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002440 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002441 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002442 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002443 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002444{
2445 BYTE* const ostart = (BYTE*)dst;
2446 BYTE* op = ostart;
2447
Yann Collet1c8e1942016-01-26 16:31:22 +01002448 /* Init */
Yann Collet27caf2a2016-04-01 15:48:48 +02002449 { size_t const errorCode = ZSTD_compressBegin_internal(ctx, dict, dictSize, params, srcSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002450 if(ZSTD_isError(errorCode)) return errorCode; }
Yann Colletf3eca252015-10-22 15:31:46 +01002451
2452 /* body (compression) */
Yann Colletd1b26842016-03-15 01:24:33 +01002453 { size_t const oSize = ZSTD_compressContinue (ctx, op, dstCapacity, src, srcSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002454 if(ZSTD_isError(oSize)) return oSize;
2455 op += oSize;
2456 dstCapacity -= oSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002457
2458 /* Close frame */
Yann Colletd1b26842016-03-15 01:24:33 +01002459 { size_t const oSize = ZSTD_compressEnd(ctx, op, dstCapacity);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002460 if(ZSTD_isError(oSize)) return oSize;
2461 op += oSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002462
2463 return (op - ostart);
2464}
2465
Yann Collet21588e32016-03-30 16:50:44 +02002466size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2467 void* dst, size_t dstCapacity,
2468 const void* src, size_t srcSize,
2469 const void* dict,size_t dictSize,
2470 ZSTD_parameters params)
2471{
Yann Collet3b719252016-03-30 19:48:05 +02002472 size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, srcSize);
Yann Collet21588e32016-03-30 16:50:44 +02002473 if (ZSTD_isError(errorCode)) return errorCode;
2474 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2475}
2476
Yann Colletd1b26842016-03-15 01:24:33 +01002477size_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 +01002478{
Yann Collet3b719252016-03-30 19:48:05 +02002479 ZSTD_parameters params;
Yann Colletc46fb922016-05-29 05:01:04 +02002480 memset(&params, 0, sizeof(params));
inikepa4dde252016-03-01 14:14:35 +01002481 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 +02002482 params.cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
2483 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002484 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002485}
2486
Yann Colletd1b26842016-03-15 01:24:33 +01002487size_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 +01002488{
inikepa4dde252016-03-01 14:14:35 +01002489 ZSTD_LOG_BLOCK("%p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, compressionLevel);
Yann Collet21588e32016-03-30 16:50:44 +02002490 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002491}
2492
Yann Colletd1b26842016-03-15 01:24:33 +01002493size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002494{
Yann Collet44fe9912015-10-29 22:02:40 +01002495 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002496 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002497 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002498 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002499 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
inikep28669512016-06-02 13:04:18 +02002500 ctxBody.customMem.customFree(ctxBody.customMem.opaque, ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002501 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002502}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002503
Yann Colletfd416f12016-01-30 03:14:15 +01002504
Yann Collet70e8c382016-02-10 13:37:52 +01002505/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01002506
Yann Collet236d94f2016-05-18 12:06:33 +02002507#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02002508#define ZSTD_MAX_CLEVEL 22
Yann Collet7d968c72016-02-03 02:11:32 +01002509unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2510
Yann Collet3b719252016-03-30 19:48:05 +02002511static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01002512{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02002513 /* W, C, H, S, L, TL, strat */
Yann Collet3b719252016-03-30 19:48:05 +02002514 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2515 { 19, 13, 14, 1, 7, 4, ZSTD_fast }, /* level 1 */
2516 { 19, 15, 16, 1, 6, 4, ZSTD_fast }, /* level 2 */
2517 { 20, 18, 20, 1, 6, 4, ZSTD_fast }, /* level 3 */
2518 { 20, 13, 17, 2, 5, 4, ZSTD_greedy }, /* level 4.*/
2519 { 20, 15, 18, 3, 5, 4, ZSTD_greedy }, /* level 5 */
2520 { 21, 16, 19, 2, 5, 4, ZSTD_lazy }, /* level 6 */
2521 { 21, 17, 20, 3, 5, 4, ZSTD_lazy }, /* level 7 */
2522 { 21, 18, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 8.*/
2523 { 21, 20, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 9 */
2524 { 21, 19, 21, 4, 5, 4, ZSTD_lazy2 }, /* level 10 */
2525 { 22, 20, 22, 4, 5, 4, ZSTD_lazy2 }, /* level 11 */
2526 { 22, 20, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 12 */
2527 { 22, 21, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 13 */
2528 { 22, 21, 22, 6, 5, 4, ZSTD_lazy2 }, /* level 14 */
2529 { 22, 21, 21, 5, 5, 4, ZSTD_btlazy2 }, /* level 15 */
2530 { 23, 22, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */
Yann Collet793c6492016-04-09 20:32:00 +02002531 { 23, 23, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 17.*/
2532 { 23, 23, 22, 6, 5, 24, ZSTD_btopt }, /* level 18.*/
2533 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19.*/
2534 { 25, 26, 23, 7, 3, 64, ZSTD_btopt }, /* level 20.*/
2535 { 26, 26, 23, 7, 3,256, ZSTD_btopt }, /* level 21.*/
2536 { 27, 27, 25, 9, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002537},
2538{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002539 /* W, C, H, S, L, T, strat */
2540 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 */
Yann Collet0dbf2872016-04-08 02:02:12 +02002541 { 18, 13, 14, 1, 6, 4, ZSTD_fast }, /* level 1 */
Yann Collet78267d12016-04-08 12:36:19 +02002542 { 18, 15, 17, 1, 5, 4, ZSTD_fast }, /* level 2 */
2543 { 18, 13, 15, 1, 5, 4, ZSTD_greedy }, /* level 3.*/
2544 { 18, 15, 17, 1, 5, 4, ZSTD_greedy }, /* level 4.*/
2545 { 18, 16, 17, 4, 5, 4, ZSTD_greedy }, /* level 5 */
2546 { 18, 17, 17, 5, 5, 4, ZSTD_greedy }, /* level 6 */
Yann Collet3b719252016-03-30 19:48:05 +02002547 { 18, 17, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */
2548 { 18, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2549 { 18, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2550 { 18, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
Yann Collet78267d12016-04-08 12:36:19 +02002551 { 18, 18, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 11.*/
2552 { 18, 18, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 12.*/
2553 { 18, 19, 17, 7, 4, 4, ZSTD_btlazy2 }, /* level 13 */
2554 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
2555 { 18, 18, 18, 8, 4, 24, ZSTD_btopt }, /* level 15.*/
2556 { 18, 19, 18, 8, 3, 48, ZSTD_btopt }, /* level 16.*/
2557 { 18, 19, 18, 8, 3, 96, ZSTD_btopt }, /* level 17.*/
2558 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
2559 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
2560 { 18, 19, 18, 11, 3,512, ZSTD_btopt }, /* level 20.*/
2561 { 18, 19, 18, 12, 3,512, ZSTD_btopt }, /* level 21.*/
2562 { 18, 19, 18, 13, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002563},
2564{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002565 /* W, C, H, S, L, T, strat */
2566 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2567 { 17, 12, 13, 1, 6, 4, ZSTD_fast }, /* level 1 */
2568 { 17, 13, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */
2569 { 17, 13, 14, 2, 5, 4, ZSTD_greedy }, /* level 3 */
2570 { 17, 13, 15, 3, 4, 4, ZSTD_greedy }, /* level 4 */
2571 { 17, 15, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */
2572 { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
2573 { 17, 15, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 7 */
2574 { 17, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2575 { 17, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2576 { 17, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
2577 { 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */
2578 { 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */
2579 { 17, 18, 17, 6, 4, 4, ZSTD_btlazy2 }, /* level 13.*/
2580 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
2581 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
2582 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
2583 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
2584 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
2585 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
2586 { 17, 18, 17, 9, 3,256, ZSTD_btopt }, /* level 20.*/
2587 { 17, 18, 17, 10, 3,256, ZSTD_btopt }, /* level 21.*/
2588 { 17, 18, 17, 11, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002589},
2590{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002591 /* W, C, H, S, L, T, strat */
2592 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 -- never used */
2593 { 14, 14, 14, 1, 4, 4, ZSTD_fast }, /* level 1 */
2594 { 14, 14, 15, 1, 4, 4, ZSTD_fast }, /* level 2 */
2595 { 14, 14, 14, 4, 4, 4, ZSTD_greedy }, /* level 3.*/
2596 { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 4.*/
2597 { 14, 14, 14, 4, 4, 4, ZSTD_lazy2 }, /* level 5 */
2598 { 14, 14, 14, 5, 4, 4, ZSTD_lazy2 }, /* level 6 */
2599 { 14, 14, 14, 6, 4, 4, ZSTD_lazy2 }, /* level 7.*/
2600 { 14, 14, 14, 7, 4, 4, ZSTD_lazy2 }, /* level 8.*/
2601 { 14, 15, 14, 6, 4, 4, ZSTD_btlazy2 }, /* level 9.*/
2602 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
2603 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
2604 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
2605 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
2606 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
2607 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
2608 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
2609 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
2610 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
2611 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
2612 { 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 20.*/
2613 { 14, 15, 15, 9, 3,256, ZSTD_btopt }, /* level 21.*/
2614 { 14, 15, 15, 10, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002615},
2616};
2617
Yann Collet236d94f2016-05-18 12:06:33 +02002618/*! ZSTD_getCParams() :
2619* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
2620* Size values are optional, provide 0 if not known or unused */
Yann Collet3b719252016-03-30 19:48:05 +02002621ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, U64 srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01002622{
Yann Collet15354142016-04-04 04:22:53 +02002623 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02002624 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02002625 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02002626 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02002627 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01002628 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02002629 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02002630 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
2631 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02002632 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02002633 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
2634 }
Yann Collet70d13012016-06-01 18:45:34 +02002635 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02002636 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01002637}