blob: 058bab9abe60f92698a6e8582ef0c78c5aff5e67 [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 Colletd0e2cd12016-06-05 00:58:01 +020058#define FSE_STATIC_LINKING_ONLY
59#include "fse.h"
Yann Collet130fe112016-06-05 00:42:28 +020060#define HUF_STATIC_LINKING_ONLY
61#include "huf.h"
Yann Colletd3b7f8d2016-06-04 19:47:02 +020062#include "zstd_internal.h" /* includes zstd.h */
Yann Colletf3eca252015-10-22 15:31:46 +010063
64
Yann Collet7d360282016-02-12 00:07:30 +010065/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010066* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010067***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010068static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Colletf3eca252015-10-22 15:31:46 +010069
Yann Colletf3eca252015-10-22 15:31:46 +010070
Yann Collet7d360282016-02-12 00:07:30 +010071/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010072* Helper functions
73***************************************/
Yann Collet59d1f792016-01-23 19:28:41 +010074size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
75
Yann Collet49bb0042016-06-04 20:17:38 +020076static U32 ZSTD_highbit32(U32 val)
77{
78# if defined(_MSC_VER) /* Visual */
79 unsigned long r=0;
80 _BitScanReverse(&r, val);
81 return (unsigned)r;
82# elif defined(__GNUC__) && (__GNUC__ >= 3) /* GCC Intrinsic */
83 return 31 - __builtin_clz(val);
84# else /* Software version */
85 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 };
86 U32 v = val;
87 int r;
88 v |= v >> 1;
89 v |= v >> 2;
90 v |= v >> 4;
91 v |= v >> 8;
92 v |= v >> 16;
93 r = DeBruijnClz[(U32)(v * 0x07C4ACDDU) >> 27];
94 return r;
95# endif
96}
Yann Collet59d1f792016-01-23 19:28:41 +010097
Yann Collet7d360282016-02-12 00:07:30 +010098/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010099* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +0100100***************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100101static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
102{
103 ssPtr->offset = ssPtr->offsetStart;
104 ssPtr->lit = ssPtr->litStart;
105 ssPtr->litLength = ssPtr->litLengthStart;
106 ssPtr->matchLength = ssPtr->matchLengthStart;
Yann Collet5d393572016-04-07 17:19:00 +0200107 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100108}
109
110
Yann Collet7d360282016-02-12 00:07:30 +0100111/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100112* Context memory management
113***************************************/
Yann Collet5be2dd22015-11-11 13:43:58 +0100114struct ZSTD_CCtx_s
Yann Colletf3eca252015-10-22 15:31:46 +0100115{
Yann Collet89db5e02015-11-13 11:27:46 +0100116 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100117 const BYTE* base; /* All regular indexes relative to this position */
118 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +0100119 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100120 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +0100121 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +0100122 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +0100123 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Collet2ce49232016-02-02 14:36:49 +0100124 U32 loadedDictEnd;
Yann Collet887e7da2016-04-11 20:12:27 +0200125 U32 stage; /* 0: created; 1: init,dictLoad; 2:started */
Yann Collet4266c0a2016-06-14 01:49:25 +0200126 U32 rep[ZSTD_REP_NUM];
127 U32 savedRep[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +0200128 U32 dictID;
Yann Collet5be2dd22015-11-11 13:43:58 +0100129 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +0100130 void* workSpace;
131 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100132 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +0200133 U64 frameContentSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200134 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +0200135 ZSTD_customMem customMem;
Yann Colletecd651b2016-01-07 15:35:18 +0100136
Yann Collet712def92015-10-29 18:41:45 +0100137 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100138 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +0100139 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +0200140 U32* chainTable;
Yann Colletb923f652016-01-26 03:14:20 +0100141 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +0100142 U32 flagStaticTables;
143 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
144 FSE_CTable matchlengthCTable [FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
145 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Colletf3eca252015-10-22 15:31:46 +0100146};
147
Yann Collet5be2dd22015-11-11 13:43:58 +0100148ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100149{
inikep3763c772016-06-03 13:28:20 +0200150 return ZSTD_createCCtx_advanced(defaultCustomMem);
inikep50e82c02016-05-23 15:49:09 +0200151}
152
153ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
154{
inikep107e2432016-05-23 16:24:52 +0200155 ZSTD_CCtx* ctx;
inikep50e82c02016-05-23 15:49:09 +0200156
inikep13ba8802016-05-23 17:04:23 +0200157 if (!customMem.customAlloc && !customMem.customFree)
inikep36fac002016-06-03 13:23:04 +0200158 customMem = defaultCustomMem;
inikep107e2432016-05-23 16:24:52 +0200159
inikep13ba8802016-05-23 17:04:23 +0200160 if (!customMem.customAlloc || !customMem.customFree)
161 return NULL;
162
inikep28669512016-06-02 13:04:18 +0200163 ctx = (ZSTD_CCtx*) customMem.customAlloc(customMem.opaque, sizeof(ZSTD_CCtx));
inikep50e82c02016-05-23 15:49:09 +0200164 if (!ctx) return NULL;
inikep50e82c02016-05-23 15:49:09 +0200165 memset(ctx, 0, sizeof(ZSTD_CCtx));
inikep28669512016-06-02 13:04:18 +0200166 memcpy(&ctx->customMem, &customMem, sizeof(ZSTD_customMem));
inikep50e82c02016-05-23 15:49:09 +0200167 return ctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100168}
169
Yann Collet5be2dd22015-11-11 13:43:58 +0100170size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100171{
inikep36403962016-06-03 16:36:50 +0200172 if (cctx==NULL) return 0; /* support free on NULL */
173 if (cctx->workSpace) cctx->customMem.customFree(cctx->customMem.opaque, cctx->workSpace);
inikep28669512016-06-02 13:04:18 +0200174 cctx->customMem.customFree(cctx->customMem.opaque, cctx);
Yann Collet982ffc72016-02-05 02:33:10 +0100175 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100176}
177
Yann Colletb44be742016-03-26 20:52:14 +0100178const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100179{
Yann Colletb44be742016-03-26 20:52:14 +0100180 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100181}
182
Yann Collet59d70632015-11-04 12:05:27 +0100183
Yann Collet21588e32016-03-30 16:50:44 +0200184#define CLAMP(val,min,max) { if (val<min) val=min; else if (val>max) val=max; }
185#define CLAMPCHECK(val,min,max) { if ((val<min) || (val>max)) return ERROR(compressionParameter_unsupported); }
186
187/** ZSTD_checkParams() :
188 ensure param values remain within authorized range.
189 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200190size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200191{
Yann Collet15354142016-04-04 04:22:53 +0200192 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200193 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200194 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
195 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
inikep75716852016-04-06 12:34:42 +0200196 { 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 +0200197 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
198 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
199 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Collet9bb87e52016-03-30 21:28:15 +0200200 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200201 return 0;
202}
203
204
Yann Collet3b719252016-03-30 19:48:05 +0200205/** ZSTD_checkCParams_advanced() :
206 temporary work-around, while the compressor compatibility remains limited regarding windowLog < 18 */
207size_t ZSTD_checkCParams_advanced(ZSTD_compressionParameters cParams, U64 srcSize)
208{
Yann Colletefb18302016-04-01 18:54:13 +0200209 if (srcSize > (1ULL << ZSTD_WINDOWLOG_MIN)) return ZSTD_checkCParams(cParams);
Yann Collet3b719252016-03-30 19:48:05 +0200210 if (cParams.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) return ERROR(compressionParameter_unsupported);
Yann Collet8a57b922016-04-04 13:49:18 +0200211 if (srcSize <= (1ULL << cParams.windowLog)) cParams.windowLog = ZSTD_WINDOWLOG_MIN; /* fake value - temporary work around */
212 if (srcSize <= (1ULL << cParams.chainLog)) cParams.chainLog = ZSTD_CHAINLOG_MIN; /* fake value - temporary work around */
Yann Colletef363902016-04-02 00:46:40 +0200213 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 +0200214 return ZSTD_checkCParams(cParams);
215}
216
217
Yann Collet70d13012016-06-01 18:45:34 +0200218/** ZSTD_adjustCParams() :
219 optimize cPar for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200220 mostly downsizing to reduce memory consumption and initialization.
221 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
222 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200223 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
224ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, U64 srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100225{
Yann Collet70d13012016-06-01 18:45:34 +0200226 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100227
Yann Collet70e45772016-03-19 18:08:32 +0100228 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200229 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
230 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200231 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Collet49bb0042016-06-04 20:17:38 +0200232 U32 const srcLog = ZSTD_highbit32((U32)(rSize)-1) + 1;
Yann Collet70d13012016-06-01 18:45:34 +0200233 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200234 } }
Yann Collet70d13012016-06-01 18:45:34 +0200235 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
236 { U32 const btPlus = (cPar.strategy == ZSTD_btlazy2) || (cPar.strategy == ZSTD_btopt);
237 U32 const maxChainLog = cPar.windowLog+btPlus;
238 if (cPar.chainLog > maxChainLog) cPar.chainLog = maxChainLog; } /* <= ZSTD_CHAINLOG_MAX */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100239
Yann Collet70d13012016-06-01 18:45:34 +0200240 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
241 if ((cPar.hashLog < ZSTD_HASHLOG_MIN) && ( (U32)cPar.strategy >= (U32)ZSTD_btlazy2)) cPar.hashLog = ZSTD_HASHLOG_MIN; /* required to ensure collision resistance in bt */
242
243 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100244}
245
246
Yann Collet51d50042016-03-30 20:42:19 +0200247size_t ZSTD_sizeofCCtx(ZSTD_compressionParameters cParams) /* hidden interface, for paramagrill */
Yann Collete74215e2016-03-19 16:09:09 +0100248{
Yann Collet06d9a732016-06-19 14:27:21 +0200249 ZSTD_CCtx* const zc = ZSTD_createCCtx();
Yann Collet51d50042016-03-30 20:42:19 +0200250 ZSTD_parameters params;
Yann Colletc46fb922016-05-29 05:01:04 +0200251 memset(&params, 0, sizeof(params));
Yann Collet51d50042016-03-30 20:42:19 +0200252 params.cParams = cParams;
253 params.fParams.contentSizeFlag = 1;
Yann Collet3b719252016-03-30 19:48:05 +0200254 ZSTD_compressBegin_advanced(zc, NULL, 0, params, 0);
Yann Colletd64f4352016-03-21 00:07:42 +0100255 { size_t const ccsize = sizeof(*zc) + zc->workSpaceSize;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100256 ZSTD_freeCCtx(zc);
Yann Colletd64f4352016-03-21 00:07:42 +0100257 return ccsize; }
Yann Collet2e91dde2016-03-08 12:22:11 +0100258}
259
Yann Collet27caf2a2016-04-01 15:48:48 +0200260/*! ZSTD_resetCCtx_advanced() :
261 note : 'params' is expected to be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100262static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Collet673f0d72016-06-06 00:26:38 +0200263 ZSTD_parameters params, U64 frameContentSize, U32 reset)
Yann Collet863ec402016-01-28 17:56:33 +0100264{ /* note : params considered validated here */
Yann Collet3b719252016-03-30 19:48:05 +0200265 const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
266 const U32 divider = (params.cParams.searchLength==3) ? 3 : 4;
Yann Colletdd54bbc2016-03-08 02:35:34 +0100267 const size_t maxNbSeq = blockSize / divider;
Yann Colletbe391432016-03-22 23:19:28 +0100268 const size_t tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet8a57b922016-04-04 13:49:18 +0200269 const size_t chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
inikep1007a1f2016-04-25 15:23:09 +0200270 const size_t hSize = ((size_t)1) << params.cParams.hashLog;
Yann Collet673f0d72016-06-06 00:26:38 +0200271 const U32 hashLog3 = (params.cParams.searchLength>3) ? 0 :
272 ( (!frameContentSize || frameContentSize >= 8192) ? ZSTD_HASHLOG3_MAX :
273 ((frameContentSize >= 2048) ? ZSTD_HASHLOG3_MIN + 1 : ZSTD_HASHLOG3_MIN) );
Yann Collet142acbd2016-06-06 00:46:56 +0200274 const size_t h3Size = ((size_t)1) << hashLog3;
Yann Collet8a57b922016-04-04 13:49:18 +0200275 const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
inikep87d4f3d2016-03-02 15:56:24 +0100276
Yann Collete74215e2016-03-19 16:09:09 +0100277 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Collet48537162016-04-07 15:24:29 +0200278 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
Yann Collete74215e2016-03-19 16:09:09 +0100279 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
280 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Yann Collet1005fc12016-04-04 13:28:28 +0200281 + ((params.cParams.strategy == ZSTD_btopt) ? optSpace : 0);
Yann Collete74215e2016-03-19 16:09:09 +0100282 if (zc->workSpaceSize < neededSpace) {
inikep28669512016-06-02 13:04:18 +0200283 zc->customMem.customFree(zc->customMem.opaque, zc->workSpace);
284 zc->workSpace = zc->customMem.customAlloc(zc->customMem.opaque, neededSpace);
Yann Collete74215e2016-03-19 16:09:09 +0100285 if (zc->workSpace == NULL) return ERROR(memory_allocation);
286 zc->workSpaceSize = neededSpace;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100287 } }
Yann Collete74215e2016-03-19 16:09:09 +0100288
Yann Colletabb5c652016-04-11 20:42:31 +0200289 if (reset) memset(zc->workSpace, 0, tableSpace ); /* reset only tables */
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200290 XXH64_reset(&zc->xxhState, 0);
Yann Collet673f0d72016-06-06 00:26:38 +0200291 zc->hashLog3 = hashLog3;
Yann Collete3d52942016-06-06 11:07:33 +0200292 zc->hashTable = (U32*)(zc->workSpace);
Yann Collet8a57b922016-04-04 13:49:18 +0200293 zc->chainTable = zc->hashTable + hSize;
Yann Collete3d52942016-06-06 11:07:33 +0200294 zc->hashTable3 = zc->chainTable + chainSize;
295 zc->seqStore.buffer = zc->hashTable3 + h3Size;
Yann Collet863ec402016-01-28 17:56:33 +0100296 zc->hufTable = (HUF_CElt*)zc->seqStore.buffer;
297 zc->flagStaticTables = 0;
Yann Collet3755eb82016-06-22 13:15:53 +0200298 zc->seqStore.buffer = ((U32*)(zc->seqStore.buffer)) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
Yann Collet083fcc82015-10-25 14:06:35 +0100299
Yann Colletf48e35c2015-11-07 01:13:31 +0100300 zc->nextToUpdate = 1;
Yann Collet89db5e02015-11-13 11:27:46 +0100301 zc->nextSrc = NULL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100302 zc->base = NULL;
303 zc->dictBase = NULL;
304 zc->dictLimit = 0;
305 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100306 zc->params = params;
Yann Collet120230b2015-12-02 14:00:45 +0100307 zc->blockSize = blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +0200308 zc->frameContentSize = frameContentSize;
Yann Collet4266c0a2016-06-14 01:49:25 +0200309 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
Yann Collet70e8c382016-02-10 13:37:52 +0100310
Yann Collet3b719252016-03-30 19:48:05 +0200311 if (params.cParams.strategy == ZSTD_btopt) {
Yann Collet72d706a2016-03-23 20:44:12 +0100312 zc->seqStore.litFreq = (U32*)(zc->seqStore.buffer);
313 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
314 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
315 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
Yann Collet3755eb82016-06-22 13:15:53 +0200316 zc->seqStore.buffer = zc->seqStore.offCodeFreq + (MaxOff+1);
317 zc->seqStore.matchTable = (ZSTD_match_t*)zc->seqStore.buffer;
318 zc->seqStore.buffer = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
319 zc->seqStore.priceTable = (ZSTD_optimal_t*)zc->seqStore.buffer;
Yann Collet72d706a2016-03-23 20:44:12 +0100320 zc->seqStore.buffer = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
321 zc->seqStore.litLengthSum = 0;
322 }
Yann Collet3755eb82016-06-22 13:15:53 +0200323 zc->seqStore.offsetStart = (U32*)(zc->seqStore.buffer);
324 zc->seqStore.buffer = zc->seqStore.offsetStart + maxNbSeq;
325 zc->seqStore.litLengthStart = (U16*)zc->seqStore.buffer;
326 zc->seqStore.matchLengthStart = zc->seqStore.litLengthStart + maxNbSeq;
Yann Colletfadda6c2016-03-22 12:14:26 +0100327 zc->seqStore.llCodeStart = (BYTE*) (zc->seqStore.matchLengthStart + maxNbSeq);
328 zc->seqStore.mlCodeStart = zc->seqStore.llCodeStart + maxNbSeq;
329 zc->seqStore.offCodeStart = zc->seqStore.mlCodeStart + maxNbSeq;
Yann Colletdd54bbc2016-03-08 02:35:34 +0100330 zc->seqStore.litStart = zc->seqStore.offCodeStart + maxNbSeq;
inikep5cccd772016-03-02 20:37:49 +0100331
Yann Collet887e7da2016-04-11 20:12:27 +0200332 zc->stage = 1;
Yann Colletc46fb922016-05-29 05:01:04 +0200333 zc->dictID = 0;
Yann Collet2ce49232016-02-02 14:36:49 +0100334 zc->loadedDictEnd = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +0100335
Yann Collet4114f952015-10-30 06:40:22 +0100336 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100337}
338
Yann Collet083fcc82015-10-25 14:06:35 +0100339
Yann Collet370b08e2016-03-08 00:03:59 +0100340/*! ZSTD_copyCCtx() :
341* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet887e7da2016-04-11 20:12:27 +0200342* Only works during stage 1 (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100343* @return : 0, or an error code */
344size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
345{
Yann Collet887e7da2016-04-11 20:12:27 +0200346 if (srcCCtx->stage!=1) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100347
inikep28669512016-06-02 13:04:18 +0200348 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Yann Collet673f0d72016-06-06 00:26:38 +0200349 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, srcCCtx->frameContentSize, 0);
Yann Collet389648c2016-04-12 19:13:08 +0200350 dstCCtx->params.fParams.contentSizeFlag = 0; /* content size different from the one set during srcCCtx init */
Yann Collet7b51a292016-01-26 15:58:49 +0100351
352 /* copy tables */
inikep0c7456c2016-04-04 14:54:53 +0200353 { const size_t chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
inikep1007a1f2016-04-25 15:23:09 +0200354 const size_t hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
Yann Collete3d52942016-06-06 11:07:33 +0200355 const size_t h3Size = (size_t)1 << srcCCtx->hashLog3;
inikep0c7456c2016-04-04 14:54:53 +0200356 const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100357 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
358 }
Yann Collet7b51a292016-01-26 15:58:49 +0100359
Yann Colletc46fb922016-05-29 05:01:04 +0200360 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100361 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
362 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
363 dstCCtx->nextSrc = srcCCtx->nextSrc;
364 dstCCtx->base = srcCCtx->base;
365 dstCCtx->dictBase = srcCCtx->dictBase;
366 dstCCtx->dictLimit = srcCCtx->dictLimit;
367 dstCCtx->lowLimit = srcCCtx->lowLimit;
368 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200369 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100370
Yann Colletfb810d62016-01-28 00:18:06 +0100371 /* copy entropy tables */
372 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100373 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100374 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100375 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
376 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
377 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
378 }
Yann Collet7b51a292016-01-26 15:58:49 +0100379
380 return 0;
381}
382
383
Yann Colletecabfe32016-03-20 16:20:06 +0100384/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100385* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100386static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100387{
Yann Colletecabfe32016-03-20 16:20:06 +0100388 U32 u;
389 for (u=0 ; u < size ; u++) {
390 if (table[u] < reducerValue) table[u] = 0;
391 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100392 }
393}
394
Yann Colletecabfe32016-03-20 16:20:06 +0100395/*! ZSTD_reduceIndex() :
396* rescale all indexes to avoid future overflow (indexes are U32) */
397static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
398{
Yann Collet3b719252016-03-30 19:48:05 +0200399 { const U32 hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100400 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
401
Yann Collet8a57b922016-04-04 13:49:18 +0200402 { const U32 chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
403 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100404
inikep7adceef2016-03-23 15:53:38 +0100405 { const U32 h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100406 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
407}
408
Yann Collet89db5e02015-11-13 11:27:46 +0100409
Yann Collet863ec402016-01-28 17:56:33 +0100410/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100411* Block entropic compression
412*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100413
Yann Colletfb797352016-03-13 11:08:40 +0100414/* Frame format description
415 Frame Header - [ Block Header - Block ] - Frame End
416 1) Frame Header
Yann Collet673f0d72016-06-06 00:26:38 +0200417 - 4 bytes : Magic Number : ZSTD_MAGICNUMBER (defined within zstd_static.h)
418 - 1 byte : Frame Header Descriptor
419 - 1-13 bytes : Optional fields
Yann Colletfb797352016-03-13 11:08:40 +0100420 2) Block Header
421 - 3 bytes, starting with a 2-bits descriptor
422 Uncompressed, Compressed, Frame End, unused
423 3) Block
424 See Block Format Description
425 4) Frame End
426 - 3 bytes, compatible with Block Header
427*/
428
429
Yann Collet2fa99042016-07-01 20:55:28 +0200430/* Frame header :
Yann Colletfb797352016-03-13 11:08:40 +0100431
Yann Collet673f0d72016-06-06 00:26:38 +0200432 1 byte - FrameHeaderDescription :
433 bit 0-1 : dictID (0, 1, 2 or 4 bytes)
434 bit 2-4 : reserved (must be zero)
435 bit 5 : SkippedWindowLog (if 1, WindowLog byte is not present)
436 bit 6-7 : FrameContentFieldsize (0, 2, 4, or 8)
437 if (SkippedWindowLog && !FrameContentFieldsize) FrameContentFieldsize=1;
438
439 Optional : WindowLog (0 or 1 byte)
440 bit 0-2 : octal Fractional (1/8th)
441 bit 3-7 : Power of 2, with 0 = 1 KB (up to 2 TB)
442
Yann Collet2fa99042016-07-01 20:55:28 +0200443 Optional : content size (0, 1, 2, 4 or 8 bytes)
444 0 : unknown
445 1 : 0-255 bytes
446 2 : 256 - 65535+256
447 8 : up to 16 exa
448
Yann Collet673f0d72016-06-06 00:26:38 +0200449 Optional : dictID (0, 1, 2 or 4 bytes)
450 Automatic adaptation
451 0 : no dictID
452 1 : 1 - 255
453 2 : 256 - 65535
454 4 : all other values
Yann Colletfb797352016-03-13 11:08:40 +0100455*/
456
457
Yann Collet59d1f792016-01-23 19:28:41 +0100458/* Block format description
459
Yann Collet2fa99042016-07-01 20:55:28 +0200460 Block = Literals Section - Sequences Section
Yann Collet59d1f792016-01-23 19:28:41 +0100461 Prerequisite : size of (compressed) block, maximum size of regenerated data
462
463 1) Literal Section
464
465 1.1) Header : 1-5 bytes
466 flags: 2 bits
467 00 compressed by Huff0
Yann Collet2fa99042016-07-01 20:55:28 +0200468 01 repeat
Yann Collet59d1f792016-01-23 19:28:41 +0100469 10 is Raw (uncompressed)
470 11 is Rle
471 Note : using 01 => Huff0 with precomputed table ?
472 Note : delta map ? => compressed ?
473
474 1.1.1) Huff0-compressed literal block : 3-5 bytes
Yann Colletafe07092016-01-25 04:10:46 +0100475 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
Yann Collet59d1f792016-01-23 19:28:41 +0100476 srcSize < 1 KB => 3 bytes (2-2-10-10)
Yann Colleta1249dc2016-01-25 04:22:03 +0100477 srcSize < 16KB => 4 bytes (2-2-14-14)
Yann Collet59d1f792016-01-23 19:28:41 +0100478 else => 5 bytes (2-2-18-18)
479 big endian convention
480
481 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
482 size : 5 bits: (IS_RAW<<6) + (0<<4) + size
483 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
484 size&255
485 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
486 size>>8&255
487 size&255
488
489 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
490 size : 5 bits: (IS_RLE<<6) + (0<<4) + size
491 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
492 size&255
493 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
494 size>>8&255
495 size&255
496
Yann Colleta1249dc2016-01-25 04:22:03 +0100497 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
498 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
499 srcSize < 1 KB => 3 bytes (2-2-10-10)
500 srcSize < 16KB => 4 bytes (2-2-14-14)
501 else => 5 bytes (2-2-18-18)
502 big endian convention
503
Yann Collet2fa99042016-07-01 20:55:28 +0200504 1- CTable available (stored into workspace)
Yann Colletb923f652016-01-26 03:14:20 +0100505 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
Yann Colleta1249dc2016-01-25 04:22:03 +0100506
Yann Collet59d1f792016-01-23 19:28:41 +0100507
508 1.2) Literal block content
509
510 1.2.1) Huff0 block, using sizes from header
511 See Huff0 format
512
Yann Colletfb810d62016-01-28 00:18:06 +0100513 1.2.2) Huff0 block, using prepared table
Yann Collet59d1f792016-01-23 19:28:41 +0100514
Yann Colletfb810d62016-01-28 00:18:06 +0100515 1.2.3) Raw content
Yann Collet59d1f792016-01-23 19:28:41 +0100516
Yann Colletfb810d62016-01-28 00:18:06 +0100517 1.2.4) single byte
Yann Collet59d1f792016-01-23 19:28:41 +0100518
519
520 2) Sequences section
Yann Colletfb810d62016-01-28 00:18:06 +0100521
522 - Nb Sequences : 2 bytes, little endian
523 - Control Token : 1 byte (see below)
524 - Dumps Length : 1 or 2 bytes (depending on control token)
525 - Dumps : as stated by dumps length
526 - Literal Lengths FSE table (as needed depending on encoding method)
527 - Offset Codes FSE table (as needed depending on encoding method)
528 - Match Lengths FSE table (as needed depending on encoding method)
529
530 2.1) Control Token
531 8 bits, divided as :
532 0-1 : dumpsLength
533 2-3 : MatchLength, FSE encoding method
534 4-5 : Offset Codes, FSE encoding method
535 6-7 : Literal Lengths, FSE encoding method
536
537 FSE encoding method :
538 FSE_ENCODING_RAW : uncompressed; no header
539 FSE_ENCODING_RLE : single repeated value; header 1 byte
540 FSE_ENCODING_STATIC : use prepared table; no header
541 FSE_ENCODING_DYNAMIC : read NCount
Yann Collet59d1f792016-01-23 19:28:41 +0100542*/
Yann Collet14983e72015-11-11 21:38:21 +0100543
Yann Colletd1b26842016-03-15 01:24:33 +0100544size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100545{
546 BYTE* const ostart = (BYTE* const)dst;
547
Yann Colletd1b26842016-03-15 01:24:33 +0100548 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100549 memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
550
551 /* Build header */
552 ostart[0] = (BYTE)(srcSize>>16);
553 ostart[1] = (BYTE)(srcSize>>8);
554 ostart[2] = (BYTE) srcSize;
555 ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
556
557 return ZSTD_blockHeaderSize+srcSize;
558}
559
560
Yann Colletd1b26842016-03-15 01:24:33 +0100561static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100562{
563 BYTE* const ostart = (BYTE* const)dst;
Yann Colleta910dc82016-03-18 12:37:45 +0100564 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100565
Yann Colletd1b26842016-03-15 01:24:33 +0100566 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100567
Yann Collet59d1f792016-01-23 19:28:41 +0100568 switch(flSize)
569 {
570 case 1: /* 2 - 1 - 5 */
Yann Collet9dd12742016-06-10 00:12:26 +0200571 ostart[0] = (BYTE)((lbt_raw<<6) + (0<<5) + srcSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100572 break;
573 case 2: /* 2 - 2 - 12 */
Yann Collet9dd12742016-06-10 00:12:26 +0200574 ostart[0] = (BYTE)((lbt_raw<<6) + (2<<4) + (srcSize >> 8));
Yann Collet59d1f792016-01-23 19:28:41 +0100575 ostart[1] = (BYTE)srcSize;
576 break;
577 default: /*note : should not be necessary : flSize is within {1,2,3} */
578 case 3: /* 2 - 2 - 20 */
Yann Collet9dd12742016-06-10 00:12:26 +0200579 ostart[0] = (BYTE)((lbt_raw<<6) + (3<<4) + (srcSize >> 16));
Yann Collet59d1f792016-01-23 19:28:41 +0100580 ostart[1] = (BYTE)(srcSize>>8);
581 ostart[2] = (BYTE)srcSize;
582 break;
583 }
584
585 memcpy(ostart + flSize, src, srcSize);
586 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100587}
588
Yann Colletd1b26842016-03-15 01:24:33 +0100589static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100590{
591 BYTE* const ostart = (BYTE* const)dst;
Yann Colleta910dc82016-03-18 12:37:45 +0100592 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100593
Yann Colletd1b26842016-03-15 01:24:33 +0100594 (void)dstCapacity; /* dstCapacity guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100595
596 switch(flSize)
597 {
598 case 1: /* 2 - 1 - 5 */
Yann Collet9dd12742016-06-10 00:12:26 +0200599 ostart[0] = (BYTE)((lbt_rle<<6) + (0<<5) + srcSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100600 break;
601 case 2: /* 2 - 2 - 12 */
Yann Collet9dd12742016-06-10 00:12:26 +0200602 ostart[0] = (BYTE)((lbt_rle<<6) + (2<<4) + (srcSize >> 8));
Yann Collet59d1f792016-01-23 19:28:41 +0100603 ostart[1] = (BYTE)srcSize;
604 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100605 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100606 case 3: /* 2 - 2 - 20 */
Yann Collet9dd12742016-06-10 00:12:26 +0200607 ostart[0] = (BYTE)((lbt_rle<<6) + (3<<4) + (srcSize >> 16));
Yann Collet59d1f792016-01-23 19:28:41 +0100608 ostart[1] = (BYTE)(srcSize>>8);
609 ostart[2] = (BYTE)srcSize;
610 break;
611 }
612
613 ostart[flSize] = *(const BYTE*)src;
614 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100615}
616
Yann Collet59d1f792016-01-23 19:28:41 +0100617
Yann Colleta5c2c082016-03-20 01:09:18 +0100618static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100619
Yann Colletb923f652016-01-26 03:14:20 +0100620static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100621 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100622 const void* src, size_t srcSize)
623{
Yann Colleta910dc82016-03-18 12:37:45 +0100624 size_t const minGain = ZSTD_minGain(srcSize);
625 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet14983e72015-11-11 21:38:21 +0100626 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100627 U32 singleStream = srcSize < 256;
Yann Collet9dd12742016-06-10 00:12:26 +0200628 litBlockType_t hType = lbt_huffman;
Yann Colleta910dc82016-03-18 12:37:45 +0100629 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100630
Yann Collet14983e72015-11-11 21:38:21 +0100631
Yann Colleta5c2c082016-03-20 01:09:18 +0100632 /* small ? don't even attempt compression (speed opt) */
633# define LITERAL_NOENTROPY 63
634 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
635 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
636 }
637
638 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Colletfb810d62016-01-28 00:18:06 +0100639 if (zc->flagStaticTables && (lhSize==3)) {
Yann Collet9dd12742016-06-10 00:12:26 +0200640 hType = lbt_repeat;
Yann Colletb923f652016-01-26 03:14:20 +0100641 singleStream = 1;
Yann Colleta910dc82016-03-18 12:37:45 +0100642 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100643 } else {
Yann Colleta910dc82016-03-18 12:37:45 +0100644 cLitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12)
Yann Colletd1b26842016-03-15 01:24:33 +0100645 : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12);
Yann Colletb923f652016-01-26 03:14:20 +0100646 }
Yann Collet14983e72015-11-11 21:38:21 +0100647
Yann Colleta910dc82016-03-18 12:37:45 +0100648 if ((cLitSize==0) || (cLitSize >= srcSize - minGain))
649 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
650 if (cLitSize==1)
651 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100652
653 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100654 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100655 {
Yann Collet59d1f792016-01-23 19:28:41 +0100656 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletb923f652016-01-26 03:14:20 +0100657 ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6));
Yann Colleta910dc82016-03-18 12:37:45 +0100658 ostart[1] = (BYTE)((srcSize<<2) + (cLitSize>>8));
659 ostart[2] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100660 break;
661 case 4: /* 2 - 2 - 14 - 14 */
Yann Colletb923f652016-01-26 03:14:20 +0100662 ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100663 ostart[1] = (BYTE)(srcSize>> 2);
Yann Colleta910dc82016-03-18 12:37:45 +0100664 ostart[2] = (BYTE)((srcSize<<6) + (cLitSize>>8));
665 ostart[3] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100666 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100667 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100668 case 5: /* 2 - 2 - 18 - 18 */
Yann Colletb923f652016-01-26 03:14:20 +0100669 ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100670 ostart[1] = (BYTE)(srcSize>>6);
Yann Colleta910dc82016-03-18 12:37:45 +0100671 ostart[2] = (BYTE)((srcSize<<2) + (cLitSize>>16));
672 ostart[3] = (BYTE)(cLitSize>>8);
673 ostart[4] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100674 break;
Yann Collet14983e72015-11-11 21:38:21 +0100675 }
Yann Colleta910dc82016-03-18 12:37:45 +0100676 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100677}
678
679
Yann Colletb44be742016-03-26 20:52:14 +0100680void ZSTD_seqToCodes(const seqStore_t* seqStorePtr, size_t const nbSeq)
681{
682 /* LL codes */
683 { static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
684 8, 9, 10, 11, 12, 13, 14, 15,
685 16, 16, 17, 17, 18, 18, 19, 19,
686 20, 20, 20, 20, 21, 21, 21, 21,
687 22, 22, 22, 22, 22, 22, 22, 22,
688 23, 23, 23, 23, 23, 23, 23, 23,
689 24, 24, 24, 24, 24, 24, 24, 24,
690 24, 24, 24, 24, 24, 24, 24, 24 };
691 const BYTE LL_deltaCode = 19;
Yann Collet5d393572016-04-07 17:19:00 +0200692 const U16* const llTable = seqStorePtr->litLengthStart;
Yann Colletb44be742016-03-26 20:52:14 +0100693 BYTE* const llCodeTable = seqStorePtr->llCodeStart;
694 size_t u;
695 for (u=0; u<nbSeq; u++) {
Yann Collet5d393572016-04-07 17:19:00 +0200696 U32 const ll = llTable[u];
Yann Collet49bb0042016-06-04 20:17:38 +0200697 llCodeTable[u] = (ll>63) ? (BYTE)ZSTD_highbit32(ll) + LL_deltaCode : LL_Code[ll];
Yann Collet5d393572016-04-07 17:19:00 +0200698 }
699 if (seqStorePtr->longLengthID==1)
700 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
701 }
Yann Colletb44be742016-03-26 20:52:14 +0100702
703 /* Offset codes */
704 { const U32* const offsetTable = seqStorePtr->offsetStart;
705 BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
706 size_t u;
Yann Collet49bb0042016-06-04 20:17:38 +0200707 for (u=0; u<nbSeq; u++) ofCodeTable[u] = (BYTE)ZSTD_highbit32(offsetTable[u]);
Yann Colletb44be742016-03-26 20:52:14 +0100708 }
709
710 /* ML codes */
711 { static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
712 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
713 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
714 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
715 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
716 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
717 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
718 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
719 const BYTE ML_deltaCode = 36;
Yann Collet5d393572016-04-07 17:19:00 +0200720 const U16* const mlTable = seqStorePtr->matchLengthStart;
Yann Colletb44be742016-03-26 20:52:14 +0100721 BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
722 size_t u;
723 for (u=0; u<nbSeq; u++) {
Yann Collet5d393572016-04-07 17:19:00 +0200724 U32 const ml = mlTable[u];
Yann Collet49bb0042016-06-04 20:17:38 +0200725 mlCodeTable[u] = (ml>127) ? (BYTE)ZSTD_highbit32(ml) + ML_deltaCode : ML_Code[ml];
Yann Collet5d393572016-04-07 17:19:00 +0200726 }
727 if (seqStorePtr->longLengthID==2)
728 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
729 }
Yann Colletb44be742016-03-26 20:52:14 +0100730}
731
732
Yann Colletb923f652016-01-26 03:14:20 +0100733size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100734 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100735 size_t srcSize)
736{
Yann Colletb923f652016-01-26 03:14:20 +0100737 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100738 U32 count[MaxSeq+1];
739 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100740 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
741 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
742 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100743 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletb0aec172016-03-21 13:24:16 +0100744 U16* const llTable = seqStorePtr->litLengthStart;
Yann Colletfadda6c2016-03-22 12:14:26 +0100745 U16* const mlTable = seqStorePtr->matchLengthStart;
Yann Collet14983e72015-11-11 21:38:21 +0100746 const U32* const offsetTable = seqStorePtr->offsetStart;
Yann Colletd64f4352016-03-21 00:07:42 +0100747 const U32* const offsetTableEnd = seqStorePtr->offset;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100748 BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
Yann Collet597847a2016-03-20 19:14:22 +0100749 BYTE* const llCodeTable = seqStorePtr->llCodeStart;
Yann Colletfadda6c2016-03-22 12:14:26 +0100750 BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
Yann Collet5054ee02015-11-23 13:34:21 +0100751 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100752 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100753 BYTE* op = ostart;
Yann Colletd64f4352016-03-21 00:07:42 +0100754 size_t const nbSeq = offsetTableEnd - offsetTable;
Yann Collet14983e72015-11-11 21:38:21 +0100755 BYTE* seqHead;
756
Yann Collet14983e72015-11-11 21:38:21 +0100757 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100758 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100759 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100760 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100761 if (ZSTD_isError(cSize)) return cSize;
762 op += cSize;
763 }
764
765 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100766 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100767 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
768 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
769 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100770 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100771
Yann Colletbe391432016-03-22 23:19:28 +0100772 /* seqHead : flags for FSE encoding type */
773 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100774
Yann Colletfb810d62016-01-28 00:18:06 +0100775#define MIN_SEQ_FOR_DYNAMIC_FSE 64
776#define MAX_SEQ_FOR_STATIC_FSE 1000
777
Yann Colletb44be742016-03-26 20:52:14 +0100778 /* convert length/distances into codes */
779 ZSTD_seqToCodes(seqStorePtr, nbSeq);
Yann Collet597847a2016-03-20 19:14:22 +0100780
Yann Collet14983e72015-11-11 21:38:21 +0100781 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100782 { U32 max = MaxLL;
783 size_t const mostFrequent = FSE_countFast(count, &max, llCodeTable, nbSeq);
784 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
785 *op++ = llCodeTable[0];
786 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
787 LLtype = FSE_ENCODING_RLE;
788 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
789 LLtype = FSE_ENCODING_STATIC;
790 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
791 FSE_buildCTable(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog);
792 LLtype = FSE_ENCODING_RAW;
793 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100794 size_t nbSeq_1 = nbSeq;
795 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
796 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
797 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100798 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
799 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
800 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100801 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
802 LLtype = FSE_ENCODING_DYNAMIC;
803 } }
Yann Collet14983e72015-11-11 21:38:21 +0100804
Yann Colletb44be742016-03-26 20:52:14 +0100805 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100806 { U32 max = MaxOff;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100807 size_t const mostFrequent = FSE_countFast(count, &max, ofCodeTable, nbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100808 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100809 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100810 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
811 Offtype = FSE_ENCODING_RLE;
812 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
813 Offtype = FSE_ENCODING_STATIC;
Yann Collet48537162016-04-07 15:24:29 +0200814 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
815 FSE_buildCTable(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog);
Yann Colletfadda6c2016-03-22 12:14:26 +0100816 Offtype = FSE_ENCODING_RAW;
817 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100818 size_t nbSeq_1 = nbSeq;
819 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100820 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100821 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100822 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
823 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
824 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100825 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
826 Offtype = FSE_ENCODING_DYNAMIC;
827 } }
828
Yann Collet14983e72015-11-11 21:38:21 +0100829 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100830 { U32 max = MaxML;
831 size_t const mostFrequent = FSE_countFast(count, &max, mlCodeTable, nbSeq);
832 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100833 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100834 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
835 MLtype = FSE_ENCODING_RLE;
836 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
837 MLtype = FSE_ENCODING_STATIC;
838 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
839 FSE_buildCTable(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog);
840 MLtype = FSE_ENCODING_RAW;
841 } else {
842 size_t nbSeq_1 = nbSeq;
843 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
844 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
845 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
846 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
847 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
848 op += NCountSize; }
849 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
850 MLtype = FSE_ENCODING_DYNAMIC;
851 } }
Yann Collet14983e72015-11-11 21:38:21 +0100852
Yann Colletbe391432016-03-22 23:19:28 +0100853 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100854 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100855
856 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100857 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100858 FSE_CState_t stateMatchLength;
859 FSE_CState_t stateOffsetBits;
860 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100861
Yann Colleta910dc82016-03-18 12:37:45 +0100862 { size_t const errorCode = BIT_initCStream(&blockStream, op, oend-op);
Yann Collet597847a2016-03-20 19:14:22 +0100863 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100864
Yann Collet597847a2016-03-20 19:14:22 +0100865 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100866 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100867 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100868 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colletb0aec172016-03-21 13:24:16 +0100869 BIT_addBits(&blockStream, llTable[nbSeq-1], LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100870 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Collet25125972016-03-23 14:00:09 +0100871 BIT_addBits(&blockStream, mlTable[nbSeq-1], ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100872 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Collet646693e2016-03-24 02:31:27 +0100873 BIT_addBits(&blockStream, offsetTable[nbSeq-1], ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100874 BIT_flushBits(&blockStream);
875
Yann Colletfadda6c2016-03-22 12:14:26 +0100876 { size_t n;
877 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Colletb9151402016-03-26 17:18:11 +0100878 const BYTE ofCode = ofCodeTable[n];
Yann Collet7cbe79a2016-03-23 22:31:57 +0100879 const BYTE mlCode = mlCodeTable[n];
880 const BYTE llCode = llCodeTable[n];
881 const U32 llBits = LL_bits[llCode];
882 const U32 mlBits = ML_bits[mlCode];
Yann Colletb9151402016-03-26 17:18:11 +0100883 const U32 ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100884 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100885 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
886 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
887 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
888 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200889 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100890 BIT_flushBits(&blockStream); /* (7)*/
Yann Collet7cbe79a2016-03-23 22:31:57 +0100891 BIT_addBits(&blockStream, llTable[n], llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100892 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100893 BIT_addBits(&blockStream, mlTable[n], mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100894 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
895 BIT_addBits(&blockStream, offsetTable[n], ofBits); /* 31 */
896 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100897 } }
Yann Collet14983e72015-11-11 21:38:21 +0100898
899 FSE_flushCState(&blockStream, &stateMatchLength);
900 FSE_flushCState(&blockStream, &stateOffsetBits);
901 FSE_flushCState(&blockStream, &stateLitLength);
902
Yann Colletb9151402016-03-26 17:18:11 +0100903 { size_t const streamSize = BIT_closeCStream(&blockStream);
904 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
905 op += streamSize;
906 } }
Yann Collet14983e72015-11-11 21:38:21 +0100907
908 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100909_check_compressibility:
Yann Colletfadda6c2016-03-22 12:14:26 +0100910 { size_t const minGain = ZSTD_minGain(srcSize);
911 size_t const maxCSize = srcSize - minGain;
912 if ((size_t)(op-ostart) >= maxCSize) return 0; }
Yann Collet14983e72015-11-11 21:38:21 +0100913
Yann Collet4266c0a2016-06-14 01:49:25 +0200914 /* confirm repcodes */
915 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->savedRep[i]; }
916
Yann Collet5054ee02015-11-23 13:34:21 +0100917 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100918}
919
920
Yann Collet95cd0c22016-03-08 18:24:21 +0100921/*! ZSTD_storeSeq() :
922 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
923 `offsetCode` : distance to match, or 0 == repCode.
924 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100925*/
Yann Collet45c03c52016-06-14 13:46:11 +0200926MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, size_t offsetCode, size_t matchCode)
Yann Collet14983e72015-11-11 21:38:21 +0100927{
Yann Collet45c03c52016-06-14 13:46:11 +0200928#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100929 static const BYTE* g_start = NULL;
Yann Colletb0aec172016-03-21 13:24:16 +0100930 const U32 pos = (U32)(literals - g_start);
Yann Collet14983e72015-11-11 21:38:21 +0100931 if (g_start==NULL) g_start = literals;
Yann Collet4266c0a2016-06-14 01:49:25 +0200932 //if ((pos > 1) && (pos < 50000))
Yann Colletb9151402016-03-26 17:18:11 +0100933 printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
Yann Collet433a5cc2016-03-25 11:43:48 +0100934 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +0100935#endif
Yann Colletd0590922016-06-14 15:34:24 +0200936 ZSTD_statsUpdatePrices(&seqStorePtr->stats, litLength, (const BYTE*)literals, offsetCode, matchCode); /* debug only */
Yann Collet14983e72015-11-11 21:38:21 +0100937
938 /* copy Literals */
939 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
940 seqStorePtr->lit += litLength;
941
942 /* literal Length */
Yann Collet5d393572016-04-07 17:19:00 +0200943 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->litLength - seqStorePtr->litLengthStart); }
944 *seqStorePtr->litLength++ = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100945
946 /* match offset */
Yann Collet646693e2016-03-24 02:31:27 +0100947 *(seqStorePtr->offset++) = (U32)offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100948
949 /* match Length */
Yann Collet5d393572016-04-07 17:19:00 +0200950 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->matchLength - seqStorePtr->matchLengthStart); }
951 *seqStorePtr->matchLength++ = (U16)matchCode;
Yann Collet14983e72015-11-11 21:38:21 +0100952}
953
954
Yann Collet7d360282016-02-12 00:07:30 +0100955/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100956* Match length counter
957***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100958static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100959{
Yann Collet863ec402016-01-28 17:56:33 +0100960 if (MEM_isLittleEndian()) {
961 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100962# if defined(_MSC_VER) && defined(_WIN64)
963 unsigned long r = 0;
964 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100965 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100966# elif defined(__GNUC__) && (__GNUC__ >= 3)
967 return (__builtin_ctzll((U64)val) >> 3);
968# else
969 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 };
970 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
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 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100976 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100977# elif defined(__GNUC__) && (__GNUC__ >= 3)
978 return (__builtin_ctz((U32)val) >> 3);
979# else
980 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 };
981 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
982# endif
983 }
Yann Collet863ec402016-01-28 17:56:33 +0100984 } else { /* Big Endian CPU */
985 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100986# if defined(_MSC_VER) && defined(_WIN64)
987 unsigned long r = 0;
988 _BitScanReverse64( &r, val );
989 return (unsigned)(r>>3);
990# elif defined(__GNUC__) && (__GNUC__ >= 3)
991 return (__builtin_clzll(val) >> 3);
992# else
993 unsigned r;
994 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
995 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
996 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
997 r += (!val);
998 return r;
999# endif
Yann Collet863ec402016-01-28 17:56:33 +01001000 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +01001001# if defined(_MSC_VER)
1002 unsigned long r = 0;
1003 _BitScanReverse( &r, (unsigned long)val );
1004 return (unsigned)(r>>3);
1005# elif defined(__GNUC__) && (__GNUC__ >= 3)
1006 return (__builtin_clz((U32)val) >> 3);
1007# else
1008 unsigned r;
1009 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
1010 r += (!val);
1011 return r;
1012# endif
Yann Collet863ec402016-01-28 17:56:33 +01001013 } }
Yann Collet14983e72015-11-11 21:38:21 +01001014}
1015
1016
Yann Colleta436a522016-06-20 23:34:04 +02001017static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +01001018{
1019 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +02001020 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +01001021
Yann Colleta436a522016-06-20 23:34:04 +02001022 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +02001023 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +01001024 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
1025 pIn += ZSTD_NbCommonBytes(diff);
1026 return (size_t)(pIn - pStart);
1027 }
Yann Collet14983e72015-11-11 21:38:21 +01001028 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
1029 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
1030 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
1031 return (size_t)(pIn - pStart);
1032}
1033
Yann Collet04b12d82016-02-11 06:23:24 +01001034/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +01001035* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +01001036* convention : on reaching mEnd, match count continue starting from iStart
1037*/
1038static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
1039{
Yann Collet7591a7f2016-05-20 11:44:43 +02001040 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
1041 size_t matchLength = ZSTD_count(ip, match, vEnd);
Yann Collet5054ee02015-11-23 13:34:21 +01001042 if (match + matchLength == mEnd)
1043 matchLength += ZSTD_count(ip+matchLength, iStart, iEnd);
1044 return matchLength;
1045}
1046
Yann Collet14983e72015-11-11 21:38:21 +01001047
Yann Collet863ec402016-01-28 17:56:33 +01001048/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001049* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +01001050***************************************/
inikepcc52a972016-02-19 10:09:35 +01001051static const U32 prime3bytes = 506832829U;
1052static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Colletd4f4e582016-06-27 01:31:35 +02001053MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
inikepcc52a972016-02-19 10:09:35 +01001054
Yann Collet4b100f42015-10-30 15:49:48 +01001055static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +01001056static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +01001057static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +01001058
Yann Collet4b100f42015-10-30 15:49:48 +01001059static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001060static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001061static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001062
1063static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001064static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001065static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001066
Yann Collet14983e72015-11-11 21:38:21 +01001067static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001068static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001069static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001070
Yann Collet5be2dd22015-11-11 13:43:58 +01001071static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001072{
1073 switch(mls)
1074 {
1075 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001076 case 4: return ZSTD_hash4Ptr(p, hBits);
1077 case 5: return ZSTD_hash5Ptr(p, hBits);
1078 case 6: return ZSTD_hash6Ptr(p, hBits);
1079 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001080 }
1081}
Yann Collet2acb5d32015-10-29 16:49:43 +01001082
Yann Collet863ec402016-01-28 17:56:33 +01001083
Yann Collet2ce49232016-02-02 14:36:49 +01001084/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001085* Fast Scan
1086***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001087static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1088{
1089 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001090 const U32 hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001091 const BYTE* const base = zc->base;
1092 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet2ce49232016-02-02 14:36:49 +01001093 const BYTE* const iend = ((const BYTE*)end) - 8;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001094 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001095
Yann Colletfb810d62016-01-28 00:18:06 +01001096 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001097 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001098 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001099 }
1100}
1101
1102
Yann Collet1f44b3f2015-11-05 17:32:18 +01001103FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +02001104void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001105 const void* src, size_t srcSize,
1106 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001107{
Yann Collet4266c0a2016-06-14 01:49:25 +02001108 U32* const hashTable = cctx->hashTable;
1109 const U32 hBits = cctx->params.cParams.hashLog;
1110 seqStore_t* seqStorePtr = &(cctx->seqStore);
1111 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001112 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001113 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001114 const BYTE* anchor = istart;
Yann Collet4266c0a2016-06-14 01:49:25 +02001115 const U32 lowestIndex = cctx->dictLimit;
1116 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001117 const BYTE* const iend = istart + srcSize;
1118 const BYTE* const ilimit = iend - 8;
Yann Collet92d75662016-07-03 01:10:53 +02001119 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1120 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001121
Yann Collet1f44b3f2015-11-05 17:32:18 +01001122 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001123 ip += (ip==lowest);
1124 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +02001125 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1126 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +02001127 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001128
1129 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +02001130 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +02001131 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +02001132 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
1133 U32 const current = (U32)(ip-base);
1134 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +01001135 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001136 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001137
Yann Colleta436a522016-06-20 23:34:04 +02001138 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1139 mLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
Yann Collet402fdcf2015-11-20 12:46:08 +01001140 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001141 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1142 } else {
Yann Collet92d75662016-07-03 01:10:53 +02001143 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001144 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001145 ip += ((ip-anchor) >> g_searchStrength) + 1;
1146 continue;
1147 }
Yann Colleta436a522016-06-20 23:34:04 +02001148 mLength = ZSTD_count(ip+EQUAL_READ32, match+EQUAL_READ32, iend) + EQUAL_READ32;
Yann Collet92d75662016-07-03 01:10:53 +02001149 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001150 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001151 offset_2 = offset_1;
1152 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001153
Yann Colleta436a522016-06-20 23:34:04 +02001154 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001155 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001156
Yann Collet402fdcf2015-11-20 12:46:08 +01001157 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001158 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001159 anchor = ip;
1160
Yann Colletfb810d62016-01-28 00:18:06 +01001161 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001162 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001163 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 +01001164 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1165 /* check immediate repcode */
1166 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001167 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001168 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001169 /* store sequence */
Yann Colleta436a522016-06-20 23:34:04 +02001170 size_t const rLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
Yann Collet92d75662016-07-03 01:10:53 +02001171 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001172 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001173 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1174 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001175 anchor = ip;
1176 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001177 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001178
Yann Collet4266c0a2016-06-14 01:49:25 +02001179 /* save reps for next block */
Yann Collet92d75662016-07-03 01:10:53 +02001180 cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved;
1181 cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001182
Yann Collet70e45772016-03-19 18:08:32 +01001183 /* Last Literals */
1184 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001185 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1186 seqStorePtr->lit += lastLLSize;
1187 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001188}
1189
1190
Yann Collet82260dd2016-02-11 07:14:25 +01001191static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001192 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001193{
Yann Collet3b719252016-03-30 19:48:05 +02001194 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001195 switch(mls)
1196 {
1197 default:
1198 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001199 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001200 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001201 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001202 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001203 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001204 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001205 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001206 }
1207}
Yann Colletf3eca252015-10-22 15:31:46 +01001208
Yann Colletf3eca252015-10-22 15:31:46 +01001209
Yann Collet82260dd2016-02-11 07:14:25 +01001210static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001211 const void* src, size_t srcSize,
1212 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001213{
1214 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001215 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001216 seqStore_t* seqStorePtr = &(ctx->seqStore);
1217 const BYTE* const base = ctx->base;
1218 const BYTE* const dictBase = ctx->dictBase;
1219 const BYTE* const istart = (const BYTE*)src;
1220 const BYTE* ip = istart;
1221 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001222 const U32 lowestIndex = ctx->lowLimit;
1223 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001224 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001225 const BYTE* const lowPrefixPtr = base + dictLimit;
1226 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001227 const BYTE* const iend = istart + srcSize;
1228 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001229 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001230
Yann Colleta436a522016-06-20 23:34:04 +02001231 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001232 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001233 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001234 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001235 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001236 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001237 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001238 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001239 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001240 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001241 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001242 hashTable[h] = current; /* update hash table */
1243
Yann Colleta436a522016-06-20 23:34:04 +02001244 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001245 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001246 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Colleta436a522016-06-20 23:34:04 +02001247 mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001248 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001249 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001250 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001251 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001252 (MEM_read32(match) != MEM_read32(ip)) ) {
1253 ip += ((ip-anchor) >> g_searchStrength) + 1;
1254 continue;
1255 }
1256 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001257 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001258 U32 offset;
1259 mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
1260 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001261 offset = current - matchIndex;
1262 offset_2 = offset_1;
1263 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001264 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001265 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001266
Yann Collet5054ee02015-11-23 13:34:21 +01001267 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001268 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001269 anchor = ip;
1270
Yann Colletfb810d62016-01-28 00:18:06 +01001271 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001272 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001273 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001274 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1275 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001276 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001277 U32 const current2 = (U32)(ip-base);
1278 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001279 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001280 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1281 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001282 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001283 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001284 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001285 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001286 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001287 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001288 anchor = ip;
1289 continue;
1290 }
Yann Collet743402c2015-11-20 12:03:53 +01001291 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001292 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001293
Yann Collet4266c0a2016-06-14 01:49:25 +02001294 /* save reps for next block */
1295 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
1296
Yann Collet89db5e02015-11-13 11:27:46 +01001297 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001298 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001299 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1300 seqStorePtr->lit += lastLLSize;
1301 }
Yann Collet89db5e02015-11-13 11:27:46 +01001302}
1303
1304
Yann Collet82260dd2016-02-11 07:14:25 +01001305static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001306 const void* src, size_t srcSize)
1307{
Yann Collet3b719252016-03-30 19:48:05 +02001308 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001309 switch(mls)
1310 {
1311 default:
1312 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001313 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001314 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001315 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001316 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001317 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001318 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001319 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001320 }
1321}
1322
1323
Yann Collet04b12d82016-02-11 06:23:24 +01001324/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001325* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001326***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001327/** ZSTD_insertBt1() : add one or multiple positions to tree.
1328* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001329* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001330static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1331 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001332{
1333 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001334 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet5be2dd22015-11-11 13:43:58 +01001335 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet8a57b922016-04-04 13:49:18 +02001336 U32* const bt = zc->chainTable;
1337 const U32 btLog = zc->params.cParams.chainLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001338 const U32 btMask= (1 << btLog) - 1;
1339 U32 matchIndex = hashTable[h];
1340 size_t commonLengthSmaller=0, commonLengthLarger=0;
1341 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001342 const BYTE* const dictBase = zc->dictBase;
1343 const U32 dictLimit = zc->dictLimit;
1344 const BYTE* const dictEnd = dictBase + dictLimit;
1345 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001346 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001347 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001348 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001349 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001350 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001351 U32 dummy32; /* to be nullified at the end */
Yann Collet03526e12015-11-23 15:29:15 +01001352 const U32 windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001353 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001354 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001355#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001356 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1357 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1358 predictedSmall += (predictedSmall>0);
1359 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001360#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001361
Yann Collet6c3e2e72015-12-11 10:44:07 +01001362 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001363
Yann Colletfb810d62016-01-28 00:18:06 +01001364 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001365 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001366 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Colletc0932082016-06-30 14:07:30 +02001367#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001368 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001369 if (matchIndex == predictedSmall) {
1370 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001371 *smallerPtr = matchIndex;
1372 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1373 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1374 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001375 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001376 continue;
1377 }
Yann Colletfb810d62016-01-28 00:18:06 +01001378 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001379 *largerPtr = matchIndex;
1380 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1381 largerPtr = nextPtr;
1382 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001383 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001384 continue;
1385 }
Yann Collet04b12d82016-02-11 06:23:24 +01001386#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001387 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001388 match = base + matchIndex;
1389 if (match[matchLength] == ip[matchLength])
1390 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001391 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001392 match = dictBase + matchIndex;
1393 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1394 if (matchIndex+matchLength >= dictLimit)
1395 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1396 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001397
Yann Colletb8a6f682016-02-15 17:06:29 +01001398 if (matchLength > bestLength) {
1399 bestLength = matchLength;
1400 if (matchLength > matchEndIdx - matchIndex)
1401 matchEndIdx = matchIndex + (U32)matchLength;
1402 }
Yann Colletee3f4512015-12-29 22:26:09 +01001403
Yann Collet59d70632015-11-04 12:05:27 +01001404 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001405 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001406
Yann Colletfb810d62016-01-28 00:18:06 +01001407 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001408 /* match is smaller than current */
1409 *smallerPtr = matchIndex; /* update smaller idx */
1410 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001411 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001412 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001413 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001414 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001415 /* match is larger than current */
1416 *largerPtr = matchIndex;
1417 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001418 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001419 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001420 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001421 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001422
Yann Collet59d70632015-11-04 12:05:27 +01001423 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02001424 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01001425 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1426 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001427}
1428
1429
Yann Collet82260dd2016-02-11 07:14:25 +01001430static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001431 ZSTD_CCtx* zc,
1432 const BYTE* const ip, const BYTE* const iend,
1433 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001434 U32 nbCompares, const U32 mls,
1435 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001436{
1437 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001438 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet03526e12015-11-23 15:29:15 +01001439 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet8a57b922016-04-04 13:49:18 +02001440 U32* const bt = zc->chainTable;
1441 const U32 btLog = zc->params.cParams.chainLog - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001442 const U32 btMask= (1 << btLog) - 1;
1443 U32 matchIndex = hashTable[h];
1444 size_t commonLengthSmaller=0, commonLengthLarger=0;
1445 const BYTE* const base = zc->base;
1446 const BYTE* const dictBase = zc->dictBase;
1447 const U32 dictLimit = zc->dictLimit;
1448 const BYTE* const dictEnd = dictBase + dictLimit;
1449 const BYTE* const prefixStart = base + dictLimit;
1450 const U32 current = (U32)(ip-base);
1451 const U32 btLow = btMask >= current ? 0 : current - btMask;
1452 const U32 windowLow = zc->lowLimit;
1453 U32* smallerPtr = bt + 2*(current&btMask);
1454 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001455 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001456 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001457 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001458
Yann Collet6c3e2e72015-12-11 10:44:07 +01001459 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001460
Yann Colletfb810d62016-01-28 00:18:06 +01001461 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001462 U32* nextPtr = bt + 2*(matchIndex & btMask);
1463 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1464 const BYTE* match;
1465
Yann Colletfb810d62016-01-28 00:18:06 +01001466 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001467 match = base + matchIndex;
1468 if (match[matchLength] == ip[matchLength])
1469 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001470 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001471 match = dictBase + matchIndex;
1472 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001473 if (matchIndex+matchLength >= dictLimit)
1474 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001475 }
1476
Yann Colletfb810d62016-01-28 00:18:06 +01001477 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001478 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001479 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02001480 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001481 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001482 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1483 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1484 }
1485
Yann Colletfb810d62016-01-28 00:18:06 +01001486 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001487 /* match is smaller than current */
1488 *smallerPtr = matchIndex; /* update smaller idx */
1489 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1490 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1491 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1492 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001493 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001494 /* match is larger than current */
1495 *largerPtr = matchIndex;
1496 commonLengthLarger = matchLength;
1497 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1498 largerPtr = nextPtr;
1499 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001500 } }
Yann Collet03526e12015-11-23 15:29:15 +01001501
1502 *smallerPtr = *largerPtr = 0;
1503
Yann Collet72e84cf2015-12-31 19:08:44 +01001504 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001505 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001506}
1507
Yann Collet2cc12cb2016-01-01 07:47:58 +01001508
Yann Colletb8a6f682016-02-15 17:06:29 +01001509static 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 +01001510{
1511 const BYTE* const base = zc->base;
1512 const U32 target = (U32)(ip - base);
1513 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001514
1515 while(idx < target)
1516 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001517}
1518
Yann Collet52447382016-03-20 16:00:00 +01001519/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001520static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001521 ZSTD_CCtx* zc,
1522 const BYTE* const ip, const BYTE* const iLimit,
1523 size_t* offsetPtr,
1524 const U32 maxNbAttempts, const U32 mls)
1525{
1526 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001527 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001528 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1529}
1530
1531
Yann Collet768c6bc2016-02-10 14:01:49 +01001532static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001533 ZSTD_CCtx* zc, /* Index table will be updated */
1534 const BYTE* ip, const BYTE* const iLimit,
1535 size_t* offsetPtr,
1536 const U32 maxNbAttempts, const U32 matchLengthSearch)
1537{
1538 switch(matchLengthSearch)
1539 {
1540 default :
1541 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1542 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1543 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1544 }
1545}
1546
1547
Yann Colletb8a6f682016-02-15 17:06:29 +01001548static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1549{
1550 const BYTE* const base = zc->base;
1551 const U32 target = (U32)(ip - base);
1552 U32 idx = zc->nextToUpdate;
1553
1554 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1555}
1556
inikep64d7bcb2016-04-07 19:14:09 +02001557
Yann Collet03526e12015-11-23 15:29:15 +01001558/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001559static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001560 ZSTD_CCtx* zc,
1561 const BYTE* const ip, const BYTE* const iLimit,
1562 size_t* offsetPtr,
1563 const U32 maxNbAttempts, const U32 mls)
1564{
Yann Colletee3f4512015-12-29 22:26:09 +01001565 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001566 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001567 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001568}
1569
1570
Yann Collet82260dd2016-02-11 07:14:25 +01001571static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001572 ZSTD_CCtx* zc, /* Index table will be updated */
1573 const BYTE* ip, const BYTE* const iLimit,
1574 size_t* offsetPtr,
1575 const U32 maxNbAttempts, const U32 matchLengthSearch)
1576{
1577 switch(matchLengthSearch)
1578 {
1579 default :
1580 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1581 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1582 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1583 }
1584}
1585
1586
Yann Collet5106a762015-11-05 15:00:24 +01001587
inikep64d7bcb2016-04-07 19:14:09 +02001588/* ***********************
1589* Hash Chain
1590*************************/
1591
1592#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1593
inikepafe1f792016-04-07 19:50:03 +02001594
inikep64d7bcb2016-04-07 19:14:09 +02001595/* Update chains up to ip (excluded)
1596 Assumption : always within prefix (ie. not within extDict) */
1597FORCE_INLINE
1598U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1599{
1600 U32* const hashTable = zc->hashTable;
1601 const U32 hashLog = zc->params.cParams.hashLog;
1602 U32* const chainTable = zc->chainTable;
1603 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1604 const BYTE* const base = zc->base;
1605 const U32 target = (U32)(ip - base);
1606 U32 idx = zc->nextToUpdate;
1607
Yann Collet22d76322016-06-21 08:01:51 +02001608 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001609 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1610 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1611 hashTable[h] = idx;
1612 idx++;
1613 }
1614
1615 zc->nextToUpdate = target;
1616 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1617}
1618
1619
1620
1621FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1622size_t ZSTD_HcFindBestMatch_generic (
1623 ZSTD_CCtx* zc, /* Index table will be updated */
1624 const BYTE* const ip, const BYTE* const iLimit,
1625 size_t* offsetPtr,
1626 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1627{
1628 U32* const chainTable = zc->chainTable;
1629 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1630 const U32 chainMask = chainSize-1;
1631 const BYTE* const base = zc->base;
1632 const BYTE* const dictBase = zc->dictBase;
1633 const U32 dictLimit = zc->dictLimit;
1634 const BYTE* const prefixStart = base + dictLimit;
1635 const BYTE* const dictEnd = dictBase + dictLimit;
1636 const U32 lowLimit = zc->lowLimit;
1637 const U32 current = (U32)(ip-base);
1638 const U32 minChain = current > chainSize ? current - chainSize : 0;
1639 int nbAttempts=maxNbAttempts;
1640 size_t ml=EQUAL_READ32-1;
1641
1642 /* HC4 match finder */
1643 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1644
Yann Collet22d76322016-06-21 08:01:51 +02001645 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02001646 const BYTE* match;
1647 size_t currentMl=0;
1648 if ((!extDict) || matchIndex >= dictLimit) {
1649 match = base + matchIndex;
1650 if (match[ml] == ip[ml]) /* potentially better */
1651 currentMl = ZSTD_count(ip, match, iLimit);
1652 } else {
1653 match = dictBase + matchIndex;
1654 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1655 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1656 }
1657
1658 /* save best solution */
Yann Collet22d76322016-06-21 08:01:51 +02001659 if (currentMl > ml) { ml = currentMl; *offsetPtr = current - matchIndex + ZSTD_REP_MOVE; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }
inikep64d7bcb2016-04-07 19:14:09 +02001660
1661 if (matchIndex <= minChain) break;
1662 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1663 }
1664
1665 return ml;
1666}
1667
1668
1669FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1670 ZSTD_CCtx* zc,
1671 const BYTE* ip, const BYTE* const iLimit,
1672 size_t* offsetPtr,
1673 const U32 maxNbAttempts, const U32 matchLengthSearch)
1674{
1675 switch(matchLengthSearch)
1676 {
1677 default :
1678 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1679 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1680 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1681 }
1682}
1683
1684
1685FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1686 ZSTD_CCtx* zc,
1687 const BYTE* ip, const BYTE* const iLimit,
1688 size_t* offsetPtr,
1689 const U32 maxNbAttempts, const U32 matchLengthSearch)
1690{
1691 switch(matchLengthSearch)
1692 {
1693 default :
1694 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1695 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1696 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1697 }
1698}
1699
inikep64d7bcb2016-04-07 19:14:09 +02001700
Yann Collet287b7d92015-11-22 13:24:05 +01001701/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001702* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001703*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001704FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001705void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1706 const void* src, size_t srcSize,
1707 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001708{
inikepfaa8d8a2016-04-05 19:01:10 +02001709 seqStore_t* seqStorePtr = &(ctx->seqStore);
1710 const BYTE* const istart = (const BYTE*)src;
1711 const BYTE* ip = istart;
1712 const BYTE* anchor = istart;
1713 const BYTE* const iend = istart + srcSize;
1714 const BYTE* const ilimit = iend - 8;
1715 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001716
Yann Collet793c6492016-04-09 20:32:00 +02001717 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1718 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001719
inikep64d7bcb2016-04-07 19:14:09 +02001720 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1721 size_t* offsetPtr,
1722 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02001723 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02001724 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02001725
inikepfaa8d8a2016-04-05 19:01:10 +02001726 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001727 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02001728 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02001729 { U32 const maxRep = (U32)(ip-base);
1730 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
1731 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
1732 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001733
inikepfaa8d8a2016-04-05 19:01:10 +02001734 /* Match Loop */
1735 while (ip < ilimit) {
1736 size_t matchLength=0;
1737 size_t offset=0;
1738 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001739
inikepfaa8d8a2016-04-05 19:01:10 +02001740 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02001741 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02001742 /* repcode : we take it */
Yann Collet9634f672016-07-03 01:23:58 +02001743 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001744 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001745 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001746
inikepfaa8d8a2016-04-05 19:01:10 +02001747 /* first search (depth 0) */
1748 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001749 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001750 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001751 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001752 }
Yann Collet5106a762015-11-05 15:00:24 +01001753
inikep7bc19b62016-04-06 09:46:01 +02001754 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001755 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1756 continue;
1757 }
1758
inikep64d7bcb2016-04-07 19:14:09 +02001759 /* let's try to find a better solution */
1760 if (depth>=1)
1761 while (ip<ilimit) {
1762 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001763 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1764 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001765 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02001766 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001767 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1768 matchLength = mlRep, offset = 0, start = ip;
1769 }
1770 { size_t offset2=99999999;
1771 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001772 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1773 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02001774 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1775 matchLength = ml2, offset = offset2, start = ip;
1776 continue; /* search a better one */
1777 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001778
inikep64d7bcb2016-04-07 19:14:09 +02001779 /* let's find an even better one */
1780 if ((depth==2) && (ip<ilimit)) {
1781 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001782 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1783 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001784 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02001785 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001786 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1787 matchLength = ml2, offset = 0, start = ip;
1788 }
1789 { size_t offset2=99999999;
1790 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001791 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1792 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02001793 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1794 matchLength = ml2, offset = offset2, start = ip;
1795 continue;
1796 } } }
1797 break; /* nothing found : store previous solution */
1798 }
1799
1800 /* catch up */
1801 if (offset) {
1802 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1803 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02001804 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02001805 }
1806
inikepfaa8d8a2016-04-05 19:01:10 +02001807 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001808_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001809 { size_t const litLength = start - anchor;
1810 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1811 anchor = ip = start + matchLength;
1812 }
Yann Collet48537162016-04-07 15:24:29 +02001813
inikepfaa8d8a2016-04-05 19:01:10 +02001814 /* check immediate repcode */
1815 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02001816 && ((offset_2>0)
1817 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02001818 /* store sequence */
Yann Collet9634f672016-07-03 01:23:58 +02001819 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
1820 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02001821 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1822 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02001823 anchor = ip;
1824 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02001825 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001826
Yann Collet4266c0a2016-06-14 01:49:25 +02001827 /* Save reps for next block */
Yann Collet9634f672016-07-03 01:23:58 +02001828 ctx->savedRep[0] = offset_1 ? offset_1 : savedOffset;
1829 ctx->savedRep[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02001830
inikepfaa8d8a2016-04-05 19:01:10 +02001831 /* Last Literals */
1832 { size_t const lastLLSize = iend - anchor;
1833 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1834 seqStorePtr->lit += lastLLSize;
inikepfb5df612016-05-24 15:36:37 +02001835 ZSTD_statsUpdatePrices(&seqStorePtr->stats, lastLLSize, anchor, 0, 0);
Yann Collet5106a762015-11-05 15:00:24 +01001836 }
Yann Collet5106a762015-11-05 15:00:24 +01001837}
1838
Yann Collet5be2dd22015-11-11 13:43:58 +01001839
inikep64d7bcb2016-04-07 19:14:09 +02001840static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1841{
1842 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
1843}
1844
1845static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1846{
1847 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
1848}
1849
1850static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1851{
1852 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
1853}
1854
1855static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1856{
1857 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
1858}
1859
1860
inikepfaa8d8a2016-04-05 19:01:10 +02001861FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001862void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1863 const void* src, size_t srcSize,
1864 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01001865{
inikepfaa8d8a2016-04-05 19:01:10 +02001866 seqStore_t* seqStorePtr = &(ctx->seqStore);
1867 const BYTE* const istart = (const BYTE*)src;
1868 const BYTE* ip = istart;
1869 const BYTE* anchor = istart;
1870 const BYTE* const iend = istart + srcSize;
1871 const BYTE* const ilimit = iend - 8;
1872 const BYTE* const base = ctx->base;
1873 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02001874 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02001875 const BYTE* const prefixStart = base + dictLimit;
1876 const BYTE* const dictBase = ctx->dictBase;
1877 const BYTE* const dictEnd = dictBase + dictLimit;
1878 const BYTE* const dictStart = dictBase + ctx->lowLimit;
1879
1880 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
1881 const U32 mls = ctx->params.cParams.searchLength;
1882
inikep64d7bcb2016-04-07 19:14:09 +02001883 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1884 size_t* offsetPtr,
1885 U32 maxNbAttempts, U32 matchLengthSearch);
1886 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
1887
inikepfaa8d8a2016-04-05 19:01:10 +02001888 /* init */
1889 U32 rep[ZSTD_REP_INIT];
Yann Collet4266c0a2016-06-14 01:49:25 +02001890 { U32 i; for (i=0; i<ZSTD_REP_INIT; i++) rep[i]=ctx->rep[i]; }
inikepfaa8d8a2016-04-05 19:01:10 +02001891
inikep64d7bcb2016-04-07 19:14:09 +02001892 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02001893 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02001894
1895 /* Match Loop */
1896 while (ip < ilimit) {
1897 size_t matchLength=0;
1898 size_t offset=0;
1899 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02001900 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02001901
1902 /* check repCode */
Yann Collet4266c0a2016-06-14 01:49:25 +02001903 { const U32 repIndex = (U32)(current+1 - rep[0]);
inikepfaa8d8a2016-04-05 19:01:10 +02001904 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1905 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02001906 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02001907 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02001908 /* repcode detected we should take it */
1909 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02001910 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1911 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02001912 } }
1913
1914 /* first search (depth 0) */
1915 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001916 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001917 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001918 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001919 }
1920
inikep7bc19b62016-04-06 09:46:01 +02001921 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001922 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1923 continue;
1924 }
1925
inikep64d7bcb2016-04-07 19:14:09 +02001926 /* let's try to find a better solution */
1927 if (depth>=1)
1928 while (ip<ilimit) {
1929 ip ++;
1930 current++;
1931 /* check repCode */
1932 if (offset) {
1933 const U32 repIndex = (U32)(current - rep[0]);
1934 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1935 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02001936 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02001937 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1938 /* repcode detected */
1939 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
1940 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1941 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02001942 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001943 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
1944 matchLength = repLength, offset = 0, start = ip;
1945 } }
1946
1947 /* search match, depth 1 */
1948 { size_t offset2=99999999;
1949 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001950 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1951 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02001952 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1953 matchLength = ml2, offset = offset2, start = ip;
1954 continue; /* search a better one */
1955 } }
1956
1957 /* let's find an even better one */
1958 if ((depth==2) && (ip<ilimit)) {
1959 ip ++;
1960 current++;
1961 /* check repCode */
1962 if (offset) {
1963 const U32 repIndex = (U32)(current - rep[0]);
1964 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1965 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02001966 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02001967 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1968 /* repcode detected */
1969 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
1970 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1971 int gain2 = (int)(repLength * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02001972 int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001973 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
1974 matchLength = repLength, offset = 0, start = ip;
1975 } }
1976
1977 /* search match, depth 2 */
1978 { size_t offset2=99999999;
1979 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001980 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1981 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02001982 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1983 matchLength = ml2, offset = offset2, start = ip;
1984 continue;
1985 } } }
1986 break; /* nothing found : store previous solution */
1987 }
1988
inikepfaa8d8a2016-04-05 19:01:10 +02001989 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001990 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02001991 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02001992 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1993 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02001994 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
inikep5ce00ae2016-04-05 21:03:43 +02001995 rep[1] = rep[0]; rep[0] = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02001996 }
inikepfaa8d8a2016-04-05 19:01:10 +02001997
inikepfaa8d8a2016-04-05 19:01:10 +02001998 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001999_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002000 { size_t const litLength = start - anchor;
2001 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
2002 anchor = ip = start + matchLength;
2003 }
2004
2005 /* check immediate repcode */
2006 while (ip <= ilimit) {
2007 const U32 repIndex = (U32)((ip-base) - rep[1]);
2008 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2009 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002010 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002011 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2012 /* repcode detected we should take it */
2013 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02002014 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
inikep5ce00ae2016-04-05 21:03:43 +02002015 offset = rep[1]; rep[1] = rep[0]; rep[0] = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002016 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2017 ip += matchLength;
2018 anchor = ip;
2019 continue; /* faster when present ... (?) */
2020 }
2021 break;
2022 } }
2023
Yann Collet4266c0a2016-06-14 01:49:25 +02002024 /* Save reps for next block */
2025 ctx->savedRep[0] = rep[0]; ctx->savedRep[1] = rep[1]; ctx->savedRep[2] = rep[2];
2026
inikepfaa8d8a2016-04-05 19:01:10 +02002027 /* Last Literals */
2028 { size_t const lastLLSize = iend - anchor;
2029 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2030 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002031 }
2032}
2033
2034
Yann Collet59d1f792016-01-23 19:28:41 +01002035void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002036{
inikep64d7bcb2016-04-07 19:14:09 +02002037 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002038}
2039
Yann Collet59d1f792016-01-23 19:28:41 +01002040static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002041{
Yann Colleta1249dc2016-01-25 04:22:03 +01002042 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002043}
Yann Collet9a24e592015-11-22 02:53:43 +01002044
Yann Collet59d1f792016-01-23 19:28:41 +01002045static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002046{
Yann Colleta1249dc2016-01-25 04:22:03 +01002047 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002048}
2049
Yann Collet59d1f792016-01-23 19:28:41 +01002050static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002051{
Yann Colleta1249dc2016-01-25 04:22:03 +01002052 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002053}
2054
inikepef519412016-04-21 11:08:43 +02002055
inikepef519412016-04-21 11:08:43 +02002056/* The optimal parser */
2057#include "zstd_opt.h"
2058
2059static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2060{
Yann Colletd4f4e582016-06-27 01:31:35 +02002061#ifdef ZSTD_OPT_H_91842398743
inikepef519412016-04-21 11:08:43 +02002062 ZSTD_compressBlock_opt_generic(ctx, src, srcSize);
Yann Colletd4f4e582016-06-27 01:31:35 +02002063#else
2064 (void)ctx; (void)src; (void)srcSize;
2065 return;
2066#endif
inikepef519412016-04-21 11:08:43 +02002067}
2068
inikepd3b8d7a2016-02-22 10:06:17 +01002069static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002070{
Yann Colletd4f4e582016-06-27 01:31:35 +02002071#ifdef ZSTD_OPT_H_91842398743
inikep5ce00ae2016-04-05 21:03:43 +02002072 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize);
Yann Colletd4f4e582016-06-27 01:31:35 +02002073#else
2074 (void)ctx; (void)src; (void)srcSize;
2075 return;
2076#endif
inikepe2bfe242016-01-31 11:25:48 +01002077}
2078
Yann Collet7a231792015-11-21 15:27:35 +01002079
Yann Collet59d1f792016-01-23 19:28:41 +01002080typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002081
Yann Colletb923f652016-01-26 03:14:20 +01002082static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002083{
inikepd3b8d7a2016-02-22 10:06:17 +01002084 static const ZSTD_blockCompressor blockCompressor[2][6] = {
2085 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt },
2086 { 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 +01002087 };
2088
2089 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002090}
2091
2092
Yann Colletd1b26842016-03-15 01:24:33 +01002093static 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 +01002094{
Yann Collet19cab462016-06-17 12:54:52 +02002095 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01002096 if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */
Yann Collet19cab462016-06-17 12:54:52 +02002097 ZSTD_resetSeqStore(&(zc->seqStore));
Yann Collet59d1f792016-01-23 19:28:41 +01002098 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002099 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002100}
2101
2102
inikep5cc4efd2016-03-25 10:52:25 +01002103
2104
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002105static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2106 void* dst, size_t dstCapacity,
2107 const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002108{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002109 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002110 size_t remaining = srcSize;
2111 const BYTE* ip = (const BYTE*)src;
2112 BYTE* const ostart = (BYTE*)dst;
2113 BYTE* op = ostart;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002114 const U32 maxDist = 1 << cctx->params.cParams.windowLog;
2115 ZSTD_stats_t* stats = &cctx->seqStore.stats;
inikep5cc4efd2016-03-25 10:52:25 +01002116 ZSTD_statsInit(stats);
Yann Collet9b11b462015-11-01 12:40:22 +01002117
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002118 if (cctx->params.fParams.checksumFlag)
2119 XXH64_update(&cctx->xxhState, src, srcSize);
2120
Yann Collet2ce49232016-02-02 14:36:49 +01002121 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01002122 size_t cSize;
Yann Collete3d52942016-06-06 11:07:33 +02002123 ZSTD_statsResetFreqs(stats); /* debug only */
Yann Collet3e358272015-11-04 18:19:39 +01002124
inikepfb5df612016-05-24 15:36:37 +02002125 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 +01002126 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002127
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002128 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002129 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002130 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2131 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2132 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002133 }
Yann Collet89db5e02015-11-13 11:27:46 +01002134
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002135 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002136 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002137
Yann Collet2ce49232016-02-02 14:36:49 +01002138 if (cSize == 0) { /* block is not compressible */
Yann Colletd1b26842016-03-15 01:24:33 +01002139 cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002140 if (ZSTD_isError(cSize)) return cSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002141 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01002142 op[0] = (BYTE)(cSize>>16);
2143 op[1] = (BYTE)(cSize>>8);
2144 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01002145 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01002146 cSize += 3;
2147 }
2148
2149 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002150 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002151 ip += blockSize;
2152 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002153 }
2154
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002155 ZSTD_statsPrint(stats, cctx->params.cParams.searchLength);
Yann Colletf3eca252015-10-22 15:31:46 +01002156 return op-ostart;
2157}
2158
2159
Yann Collet6236eba2016-04-12 15:52:33 +02002160static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002161 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002162{ BYTE* const op = (BYTE*)dst;
Yann Colletc46fb922016-05-29 05:01:04 +02002163 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
Yann Collet2cc72f12016-06-06 17:50:07 +02002164 U32 const checksumFlag = params.fParams.checksumFlag>0;
Yann Collet673f0d72016-06-06 00:26:38 +02002165 U32 const windowSize = 1U << params.cParams.windowLog;
2166 U32 const directModeFlag = params.fParams.contentSizeFlag && (windowSize > (pledgedSrcSize-1));
2167 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2168 U32 const fcsCode = params.fParams.contentSizeFlag ?
2169 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
2170 0;
2171 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (directModeFlag<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002172 size_t pos;
2173
2174 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet6236eba2016-04-12 15:52:33 +02002175
2176 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002177 op[4] = frameHeaderDecriptionByte; pos=5;
2178 if (!directModeFlag) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002179 switch(dictIDSizeCode)
2180 {
2181 default: /* impossible */
2182 case 0 : break;
2183 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
2184 case 2 : MEM_writeLE16(op+pos, (U16)(dictID)); pos+=2; break;
2185 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2186 }
Yann Collet673f0d72016-06-06 00:26:38 +02002187 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002188 {
2189 default: /* impossible */
Yann Collet673f0d72016-06-06 00:26:38 +02002190 case 0 : if (directModeFlag) op[pos++] = (BYTE)(pledgedSrcSize); break;
2191 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2192 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002193 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002194 }
Yann Colletc46fb922016-05-29 05:01:04 +02002195 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002196}
2197
2198
Yann Colletbf42c8e2016-01-09 01:08:23 +01002199static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002200 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002201 const void* src, size_t srcSize,
2202 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01002203{
Yann Collet2acb5d32015-10-29 16:49:43 +01002204 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002205 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002206
Yann Collet887e7da2016-04-11 20:12:27 +02002207 if (zc->stage==0) return ERROR(stage_wrong);
2208 if (frame && (zc->stage==1)) { /* copy saved header */
Yann Collet673f0d72016-06-06 00:26:38 +02002209 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, zc->params, zc->frameContentSize, zc->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002210 if (ZSTD_isError(fhSize)) return fhSize;
2211 dstCapacity -= fhSize;
2212 dst = (char*)dst + fhSize;
Yann Collet887e7da2016-04-11 20:12:27 +02002213 zc->stage = 2;
Yann Colletecd651b2016-01-07 15:35:18 +01002214 }
Yann Colletf3eca252015-10-22 15:31:46 +01002215
Yann Collet417890c2015-12-04 17:16:37 +01002216 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01002217 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002218 /* not contiguous */
Yann Collet70e45772016-03-19 18:08:32 +01002219 size_t const delta = zc->nextSrc - ip;
Yann Collet417890c2015-12-04 17:16:37 +01002220 zc->lowLimit = zc->dictLimit;
2221 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2222 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01002223 zc->base -= delta;
2224 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01002225 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002226 }
2227
Yann Collet89db5e02015-11-13 11:27:46 +01002228 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01002229 if (zc->lowLimit > (1<<30)) {
Yann Collet4623d112016-06-20 19:15:37 +02002230 U32 const btplus = (zc->params.cParams.strategy == ZSTD_btlazy2) | (zc->params.cParams.strategy == ZSTD_btopt);
Yann Collet8a57b922016-04-04 13:49:18 +02002231 U32 const chainMask = (1 << (zc->params.cParams.chainLog - btplus)) - 1;
2232 U32 const newLowLimit = zc->lowLimit & chainMask; /* preserve position % chainSize */
Yann Collet70e45772016-03-19 18:08:32 +01002233 U32 const correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002234 ZSTD_reduceIndex(zc, correction);
2235 zc->base += correction;
2236 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002237 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002238 zc->dictLimit -= correction;
2239 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2240 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01002241 }
2242
Yann Colletbf42c8e2016-01-09 01:08:23 +01002243 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01002244 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01002245 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2246 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002247 }
2248
Yann Colletc3652152015-11-24 14:06:07 +01002249 zc->nextSrc = ip + srcSize;
Yann Collet70e45772016-03-19 18:08:32 +01002250 { size_t const cSize = frame ?
Yann Collet7cbe79a2016-03-23 22:31:57 +01002251 ZSTD_compress_generic (zc, dst, dstCapacity, src, srcSize) :
2252 ZSTD_compressBlock_internal (zc, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002253 if (ZSTD_isError(cSize)) return cSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002254 return cSize + fhSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002255 }
Yann Colletf3eca252015-10-22 15:31:46 +01002256}
2257
Yann Colletbf42c8e2016-01-09 01:08:23 +01002258
2259size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002260 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002261 const void* src, size_t srcSize)
2262{
Yann Collet7cbe79a2016-03-23 22:31:57 +01002263 return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 1);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002264}
2265
2266
Yann Colletd1b26842016-03-15 01:24:33 +01002267size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002268{
Yann Collet569b81a2016-03-16 15:26:51 +01002269 if (srcSize > ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
inikepd6f208b2016-04-04 21:15:23 +02002270 ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.cParams.searchLength);
Yann Colletd1b26842016-03-15 01:24:33 +01002271 return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002272}
2273
2274
Yann Colletb923f652016-01-26 03:14:20 +01002275static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002276{
2277 const BYTE* const ip = (const BYTE*) src;
2278 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002279
Yann Collet417890c2015-12-04 17:16:37 +01002280 /* input becomes current prefix */
2281 zc->lowLimit = zc->dictLimit;
2282 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2283 zc->dictBase = zc->base;
2284 zc->base += ip - zc->nextSrc;
2285 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002286 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002287
2288 zc->nextSrc = iend;
2289 if (srcSize <= 8) return 0;
2290
Yann Collet3b719252016-03-30 19:48:05 +02002291 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002292 {
2293 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002294 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002295 break;
2296
2297 case ZSTD_greedy:
2298 case ZSTD_lazy:
2299 case ZSTD_lazy2:
Yann Collet3b719252016-03-30 19:48:05 +02002300 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002301 break;
2302
2303 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002304 case ZSTD_btopt:
Yann Collet3b719252016-03-30 19:48:05 +02002305 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002306 break;
2307
2308 default:
2309 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2310 }
2311
Yann Collet2ce49232016-02-02 14:36:49 +01002312 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002313 return 0;
2314}
2315
2316
Yann Colletb923f652016-01-26 03:14:20 +01002317/* Dictionary format :
2318 Magic == ZSTD_DICT_MAGIC (4 bytes)
Yann Colletfb797352016-03-13 11:08:40 +01002319 HUF_writeCTable(256)
Yann Collet736d4192016-06-15 18:48:51 +02002320 FSE_writeNCount(ml)
2321 FSE_writeNCount(off)
2322 FSE_writeNCount(ll)
2323 RepOffsets
Yann Colletb923f652016-01-26 03:14:20 +01002324 Dictionary content
2325*/
Yann Colletfb797352016-03-13 11:08:40 +01002326/*! ZSTD_loadDictEntropyStats() :
Yann Collet736d4192016-06-15 18:48:51 +02002327 @return : size read from dictionary
2328 note : magic number supposed already checked */
2329static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002330{
Yann Collet52a06222016-06-15 13:53:34 +02002331 const BYTE* dictPtr = (const BYTE*)dict;
2332 const BYTE* const dictEnd = dictPtr + dictSize;
Yann Colletfb810d62016-01-28 00:18:06 +01002333
Yann Collet736d4192016-06-15 18:48:51 +02002334 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dict, dictSize);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002335 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002336 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002337 }
Yann Colletfb810d62016-01-28 00:18:06 +01002338
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002339 { short offcodeNCount[MaxOff+1];
2340 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
Yann Collet52a06222016-06-15 13:53:34 +02002341 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002342 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet736d4192016-06-15 18:48:51 +02002343 { size_t const errorCode = FSE_buildCTable(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002344 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
Yann Collet52a06222016-06-15 13:53:34 +02002345 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002346 }
Yann Colletfb810d62016-01-28 00:18:06 +01002347
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002348 { short matchlengthNCount[MaxML+1];
2349 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
Yann Collet52a06222016-06-15 13:53:34 +02002350 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002351 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet736d4192016-06-15 18:48:51 +02002352 { size_t const errorCode = FSE_buildCTable(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002353 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
Yann Collet52a06222016-06-15 13:53:34 +02002354 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002355 }
Yann Colletfb810d62016-01-28 00:18:06 +01002356
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002357 { short litlengthNCount[MaxLL+1];
2358 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
Yann Collet52a06222016-06-15 13:53:34 +02002359 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002360 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet736d4192016-06-15 18:48:51 +02002361 { size_t const errorCode = FSE_buildCTable(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002362 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
Yann Collet52a06222016-06-15 13:53:34 +02002363 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002364 }
Yann Colletfb810d62016-01-28 00:18:06 +01002365
Yann Collet52a06222016-06-15 13:53:34 +02002366 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Yann Collet736d4192016-06-15 18:48:51 +02002367 cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);
2368 cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);
2369 cctx->rep[2] = MEM_readLE32(dictPtr+8); if (cctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002370 dictPtr += 12;
2371
Yann Collet736d4192016-06-15 18:48:51 +02002372 cctx->flagStaticTables = 1;
Yann Collet52a06222016-06-15 13:53:34 +02002373 return dictPtr - (const BYTE*)dict;
Yann Colletb923f652016-01-26 03:14:20 +01002374}
2375
Yann Colletd1b26842016-03-15 01:24:33 +01002376/** ZSTD_compress_insertDictionary() :
2377* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002378static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002379{
Yann Colletc46fb922016-05-29 05:01:04 +02002380 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002381
Yann Colletd1b26842016-03-15 01:24:33 +01002382 /* default : dict is pure content */
2383 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletc46fb922016-05-29 05:01:04 +02002384 zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4);
Yann Colletd1b26842016-03-15 01:24:33 +01002385
2386 /* known magic number : dict is parsed for entropy stats and content */
Yann Colletc46fb922016-05-29 05:01:04 +02002387 { size_t const eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8) + 8;
Yann Collet21588e32016-03-30 16:50:44 +02002388 if (ZSTD_isError(eSize)) return eSize;
2389 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002390 }
Yann Colletecd651b2016-01-07 15:35:18 +01002391}
2392
Yann Collet0085cd32016-04-12 14:14:10 +02002393
Yann Collet27caf2a2016-04-01 15:48:48 +02002394/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002395* @return : 0, or an error code */
Yann Collet27caf2a2016-04-01 15:48:48 +02002396static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* zc,
Yann Collet1c8e1942016-01-26 16:31:22 +01002397 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002398 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002399{
Yann Collet673f0d72016-06-06 00:26:38 +02002400 size_t const resetError = ZSTD_resetCCtx_advanced(zc, params, pledgedSrcSize, 1);
2401 if (ZSTD_isError(resetError)) return resetError;
Yann Collet89db5e02015-11-13 11:27:46 +01002402
Yann Collet1c8e1942016-01-26 16:31:22 +01002403 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002404}
2405
2406
Yann Collet27caf2a2016-04-01 15:48:48 +02002407/*! ZSTD_compressBegin_advanced() :
2408* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002409size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002410 const void* dict, size_t dictSize,
2411 ZSTD_parameters params, U64 pledgedSrcSize)
2412{
2413 /* compression parameters verification and optimization */
2414 { size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize);
2415 if (ZSTD_isError(errorCode)) return errorCode; }
2416
Yann Collet81e13ef2016-06-07 00:51:51 +02002417 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002418}
2419
2420
Yann Collet81e13ef2016-06-07 00:51:51 +02002421size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002422{
Yann Collet6c6e1752016-06-27 15:28:45 +02002423 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002424 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", cctx->base, compressionLevel);
2425 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002426}
Yann Collet083fcc82015-10-25 14:06:35 +01002427
inikep19bd48f2016-04-04 12:10:00 +02002428
Yann Collet1c8e1942016-01-26 16:31:22 +01002429size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002430{
inikepa4dde252016-03-01 14:14:35 +01002431 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet3b719252016-03-30 19:48:05 +02002432 return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002433}
2434
2435
Yann Colletfb797352016-03-13 11:08:40 +01002436/*! ZSTD_compressEnd() :
2437* Write frame epilogue.
Yann Collet88fcd292015-11-25 14:42:45 +01002438* @return : nb of bytes written into dst (or an error code) */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002439size_t ZSTD_compressEnd(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002440{
2441 BYTE* op = (BYTE*)dst;
Yann Collet6236eba2016-04-12 15:52:33 +02002442 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002443
Yann Collet887e7da2016-04-11 20:12:27 +02002444 /* not even init ! */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002445 if (cctx->stage==0) return ERROR(stage_wrong);
Yann Collet887e7da2016-04-11 20:12:27 +02002446
2447 /* special case : empty frame */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002448 if (cctx->stage==1) {
2449 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002450 if (ZSTD_isError(fhSize)) return fhSize;
2451 dstCapacity -= fhSize;
2452 op += fhSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002453 cctx->stage = 2;
Yann Colletecd651b2016-01-07 15:35:18 +01002454 }
2455
2456 /* frame epilogue */
Yann Colletd1b26842016-03-15 01:24:33 +01002457 if (dstCapacity < 3) return ERROR(dstSize_tooSmall);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002458 { U32 const checksum = cctx->params.fParams.checksumFlag ?
2459 (U32)((XXH64_digest(&cctx->xxhState) >> 11) & ((1<<22)-1)) :
2460 0;
2461 op[0] = (BYTE)((bt_end<<6) + (checksum>>16));
2462 op[1] = (BYTE)(checksum>>8);
2463 op[2] = (BYTE)checksum;
2464 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002465
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002466 cctx->stage = 0; /* return to "created but not init" status */
Yann Collet6236eba2016-04-12 15:52:33 +02002467 return 3+fhSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002468}
2469
Yann Colletfd416f12016-01-30 03:14:15 +01002470
Yann Collet302fb532016-06-07 12:16:49 +02002471/*! ZSTD_compress_usingPreparedCCtx() :
2472* Same as ZSTD_compress_usingDict, but using a reference context `preparedCCtx`, where dictionary has been loaded.
2473* It avoids reloading the dictionary each time.
2474* `preparedCCtx` must have been properly initialized using ZSTD_compressBegin_usingDict() or ZSTD_compressBegin_advanced().
2475* Requires 2 contexts : 1 for reference (preparedCCtx) which will not be modified, and 1 to run the compression operation (cctx) */
2476static size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
Yann Colletd1b26842016-03-15 01:24:33 +01002477 void* dst, size_t dstCapacity,
Yann Colletfd416f12016-01-30 03:14:15 +01002478 const void* src, size_t srcSize)
2479{
Yann Collet70e45772016-03-19 18:08:32 +01002480 { size_t const errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2481 if (ZSTD_isError(errorCode)) return errorCode;
2482 }
2483 { size_t const cSize = ZSTD_compressContinue(cctx, dst, dstCapacity, src, srcSize);
2484 if (ZSTD_isError(cSize)) return cSize;
Yann Collet0dbf2872016-04-08 02:02:12 +02002485
Yann Collet70e45772016-03-19 18:08:32 +01002486 { size_t const endSize = ZSTD_compressEnd(cctx, (char*)dst+cSize, dstCapacity-cSize);
2487 if (ZSTD_isError(endSize)) return endSize;
2488 return cSize + endSize;
2489 } }
Yann Colletfd416f12016-01-30 03:14:15 +01002490}
2491
2492
Yann Collet21588e32016-03-30 16:50:44 +02002493static size_t ZSTD_compress_internal (ZSTD_CCtx* ctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002494 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002495 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002496 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002497 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002498{
2499 BYTE* const ostart = (BYTE*)dst;
2500 BYTE* op = ostart;
2501
Yann Collet1c8e1942016-01-26 16:31:22 +01002502 /* Init */
Yann Collet27caf2a2016-04-01 15:48:48 +02002503 { size_t const errorCode = ZSTD_compressBegin_internal(ctx, dict, dictSize, params, srcSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002504 if(ZSTD_isError(errorCode)) return errorCode; }
Yann Colletf3eca252015-10-22 15:31:46 +01002505
2506 /* body (compression) */
Yann Colletd1b26842016-03-15 01:24:33 +01002507 { size_t const oSize = ZSTD_compressContinue (ctx, op, dstCapacity, src, srcSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002508 if(ZSTD_isError(oSize)) return oSize;
2509 op += oSize;
2510 dstCapacity -= oSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002511
2512 /* Close frame */
Yann Colletd1b26842016-03-15 01:24:33 +01002513 { size_t const oSize = ZSTD_compressEnd(ctx, op, dstCapacity);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002514 if(ZSTD_isError(oSize)) return oSize;
2515 op += oSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002516
2517 return (op - ostart);
2518}
2519
Yann Collet21588e32016-03-30 16:50:44 +02002520size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2521 void* dst, size_t dstCapacity,
2522 const void* src, size_t srcSize,
2523 const void* dict,size_t dictSize,
2524 ZSTD_parameters params)
2525{
Yann Collet3b719252016-03-30 19:48:05 +02002526 size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, srcSize);
Yann Collet21588e32016-03-30 16:50:44 +02002527 if (ZSTD_isError(errorCode)) return errorCode;
2528 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2529}
2530
Yann Colletd1b26842016-03-15 01:24:33 +01002531size_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 +01002532{
Yann Collet6c6e1752016-06-27 15:28:45 +02002533 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dictSize);
Yann Collet3b719252016-03-30 19:48:05 +02002534 params.fParams.contentSizeFlag = 1;
Yann Collet6c6e1752016-06-27 15:28:45 +02002535 ZSTD_LOG_BLOCK("%p: ZSTD_compress_usingDict srcSize=%d dictSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, (int)dictSize, compressionLevel);
Yann Collet21588e32016-03-30 16:50:44 +02002536 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002537}
2538
Yann Colletd1b26842016-03-15 01:24:33 +01002539size_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 +01002540{
inikepa4dde252016-03-01 14:14:35 +01002541 ZSTD_LOG_BLOCK("%p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, compressionLevel);
Yann Collet21588e32016-03-30 16:50:44 +02002542 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002543}
2544
Yann Colletd1b26842016-03-15 01:24:33 +01002545size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002546{
Yann Collet44fe9912015-10-29 22:02:40 +01002547 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002548 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002549 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002550 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002551 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
inikep28669512016-06-02 13:04:18 +02002552 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 +01002553 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002554}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002555
Yann Colletfd416f12016-01-30 03:14:15 +01002556
Yann Collet81e13ef2016-06-07 00:51:51 +02002557/* ===== Dictionary API ===== */
2558
2559struct ZSTD_CDict_s {
2560 void* dictContent;
2561 size_t dictContentSize;
2562 ZSTD_CCtx* refContext;
2563}; /* typedef'd tp ZSTD_CDict within zstd.h */
2564
2565ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, ZSTD_parameters params, ZSTD_customMem customMem)
2566{
2567 if (!customMem.customAlloc && !customMem.customFree)
2568 customMem = defaultCustomMem;
2569
Yann Collet3d2cd7f2016-06-27 15:12:26 +02002570 if (!customMem.customAlloc || !customMem.customFree) /* can't have 1/2 custom alloc/free as NULL */
Yann Collet81e13ef2016-06-07 00:51:51 +02002571 return NULL;
2572
2573 { ZSTD_CDict* const cdict = (ZSTD_CDict*) customMem.customAlloc(customMem.opaque, sizeof(*cdict));
2574 void* const dictContent = customMem.customAlloc(customMem.opaque, dictSize);
2575 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2576
2577 if (!dictContent || !cdict || !cctx) {
2578 customMem.customFree(customMem.opaque, dictContent);
2579 customMem.customFree(customMem.opaque, cdict);
2580 customMem.customFree(customMem.opaque, cctx);
2581 return NULL;
2582 }
2583
2584 memcpy(dictContent, dict, dictSize);
2585 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, dictContent, dictSize, params, 0);
2586 if (ZSTD_isError(errorCode)) {
2587 customMem.customFree(customMem.opaque, dictContent);
2588 customMem.customFree(customMem.opaque, cdict);
2589 customMem.customFree(customMem.opaque, cctx);
2590 return NULL;
2591 } }
2592
2593 cdict->dictContent = dictContent;
2594 cdict->dictContentSize = dictSize;
2595 cdict->refContext = cctx;
2596 return cdict;
2597 }
2598}
2599
2600ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2601{
2602 ZSTD_customMem const allocator = { NULL, NULL, NULL };
2603 ZSTD_parameters params;
2604 memset(&params, 0, sizeof(params));
2605 params.cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
2606 params.fParams.contentSizeFlag = 1;
2607 return ZSTD_createCDict_advanced(dict, dictSize, params, allocator);
2608}
2609
2610size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2611{
2612 ZSTD_freeFunction const cFree = cdict->refContext->customMem.customFree;
2613 void* const opaque = cdict->refContext->customMem.opaque;
2614 ZSTD_freeCCtx(cdict->refContext);
2615 cFree(opaque, cdict->dictContent);
2616 cFree(opaque, cdict);
2617 return 0;
2618}
2619
2620ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2621 void* dst, size_t dstCapacity,
2622 const void* src, size_t srcSize,
2623 const ZSTD_CDict* cdict)
2624{
2625 return ZSTD_compress_usingPreparedCCtx(cctx, cdict->refContext,
2626 dst, dstCapacity,
2627 src, srcSize);
2628}
2629
2630
2631
Yann Collet70e8c382016-02-10 13:37:52 +01002632/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01002633
Yann Collet236d94f2016-05-18 12:06:33 +02002634#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02002635#define ZSTD_MAX_CLEVEL 22
Yann Collet7d968c72016-02-03 02:11:32 +01002636unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2637
Yann Collet3b719252016-03-30 19:48:05 +02002638static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01002639{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02002640 /* W, C, H, S, L, TL, strat */
Yann Collet3b719252016-03-30 19:48:05 +02002641 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2642 { 19, 13, 14, 1, 7, 4, ZSTD_fast }, /* level 1 */
2643 { 19, 15, 16, 1, 6, 4, ZSTD_fast }, /* level 2 */
2644 { 20, 18, 20, 1, 6, 4, ZSTD_fast }, /* level 3 */
2645 { 20, 13, 17, 2, 5, 4, ZSTD_greedy }, /* level 4.*/
2646 { 20, 15, 18, 3, 5, 4, ZSTD_greedy }, /* level 5 */
2647 { 21, 16, 19, 2, 5, 4, ZSTD_lazy }, /* level 6 */
2648 { 21, 17, 20, 3, 5, 4, ZSTD_lazy }, /* level 7 */
2649 { 21, 18, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 8.*/
2650 { 21, 20, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 9 */
2651 { 21, 19, 21, 4, 5, 4, ZSTD_lazy2 }, /* level 10 */
2652 { 22, 20, 22, 4, 5, 4, ZSTD_lazy2 }, /* level 11 */
2653 { 22, 20, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 12 */
2654 { 22, 21, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 13 */
2655 { 22, 21, 22, 6, 5, 4, ZSTD_lazy2 }, /* level 14 */
2656 { 22, 21, 21, 5, 5, 4, ZSTD_btlazy2 }, /* level 15 */
2657 { 23, 22, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */
Yann Collet793c6492016-04-09 20:32:00 +02002658 { 23, 23, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 17.*/
2659 { 23, 23, 22, 6, 5, 24, ZSTD_btopt }, /* level 18.*/
2660 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19.*/
2661 { 25, 26, 23, 7, 3, 64, ZSTD_btopt }, /* level 20.*/
2662 { 26, 26, 23, 7, 3,256, ZSTD_btopt }, /* level 21.*/
2663 { 27, 27, 25, 9, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002664},
2665{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002666 /* W, C, H, S, L, T, strat */
2667 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 */
Yann Collet0dbf2872016-04-08 02:02:12 +02002668 { 18, 13, 14, 1, 6, 4, ZSTD_fast }, /* level 1 */
Yann Collet78267d12016-04-08 12:36:19 +02002669 { 18, 15, 17, 1, 5, 4, ZSTD_fast }, /* level 2 */
2670 { 18, 13, 15, 1, 5, 4, ZSTD_greedy }, /* level 3.*/
2671 { 18, 15, 17, 1, 5, 4, ZSTD_greedy }, /* level 4.*/
2672 { 18, 16, 17, 4, 5, 4, ZSTD_greedy }, /* level 5 */
2673 { 18, 17, 17, 5, 5, 4, ZSTD_greedy }, /* level 6 */
Yann Collet3b719252016-03-30 19:48:05 +02002674 { 18, 17, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */
2675 { 18, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2676 { 18, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2677 { 18, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
Yann Collet78267d12016-04-08 12:36:19 +02002678 { 18, 18, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 11.*/
2679 { 18, 18, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 12.*/
2680 { 18, 19, 17, 7, 4, 4, ZSTD_btlazy2 }, /* level 13 */
2681 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
2682 { 18, 18, 18, 8, 4, 24, ZSTD_btopt }, /* level 15.*/
2683 { 18, 19, 18, 8, 3, 48, ZSTD_btopt }, /* level 16.*/
2684 { 18, 19, 18, 8, 3, 96, ZSTD_btopt }, /* level 17.*/
2685 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
2686 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
2687 { 18, 19, 18, 11, 3,512, ZSTD_btopt }, /* level 20.*/
2688 { 18, 19, 18, 12, 3,512, ZSTD_btopt }, /* level 21.*/
2689 { 18, 19, 18, 13, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002690},
2691{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002692 /* W, C, H, S, L, T, strat */
2693 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2694 { 17, 12, 13, 1, 6, 4, ZSTD_fast }, /* level 1 */
2695 { 17, 13, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */
2696 { 17, 13, 14, 2, 5, 4, ZSTD_greedy }, /* level 3 */
2697 { 17, 13, 15, 3, 4, 4, ZSTD_greedy }, /* level 4 */
2698 { 17, 15, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */
2699 { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
2700 { 17, 15, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 7 */
2701 { 17, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2702 { 17, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2703 { 17, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
2704 { 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */
2705 { 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */
2706 { 17, 18, 17, 6, 4, 4, ZSTD_btlazy2 }, /* level 13.*/
2707 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
2708 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
2709 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
2710 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
2711 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
2712 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
2713 { 17, 18, 17, 9, 3,256, ZSTD_btopt }, /* level 20.*/
2714 { 17, 18, 17, 10, 3,256, ZSTD_btopt }, /* level 21.*/
2715 { 17, 18, 17, 11, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002716},
2717{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002718 /* W, C, H, S, L, T, strat */
2719 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 -- never used */
2720 { 14, 14, 14, 1, 4, 4, ZSTD_fast }, /* level 1 */
2721 { 14, 14, 15, 1, 4, 4, ZSTD_fast }, /* level 2 */
2722 { 14, 14, 14, 4, 4, 4, ZSTD_greedy }, /* level 3.*/
2723 { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 4.*/
2724 { 14, 14, 14, 4, 4, 4, ZSTD_lazy2 }, /* level 5 */
2725 { 14, 14, 14, 5, 4, 4, ZSTD_lazy2 }, /* level 6 */
2726 { 14, 14, 14, 6, 4, 4, ZSTD_lazy2 }, /* level 7.*/
2727 { 14, 14, 14, 7, 4, 4, ZSTD_lazy2 }, /* level 8.*/
2728 { 14, 15, 14, 6, 4, 4, ZSTD_btlazy2 }, /* level 9.*/
2729 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
2730 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
2731 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
2732 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
2733 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
2734 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
2735 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
2736 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
2737 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
2738 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
2739 { 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 20.*/
2740 { 14, 15, 15, 9, 3,256, ZSTD_btopt }, /* level 21.*/
2741 { 14, 15, 15, 10, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002742},
2743};
2744
Yann Collet236d94f2016-05-18 12:06:33 +02002745/*! ZSTD_getCParams() :
2746* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
2747* Size values are optional, provide 0 if not known or unused */
Yann Collet3b719252016-03-30 19:48:05 +02002748ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, U64 srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01002749{
Yann Collet15354142016-04-04 04:22:53 +02002750 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02002751 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02002752 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02002753 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02002754 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01002755 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02002756 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02002757 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
2758 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02002759 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02002760 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
2761 }
Yann Collet70d13012016-06-01 18:45:34 +02002762 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02002763 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01002764}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02002765
2766/*! ZSTD_getParams() :
2767* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object instead of a `ZSTD_compressionParameters`.
2768* All fields of `ZSTD_frameParameters` are set to default (0) */
2769ZSTD_parameters ZSTD_getParams(int compressionLevel, U64 srcSize, size_t dictSize) {
2770 ZSTD_parameters params;
2771 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
2772 memset(&params, 0, sizeof(params));
2773 params.cParams = cParams;
2774 return params;
2775}