blob: 34c6cf3ed167515a59dc7a1da5b80d9c06b3c359 [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 Collet5a0c8e22016-08-12 01:20:36 +020035/*-*******************************************************
Yann Collet4b100f42015-10-30 15:49:48 +010036* 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 Collet5a0c8e22016-08-12 01:20:36 +020058#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
Yann Colletd0e2cd12016-06-05 00:58:01 +020059#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 Collet731ef162016-07-27 21:05:12 +020069#define HASH_READ_SIZE 8
70typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
Yann Colletf3eca252015-10-22 15:31:46 +010071
Yann Colletf3eca252015-10-22 15:31:46 +010072
Yann Collet7d360282016-02-12 00:07:30 +010073/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010074* Helper functions
75***************************************/
Yann Collet59d1f792016-01-23 19:28:41 +010076size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
77
78
Yann Collet7d360282016-02-12 00:07:30 +010079/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010080* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010081***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010082static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
83{
Yann Collet14983e72015-11-11 21:38:21 +010084 ssPtr->lit = ssPtr->litStart;
Yann Colletc0ce4f12016-07-30 00:55:13 +020085 ssPtr->sequences = ssPtr->sequencesStart;
Yann Collet5d393572016-04-07 17:19:00 +020086 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010087}
88
89
Yann Collet7d360282016-02-12 00:07:30 +010090/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010091* Context memory management
92***************************************/
Yann Collet5be2dd22015-11-11 13:43:58 +010093struct ZSTD_CCtx_s
Yann Colletf3eca252015-10-22 15:31:46 +010094{
Yann Collet89db5e02015-11-13 11:27:46 +010095 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010096 const BYTE* base; /* All regular indexes relative to this position */
97 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010098 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010099 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +0100100 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +0100101 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +0100102 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Collet2ce49232016-02-02 14:36:49 +0100103 U32 loadedDictEnd;
Yann Collet731ef162016-07-27 21:05:12 +0200104 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +0200105 U32 rep[ZSTD_REP_NUM];
106 U32 savedRep[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +0200107 U32 dictID;
Yann Collet5be2dd22015-11-11 13:43:58 +0100108 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +0100109 void* workSpace;
110 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100111 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +0200112 U64 frameContentSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200113 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +0200114 ZSTD_customMem customMem;
Yann Colletecd651b2016-01-07 15:35:18 +0100115
Yann Collet712def92015-10-29 18:41:45 +0100116 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100117 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +0100118 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +0200119 U32* chainTable;
Yann Colletb923f652016-01-26 03:14:20 +0100120 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +0100121 U32 flagStaticTables;
Yann Collet731ef162016-07-27 21:05:12 +0200122 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
123 FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
124 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Colletf3eca252015-10-22 15:31:46 +0100125};
126
Yann Collet5be2dd22015-11-11 13:43:58 +0100127ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100128{
inikep3763c772016-06-03 13:28:20 +0200129 return ZSTD_createCCtx_advanced(defaultCustomMem);
inikep50e82c02016-05-23 15:49:09 +0200130}
131
132ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
133{
Yann Collet69c2cdb2016-07-14 16:52:45 +0200134 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +0200135
Yann Collet23b6e052016-08-28 21:05:43 -0700136 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
137 if (!customMem.customAlloc || !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200138
Yann Collet23b6e052016-08-28 21:05:43 -0700139 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200140 if (!cctx) return NULL;
141 memset(cctx, 0, sizeof(ZSTD_CCtx));
142 memcpy(&(cctx->customMem), &customMem, sizeof(ZSTD_customMem));
143 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100144}
145
Yann Collet5be2dd22015-11-11 13:43:58 +0100146size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100147{
inikep36403962016-06-03 16:36:50 +0200148 if (cctx==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -0700149 ZSTD_free(cctx->workSpace, cctx->customMem);
150 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100151 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100152}
153
Yann Collet70e3b312016-08-23 01:18:06 +0200154size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200155{
156 return sizeof(*cctx) + cctx->workSpaceSize;
157}
158
Yann Colletb44be742016-03-26 20:52:14 +0100159const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100160{
Yann Colletb44be742016-03-26 20:52:14 +0100161 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100162}
163
Yann Collet59d70632015-11-04 12:05:27 +0100164
Yann Collet21588e32016-03-30 16:50:44 +0200165#define CLAMP(val,min,max) { if (val<min) val=min; else if (val>max) val=max; }
166#define CLAMPCHECK(val,min,max) { if ((val<min) || (val>max)) return ERROR(compressionParameter_unsupported); }
167
168/** ZSTD_checkParams() :
169 ensure param values remain within authorized range.
170 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200171size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200172{
Yann Collet15354142016-04-04 04:22:53 +0200173 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200174 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200175 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
176 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
inikep75716852016-04-06 12:34:42 +0200177 { 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 +0200178 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
179 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
180 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Collet9bb87e52016-03-30 21:28:15 +0200181 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200182 return 0;
183}
184
185
Yann Collet3b719252016-03-30 19:48:05 +0200186/** ZSTD_checkCParams_advanced() :
187 temporary work-around, while the compressor compatibility remains limited regarding windowLog < 18 */
188size_t ZSTD_checkCParams_advanced(ZSTD_compressionParameters cParams, U64 srcSize)
189{
Yann Colletefb18302016-04-01 18:54:13 +0200190 if (srcSize > (1ULL << ZSTD_WINDOWLOG_MIN)) return ZSTD_checkCParams(cParams);
Yann Collet3b719252016-03-30 19:48:05 +0200191 if (cParams.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) return ERROR(compressionParameter_unsupported);
Yann Collet8a57b922016-04-04 13:49:18 +0200192 if (srcSize <= (1ULL << cParams.windowLog)) cParams.windowLog = ZSTD_WINDOWLOG_MIN; /* fake value - temporary work around */
193 if (srcSize <= (1ULL << cParams.chainLog)) cParams.chainLog = ZSTD_CHAINLOG_MIN; /* fake value - temporary work around */
Yann Colletef363902016-04-02 00:46:40 +0200194 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 +0200195 return ZSTD_checkCParams(cParams);
196}
197
198
Yann Collet70d13012016-06-01 18:45:34 +0200199/** ZSTD_adjustCParams() :
200 optimize cPar for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200201 mostly downsizing to reduce memory consumption and initialization.
202 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
203 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200204 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200205ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100206{
Yann Collet70d13012016-06-01 18:45:34 +0200207 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100208
Yann Collet70e45772016-03-19 18:08:32 +0100209 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200210 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
211 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200212 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Collet49bb0042016-06-04 20:17:38 +0200213 U32 const srcLog = ZSTD_highbit32((U32)(rSize)-1) + 1;
Yann Collet70d13012016-06-01 18:45:34 +0200214 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200215 } }
Yann Collet70d13012016-06-01 18:45:34 +0200216 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
217 { U32 const btPlus = (cPar.strategy == ZSTD_btlazy2) || (cPar.strategy == ZSTD_btopt);
218 U32 const maxChainLog = cPar.windowLog+btPlus;
219 if (cPar.chainLog > maxChainLog) cPar.chainLog = maxChainLog; } /* <= ZSTD_CHAINLOG_MAX */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100220
Yann Collet70d13012016-06-01 18:45:34 +0200221 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
222 if ((cPar.hashLog < ZSTD_HASHLOG_MIN) && ( (U32)cPar.strategy >= (U32)ZSTD_btlazy2)) cPar.hashLog = ZSTD_HASHLOG_MIN; /* required to ensure collision resistance in bt */
223
224 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100225}
226
227
Yann Collet88472382016-07-14 17:05:38 +0200228size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100229{
Yann Collet731ef162016-07-27 21:05:12 +0200230 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
231 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
232 size_t const maxNbSeq = blockSize / divider;
233 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200234
Yann Collet731ef162016-07-27 21:05:12 +0200235 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
236 size_t const hSize = ((size_t)1) << cParams.hashLog;
237 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
238 size_t const h3Size = ((size_t)1) << hashLog3;
239 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200240
241 size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
242 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
243 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
244 + ((cParams.strategy == ZSTD_btopt) ? optSpace : 0);
245
246 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100247}
248
Yann Collet27caf2a2016-04-01 15:48:48 +0200249/*! ZSTD_resetCCtx_advanced() :
250 note : 'params' is expected to be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100251static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Colletea2ecdc2016-07-14 22:43:12 +0200252 ZSTD_parameters params, U64 frameContentSize,
Yann Collet961b6a02016-07-15 11:56:53 +0200253 U32 reset)
Yann Collet863ec402016-01-28 17:56:33 +0100254{ /* note : params considered validated here */
Yann Collet731ef162016-07-27 21:05:12 +0200255 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
256 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
257 size_t const maxNbSeq = blockSize / divider;
258 size_t const tokenSpace = blockSize + 11*maxNbSeq;
259 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
260 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
261 U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
262 size_t const h3Size = ((size_t)1) << hashLog3;
263 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colleted57d852016-07-29 21:22:17 +0200264 void* ptr;
inikep87d4f3d2016-03-02 15:56:24 +0100265
Yann Collete74215e2016-03-19 16:09:09 +0100266 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Collet48537162016-04-07 15:24:29 +0200267 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
Yann Collete74215e2016-03-19 16:09:09 +0100268 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
269 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Yann Collet1005fc12016-04-04 13:28:28 +0200270 + ((params.cParams.strategy == ZSTD_btopt) ? optSpace : 0);
Yann Collete74215e2016-03-19 16:09:09 +0100271 if (zc->workSpaceSize < neededSpace) {
Yann Collet23b6e052016-08-28 21:05:43 -0700272 ZSTD_free(zc->workSpace, zc->customMem);
273 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
Yann Collete74215e2016-03-19 16:09:09 +0100274 if (zc->workSpace == NULL) return ERROR(memory_allocation);
275 zc->workSpaceSize = neededSpace;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100276 } }
Yann Collete74215e2016-03-19 16:09:09 +0100277
Yann Colletabb5c652016-04-11 20:42:31 +0200278 if (reset) memset(zc->workSpace, 0, tableSpace ); /* reset only tables */
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200279 XXH64_reset(&zc->xxhState, 0);
Yann Collet673f0d72016-06-06 00:26:38 +0200280 zc->hashLog3 = hashLog3;
Yann Collete3d52942016-06-06 11:07:33 +0200281 zc->hashTable = (U32*)(zc->workSpace);
Yann Collet8a57b922016-04-04 13:49:18 +0200282 zc->chainTable = zc->hashTable + hSize;
Yann Collete3d52942016-06-06 11:07:33 +0200283 zc->hashTable3 = zc->chainTable + chainSize;
Yann Colleted57d852016-07-29 21:22:17 +0200284 ptr = zc->hashTable3 + h3Size;
285 zc->hufTable = (HUF_CElt*)ptr;
Yann Collet863ec402016-01-28 17:56:33 +0100286 zc->flagStaticTables = 0;
Yann Colleted57d852016-07-29 21:22:17 +0200287 ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
Yann Collet083fcc82015-10-25 14:06:35 +0100288
Yann Colletf48e35c2015-11-07 01:13:31 +0100289 zc->nextToUpdate = 1;
Yann Collet89db5e02015-11-13 11:27:46 +0100290 zc->nextSrc = NULL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100291 zc->base = NULL;
292 zc->dictBase = NULL;
293 zc->dictLimit = 0;
294 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100295 zc->params = params;
Yann Collet120230b2015-12-02 14:00:45 +0100296 zc->blockSize = blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +0200297 zc->frameContentSize = frameContentSize;
Yann Collet4266c0a2016-06-14 01:49:25 +0200298 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
Yann Collet70e8c382016-02-10 13:37:52 +0100299
Yann Collet3b719252016-03-30 19:48:05 +0200300 if (params.cParams.strategy == ZSTD_btopt) {
Yann Colleted57d852016-07-29 21:22:17 +0200301 zc->seqStore.litFreq = (U32*)ptr;
Yann Collet72d706a2016-03-23 20:44:12 +0100302 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
303 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
304 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
Yann Colleted57d852016-07-29 21:22:17 +0200305 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
306 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
307 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
308 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
309 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
Yann Collet72d706a2016-03-23 20:44:12 +0100310 zc->seqStore.litLengthSum = 0;
311 }
Yann Colletc0ce4f12016-07-30 00:55:13 +0200312 zc->seqStore.sequencesStart = (seqDef*)ptr;
313 ptr = zc->seqStore.sequencesStart + maxNbSeq;
Yann Colleted57d852016-07-29 21:22:17 +0200314 zc->seqStore.llCode = (BYTE*) ptr;
315 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
316 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
317 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
inikep5cccd772016-03-02 20:37:49 +0100318
Yann Collet731ef162016-07-27 21:05:12 +0200319 zc->stage = ZSTDcs_init;
Yann Colletc46fb922016-05-29 05:01:04 +0200320 zc->dictID = 0;
Yann Collet2ce49232016-02-02 14:36:49 +0100321 zc->loadedDictEnd = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +0100322
Yann Collet4114f952015-10-30 06:40:22 +0100323 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100324}
325
Yann Collet083fcc82015-10-25 14:06:35 +0100326
Yann Collet370b08e2016-03-08 00:03:59 +0100327/*! ZSTD_copyCCtx() :
328* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet731ef162016-07-27 21:05:12 +0200329* Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100330* @return : 0, or an error code */
331size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
332{
Yann Collet731ef162016-07-27 21:05:12 +0200333 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100334
inikep28669512016-06-02 13:04:18 +0200335 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Yann Collet961b6a02016-07-15 11:56:53 +0200336 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, srcCCtx->frameContentSize, 0);
Yann Collet389648c2016-04-12 19:13:08 +0200337 dstCCtx->params.fParams.contentSizeFlag = 0; /* content size different from the one set during srcCCtx init */
Yann Collet7b51a292016-01-26 15:58:49 +0100338
339 /* copy tables */
Yann Collet731ef162016-07-27 21:05:12 +0200340 { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
341 size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
342 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
343 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100344 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
345 }
Yann Collet7b51a292016-01-26 15:58:49 +0100346
Yann Colletc46fb922016-05-29 05:01:04 +0200347 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100348 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
349 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
350 dstCCtx->nextSrc = srcCCtx->nextSrc;
351 dstCCtx->base = srcCCtx->base;
352 dstCCtx->dictBase = srcCCtx->dictBase;
353 dstCCtx->dictLimit = srcCCtx->dictLimit;
354 dstCCtx->lowLimit = srcCCtx->lowLimit;
355 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200356 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100357
Yann Colletfb810d62016-01-28 00:18:06 +0100358 /* copy entropy tables */
359 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100360 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100361 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100362 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
363 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
364 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
365 }
Yann Collet7b51a292016-01-26 15:58:49 +0100366
367 return 0;
368}
369
370
Yann Colletecabfe32016-03-20 16:20:06 +0100371/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100372* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100373static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100374{
Yann Colletecabfe32016-03-20 16:20:06 +0100375 U32 u;
376 for (u=0 ; u < size ; u++) {
377 if (table[u] < reducerValue) table[u] = 0;
378 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100379 }
380}
381
Yann Colletecabfe32016-03-20 16:20:06 +0100382/*! ZSTD_reduceIndex() :
383* rescale all indexes to avoid future overflow (indexes are U32) */
384static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
385{
Yann Collet731ef162016-07-27 21:05:12 +0200386 { U32 const hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100387 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
388
Yann Collet731ef162016-07-27 21:05:12 +0200389 { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200390 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100391
Yann Collet731ef162016-07-27 21:05:12 +0200392 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100393 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
394}
395
Yann Collet89db5e02015-11-13 11:27:46 +0100396
Yann Collet863ec402016-01-28 17:56:33 +0100397/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100398* Block entropic compression
399*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100400
Yann Colletc2e1a682016-07-22 17:30:52 +0200401/* See zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100402
Yann Colletd1b26842016-03-15 01:24:33 +0100403size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100404{
Yann Colletd1b26842016-03-15 01:24:33 +0100405 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200406 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
407 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100408 return ZSTD_blockHeaderSize+srcSize;
409}
410
411
Yann Colletd1b26842016-03-15 01:24:33 +0100412static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100413{
414 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200415 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100416
Yann Colletd1b26842016-03-15 01:24:33 +0100417 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100418
Yann Collet59d1f792016-01-23 19:28:41 +0100419 switch(flSize)
420 {
421 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200422 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100423 break;
424 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200425 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100426 break;
427 default: /*note : should not be necessary : flSize is within {1,2,3} */
428 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200429 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100430 break;
431 }
432
433 memcpy(ostart + flSize, src, srcSize);
434 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100435}
436
Yann Colletd1b26842016-03-15 01:24:33 +0100437static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100438{
439 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200440 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100441
Yann Collet198e6aa2016-07-20 20:12:24 +0200442 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100443
444 switch(flSize)
445 {
446 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200447 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100448 break;
449 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200450 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100451 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100452 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100453 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200454 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100455 break;
456 }
457
458 ostart[flSize] = *(const BYTE*)src;
459 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100460}
461
Yann Collet59d1f792016-01-23 19:28:41 +0100462
Yann Colleta5c2c082016-03-20 01:09:18 +0100463static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100464
Yann Colletb923f652016-01-26 03:14:20 +0100465static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100466 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100467 const void* src, size_t srcSize)
468{
Yann Colleta910dc82016-03-18 12:37:45 +0100469 size_t const minGain = ZSTD_minGain(srcSize);
470 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200471 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100472 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200473 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100474 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100475
Yann Collet14983e72015-11-11 21:38:21 +0100476
Yann Colleta5c2c082016-03-20 01:09:18 +0100477 /* small ? don't even attempt compression (speed opt) */
478# define LITERAL_NOENTROPY 63
479 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
480 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
481 }
482
483 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Colletfb810d62016-01-28 00:18:06 +0100484 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200485 hType = set_repeat;
Yann Colletb923f652016-01-26 03:14:20 +0100486 singleStream = 1;
Yann Colleta910dc82016-03-18 12:37:45 +0100487 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100488 } else {
Yann Collet6cacd342016-07-15 17:58:13 +0200489 cLitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11)
490 : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11);
Yann Colletb923f652016-01-26 03:14:20 +0100491 }
Yann Collet14983e72015-11-11 21:38:21 +0100492
Yann Collet98c88842016-07-15 16:12:38 +0200493 if ((cLitSize==0) | (cLitSize >= srcSize - minGain))
Yann Colleta910dc82016-03-18 12:37:45 +0100494 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
495 if (cLitSize==1)
496 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100497
498 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100499 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100500 {
Yann Collet59d1f792016-01-23 19:28:41 +0100501 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200502 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200503 MEM_writeLE24(ostart, lhc);
504 break;
505 }
Yann Collet59d1f792016-01-23 19:28:41 +0100506 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200507 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200508 MEM_writeLE32(ostart, lhc);
509 break;
510 }
Yann Colleta910dc82016-03-18 12:37:45 +0100511 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100512 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200513 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200514 MEM_writeLE32(ostart, lhc);
515 ostart[4] = (BYTE)(cLitSize >> 10);
516 break;
517 }
Yann Collet14983e72015-11-11 21:38:21 +0100518 }
Yann Colleta910dc82016-03-18 12:37:45 +0100519 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100520}
521
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200522static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
523 8, 9, 10, 11, 12, 13, 14, 15,
524 16, 16, 17, 17, 18, 18, 19, 19,
525 20, 20, 20, 20, 21, 21, 21, 21,
526 22, 22, 22, 22, 22, 22, 22, 22,
527 23, 23, 23, 23, 23, 23, 23, 23,
528 24, 24, 24, 24, 24, 24, 24, 24,
529 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100530
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200531static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
532 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
533 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
534 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
535 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
536 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
537 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
538 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200539
540
541void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100542{
Yann Colleted57d852016-07-29 21:22:17 +0200543 BYTE const LL_deltaCode = 19;
544 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200545 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200546 BYTE* const llCodeTable = seqStorePtr->llCode;
547 BYTE* const ofCodeTable = seqStorePtr->ofCode;
548 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200549 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200550 U32 u;
551 for (u=0; u<nbSeq; u++) {
552 U32 const llv = sequences[u].litLength;
553 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200554 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200555 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200556 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200557 }
Yann Colleted57d852016-07-29 21:22:17 +0200558 if (seqStorePtr->longLengthID==1)
559 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
560 if (seqStorePtr->longLengthID==2)
561 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100562}
563
564
Yann Colletb923f652016-01-26 03:14:20 +0100565size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100566 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100567 size_t srcSize)
568{
Yann Colletb923f652016-01-26 03:14:20 +0100569 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100570 U32 count[MaxSeq+1];
571 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100572 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
573 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
574 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100575 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200576 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200577 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
578 const BYTE* const llCodeTable = seqStorePtr->llCode;
579 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +0100580 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100581 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100582 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200583 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +0100584 BYTE* seqHead;
585
Yann Collet14983e72015-11-11 21:38:21 +0100586 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100587 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100588 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100589 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100590 if (ZSTD_isError(cSize)) return cSize;
591 op += cSize;
592 }
593
594 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100595 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100596 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
597 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
598 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100599 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100600
Yann Colletbe391432016-03-22 23:19:28 +0100601 /* seqHead : flags for FSE encoding type */
602 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100603
Yann Colletfb810d62016-01-28 00:18:06 +0100604#define MIN_SEQ_FOR_DYNAMIC_FSE 64
605#define MAX_SEQ_FOR_STATIC_FSE 1000
606
Yann Colletb44be742016-03-26 20:52:14 +0100607 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +0200608 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +0100609
Yann Collet14983e72015-11-11 21:38:21 +0100610 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100611 { U32 max = MaxLL;
612 size_t const mostFrequent = FSE_countFast(count, &max, llCodeTable, nbSeq);
613 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
614 *op++ = llCodeTable[0];
615 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200616 LLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100617 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200618 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100619 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
620 FSE_buildCTable(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog);
Yann Colletf8e7b532016-07-23 16:31:49 +0200621 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100622 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100623 size_t nbSeq_1 = nbSeq;
624 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
625 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
626 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100627 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
628 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
629 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100630 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
Yann Colletf8e7b532016-07-23 16:31:49 +0200631 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100632 } }
Yann Collet14983e72015-11-11 21:38:21 +0100633
Yann Colletb44be742016-03-26 20:52:14 +0100634 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100635 { U32 max = MaxOff;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100636 size_t const mostFrequent = FSE_countFast(count, &max, ofCodeTable, nbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100637 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100638 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100639 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200640 Offtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100641 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200642 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +0200643 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
644 FSE_buildCTable(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog);
Yann Colletf8e7b532016-07-23 16:31:49 +0200645 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100646 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100647 size_t nbSeq_1 = nbSeq;
648 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100649 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100650 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100651 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
652 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
653 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100654 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
Yann Colletf8e7b532016-07-23 16:31:49 +0200655 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100656 } }
657
Yann Collet14983e72015-11-11 21:38:21 +0100658 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100659 { U32 max = MaxML;
660 size_t const mostFrequent = FSE_countFast(count, &max, mlCodeTable, nbSeq);
661 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100662 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100663 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200664 MLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100665 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200666 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100667 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
668 FSE_buildCTable(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog);
Yann Colletf8e7b532016-07-23 16:31:49 +0200669 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100670 } else {
671 size_t nbSeq_1 = nbSeq;
672 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
673 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
674 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
675 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
676 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
677 op += NCountSize; }
678 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
Yann Colletf8e7b532016-07-23 16:31:49 +0200679 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100680 } }
Yann Collet14983e72015-11-11 21:38:21 +0100681
Yann Colletbe391432016-03-22 23:19:28 +0100682 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100683 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100684
685 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100686 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100687 FSE_CState_t stateMatchLength;
688 FSE_CState_t stateOffsetBits;
689 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100690
Yann Colleta910dc82016-03-18 12:37:45 +0100691 { size_t const errorCode = BIT_initCStream(&blockStream, op, oend-op);
Yann Collet597847a2016-03-20 19:14:22 +0100692 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100693
Yann Collet597847a2016-03-20 19:14:22 +0100694 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100695 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100696 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100697 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +0200698 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100699 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200700 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100701 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200702 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100703 BIT_flushBits(&blockStream);
704
Yann Colletfadda6c2016-03-22 12:14:26 +0100705 { size_t n;
706 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +0200707 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200708 BYTE const ofCode = ofCodeTable[n];
709 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200710 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +0200711 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200712 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +0100713 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100714 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
715 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
716 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
717 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200718 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100719 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +0200720 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100721 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200722 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100723 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200724 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
Yann Colletb9151402016-03-26 17:18:11 +0100725 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100726 } }
Yann Collet14983e72015-11-11 21:38:21 +0100727
728 FSE_flushCState(&blockStream, &stateMatchLength);
729 FSE_flushCState(&blockStream, &stateOffsetBits);
730 FSE_flushCState(&blockStream, &stateLitLength);
731
Yann Colletb9151402016-03-26 17:18:11 +0100732 { size_t const streamSize = BIT_closeCStream(&blockStream);
733 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
734 op += streamSize;
735 } }
Yann Collet14983e72015-11-11 21:38:21 +0100736
737 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100738_check_compressibility:
Yann Colletfadda6c2016-03-22 12:14:26 +0100739 { size_t const minGain = ZSTD_minGain(srcSize);
740 size_t const maxCSize = srcSize - minGain;
741 if ((size_t)(op-ostart) >= maxCSize) return 0; }
Yann Collet14983e72015-11-11 21:38:21 +0100742
Yann Collet4266c0a2016-06-14 01:49:25 +0200743 /* confirm repcodes */
744 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->savedRep[i]; }
745
Yann Collet5054ee02015-11-23 13:34:21 +0100746 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100747}
748
749
Yann Collet95cd0c22016-03-08 18:24:21 +0100750/*! ZSTD_storeSeq() :
751 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
752 `offsetCode` : distance to match, or 0 == repCode.
753 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100754*/
Yann Colletd57dffb2016-07-03 01:48:26 +0200755MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)
Yann Collet14983e72015-11-11 21:38:21 +0100756{
Yann Collet45c03c52016-06-14 13:46:11 +0200757#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100758 static const BYTE* g_start = NULL;
Yann Colletb0aec172016-03-21 13:24:16 +0100759 const U32 pos = (U32)(literals - g_start);
Yann Collet14983e72015-11-11 21:38:21 +0100760 if (g_start==NULL) g_start = literals;
Yann Collet4266c0a2016-06-14 01:49:25 +0200761 //if ((pos > 1) && (pos < 50000))
Yann Colletb9151402016-03-26 17:18:11 +0100762 printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
Yann Collet433a5cc2016-03-25 11:43:48 +0100763 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +0100764#endif
Yann Collet14983e72015-11-11 21:38:21 +0100765 /* copy Literals */
766 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
767 seqStorePtr->lit += litLength;
768
769 /* literal Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200770 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
771 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100772
773 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200774 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100775
776 /* match Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200777 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
778 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +0200779
Yann Colletc0ce4f12016-07-30 00:55:13 +0200780 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +0100781}
782
783
Yann Collet7d360282016-02-12 00:07:30 +0100784/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100785* Match length counter
786***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100787static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100788{
Yann Collet863ec402016-01-28 17:56:33 +0100789 if (MEM_isLittleEndian()) {
790 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100791# if defined(_MSC_VER) && defined(_WIN64)
792 unsigned long r = 0;
793 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100794 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100795# elif defined(__GNUC__) && (__GNUC__ >= 3)
796 return (__builtin_ctzll((U64)val) >> 3);
797# else
798 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 };
799 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
800# endif
Yann Collet863ec402016-01-28 17:56:33 +0100801 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100802# if defined(_MSC_VER)
803 unsigned long r=0;
804 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100805 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100806# elif defined(__GNUC__) && (__GNUC__ >= 3)
807 return (__builtin_ctz((U32)val) >> 3);
808# else
809 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 };
810 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
811# endif
812 }
Yann Collet863ec402016-01-28 17:56:33 +0100813 } else { /* Big Endian CPU */
814 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100815# if defined(_MSC_VER) && defined(_WIN64)
816 unsigned long r = 0;
817 _BitScanReverse64( &r, val );
818 return (unsigned)(r>>3);
819# elif defined(__GNUC__) && (__GNUC__ >= 3)
820 return (__builtin_clzll(val) >> 3);
821# else
822 unsigned r;
823 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
824 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
825 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
826 r += (!val);
827 return r;
828# endif
Yann Collet863ec402016-01-28 17:56:33 +0100829 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100830# if defined(_MSC_VER)
831 unsigned long r = 0;
832 _BitScanReverse( &r, (unsigned long)val );
833 return (unsigned)(r>>3);
834# elif defined(__GNUC__) && (__GNUC__ >= 3)
835 return (__builtin_clz((U32)val) >> 3);
836# else
837 unsigned r;
838 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
839 r += (!val);
840 return r;
841# endif
Yann Collet863ec402016-01-28 17:56:33 +0100842 } }
Yann Collet14983e72015-11-11 21:38:21 +0100843}
844
845
Yann Colleta436a522016-06-20 23:34:04 +0200846static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100847{
848 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +0200849 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +0100850
Yann Colleta436a522016-06-20 23:34:04 +0200851 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +0200852 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100853 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
854 pIn += ZSTD_NbCommonBytes(diff);
855 return (size_t)(pIn - pStart);
856 }
Yann Collet14983e72015-11-11 21:38:21 +0100857 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
858 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
859 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
860 return (size_t)(pIn - pStart);
861}
862
Yann Collet04b12d82016-02-11 06:23:24 +0100863/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100864* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100865* convention : on reaching mEnd, match count continue starting from iStart
866*/
867static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
868{
Yann Collet7591a7f2016-05-20 11:44:43 +0200869 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +0200870 size_t const matchLength = ZSTD_count(ip, match, vEnd);
871 if (match + matchLength != mEnd) return matchLength;
872 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +0100873}
874
Yann Collet14983e72015-11-11 21:38:21 +0100875
Yann Collet863ec402016-01-28 17:56:33 +0100876/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100877* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100878***************************************/
inikepcc52a972016-02-19 10:09:35 +0100879static const U32 prime3bytes = 506832829U;
880static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Colletd4f4e582016-06-27 01:31:35 +0200881MEM_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 +0100882
Yann Collet4b100f42015-10-30 15:49:48 +0100883static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100884static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100885static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100886
Yann Collet4b100f42015-10-30 15:49:48 +0100887static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100888static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100889static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100890
891static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100892static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100893static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100894
Yann Collet14983e72015-11-11 21:38:21 +0100895static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100896static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100897static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100898
Yann Collet45dc3562016-07-12 09:47:31 +0200899static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
900static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
901static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
902
Yann Collet5be2dd22015-11-11 13:43:58 +0100903static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100904{
905 switch(mls)
906 {
907 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100908 case 4: return ZSTD_hash4Ptr(p, hBits);
909 case 5: return ZSTD_hash5Ptr(p, hBits);
910 case 6: return ZSTD_hash6Ptr(p, hBits);
911 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +0200912 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100913 }
914}
Yann Collet2acb5d32015-10-29 16:49:43 +0100915
Yann Collet863ec402016-01-28 17:56:33 +0100916
Yann Collet2ce49232016-02-02 14:36:49 +0100917/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +0100918* Fast Scan
919***************************************/
Yann Collet417890c2015-12-04 17:16:37 +0100920static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
921{
922 U32* const hashTable = zc->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200923 U32 const hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +0100924 const BYTE* const base = zc->base;
925 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +0200926 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +0100927 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +0100928
Yann Colletfb810d62016-01-28 00:18:06 +0100929 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +0100930 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +0100931 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +0100932 }
933}
934
935
Yann Collet1f44b3f2015-11-05 17:32:18 +0100936FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +0200937void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +0200938 const void* src, size_t srcSize,
939 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100940{
Yann Collet4266c0a2016-06-14 01:49:25 +0200941 U32* const hashTable = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200942 U32 const hBits = cctx->params.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +0200943 seqStore_t* seqStorePtr = &(cctx->seqStore);
944 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100945 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100946 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100947 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +0200948 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +0200949 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100950 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +0200951 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +0200952 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
953 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100954
Yann Collet1f44b3f2015-11-05 17:32:18 +0100955 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +0200956 ip += (ip==lowest);
957 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +0200958 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
959 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +0200960 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100961
962 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +0200963 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +0200964 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +0200965 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
966 U32 const current = (U32)(ip-base);
967 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +0100968 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +0100969 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100970
Yann Collet280f9a82016-08-08 00:44:00 +0200971 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +0200972 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +0100973 ip++;
Yann Colleta436a522016-06-20 23:34:04 +0200974 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
975 } else {
Yann Collet92d75662016-07-03 01:10:53 +0200976 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +0200977 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100978 ip += ((ip-anchor) >> g_searchStrength) + 1;
979 continue;
980 }
Yann Collet45dc3562016-07-12 09:47:31 +0200981 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +0200982 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +0200983 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +0100984 offset_2 = offset_1;
985 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +0100986
Yann Colleta436a522016-06-20 23:34:04 +0200987 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +0100988 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100989
Yann Collet402fdcf2015-11-20 12:46:08 +0100990 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +0200991 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +0100992 anchor = ip;
993
Yann Colletfb810d62016-01-28 00:18:06 +0100994 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100995 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +0100996 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 +0100997 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
998 /* check immediate repcode */
999 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001000 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001001 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001002 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001003 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001004 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001005 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001006 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1007 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001008 anchor = ip;
1009 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001010 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001011
Yann Collet4266c0a2016-06-14 01:49:25 +02001012 /* save reps for next block */
Yann Collet92d75662016-07-03 01:10:53 +02001013 cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved;
1014 cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001015
Yann Collet70e45772016-03-19 18:08:32 +01001016 /* Last Literals */
1017 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001018 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1019 seqStorePtr->lit += lastLLSize;
1020 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001021}
1022
1023
Yann Collet82260dd2016-02-11 07:14:25 +01001024static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001025 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001026{
Yann Collet3b719252016-03-30 19:48:05 +02001027 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001028 switch(mls)
1029 {
1030 default:
1031 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001032 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001033 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001034 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001035 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001036 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001037 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001038 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001039 }
1040}
Yann Colletf3eca252015-10-22 15:31:46 +01001041
Yann Colletf3eca252015-10-22 15:31:46 +01001042
Yann Collet82260dd2016-02-11 07:14:25 +01001043static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001044 const void* src, size_t srcSize,
1045 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001046{
1047 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001048 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001049 seqStore_t* seqStorePtr = &(ctx->seqStore);
1050 const BYTE* const base = ctx->base;
1051 const BYTE* const dictBase = ctx->dictBase;
1052 const BYTE* const istart = (const BYTE*)src;
1053 const BYTE* ip = istart;
1054 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001055 const U32 lowestIndex = ctx->lowLimit;
1056 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001057 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001058 const BYTE* const lowPrefixPtr = base + dictLimit;
1059 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001060 const BYTE* const iend = istart + srcSize;
1061 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001062 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001063
Yann Colleta436a522016-06-20 23:34:04 +02001064 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001065 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001066 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001067 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001068 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001069 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001070 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001071 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001072 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001073 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001074 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001075 hashTable[h] = current; /* update hash table */
1076
Yann Colleta436a522016-06-20 23:34:04 +02001077 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001078 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001079 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Colleta436a522016-06-20 23:34:04 +02001080 mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001081 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001082 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001083 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001084 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001085 (MEM_read32(match) != MEM_read32(ip)) ) {
1086 ip += ((ip-anchor) >> g_searchStrength) + 1;
1087 continue;
1088 }
1089 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001090 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001091 U32 offset;
1092 mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
1093 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001094 offset = current - matchIndex;
1095 offset_2 = offset_1;
1096 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001097 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001098 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001099
Yann Collet5054ee02015-11-23 13:34:21 +01001100 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001101 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001102 anchor = ip;
1103
Yann Colletfb810d62016-01-28 00:18:06 +01001104 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001105 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001106 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001107 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1108 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001109 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001110 U32 const current2 = (U32)(ip-base);
1111 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001112 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001113 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1114 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001115 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001116 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001117 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001118 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001119 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001120 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001121 anchor = ip;
1122 continue;
1123 }
Yann Collet743402c2015-11-20 12:03:53 +01001124 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001125 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001126
Yann Collet4266c0a2016-06-14 01:49:25 +02001127 /* save reps for next block */
1128 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
1129
Yann Collet89db5e02015-11-13 11:27:46 +01001130 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001131 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001132 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1133 seqStorePtr->lit += lastLLSize;
1134 }
Yann Collet89db5e02015-11-13 11:27:46 +01001135}
1136
1137
Yann Collet82260dd2016-02-11 07:14:25 +01001138static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001139 const void* src, size_t srcSize)
1140{
Yann Collet731ef162016-07-27 21:05:12 +02001141 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001142 switch(mls)
1143 {
1144 default:
1145 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001146 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001147 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001148 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001149 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001150 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001151 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001152 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001153 }
1154}
1155
1156
Yann Collet04b12d82016-02-11 06:23:24 +01001157/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001158* Double Fast
1159***************************************/
1160static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1161{
1162 U32* const hashLarge = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001163 U32 const hBitsL = cctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001164 U32* const hashSmall = cctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001165 U32 const hBitsS = cctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001166 const BYTE* const base = cctx->base;
1167 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001168 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001169 const size_t fastHashFillStep = 3;
1170
1171 while(ip <= iend) {
1172 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1173 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1174 ip += fastHashFillStep;
1175 }
1176}
1177
1178
1179FORCE_INLINE
1180void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1181 const void* src, size_t srcSize,
1182 const U32 mls)
1183{
1184 U32* const hashLong = cctx->hashTable;
1185 const U32 hBitsL = cctx->params.cParams.hashLog;
1186 U32* const hashSmall = cctx->chainTable;
1187 const U32 hBitsS = cctx->params.cParams.chainLog;
1188 seqStore_t* seqStorePtr = &(cctx->seqStore);
1189 const BYTE* const base = cctx->base;
1190 const BYTE* const istart = (const BYTE*)src;
1191 const BYTE* ip = istart;
1192 const BYTE* anchor = istart;
1193 const U32 lowestIndex = cctx->dictLimit;
1194 const BYTE* const lowest = base + lowestIndex;
1195 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001196 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001197 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1198 U32 offsetSaved = 0;
1199
1200 /* init */
1201 ip += (ip==lowest);
1202 { U32 const maxRep = (U32)(ip-lowest);
1203 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1204 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1205 }
1206
1207 /* Main Search Loop */
1208 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1209 size_t mLength;
1210 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1211 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1212 U32 const current = (U32)(ip-base);
1213 U32 const matchIndexL = hashLong[h2];
1214 U32 const matchIndexS = hashSmall[h];
1215 const BYTE* matchLong = base + matchIndexL;
1216 const BYTE* match = base + matchIndexS;
1217 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1218
1219 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1220 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1221 ip++;
1222 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1223 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001224 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001225 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1226 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001227 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001228 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1229 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Colletc54692f2016-08-24 01:10:42 +02001230 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1231 U32 const matchIndex3 = hashLong[h3];
1232 const BYTE* match3 = base + matchIndex3;
1233 hashLong[h3] = current + 1;
1234 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1235 mLength = ZSTD_count(ip+9, match3+8, iend) + 8;
1236 ip++;
1237 offset = (U32)(ip-match3);
1238 while (((ip>anchor) & (match3>lowest)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1239 } else {
1240 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1241 offset = (U32)(ip-match);
1242 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1243 }
Yann Collet45dc3562016-07-12 09:47:31 +02001244 } else {
1245 ip += ((ip-anchor) >> g_searchStrength) + 1;
1246 continue;
1247 }
1248
1249 offset_2 = offset_1;
1250 offset_1 = offset;
1251
1252 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1253 }
1254
1255 /* match found */
1256 ip += mLength;
1257 anchor = ip;
1258
1259 if (ip <= ilimit) {
1260 /* Fill Table */
1261 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1262 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1263 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1264 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1265
1266 /* check immediate repcode */
1267 while ( (ip <= ilimit)
1268 && ( (offset_2>0)
1269 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1270 /* store sequence */
1271 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001272 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001273 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1274 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1275 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1276 ip += rLength;
1277 anchor = ip;
1278 continue; /* faster when present ... (?) */
1279 } } }
1280
1281 /* save reps for next block */
1282 cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved;
1283 cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved;
1284
1285 /* Last Literals */
1286 { size_t const lastLLSize = iend - anchor;
1287 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1288 seqStorePtr->lit += lastLLSize;
1289 }
1290}
1291
1292
1293static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1294{
1295 const U32 mls = ctx->params.cParams.searchLength;
1296 switch(mls)
1297 {
1298 default:
1299 case 4 :
1300 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1301 case 5 :
1302 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1303 case 6 :
1304 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1305 case 7 :
1306 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1307 }
1308}
1309
1310
1311static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1312 const void* src, size_t srcSize,
1313 const U32 mls)
1314{
1315 U32* const hashLong = ctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001316 U32 const hBitsL = ctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001317 U32* const hashSmall = ctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001318 U32 const hBitsS = ctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001319 seqStore_t* seqStorePtr = &(ctx->seqStore);
1320 const BYTE* const base = ctx->base;
1321 const BYTE* const dictBase = ctx->dictBase;
1322 const BYTE* const istart = (const BYTE*)src;
1323 const BYTE* ip = istart;
1324 const BYTE* anchor = istart;
1325 const U32 lowestIndex = ctx->lowLimit;
1326 const BYTE* const dictStart = dictBase + lowestIndex;
1327 const U32 dictLimit = ctx->dictLimit;
1328 const BYTE* const lowPrefixPtr = base + dictLimit;
1329 const BYTE* const dictEnd = dictBase + dictLimit;
1330 const BYTE* const iend = istart + srcSize;
1331 const BYTE* const ilimit = iend - 8;
1332 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1333
1334 /* Search Loop */
1335 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1336 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1337 const U32 matchIndex = hashSmall[hSmall];
1338 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1339 const BYTE* match = matchBase + matchIndex;
1340
1341 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1342 const U32 matchLongIndex = hashLong[hLong];
1343 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1344 const BYTE* matchLong = matchLongBase + matchLongIndex;
1345
1346 const U32 current = (U32)(ip-base);
1347 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1348 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1349 const BYTE* repMatch = repBase + repIndex;
1350 size_t mLength;
1351 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1352
1353 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1354 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1355 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1356 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1357 ip++;
1358 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1359 } else {
1360 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1361 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1362 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1363 U32 offset;
1364 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1365 offset = current - matchLongIndex;
1366 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1367 offset_2 = offset_1;
1368 offset_1 = offset;
1369 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001370
Yann Collet73d74a02016-07-12 13:03:48 +02001371 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001372 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1373 U32 const matchIndex3 = hashLong[h3];
1374 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1375 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001376 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001377 hashLong[h3] = current + 1;
1378 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1379 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1380 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1381 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1382 ip++;
1383 offset = current+1 - matchIndex3;
1384 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1385 } else {
1386 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1387 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1388 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1389 offset = current - matchIndex;
1390 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1391 }
Yann Collet45dc3562016-07-12 09:47:31 +02001392 offset_2 = offset_1;
1393 offset_1 = offset;
1394 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001395
Yann Collet45dc3562016-07-12 09:47:31 +02001396 } else {
1397 ip += ((ip-anchor) >> g_searchStrength) + 1;
1398 continue;
1399 } }
1400
1401 /* found a match : store it */
1402 ip += mLength;
1403 anchor = ip;
1404
1405 if (ip <= ilimit) {
1406 /* Fill Table */
1407 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1408 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
1409 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1410 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1411 /* check immediate repcode */
1412 while (ip <= ilimit) {
1413 U32 const current2 = (U32)(ip-base);
1414 U32 const repIndex2 = current2 - offset_2;
1415 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1416 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1417 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1418 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1419 size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1420 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1421 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1422 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1423 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1424 ip += repLength2;
1425 anchor = ip;
1426 continue;
1427 }
1428 break;
1429 } } }
1430
1431 /* save reps for next block */
1432 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
1433
1434 /* Last Literals */
1435 { size_t const lastLLSize = iend - anchor;
1436 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1437 seqStorePtr->lit += lastLLSize;
1438 }
1439}
1440
1441
1442static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1443 const void* src, size_t srcSize)
1444{
Yann Collet731ef162016-07-27 21:05:12 +02001445 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001446 switch(mls)
1447 {
1448 default:
1449 case 4 :
1450 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1451 case 5 :
1452 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1453 case 6 :
1454 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1455 case 7 :
1456 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1457 }
1458}
1459
1460
1461/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001462* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001463***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001464/** ZSTD_insertBt1() : add one or multiple positions to tree.
1465* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001466* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001467static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1468 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001469{
Yann Collet731ef162016-07-27 21:05:12 +02001470 U32* const hashTable = zc->hashTable;
1471 U32 const hashLog = zc->params.cParams.hashLog;
1472 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1473 U32* const bt = zc->chainTable;
1474 U32 const btLog = zc->params.cParams.chainLog - 1;
1475 U32 const btMask = (1 << btLog) - 1;
1476 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001477 size_t commonLengthSmaller=0, commonLengthLarger=0;
1478 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001479 const BYTE* const dictBase = zc->dictBase;
1480 const U32 dictLimit = zc->dictLimit;
1481 const BYTE* const dictEnd = dictBase + dictLimit;
1482 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001483 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001484 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001485 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001486 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001487 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001488 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001489 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001490 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001491 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001492#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001493 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1494 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1495 predictedSmall += (predictedSmall>0);
1496 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001497#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001498
Yann Collet6c3e2e72015-12-11 10:44:07 +01001499 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001500
Yann Colletfb810d62016-01-28 00:18:06 +01001501 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001502 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001503 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Colletc0932082016-06-30 14:07:30 +02001504#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001505 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001506 if (matchIndex == predictedSmall) {
1507 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001508 *smallerPtr = matchIndex;
1509 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1510 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1511 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001512 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001513 continue;
1514 }
Yann Colletfb810d62016-01-28 00:18:06 +01001515 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001516 *largerPtr = matchIndex;
1517 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1518 largerPtr = nextPtr;
1519 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001520 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001521 continue;
1522 }
Yann Collet04b12d82016-02-11 06:23:24 +01001523#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001524 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001525 match = base + matchIndex;
1526 if (match[matchLength] == ip[matchLength])
1527 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001528 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001529 match = dictBase + matchIndex;
1530 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1531 if (matchIndex+matchLength >= dictLimit)
1532 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1533 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001534
Yann Colletb8a6f682016-02-15 17:06:29 +01001535 if (matchLength > bestLength) {
1536 bestLength = matchLength;
1537 if (matchLength > matchEndIdx - matchIndex)
1538 matchEndIdx = matchIndex + (U32)matchLength;
1539 }
Yann Colletee3f4512015-12-29 22:26:09 +01001540
Yann Collet59d70632015-11-04 12:05:27 +01001541 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001542 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001543
Yann Colletfb810d62016-01-28 00:18:06 +01001544 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001545 /* match is smaller than current */
1546 *smallerPtr = matchIndex; /* update smaller idx */
1547 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001548 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001549 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001550 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001551 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001552 /* match is larger than current */
1553 *largerPtr = matchIndex;
1554 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001555 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001556 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001557 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001558 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001559
Yann Collet59d70632015-11-04 12:05:27 +01001560 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02001561 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01001562 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1563 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001564}
1565
1566
Yann Collet82260dd2016-02-11 07:14:25 +01001567static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001568 ZSTD_CCtx* zc,
1569 const BYTE* const ip, const BYTE* const iend,
1570 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001571 U32 nbCompares, const U32 mls,
1572 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001573{
Yann Collet731ef162016-07-27 21:05:12 +02001574 U32* const hashTable = zc->hashTable;
1575 U32 const hashLog = zc->params.cParams.hashLog;
1576 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1577 U32* const bt = zc->chainTable;
1578 U32 const btLog = zc->params.cParams.chainLog - 1;
1579 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001580 U32 matchIndex = hashTable[h];
1581 size_t commonLengthSmaller=0, commonLengthLarger=0;
1582 const BYTE* const base = zc->base;
1583 const BYTE* const dictBase = zc->dictBase;
1584 const U32 dictLimit = zc->dictLimit;
1585 const BYTE* const dictEnd = dictBase + dictLimit;
1586 const BYTE* const prefixStart = base + dictLimit;
1587 const U32 current = (U32)(ip-base);
1588 const U32 btLow = btMask >= current ? 0 : current - btMask;
1589 const U32 windowLow = zc->lowLimit;
1590 U32* smallerPtr = bt + 2*(current&btMask);
1591 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001592 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001593 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001594 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001595
Yann Collet6c3e2e72015-12-11 10:44:07 +01001596 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001597
Yann Colletfb810d62016-01-28 00:18:06 +01001598 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001599 U32* nextPtr = bt + 2*(matchIndex & btMask);
1600 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1601 const BYTE* match;
1602
Yann Colletfb810d62016-01-28 00:18:06 +01001603 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001604 match = base + matchIndex;
1605 if (match[matchLength] == ip[matchLength])
1606 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001607 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001608 match = dictBase + matchIndex;
1609 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001610 if (matchIndex+matchLength >= dictLimit)
1611 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001612 }
1613
Yann Colletfb810d62016-01-28 00:18:06 +01001614 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001615 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001616 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02001617 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001618 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001619 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1620 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1621 }
1622
Yann Colletfb810d62016-01-28 00:18:06 +01001623 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001624 /* match is smaller than current */
1625 *smallerPtr = matchIndex; /* update smaller idx */
1626 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1627 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1628 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1629 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001630 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001631 /* match is larger than current */
1632 *largerPtr = matchIndex;
1633 commonLengthLarger = matchLength;
1634 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1635 largerPtr = nextPtr;
1636 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001637 } }
Yann Collet03526e12015-11-23 15:29:15 +01001638
1639 *smallerPtr = *largerPtr = 0;
1640
Yann Collet72e84cf2015-12-31 19:08:44 +01001641 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001642 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001643}
1644
Yann Collet2cc12cb2016-01-01 07:47:58 +01001645
Yann Colletb8a6f682016-02-15 17:06:29 +01001646static 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 +01001647{
1648 const BYTE* const base = zc->base;
1649 const U32 target = (U32)(ip - base);
1650 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001651
1652 while(idx < target)
1653 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001654}
1655
Yann Collet52447382016-03-20 16:00:00 +01001656/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001657static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001658 ZSTD_CCtx* zc,
1659 const BYTE* const ip, const BYTE* const iLimit,
1660 size_t* offsetPtr,
1661 const U32 maxNbAttempts, const U32 mls)
1662{
1663 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001664 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001665 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1666}
1667
1668
Yann Collet768c6bc2016-02-10 14:01:49 +01001669static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001670 ZSTD_CCtx* zc, /* Index table will be updated */
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_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1679 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1680 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1681 }
1682}
1683
1684
Yann Colletb8a6f682016-02-15 17:06:29 +01001685static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1686{
1687 const BYTE* const base = zc->base;
1688 const U32 target = (U32)(ip - base);
1689 U32 idx = zc->nextToUpdate;
1690
1691 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1692}
1693
inikep64d7bcb2016-04-07 19:14:09 +02001694
Yann Collet03526e12015-11-23 15:29:15 +01001695/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001696static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001697 ZSTD_CCtx* zc,
1698 const BYTE* const ip, const BYTE* const iLimit,
1699 size_t* offsetPtr,
1700 const U32 maxNbAttempts, const U32 mls)
1701{
Yann Colletee3f4512015-12-29 22:26:09 +01001702 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001703 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001704 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001705}
1706
1707
Yann Collet82260dd2016-02-11 07:14:25 +01001708static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001709 ZSTD_CCtx* zc, /* Index table will be updated */
1710 const BYTE* ip, const BYTE* const iLimit,
1711 size_t* offsetPtr,
1712 const U32 maxNbAttempts, const U32 matchLengthSearch)
1713{
1714 switch(matchLengthSearch)
1715 {
1716 default :
1717 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1718 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1719 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1720 }
1721}
1722
1723
Yann Collet5106a762015-11-05 15:00:24 +01001724
Yann Collet731ef162016-07-27 21:05:12 +02001725/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02001726* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02001727***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02001728#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1729
1730/* Update chains up to ip (excluded)
1731 Assumption : always within prefix (ie. not within extDict) */
1732FORCE_INLINE
1733U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1734{
1735 U32* const hashTable = zc->hashTable;
1736 const U32 hashLog = zc->params.cParams.hashLog;
1737 U32* const chainTable = zc->chainTable;
1738 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1739 const BYTE* const base = zc->base;
1740 const U32 target = (U32)(ip - base);
1741 U32 idx = zc->nextToUpdate;
1742
Yann Collet22d76322016-06-21 08:01:51 +02001743 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001744 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1745 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1746 hashTable[h] = idx;
1747 idx++;
1748 }
1749
1750 zc->nextToUpdate = target;
1751 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1752}
1753
1754
1755
1756FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1757size_t ZSTD_HcFindBestMatch_generic (
1758 ZSTD_CCtx* zc, /* Index table will be updated */
1759 const BYTE* const ip, const BYTE* const iLimit,
1760 size_t* offsetPtr,
1761 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1762{
1763 U32* const chainTable = zc->chainTable;
1764 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1765 const U32 chainMask = chainSize-1;
1766 const BYTE* const base = zc->base;
1767 const BYTE* const dictBase = zc->dictBase;
1768 const U32 dictLimit = zc->dictLimit;
1769 const BYTE* const prefixStart = base + dictLimit;
1770 const BYTE* const dictEnd = dictBase + dictLimit;
1771 const U32 lowLimit = zc->lowLimit;
1772 const U32 current = (U32)(ip-base);
1773 const U32 minChain = current > chainSize ? current - chainSize : 0;
1774 int nbAttempts=maxNbAttempts;
1775 size_t ml=EQUAL_READ32-1;
1776
1777 /* HC4 match finder */
1778 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1779
Yann Collet22d76322016-06-21 08:01:51 +02001780 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02001781 const BYTE* match;
1782 size_t currentMl=0;
1783 if ((!extDict) || matchIndex >= dictLimit) {
1784 match = base + matchIndex;
1785 if (match[ml] == ip[ml]) /* potentially better */
1786 currentMl = ZSTD_count(ip, match, iLimit);
1787 } else {
1788 match = dictBase + matchIndex;
1789 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1790 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1791 }
1792
1793 /* save best solution */
Yann Collet22d76322016-06-21 08:01:51 +02001794 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 +02001795
1796 if (matchIndex <= minChain) break;
1797 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1798 }
1799
1800 return ml;
1801}
1802
1803
1804FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1805 ZSTD_CCtx* zc,
1806 const BYTE* ip, const BYTE* const iLimit,
1807 size_t* offsetPtr,
1808 const U32 maxNbAttempts, const U32 matchLengthSearch)
1809{
1810 switch(matchLengthSearch)
1811 {
1812 default :
1813 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1814 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1815 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1816 }
1817}
1818
1819
1820FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1821 ZSTD_CCtx* zc,
1822 const BYTE* ip, const BYTE* const iLimit,
1823 size_t* offsetPtr,
1824 const U32 maxNbAttempts, const U32 matchLengthSearch)
1825{
1826 switch(matchLengthSearch)
1827 {
1828 default :
1829 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1830 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1831 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1832 }
1833}
1834
inikep64d7bcb2016-04-07 19:14:09 +02001835
Yann Collet287b7d92015-11-22 13:24:05 +01001836/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001837* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001838*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001839FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001840void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1841 const void* src, size_t srcSize,
1842 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001843{
inikepfaa8d8a2016-04-05 19:01:10 +02001844 seqStore_t* seqStorePtr = &(ctx->seqStore);
1845 const BYTE* const istart = (const BYTE*)src;
1846 const BYTE* ip = istart;
1847 const BYTE* anchor = istart;
1848 const BYTE* const iend = istart + srcSize;
1849 const BYTE* const ilimit = iend - 8;
1850 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001851
Yann Collet793c6492016-04-09 20:32:00 +02001852 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1853 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001854
inikep64d7bcb2016-04-07 19:14:09 +02001855 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1856 size_t* offsetPtr,
1857 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02001858 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02001859 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02001860
inikepfaa8d8a2016-04-05 19:01:10 +02001861 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001862 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02001863 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02001864 { U32 const maxRep = (U32)(ip-base);
1865 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
1866 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
1867 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001868
inikepfaa8d8a2016-04-05 19:01:10 +02001869 /* Match Loop */
1870 while (ip < ilimit) {
1871 size_t matchLength=0;
1872 size_t offset=0;
1873 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001874
inikepfaa8d8a2016-04-05 19:01:10 +02001875 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02001876 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02001877 /* repcode : we take it */
Yann Collet9634f672016-07-03 01:23:58 +02001878 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001879 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001880 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001881
inikepfaa8d8a2016-04-05 19:01:10 +02001882 /* first search (depth 0) */
1883 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001884 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001885 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001886 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001887 }
Yann Collet5106a762015-11-05 15:00:24 +01001888
inikep7bc19b62016-04-06 09:46:01 +02001889 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001890 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1891 continue;
1892 }
1893
inikep64d7bcb2016-04-07 19:14:09 +02001894 /* let's try to find a better solution */
1895 if (depth>=1)
1896 while (ip<ilimit) {
1897 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001898 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1899 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001900 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02001901 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001902 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1903 matchLength = mlRep, offset = 0, start = ip;
1904 }
1905 { size_t offset2=99999999;
1906 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001907 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1908 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02001909 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1910 matchLength = ml2, offset = offset2, start = ip;
1911 continue; /* search a better one */
1912 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001913
inikep64d7bcb2016-04-07 19:14:09 +02001914 /* let's find an even better one */
1915 if ((depth==2) && (ip<ilimit)) {
1916 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001917 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1918 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001919 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02001920 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001921 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1922 matchLength = ml2, offset = 0, start = ip;
1923 }
1924 { size_t offset2=99999999;
1925 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001926 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1927 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02001928 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1929 matchLength = ml2, offset = offset2, start = ip;
1930 continue;
1931 } } }
1932 break; /* nothing found : store previous solution */
1933 }
1934
1935 /* catch up */
1936 if (offset) {
1937 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1938 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02001939 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02001940 }
1941
inikepfaa8d8a2016-04-05 19:01:10 +02001942 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001943_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001944 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02001945 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02001946 anchor = ip = start + matchLength;
1947 }
Yann Collet48537162016-04-07 15:24:29 +02001948
inikepfaa8d8a2016-04-05 19:01:10 +02001949 /* check immediate repcode */
1950 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02001951 && ((offset_2>0)
1952 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02001953 /* store sequence */
Yann Collet9634f672016-07-03 01:23:58 +02001954 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
1955 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02001956 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1957 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02001958 anchor = ip;
1959 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02001960 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001961
Yann Collet4266c0a2016-06-14 01:49:25 +02001962 /* Save reps for next block */
Yann Collet9634f672016-07-03 01:23:58 +02001963 ctx->savedRep[0] = offset_1 ? offset_1 : savedOffset;
1964 ctx->savedRep[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02001965
inikepfaa8d8a2016-04-05 19:01:10 +02001966 /* Last Literals */
1967 { size_t const lastLLSize = iend - anchor;
1968 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1969 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01001970 }
Yann Collet5106a762015-11-05 15:00:24 +01001971}
1972
Yann Collet5be2dd22015-11-11 13:43:58 +01001973
inikep64d7bcb2016-04-07 19:14:09 +02001974static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1975{
1976 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
1977}
1978
1979static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1980{
1981 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
1982}
1983
1984static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1985{
1986 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
1987}
1988
1989static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1990{
1991 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
1992}
1993
1994
inikepfaa8d8a2016-04-05 19:01:10 +02001995FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001996void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1997 const void* src, size_t srcSize,
1998 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01001999{
inikepfaa8d8a2016-04-05 19:01:10 +02002000 seqStore_t* seqStorePtr = &(ctx->seqStore);
2001 const BYTE* const istart = (const BYTE*)src;
2002 const BYTE* ip = istart;
2003 const BYTE* anchor = istart;
2004 const BYTE* const iend = istart + srcSize;
2005 const BYTE* const ilimit = iend - 8;
2006 const BYTE* const base = ctx->base;
2007 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002008 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002009 const BYTE* const prefixStart = base + dictLimit;
2010 const BYTE* const dictBase = ctx->dictBase;
2011 const BYTE* const dictEnd = dictBase + dictLimit;
2012 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2013
2014 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2015 const U32 mls = ctx->params.cParams.searchLength;
2016
inikep64d7bcb2016-04-07 19:14:09 +02002017 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2018 size_t* offsetPtr,
2019 U32 maxNbAttempts, U32 matchLengthSearch);
2020 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2021
Yann Collet302ff032016-07-03 01:28:16 +02002022 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002023
Yann Collet302ff032016-07-03 01:28:16 +02002024 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002025 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002026 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002027
2028 /* Match Loop */
2029 while (ip < ilimit) {
2030 size_t matchLength=0;
2031 size_t offset=0;
2032 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002033 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002034
2035 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002036 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002037 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2038 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002039 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002040 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002041 /* repcode detected we should take it */
2042 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02002043 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2044 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002045 } }
2046
2047 /* first search (depth 0) */
2048 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002049 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002050 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002051 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002052 }
2053
inikep7bc19b62016-04-06 09:46:01 +02002054 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02002055 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2056 continue;
2057 }
2058
inikep64d7bcb2016-04-07 19:14:09 +02002059 /* let's try to find a better solution */
2060 if (depth>=1)
2061 while (ip<ilimit) {
2062 ip ++;
2063 current++;
2064 /* check repCode */
2065 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002066 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002067 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2068 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002069 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002070 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2071 /* repcode detected */
2072 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2073 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2074 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002075 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002076 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2077 matchLength = repLength, offset = 0, start = ip;
2078 } }
2079
2080 /* search match, depth 1 */
2081 { size_t offset2=99999999;
2082 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002083 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2084 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02002085 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2086 matchLength = ml2, offset = offset2, start = ip;
2087 continue; /* search a better one */
2088 } }
2089
2090 /* let's find an even better one */
2091 if ((depth==2) && (ip<ilimit)) {
2092 ip ++;
2093 current++;
2094 /* check repCode */
2095 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002096 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002097 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2098 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002099 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002100 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2101 /* repcode detected */
2102 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2103 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2104 int gain2 = (int)(repLength * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002105 int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002106 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2107 matchLength = repLength, offset = 0, start = ip;
2108 } }
2109
2110 /* search match, depth 2 */
2111 { size_t offset2=99999999;
2112 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002113 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2114 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02002115 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2116 matchLength = ml2, offset = offset2, start = ip;
2117 continue;
2118 } } }
2119 break; /* nothing found : store previous solution */
2120 }
2121
inikepfaa8d8a2016-04-05 19:01:10 +02002122 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002123 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002124 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002125 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2126 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002127 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002128 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002129 }
inikepfaa8d8a2016-04-05 19:01:10 +02002130
inikepfaa8d8a2016-04-05 19:01:10 +02002131 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002132_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002133 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002134 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002135 anchor = ip = start + matchLength;
2136 }
2137
2138 /* check immediate repcode */
2139 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002140 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002141 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2142 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002143 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002144 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2145 /* repcode detected we should take it */
2146 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02002147 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
Yann Collet302ff032016-07-03 01:28:16 +02002148 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002149 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2150 ip += matchLength;
2151 anchor = ip;
2152 continue; /* faster when present ... (?) */
2153 }
2154 break;
2155 } }
2156
Yann Collet4266c0a2016-06-14 01:49:25 +02002157 /* Save reps for next block */
Yann Collet302ff032016-07-03 01:28:16 +02002158 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002159
inikepfaa8d8a2016-04-05 19:01:10 +02002160 /* Last Literals */
2161 { size_t const lastLLSize = iend - anchor;
2162 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2163 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002164 }
2165}
2166
2167
Yann Collet59d1f792016-01-23 19:28:41 +01002168void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002169{
inikep64d7bcb2016-04-07 19:14:09 +02002170 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002171}
2172
Yann Collet59d1f792016-01-23 19:28:41 +01002173static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002174{
Yann Colleta1249dc2016-01-25 04:22:03 +01002175 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002176}
Yann Collet9a24e592015-11-22 02:53:43 +01002177
Yann Collet59d1f792016-01-23 19:28:41 +01002178static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002179{
Yann Colleta1249dc2016-01-25 04:22:03 +01002180 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002181}
2182
Yann Collet59d1f792016-01-23 19:28:41 +01002183static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002184{
Yann Colleta1249dc2016-01-25 04:22:03 +01002185 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002186}
2187
inikepef519412016-04-21 11:08:43 +02002188
inikepef519412016-04-21 11:08:43 +02002189/* The optimal parser */
2190#include "zstd_opt.h"
2191
2192static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2193{
Yann Colletd4f4e582016-06-27 01:31:35 +02002194#ifdef ZSTD_OPT_H_91842398743
inikepef519412016-04-21 11:08:43 +02002195 ZSTD_compressBlock_opt_generic(ctx, src, srcSize);
Yann Colletd4f4e582016-06-27 01:31:35 +02002196#else
2197 (void)ctx; (void)src; (void)srcSize;
2198 return;
2199#endif
inikepef519412016-04-21 11:08:43 +02002200}
2201
inikepd3b8d7a2016-02-22 10:06:17 +01002202static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002203{
Yann Colletd4f4e582016-06-27 01:31:35 +02002204#ifdef ZSTD_OPT_H_91842398743
inikep5ce00ae2016-04-05 21:03:43 +02002205 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize);
Yann Colletd4f4e582016-06-27 01:31:35 +02002206#else
2207 (void)ctx; (void)src; (void)srcSize;
2208 return;
2209#endif
inikepe2bfe242016-01-31 11:25:48 +01002210}
2211
Yann Collet7a231792015-11-21 15:27:35 +01002212
Yann Collet59d1f792016-01-23 19:28:41 +01002213typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002214
Yann Colletb923f652016-01-26 03:14:20 +01002215static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002216{
Yann Collet45dc3562016-07-12 09:47:31 +02002217 static const ZSTD_blockCompressor blockCompressor[2][7] = {
2218 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt },
2219 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_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 +01002220 };
2221
2222 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002223}
2224
2225
Yann Colletd1b26842016-03-15 01:24:33 +01002226static 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 +01002227{
Yann Collet19cab462016-06-17 12:54:52 +02002228 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002229 const BYTE* const base = zc->base;
2230 const BYTE* const istart = (const BYTE*)src;
2231 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002232 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 +02002233 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002234 if (current > zc->nextToUpdate + 384)
2235 zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384)); /* update tree not updated after finding very long rep matches */
Yann Collet59d1f792016-01-23 19:28:41 +01002236 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002237 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002238}
2239
2240
Yann Colletc991cc12016-07-28 00:55:43 +02002241/*! ZSTD_compress_generic() :
2242* Compress a chunk of data into one or multiple blocks.
2243* All blocks will be terminated, all input will be consumed.
2244* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2245* Frame is supposed already started (header already produced)
2246* @return : compressed size, or an error code
2247*/
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002248static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2249 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002250 const void* src, size_t srcSize,
2251 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002252{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002253 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002254 size_t remaining = srcSize;
2255 const BYTE* ip = (const BYTE*)src;
2256 BYTE* const ostart = (BYTE*)dst;
2257 BYTE* op = ostart;
Yann Colletd4180ca2016-07-27 21:21:36 +02002258 U32 const maxDist = 1 << cctx->params.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002259
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002260 if (cctx->params.fParams.checksumFlag)
2261 XXH64_update(&cctx->xxhState, src, srcSize);
2262
Yann Collet2ce49232016-02-02 14:36:49 +01002263 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002264 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002265 size_t cSize;
2266
inikepfb5df612016-05-24 15:36:37 +02002267 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 +01002268 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002269
Yann Collet346efcc2016-08-02 14:26:00 +02002270 /* preemptive overflow correction */
2271 if (cctx->lowLimit > (1<<30)) {
2272 U32 const btplus = (cctx->params.cParams.strategy == ZSTD_btlazy2) | (cctx->params.cParams.strategy == ZSTD_btopt);
2273 U32 const chainMask = (1 << (cctx->params.cParams.chainLog - btplus)) - 1;
Yann Collet5a02b692016-08-25 22:24:59 +02002274 U32 const supLog = MAX(cctx->params.cParams.chainLog, 17 /* blockSize */);
2275 U32 const newLowLimit = (cctx->lowLimit & chainMask) + (1 << supLog); /* preserve position % chainSize, ensure current-repcode doesn't underflow */
Yann Collet346efcc2016-08-02 14:26:00 +02002276 U32 const correction = cctx->lowLimit - newLowLimit;
2277 ZSTD_reduceIndex(cctx, correction);
2278 cctx->base += correction;
2279 cctx->dictBase += correction;
2280 cctx->lowLimit = newLowLimit;
2281 cctx->dictLimit -= correction;
2282 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2283 else cctx->nextToUpdate -= correction;
2284 }
2285
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002286 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002287 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002288 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2289 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2290 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002291 }
Yann Collet89db5e02015-11-13 11:27:46 +01002292
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002293 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002294 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002295
Yann Collet2ce49232016-02-02 14:36:49 +01002296 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002297 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2298 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2299 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2300 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2301 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002302 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002303 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002304 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002305 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002306 }
2307
2308 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002309 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002310 ip += blockSize;
2311 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002312 }
2313
Yann Collet62470b42016-07-28 15:29:08 +02002314 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002315 return op-ostart;
2316}
2317
2318
Yann Collet6236eba2016-04-12 15:52:33 +02002319static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002320 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002321{ BYTE* const op = (BYTE*)dst;
Yann Collet731ef162016-07-27 21:05:12 +02002322 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2323 U32 const checksumFlag = params.fParams.checksumFlag>0;
2324 U32 const windowSize = 1U << params.cParams.windowLog;
2325 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize > (pledgedSrcSize-1));
2326 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2327 U32 const fcsCode = params.fParams.contentSizeFlag ?
Yann Collet673f0d72016-06-06 00:26:38 +02002328 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
2329 0;
Yann Collet731ef162016-07-27 21:05:12 +02002330 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002331 size_t pos;
2332
2333 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet6236eba2016-04-12 15:52:33 +02002334
2335 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002336 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002337 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002338 switch(dictIDSizeCode)
2339 {
2340 default: /* impossible */
2341 case 0 : break;
2342 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002343 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002344 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2345 }
Yann Collet673f0d72016-06-06 00:26:38 +02002346 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002347 {
2348 default: /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002349 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002350 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2351 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002352 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002353 }
Yann Colletc46fb922016-05-29 05:01:04 +02002354 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002355}
2356
2357
Yann Collet346efcc2016-08-02 14:26:00 +02002358static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002359 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002360 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002361 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002362{
Yann Collet2acb5d32015-10-29 16:49:43 +01002363 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002364 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002365
Yann Collet346efcc2016-08-02 14:26:00 +02002366 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002367
Yann Collet346efcc2016-08-02 14:26:00 +02002368 if (frame && (cctx->stage==ZSTDcs_init)) {
2369 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002370 if (ZSTD_isError(fhSize)) return fhSize;
2371 dstCapacity -= fhSize;
2372 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002373 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002374 }
Yann Colletf3eca252015-10-22 15:31:46 +01002375
Yann Collet417890c2015-12-04 17:16:37 +01002376 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002377 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002378 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002379 ptrdiff_t const delta = cctx->nextSrc - ip;
2380 cctx->lowLimit = cctx->dictLimit;
2381 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2382 cctx->dictBase = cctx->base;
2383 cctx->base -= delta;
2384 cctx->nextToUpdate = cctx->dictLimit;
2385 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002386 }
2387
Yann Collet346efcc2016-08-02 14:26:00 +02002388 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2389 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2390 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2391 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2392 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002393 }
2394
Yann Collet346efcc2016-08-02 14:26:00 +02002395 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002396
Yann Collet70e45772016-03-19 18:08:32 +01002397 { size_t const cSize = frame ?
Yann Collet346efcc2016-08-02 14:26:00 +02002398 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2399 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002400 if (ZSTD_isError(cSize)) return cSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002401 return cSize + fhSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002402 }
Yann Colletf3eca252015-10-22 15:31:46 +01002403}
2404
Yann Colletbf42c8e2016-01-09 01:08:23 +01002405
Yann Collet5b567392016-07-28 01:17:22 +02002406size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002407 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002408 const void* src, size_t srcSize)
2409{
Yann Collet5b567392016-07-28 01:17:22 +02002410 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 0);
2411}
2412
2413
Yann Colletcf05b9d2016-07-18 16:52:10 +02002414size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002415{
Yann Colletcf05b9d2016-07-18 16:52:10 +02002416 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
2417}
2418
2419size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2420{
2421 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002422 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Colletc991cc12016-07-28 00:55:43 +02002423 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002424}
2425
2426
Yann Colletb923f652016-01-26 03:14:20 +01002427static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002428{
2429 const BYTE* const ip = (const BYTE*) src;
2430 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002431
Yann Collet417890c2015-12-04 17:16:37 +01002432 /* input becomes current prefix */
2433 zc->lowLimit = zc->dictLimit;
2434 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2435 zc->dictBase = zc->base;
2436 zc->base += ip - zc->nextSrc;
2437 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002438 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002439
2440 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002441 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002442
Yann Collet3b719252016-03-30 19:48:05 +02002443 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002444 {
2445 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002446 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002447 break;
2448
Yann Collet45dc3562016-07-12 09:47:31 +02002449 case ZSTD_dfast:
2450 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2451 break;
2452
Yann Collet417890c2015-12-04 17:16:37 +01002453 case ZSTD_greedy:
2454 case ZSTD_lazy:
2455 case ZSTD_lazy2:
Yann Collet731ef162016-07-27 21:05:12 +02002456 ZSTD_insertAndFindFirstIndex (zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002457 break;
2458
2459 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002460 case ZSTD_btopt:
Yann Collet731ef162016-07-27 21:05:12 +02002461 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002462 break;
2463
2464 default:
2465 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2466 }
2467
Yann Collet2ce49232016-02-02 14:36:49 +01002468 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002469 return 0;
2470}
2471
2472
Yann Colletb923f652016-01-26 03:14:20 +01002473/* Dictionary format :
2474 Magic == ZSTD_DICT_MAGIC (4 bytes)
Yann Colletfb797352016-03-13 11:08:40 +01002475 HUF_writeCTable(256)
Yann Collet736d4192016-06-15 18:48:51 +02002476 FSE_writeNCount(off)
Yann Collet731ef162016-07-27 21:05:12 +02002477 FSE_writeNCount(ml)
Yann Collet736d4192016-06-15 18:48:51 +02002478 FSE_writeNCount(ll)
2479 RepOffsets
Yann Colletb923f652016-01-26 03:14:20 +01002480 Dictionary content
2481*/
Yann Colletfb797352016-03-13 11:08:40 +01002482/*! ZSTD_loadDictEntropyStats() :
Yann Collet736d4192016-06-15 18:48:51 +02002483 @return : size read from dictionary
2484 note : magic number supposed already checked */
2485static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002486{
Yann Collet52a06222016-06-15 13:53:34 +02002487 const BYTE* dictPtr = (const BYTE*)dict;
2488 const BYTE* const dictEnd = dictPtr + dictSize;
Yann Colletfb810d62016-01-28 00:18:06 +01002489
Yann Collet736d4192016-06-15 18:48:51 +02002490 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dict, dictSize);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002491 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002492 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002493 }
Yann Colletfb810d62016-01-28 00:18:06 +01002494
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002495 { short offcodeNCount[MaxOff+1];
2496 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
Yann Collet52a06222016-06-15 13:53:34 +02002497 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002498 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet736d4192016-06-15 18:48:51 +02002499 { size_t const errorCode = FSE_buildCTable(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002500 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
Yann Collet52a06222016-06-15 13:53:34 +02002501 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002502 }
Yann Colletfb810d62016-01-28 00:18:06 +01002503
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002504 { short matchlengthNCount[MaxML+1];
2505 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
Yann Collet52a06222016-06-15 13:53:34 +02002506 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002507 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet736d4192016-06-15 18:48:51 +02002508 { size_t const errorCode = FSE_buildCTable(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002509 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
Yann Collet52a06222016-06-15 13:53:34 +02002510 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002511 }
Yann Colletfb810d62016-01-28 00:18:06 +01002512
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002513 { short litlengthNCount[MaxLL+1];
2514 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
Yann Collet52a06222016-06-15 13:53:34 +02002515 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002516 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet736d4192016-06-15 18:48:51 +02002517 { size_t const errorCode = FSE_buildCTable(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002518 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
Yann Collet52a06222016-06-15 13:53:34 +02002519 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002520 }
Yann Colletfb810d62016-01-28 00:18:06 +01002521
Yann Collet52a06222016-06-15 13:53:34 +02002522 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Yann Collet736d4192016-06-15 18:48:51 +02002523 cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);
2524 cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);
2525 cctx->rep[2] = MEM_readLE32(dictPtr+8); if (cctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002526 dictPtr += 12;
2527
Yann Collet736d4192016-06-15 18:48:51 +02002528 cctx->flagStaticTables = 1;
Yann Collet52a06222016-06-15 13:53:34 +02002529 return dictPtr - (const BYTE*)dict;
Yann Colletb923f652016-01-26 03:14:20 +01002530}
2531
Yann Colletd1b26842016-03-15 01:24:33 +01002532/** ZSTD_compress_insertDictionary() :
2533* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002534static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002535{
Yann Colletc46fb922016-05-29 05:01:04 +02002536 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002537
Yann Colletd1b26842016-03-15 01:24:33 +01002538 /* default : dict is pure content */
2539 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletc46fb922016-05-29 05:01:04 +02002540 zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4);
Yann Colletd1b26842016-03-15 01:24:33 +01002541
2542 /* known magic number : dict is parsed for entropy stats and content */
Yann Collet14200a22016-08-30 06:51:00 -07002543 { size_t const eSize_8 = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8);
2544 size_t const eSize = eSize_8 + 8;
2545 if (ZSTD_isError(eSize_8)) return eSize_8;
Yann Collet21588e32016-03-30 16:50:44 +02002546 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002547 }
Yann Colletecd651b2016-01-07 15:35:18 +01002548}
2549
Yann Collet0085cd32016-04-12 14:14:10 +02002550
Yann Collet27caf2a2016-04-01 15:48:48 +02002551/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002552* @return : 0, or an error code */
Yann Collet27caf2a2016-04-01 15:48:48 +02002553static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* zc,
Yann Collet1c8e1942016-01-26 16:31:22 +01002554 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002555 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002556{
Yann Collet961b6a02016-07-15 11:56:53 +02002557 size_t const resetError = ZSTD_resetCCtx_advanced(zc, params, pledgedSrcSize, 1);
Yann Collet673f0d72016-06-06 00:26:38 +02002558 if (ZSTD_isError(resetError)) return resetError;
Yann Collet89db5e02015-11-13 11:27:46 +01002559
Yann Collet1c8e1942016-01-26 16:31:22 +01002560 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002561}
2562
2563
Yann Collet27caf2a2016-04-01 15:48:48 +02002564/*! ZSTD_compressBegin_advanced() :
2565* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002566size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002567 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02002568 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02002569{
2570 /* compression parameters verification and optimization */
2571 { size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize);
2572 if (ZSTD_isError(errorCode)) return errorCode; }
2573
Yann Collet81e13ef2016-06-07 00:51:51 +02002574 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002575}
2576
2577
Yann Collet81e13ef2016-06-07 00:51:51 +02002578size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002579{
Yann Collet6c6e1752016-06-27 15:28:45 +02002580 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002581 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002582}
Yann Collet083fcc82015-10-25 14:06:35 +01002583
inikep19bd48f2016-04-04 12:10:00 +02002584
Yann Collet1c8e1942016-01-26 16:31:22 +01002585size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002586{
Yann Collet3b719252016-03-30 19:48:05 +02002587 return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002588}
2589
2590
Yann Collet62470b42016-07-28 15:29:08 +02002591/*! ZSTD_writeEpilogue() :
2592* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01002593* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02002594static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002595{
Yann Colletc991cc12016-07-28 00:55:43 +02002596 BYTE* const ostart = (BYTE*)dst;
2597 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02002598 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002599
Yann Collet87c18b22016-08-26 01:43:47 +02002600 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02002601
2602 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02002603 if (cctx->stage == ZSTDcs_init) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002604 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002605 if (ZSTD_isError(fhSize)) return fhSize;
2606 dstCapacity -= fhSize;
2607 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02002608 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002609 }
2610
Yann Colletc991cc12016-07-28 00:55:43 +02002611 if (cctx->stage != ZSTDcs_ending) {
2612 /* write one last empty block, make it the "last" block */
2613 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2614 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2615 MEM_writeLE32(op, cBlockHeader24);
2616 op += ZSTD_blockHeaderSize;
2617 dstCapacity -= ZSTD_blockHeaderSize;
2618 }
2619
2620 if (cctx->params.fParams.checksumFlag) {
2621 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2622 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2623 MEM_writeLE32(op, checksum);
2624 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002625 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002626
Yann Collet731ef162016-07-27 21:05:12 +02002627 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02002628 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01002629}
2630
Yann Colletfd416f12016-01-30 03:14:15 +01002631
Yann Collet62470b42016-07-28 15:29:08 +02002632size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2633 void* dst, size_t dstCapacity,
2634 const void* src, size_t srcSize)
2635{
2636 size_t endResult;
2637 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 1);
2638 if (ZSTD_isError(cSize)) return cSize;
2639 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2640 if (ZSTD_isError(endResult)) return endResult;
2641 return cSize + endResult;
2642}
2643
2644
Yann Collet19c10022016-07-28 01:25:46 +02002645static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002646 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002647 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002648 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002649 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002650{
Yann Collet62470b42016-07-28 15:29:08 +02002651 size_t const errorCode = ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize);
2652 if(ZSTD_isError(errorCode)) return errorCode;
Yann Colletf3eca252015-10-22 15:31:46 +01002653
Yann Collet62470b42016-07-28 15:29:08 +02002654 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002655}
2656
Yann Collet21588e32016-03-30 16:50:44 +02002657size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2658 void* dst, size_t dstCapacity,
2659 const void* src, size_t srcSize,
2660 const void* dict,size_t dictSize,
2661 ZSTD_parameters params)
2662{
Yann Collet3b719252016-03-30 19:48:05 +02002663 size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, srcSize);
Yann Collet21588e32016-03-30 16:50:44 +02002664 if (ZSTD_isError(errorCode)) return errorCode;
2665 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2666}
2667
Yann Colletd1b26842016-03-15 01:24:33 +01002668size_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 +01002669{
Yann Collet6c6e1752016-06-27 15:28:45 +02002670 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dictSize);
Yann Collet3b719252016-03-30 19:48:05 +02002671 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002672 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002673}
2674
Yann Colletd1b26842016-03-15 01:24:33 +01002675size_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 +01002676{
Yann Collet21588e32016-03-30 16:50:44 +02002677 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002678}
2679
Yann Colletd1b26842016-03-15 01:24:33 +01002680size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002681{
Yann Collet44fe9912015-10-29 22:02:40 +01002682 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002683 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002684 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002685 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002686 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Collet23b6e052016-08-28 21:05:43 -07002687 ZSTD_free(ctxBody.workSpace, defaultCustomMem); /* can't free ctxBody itself, as it's on stack; free only heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002688 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002689}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002690
Yann Colletfd416f12016-01-30 03:14:15 +01002691
Yann Collet81e13ef2016-06-07 00:51:51 +02002692/* ===== Dictionary API ===== */
2693
2694struct ZSTD_CDict_s {
2695 void* dictContent;
2696 size_t dictContentSize;
2697 ZSTD_CCtx* refContext;
2698}; /* typedef'd tp ZSTD_CDict within zstd.h */
2699
2700ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, ZSTD_parameters params, ZSTD_customMem customMem)
2701{
Yann Collet23b6e052016-08-28 21:05:43 -07002702 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2703 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02002704
Yann Collet23b6e052016-08-28 21:05:43 -07002705 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
2706 void* const dictContent = ZSTD_malloc(dictSize, customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002707 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2708
2709 if (!dictContent || !cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07002710 ZSTD_free(dictContent, customMem);
2711 ZSTD_free(cdict, customMem);
2712 ZSTD_free(cctx, customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002713 return NULL;
2714 }
2715
2716 memcpy(dictContent, dict, dictSize);
2717 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, dictContent, dictSize, params, 0);
2718 if (ZSTD_isError(errorCode)) {
Yann Collet23b6e052016-08-28 21:05:43 -07002719 ZSTD_free(dictContent, customMem);
2720 ZSTD_free(cdict, customMem);
2721 ZSTD_free(cctx, customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002722 return NULL;
2723 } }
2724
2725 cdict->dictContent = dictContent;
2726 cdict->dictContentSize = dictSize;
2727 cdict->refContext = cctx;
2728 return cdict;
2729 }
2730}
2731
2732ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2733{
2734 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet07639052016-08-03 01:57:57 +02002735 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002736 params.fParams.contentSizeFlag = 1;
2737 return ZSTD_createCDict_advanced(dict, dictSize, params, allocator);
2738}
2739
2740size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2741{
Yann Collet23b6e052016-08-28 21:05:43 -07002742 if (cdict==NULL) return 0; /* support free on NULL */
2743 { ZSTD_customMem cMem = cdict->refContext->customMem;
2744 ZSTD_freeCCtx(cdict->refContext);
2745 ZSTD_free(cdict->dictContent, cMem);
2746 ZSTD_free(cdict, cMem);
2747 return 0;
2748 }
Yann Collet81e13ef2016-06-07 00:51:51 +02002749}
2750
Yann Collet07639052016-08-03 01:57:57 +02002751/*! ZSTD_compress_usingCDict() :
2752* Compression using a digested Dictionary.
2753* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
2754* Note that compression level is decided during dictionary creation */
Yann Collet81e13ef2016-06-07 00:51:51 +02002755ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2756 void* dst, size_t dstCapacity,
2757 const void* src, size_t srcSize,
2758 const ZSTD_CDict* cdict)
2759{
Yann Collet07639052016-08-03 01:57:57 +02002760 size_t const errorCode = ZSTD_copyCCtx(cctx, cdict->refContext);
2761 if (ZSTD_isError(errorCode)) return errorCode;
2762
2763 if (cdict->refContext->params.fParams.contentSizeFlag==1) {
2764 cctx->params.fParams.contentSizeFlag = 1;
2765 cctx->frameContentSize = srcSize;
2766 }
2767
2768 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002769}
2770
2771
2772
Yann Collet104e5b02016-08-12 13:04:27 +02002773/* ******************************************************************
2774* Streaming
2775********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002776
2777typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
2778
2779struct ZSTD_CStream_s {
2780 ZSTD_CCtx* zc;
2781 char* inBuff;
2782 size_t inBuffSize;
2783 size_t inToCompress;
2784 size_t inBuffPos;
2785 size_t inBuffTarget;
2786 size_t blockSize;
2787 char* outBuff;
2788 size_t outBuffSize;
2789 size_t outBuffContentSize;
2790 size_t outBuffFlushedSize;
2791 ZSTD_cStreamStage stage;
2792 U32 checksum;
2793 U32 frameEnded;
2794 ZSTD_customMem customMem;
2795}; /* typedef'd to ZSTD_CStream within "zstd.h" */
2796
2797ZSTD_CStream* ZSTD_createCStream(void)
2798{
2799 return ZSTD_createCStream_advanced(defaultCustomMem);
2800}
2801
2802ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
2803{
2804 ZSTD_CStream* zcs;
2805
Yann Collet23b6e052016-08-28 21:05:43 -07002806 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2807 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002808
Yann Collet23b6e052016-08-28 21:05:43 -07002809 zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002810 if (zcs==NULL) return NULL;
2811 memset(zcs, 0, sizeof(ZSTD_CStream));
2812 memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
2813 zcs->zc = ZSTD_createCCtx_advanced(customMem);
2814 if (zcs->zc == NULL) { ZSTD_freeCStream(zcs); return NULL; }
2815 return zcs;
2816}
2817
2818size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
2819{
2820 if (zcs==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -07002821 { ZSTD_customMem const cMem = zcs->customMem;
2822 ZSTD_freeCCtx(zcs->zc);
2823 ZSTD_free(zcs->inBuff, cMem);
2824 ZSTD_free(zcs->outBuff, cMem);
2825 ZSTD_free(zcs, cMem);
2826 return 0;
2827 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002828}
2829
2830
Yann Collet104e5b02016-08-12 13:04:27 +02002831/*====== Initialization ======*/
2832
2833size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
2834size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002835
2836size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
2837 const void* dict, size_t dictSize,
2838 ZSTD_parameters params, unsigned long long pledgedSrcSize)
2839{
2840 /* allocate buffers */
2841 { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
2842 if (zcs->inBuffSize < neededInBuffSize) {
2843 zcs->inBuffSize = neededInBuffSize;
Yann Collet23b6e052016-08-28 21:05:43 -07002844 ZSTD_free(zcs->inBuff, zcs->customMem); /* should not be necessary */
2845 zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002846 if (zcs->inBuff == NULL) return ERROR(memory_allocation);
2847 }
2848 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
2849 }
2850 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
2851 zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
Yann Collet23b6e052016-08-28 21:05:43 -07002852 ZSTD_free(zcs->outBuff, zcs->customMem); /* should not be necessary */
2853 zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002854 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
2855 }
2856
2857 { size_t const errorCode = ZSTD_compressBegin_advanced(zcs->zc, dict, dictSize, params, pledgedSrcSize);
2858 if (ZSTD_isError(errorCode)) return errorCode; }
2859
2860 zcs->inToCompress = 0;
2861 zcs->inBuffPos = 0;
2862 zcs->inBuffTarget = zcs->blockSize;
2863 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
2864 zcs->stage = zcss_load;
2865 zcs->checksum = params.fParams.checksumFlag > 0;
2866 zcs->frameEnded = 0;
2867 return 0; /* ready to go */
2868}
2869
2870size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
2871{
2872 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
2873 return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0);
2874}
2875
2876size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
2877{
2878 return ZSTD_initCStream_usingDict(zcs, NULL, 0, compressionLevel);
2879}
2880
Yann Collet70e3b312016-08-23 01:18:06 +02002881size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
Yann Colletcb327632016-08-23 00:30:31 +02002882{
Yann Collet70e3b312016-08-23 01:18:06 +02002883 return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->zc) + zcs->outBuffSize + zcs->inBuffSize;
Yann Colletcb327632016-08-23 00:30:31 +02002884}
Yann Collet5a0c8e22016-08-12 01:20:36 +02002885
Yann Collet104e5b02016-08-12 13:04:27 +02002886/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002887
2888typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
2889
2890MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2891{
2892 size_t const length = MIN(dstCapacity, srcSize);
2893 memcpy(dst, src, length);
2894 return length;
2895}
2896
2897static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
2898 void* dst, size_t* dstCapacityPtr,
2899 const void* src, size_t* srcSizePtr,
2900 ZSTD_flush_e const flush)
2901{
2902 U32 someMoreWork = 1;
2903 const char* const istart = (const char*)src;
2904 const char* const iend = istart + *srcSizePtr;
2905 const char* ip = istart;
2906 char* const ostart = (char*)dst;
2907 char* const oend = ostart + *dstCapacityPtr;
2908 char* op = ostart;
2909
2910 while (someMoreWork) {
2911 switch(zcs->stage)
2912 {
2913 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
2914
2915 case zcss_load:
2916 /* complete inBuffer */
2917 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
2918 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
2919 zcs->inBuffPos += loaded;
2920 ip += loaded;
2921 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
2922 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
2923 } }
2924 /* compress current block (note : this stage cannot be stopped in the middle) */
2925 { void* cDst;
2926 size_t cSize;
2927 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
2928 size_t oSize = oend-op;
2929 if (oSize >= ZSTD_compressBound(iSize))
2930 cDst = op; /* compress directly into output buffer (avoid flush stage) */
2931 else
2932 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
2933 cSize = (flush == zsf_end) ?
2934 ZSTD_compressEnd(zcs->zc, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
2935 ZSTD_compressContinue(zcs->zc, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
2936 if (ZSTD_isError(cSize)) return cSize;
2937 if (flush == zsf_end) zcs->frameEnded = 1;
2938 /* prepare next block */
2939 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
2940 if (zcs->inBuffTarget > zcs->inBuffSize)
2941 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
2942 zcs->inToCompress = zcs->inBuffPos;
2943 if (cDst == op) { op += cSize; break; } /* no need to flush */
2944 zcs->outBuffContentSize = cSize;
2945 zcs->outBuffFlushedSize = 0;
2946 zcs->stage = zcss_flush; /* pass-through to flush stage */
2947 }
2948
2949 case zcss_flush:
2950 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
2951 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
2952 op += flushed;
2953 zcs->outBuffFlushedSize += flushed;
2954 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
2955 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
2956 zcs->stage = zcss_load;
2957 break;
2958 }
2959
2960 case zcss_final:
2961 someMoreWork = 0; /* do nothing */
2962 break;
2963
2964 default:
2965 return ERROR(GENERIC); /* impossible */
2966 }
2967 }
2968
2969 *srcSizePtr = ip - istart;
2970 *dstCapacityPtr = op - ostart;
2971 if (zcs->frameEnded) return 0;
2972 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
2973 if (hintInSize==0) hintInSize = zcs->blockSize;
2974 return hintInSize;
2975 }
2976}
2977
Yann Collet53e17fb2016-08-17 01:39:22 +02002978size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02002979{
Yann Collet53e17fb2016-08-17 01:39:22 +02002980 size_t sizeRead = input->size - input->pos;
2981 size_t sizeWritten = output->size - output->pos;
2982 size_t const result = ZSTD_compressStream_generic(zcs,
2983 (char*)(output->dst) + output->pos, &sizeWritten,
2984 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
2985 input->pos += sizeRead;
2986 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002987 return result;
2988}
2989
2990
Yann Collet104e5b02016-08-12 13:04:27 +02002991/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002992
2993/*! ZSTD_flushStream() :
2994* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02002995size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02002996{
2997 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02002998 size_t sizeWritten = output->size - output->pos;
Yann Colletc4119022016-08-17 01:50:54 +02002999 size_t const result = ZSTD_compressStream_generic(zcs,
3000 (char*)(output->dst) + output->pos, &sizeWritten,
3001 &srcSize, &srcSize, /* use a valid src address instead of NULL */
3002 zsf_flush);
Yann Collet53e17fb2016-08-17 01:39:22 +02003003 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003004 if (ZSTD_isError(result)) return result;
3005 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3006}
3007
3008
Yann Collet53e17fb2016-08-17 01:39:22 +02003009size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003010{
Yann Collet53e17fb2016-08-17 01:39:22 +02003011 BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
3012 BYTE* const oend = (BYTE*)(output->dst) + output->size;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003013 BYTE* op = ostart;
3014
3015 if (zcs->stage != zcss_final) {
3016 /* flush whatever remains */
3017 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003018 size_t sizeWritten = output->size - output->pos;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003019 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
3020 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3021 op += sizeWritten;
3022 if (remainingToFlush) {
Yann Collet53e17fb2016-08-17 01:39:22 +02003023 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003024 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4);
3025 }
3026 /* create epilogue */
3027 zcs->stage = zcss_final;
3028 zcs->outBuffContentSize = !notEnded ? 0 :
3029 ZSTD_compressEnd(zcs->zc, zcs->outBuff, zcs->outBuffSize, NULL, 0); /* write epilogue, including final empty block, into outBuff */
3030 }
3031
3032 /* flush epilogue */
3033 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3034 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3035 op += flushed;
3036 zcs->outBuffFlushedSize += flushed;
Yann Collet53e17fb2016-08-17 01:39:22 +02003037 output->pos += op-ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003038 if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */
3039 return toFlush - flushed;
3040 }
3041}
3042
3043
3044
Yann Collet70e8c382016-02-10 13:37:52 +01003045/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003046
Yann Collet236d94f2016-05-18 12:06:33 +02003047#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02003048#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003049int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003050
Yann Collet3b719252016-03-30 19:48:05 +02003051static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003052{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003053 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003054 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003055 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3056 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003057 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3058 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003059 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3060 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3061 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003062 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003063 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3064 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3065 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3066 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3067 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3068 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3069 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3070 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003071 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
3072 { 23, 23, 22, 6, 5, 32, ZSTD_btopt }, /* level 18 */
3073 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
3074 { 25, 25, 23, 7, 3, 64, ZSTD_btopt }, /* level 20 */
3075 { 26, 26, 23, 7, 3,256, ZSTD_btopt }, /* level 21 */
3076 { 27, 27, 25, 9, 3,512, ZSTD_btopt }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003077},
3078{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003079 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003080 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003081 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003082 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3083 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3084 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3085 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3086 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3087 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3088 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3089 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3090 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3091 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3092 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3093 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003094 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003095 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3096 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3097 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003098 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3099 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
3100 { 18, 19, 18, 11, 3,512, ZSTD_btopt }, /* level 20.*/
3101 { 18, 19, 18, 12, 3,512, ZSTD_btopt }, /* level 21.*/
3102 { 18, 19, 18, 13, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003103},
3104{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003105 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003106 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3107 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3108 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3109 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3110 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3111 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3112 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3113 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3114 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3115 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3116 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3117 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3118 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3119 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003120 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3121 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3122 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3123 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3124 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3125 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
3126 { 17, 18, 17, 9, 3,256, ZSTD_btopt }, /* level 20.*/
3127 { 17, 18, 17, 10, 3,256, ZSTD_btopt }, /* level 21.*/
Yann Collet5894ea82016-07-22 14:36:46 +02003128 { 17, 18, 17, 11, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003129},
3130{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003131 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003132 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003133 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003134 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3135 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3136 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3137 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3138 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3139 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3140 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3141 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003142 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3143 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3144 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3145 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3146 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3147 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3148 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3149 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3150 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3151 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
3152 { 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 20.*/
3153 { 14, 15, 15, 9, 3,256, ZSTD_btopt }, /* level 21.*/
3154 { 14, 15, 15, 10, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003155},
3156};
3157
Yann Collet236d94f2016-05-18 12:06:33 +02003158/*! ZSTD_getCParams() :
3159* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3160* Size values are optional, provide 0 if not known or unused */
Yann Collet52c04fe2016-07-07 11:53:18 +02003161ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003162{
Yann Collet15354142016-04-04 04:22:53 +02003163 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02003164 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02003165 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003166 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02003167 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003168 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003169 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003170 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3171 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003172 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003173 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3174 }
Yann Collet70d13012016-06-01 18:45:34 +02003175 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003176 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003177}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003178
3179/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003180* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003181* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet52c04fe2016-07-07 11:53:18 +02003182ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003183 ZSTD_parameters params;
3184 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3185 memset(&params, 0, sizeof(params));
3186 params.cParams = cParams;
3187 return params;
3188}