blob: d4128581223d5774e8b78c58620402b976cb22cf [file] [log] [blame]
Yann Collet4ded9e52016-08-30 10:04:33 -07001/**
2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 */
Yann Colletf3eca252015-10-22 15:31:46 +01009
Yann Colletf3eca252015-10-22 15:31:46 +010010
Yann Collet5a0c8e22016-08-12 01:20:36 +020011/*-*******************************************************
Yann Collet4b100f42015-10-30 15:49:48 +010012* Compiler specifics
13*********************************************************/
14#ifdef _MSC_VER /* Visual Studio */
15# define FORCE_INLINE static __forceinline
16# include <intrin.h> /* For Visual 2005 */
17# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
Yann Collet4b100f42015-10-30 15:49:48 +010018#else
Yann Collet1563bfe2016-09-02 11:44:21 -070019# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
20# ifdef __GNUC__
21# define FORCE_INLINE static inline __attribute__((always_inline))
22# else
23# define FORCE_INLINE static inline
24# endif
Yann Collet4b100f42015-10-30 15:49:48 +010025# else
Yann Collet1563bfe2016-09-02 11:44:21 -070026# define FORCE_INLINE static
27# endif /* __STDC_VERSION__ */
Yann Collet4b100f42015-10-30 15:49:48 +010028#endif
29
30
Yann Collet7d360282016-02-12 00:07:30 +010031/*-*************************************
Yann Colletae7aa062016-02-03 02:46:46 +010032* Dependencies
Yann Colletf3eca252015-10-22 15:31:46 +010033***************************************/
Yann Colletd3b7f8d2016-06-04 19:47:02 +020034#include <string.h> /* memset */
Yann Collet14983e72015-11-11 21:38:21 +010035#include "mem.h"
Yann Colletf2a3b6e2016-05-31 18:13:56 +020036#define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
Yann Collet7ae67bb2016-09-06 06:28:05 +020037#include "xxhash.h" /* XXH_reset, update, digest */
Yann Collet5a0c8e22016-08-12 01:20:36 +020038#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
Yann Colletd0e2cd12016-06-05 00:58:01 +020039#include "fse.h"
Yann Collet130fe112016-06-05 00:42:28 +020040#define HUF_STATIC_LINKING_ONLY
41#include "huf.h"
Yann Colletd3b7f8d2016-06-04 19:47:02 +020042#include "zstd_internal.h" /* includes zstd.h */
Yann Colletf3eca252015-10-22 15:31:46 +010043
44
Yann Collet7d360282016-02-12 00:07:30 +010045/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010046* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010047***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010048static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Collet731ef162016-07-27 21:05:12 +020049#define HASH_READ_SIZE 8
50typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
Yann Colletf3eca252015-10-22 15:31:46 +010051
Yann Colletf3eca252015-10-22 15:31:46 +010052
Yann Collet7d360282016-02-12 00:07:30 +010053/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010054* Helper functions
55***************************************/
Yann Collet59d1f792016-01-23 19:28:41 +010056size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
57
58
Yann Collet7d360282016-02-12 00:07:30 +010059/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010060* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010061***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010062static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
63{
Yann Collet14983e72015-11-11 21:38:21 +010064 ssPtr->lit = ssPtr->litStart;
Yann Colletc0ce4f12016-07-30 00:55:13 +020065 ssPtr->sequences = ssPtr->sequencesStart;
Yann Collet5d393572016-04-07 17:19:00 +020066 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010067}
68
69
Yann Collet7d360282016-02-12 00:07:30 +010070/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010071* Context memory management
72***************************************/
Yann Collet5be2dd22015-11-11 13:43:58 +010073struct ZSTD_CCtx_s
Yann Colletf3eca252015-10-22 15:31:46 +010074{
Yann Collet89db5e02015-11-13 11:27:46 +010075 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010076 const BYTE* base; /* All regular indexes relative to this position */
77 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010078 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010079 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010080 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010081 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +010082 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Collet2ce49232016-02-02 14:36:49 +010083 U32 loadedDictEnd;
Yann Collet731ef162016-07-27 21:05:12 +020084 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +020085 U32 rep[ZSTD_REP_NUM];
86 U32 savedRep[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +020087 U32 dictID;
Yann Collet5be2dd22015-11-11 13:43:58 +010088 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +010089 void* workSpace;
90 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +010091 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +020092 U64 frameContentSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +020093 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +020094 ZSTD_customMem customMem;
Yann Colletecd651b2016-01-07 15:35:18 +010095
Yann Collet712def92015-10-29 18:41:45 +010096 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +010097 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +010098 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +020099 U32* chainTable;
Yann Colletb923f652016-01-26 03:14:20 +0100100 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +0100101 U32 flagStaticTables;
Yann Collet731ef162016-07-27 21:05:12 +0200102 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
103 FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
104 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Colletf3eca252015-10-22 15:31:46 +0100105};
106
Yann Collet5be2dd22015-11-11 13:43:58 +0100107ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100108{
inikep3763c772016-06-03 13:28:20 +0200109 return ZSTD_createCCtx_advanced(defaultCustomMem);
inikep50e82c02016-05-23 15:49:09 +0200110}
111
112ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
113{
Yann Collet69c2cdb2016-07-14 16:52:45 +0200114 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +0200115
Yann Collet23b6e052016-08-28 21:05:43 -0700116 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
117 if (!customMem.customAlloc || !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200118
Yann Collet23b6e052016-08-28 21:05:43 -0700119 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200120 if (!cctx) return NULL;
121 memset(cctx, 0, sizeof(ZSTD_CCtx));
Yann Colletedbcd9f2016-09-06 14:30:57 +0200122 memcpy(&(cctx->customMem), &customMem, sizeof(customMem));
Yann Collet69c2cdb2016-07-14 16:52:45 +0200123 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100124}
125
Yann Collet5be2dd22015-11-11 13:43:58 +0100126size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100127{
inikep36403962016-06-03 16:36:50 +0200128 if (cctx==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -0700129 ZSTD_free(cctx->workSpace, cctx->customMem);
130 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100131 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100132}
133
Yann Collet70e3b312016-08-23 01:18:06 +0200134size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200135{
136 return sizeof(*cctx) + cctx->workSpaceSize;
137}
138
Yann Colletb44be742016-03-26 20:52:14 +0100139const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100140{
Yann Colletb44be742016-03-26 20:52:14 +0100141 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100142}
143
Yann Collet59d70632015-11-04 12:05:27 +0100144
Yann Collet7ae67bb2016-09-06 06:28:05 +0200145#define CLAMPCHECK(val,min,max) { if ((val<min) | (val>max)) return ERROR(compressionParameter_unsupported); }
Yann Collet21588e32016-03-30 16:50:44 +0200146
147/** ZSTD_checkParams() :
148 ensure param values remain within authorized range.
149 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200150size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200151{
Yann Collet15354142016-04-04 04:22:53 +0200152 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200153 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200154 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
155 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Colletedbcd9f2016-09-06 14:30:57 +0200156 { 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 +0200157 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
158 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
159 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Collet9bb87e52016-03-30 21:28:15 +0200160 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200161 return 0;
162}
163
164
Yann Collet3b719252016-03-30 19:48:05 +0200165/** ZSTD_checkCParams_advanced() :
166 temporary work-around, while the compressor compatibility remains limited regarding windowLog < 18 */
167size_t ZSTD_checkCParams_advanced(ZSTD_compressionParameters cParams, U64 srcSize)
168{
Yann Colletefb18302016-04-01 18:54:13 +0200169 if (srcSize > (1ULL << ZSTD_WINDOWLOG_MIN)) return ZSTD_checkCParams(cParams);
Yann Collet3b719252016-03-30 19:48:05 +0200170 if (cParams.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) return ERROR(compressionParameter_unsupported);
Yann Collet8a57b922016-04-04 13:49:18 +0200171 if (srcSize <= (1ULL << cParams.windowLog)) cParams.windowLog = ZSTD_WINDOWLOG_MIN; /* fake value - temporary work around */
172 if (srcSize <= (1ULL << cParams.chainLog)) cParams.chainLog = ZSTD_CHAINLOG_MIN; /* fake value - temporary work around */
Yann Collet7ae67bb2016-09-06 06:28:05 +0200173 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 +0200174 return ZSTD_checkCParams(cParams);
175}
176
177
Yann Collet70d13012016-06-01 18:45:34 +0200178/** ZSTD_adjustCParams() :
179 optimize cPar for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200180 mostly downsizing to reduce memory consumption and initialization.
181 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
182 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200183 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200184ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100185{
Yann Collet70d13012016-06-01 18:45:34 +0200186 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100187
Yann Collet70e45772016-03-19 18:08:32 +0100188 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200189 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
190 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200191 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Collet49bb0042016-06-04 20:17:38 +0200192 U32 const srcLog = ZSTD_highbit32((U32)(rSize)-1) + 1;
Yann Collet70d13012016-06-01 18:45:34 +0200193 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200194 } }
Yann Collet70d13012016-06-01 18:45:34 +0200195 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Collet7ae67bb2016-09-06 06:28:05 +0200196 { U32 const btPlus = (cPar.strategy == ZSTD_btlazy2) | (cPar.strategy == ZSTD_btopt);
Yann Collet70d13012016-06-01 18:45:34 +0200197 U32 const maxChainLog = cPar.windowLog+btPlus;
198 if (cPar.chainLog > maxChainLog) cPar.chainLog = maxChainLog; } /* <= ZSTD_CHAINLOG_MAX */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100199
Yann Collet70d13012016-06-01 18:45:34 +0200200 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet7ae67bb2016-09-06 06:28:05 +0200201 if ((cPar.hashLog < ZSTD_HASHLOG_MIN) & ((U32)cPar.strategy >= (U32)ZSTD_btlazy2)) cPar.hashLog = ZSTD_HASHLOG_MIN; /* required to ensure collision resistance in bt */
Yann Collet70d13012016-06-01 18:45:34 +0200202
203 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100204}
205
206
Yann Collet88472382016-07-14 17:05:38 +0200207size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100208{
Yann Collet731ef162016-07-27 21:05:12 +0200209 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
210 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
211 size_t const maxNbSeq = blockSize / divider;
212 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200213
Yann Collet731ef162016-07-27 21:05:12 +0200214 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
215 size_t const hSize = ((size_t)1) << cParams.hashLog;
216 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
217 size_t const h3Size = ((size_t)1) << hashLog3;
218 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200219
220 size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
221 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
222 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
223 + ((cParams.strategy == ZSTD_btopt) ? optSpace : 0);
224
225 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100226}
227
Yann Colleta7737f62016-09-06 09:44:59 +0200228
229static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2)
230{
231 return (param1.cParams.hashLog == param2.cParams.hashLog)
232 & (param1.cParams.chainLog == param2.cParams.chainLog)
Yann Colletedbcd9f2016-09-06 14:30:57 +0200233 & (param1.cParams.strategy == param2.cParams.strategy)
234 & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3));
Yann Colleta7737f62016-09-06 09:44:59 +0200235}
236
237/*! ZSTD_continueCCtx() :
238 reuse CCtx without reset (note : requires no dictionary) */
239static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
240{
241 U32 const end = (U32)(cctx->nextSrc - cctx->base);
242 cctx->params = params;
243 cctx->frameContentSize = frameContentSize;
244 cctx->lowLimit = end;
245 cctx->dictLimit = end;
246 cctx->nextToUpdate = end+1;
247 cctx->stage = ZSTDcs_init;
248 cctx->dictID = 0;
249 cctx->loadedDictEnd = 0;
250 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200251 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
252 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200253 return 0;
254}
255
256typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e;
257
Yann Collet27caf2a2016-04-01 15:48:48 +0200258/*! ZSTD_resetCCtx_advanced() :
Yann Colleta7737f62016-09-06 09:44:59 +0200259 note : 'params' must be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100260static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Colletea2ecdc2016-07-14 22:43:12 +0200261 ZSTD_parameters params, U64 frameContentSize,
Yann Colleta7737f62016-09-06 09:44:59 +0200262 ZSTD_compResetPolicy_e crp)
263{
264 if (crp == ZSTDcrp_continue) /* still some issues */
265 if (ZSTD_equivalentParams(params, zc->params))
266 return ZSTD_continueCCtx(zc, params, frameContentSize);
inikep87d4f3d2016-03-02 15:56:24 +0100267
Yann Colleta7737f62016-09-06 09:44:59 +0200268 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
269 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
270 size_t const maxNbSeq = blockSize / divider;
271 size_t const tokenSpace = blockSize + 11*maxNbSeq;
272 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
273 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
274 U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
275 size_t const h3Size = ((size_t)1) << hashLog3;
276 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
277 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100278
Yann Colleta7737f62016-09-06 09:44:59 +0200279 /* Check if workSpace is large enough, alloc a new one if needed */
280 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
281 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
282 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
283 + ((params.cParams.strategy == ZSTD_btopt) ? optSpace : 0);
284 if (zc->workSpaceSize < neededSpace) {
285 ZSTD_free(zc->workSpace, zc->customMem);
286 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
287 if (zc->workSpace == NULL) return ERROR(memory_allocation);
288 zc->workSpaceSize = neededSpace;
289 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100290
Yann Colleta7737f62016-09-06 09:44:59 +0200291 if (crp!=ZSTDcrp_noMemset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */
292 XXH64_reset(&zc->xxhState, 0);
293 zc->hashLog3 = hashLog3;
294 zc->hashTable = (U32*)(zc->workSpace);
295 zc->chainTable = zc->hashTable + hSize;
296 zc->hashTable3 = zc->chainTable + chainSize;
297 ptr = zc->hashTable3 + h3Size;
298 zc->hufTable = (HUF_CElt*)ptr;
299 zc->flagStaticTables = 0;
300 ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
Yann Collet70e8c382016-02-10 13:37:52 +0100301
Yann Colleta7737f62016-09-06 09:44:59 +0200302 zc->nextToUpdate = 1;
303 zc->nextSrc = NULL;
304 zc->base = NULL;
305 zc->dictBase = NULL;
306 zc->dictLimit = 0;
307 zc->lowLimit = 0;
308 zc->params = params;
309 zc->blockSize = blockSize;
310 zc->frameContentSize = frameContentSize;
311 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
312
313 if (params.cParams.strategy == ZSTD_btopt) {
314 zc->seqStore.litFreq = (U32*)ptr;
315 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
316 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
317 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
318 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
319 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
320 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
321 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
322 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
323 zc->seqStore.litLengthSum = 0;
324 }
325 zc->seqStore.sequencesStart = (seqDef*)ptr;
326 ptr = zc->seqStore.sequencesStart + maxNbSeq;
327 zc->seqStore.llCode = (BYTE*) ptr;
328 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
329 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
330 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
331
332 zc->stage = ZSTDcs_init;
333 zc->dictID = 0;
334 zc->loadedDictEnd = 0;
335
336 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100337 }
Yann Colletf3eca252015-10-22 15:31:46 +0100338}
339
Yann Collet083fcc82015-10-25 14:06:35 +0100340
Yann Collet370b08e2016-03-08 00:03:59 +0100341/*! ZSTD_copyCCtx() :
342* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet731ef162016-07-27 21:05:12 +0200343* Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100344* @return : 0, or an error code */
345size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
346{
Yann Collet731ef162016-07-27 21:05:12 +0200347 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100348
inikep28669512016-06-02 13:04:18 +0200349 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Yann Colleta7737f62016-09-06 09:44:59 +0200350 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, srcCCtx->frameContentSize, ZSTDcrp_noMemset);
Yann Collet389648c2016-04-12 19:13:08 +0200351 dstCCtx->params.fParams.contentSizeFlag = 0; /* content size different from the one set during srcCCtx init */
Yann Collet7b51a292016-01-26 15:58:49 +0100352
353 /* copy tables */
Yann Collet731ef162016-07-27 21:05:12 +0200354 { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
355 size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
356 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
357 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100358 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
359 }
Yann Collet7b51a292016-01-26 15:58:49 +0100360
Yann Colletc46fb922016-05-29 05:01:04 +0200361 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100362 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
363 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
364 dstCCtx->nextSrc = srcCCtx->nextSrc;
365 dstCCtx->base = srcCCtx->base;
366 dstCCtx->dictBase = srcCCtx->dictBase;
367 dstCCtx->dictLimit = srcCCtx->dictLimit;
368 dstCCtx->lowLimit = srcCCtx->lowLimit;
369 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200370 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100371
Yann Colletfb810d62016-01-28 00:18:06 +0100372 /* copy entropy tables */
373 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100374 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100375 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100376 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
377 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
378 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
379 }
Yann Collet7b51a292016-01-26 15:58:49 +0100380
381 return 0;
382}
383
384
Yann Colletecabfe32016-03-20 16:20:06 +0100385/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100386* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100387static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100388{
Yann Colletecabfe32016-03-20 16:20:06 +0100389 U32 u;
390 for (u=0 ; u < size ; u++) {
391 if (table[u] < reducerValue) table[u] = 0;
392 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100393 }
394}
395
Yann Colletecabfe32016-03-20 16:20:06 +0100396/*! ZSTD_reduceIndex() :
397* rescale all indexes to avoid future overflow (indexes are U32) */
398static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
399{
Yann Collet731ef162016-07-27 21:05:12 +0200400 { U32 const hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100401 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
402
Yann Collet731ef162016-07-27 21:05:12 +0200403 { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200404 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100405
Yann Collet731ef162016-07-27 21:05:12 +0200406 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100407 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
408}
409
Yann Collet89db5e02015-11-13 11:27:46 +0100410
Yann Collet863ec402016-01-28 17:56:33 +0100411/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100412* Block entropic compression
413*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100414
Yann Colletc2e1a682016-07-22 17:30:52 +0200415/* See zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100416
Yann Colletd1b26842016-03-15 01:24:33 +0100417size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100418{
Yann Colletd1b26842016-03-15 01:24:33 +0100419 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200420 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
421 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100422 return ZSTD_blockHeaderSize+srcSize;
423}
424
425
Yann Colletd1b26842016-03-15 01:24:33 +0100426static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100427{
428 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200429 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100430
Yann Colletd1b26842016-03-15 01:24:33 +0100431 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100432
Yann Collet59d1f792016-01-23 19:28:41 +0100433 switch(flSize)
434 {
435 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200436 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100437 break;
438 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200439 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100440 break;
441 default: /*note : should not be necessary : flSize is within {1,2,3} */
442 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200443 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100444 break;
445 }
446
447 memcpy(ostart + flSize, src, srcSize);
448 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100449}
450
Yann Colletd1b26842016-03-15 01:24:33 +0100451static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100452{
453 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200454 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100455
Yann Collet198e6aa2016-07-20 20:12:24 +0200456 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100457
458 switch(flSize)
459 {
460 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200461 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100462 break;
463 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200464 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100465 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100466 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100467 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200468 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100469 break;
470 }
471
472 ostart[flSize] = *(const BYTE*)src;
473 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100474}
475
Yann Collet59d1f792016-01-23 19:28:41 +0100476
Yann Colleta5c2c082016-03-20 01:09:18 +0100477static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100478
Yann Colletb923f652016-01-26 03:14:20 +0100479static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100480 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100481 const void* src, size_t srcSize)
482{
Yann Colleta910dc82016-03-18 12:37:45 +0100483 size_t const minGain = ZSTD_minGain(srcSize);
484 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200485 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100486 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200487 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100488 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100489
Yann Collet14983e72015-11-11 21:38:21 +0100490
Yann Colleta5c2c082016-03-20 01:09:18 +0100491 /* small ? don't even attempt compression (speed opt) */
492# define LITERAL_NOENTROPY 63
493 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
494 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
495 }
496
497 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Colletfb810d62016-01-28 00:18:06 +0100498 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200499 hType = set_repeat;
Yann Colletb923f652016-01-26 03:14:20 +0100500 singleStream = 1;
Yann Colleta910dc82016-03-18 12:37:45 +0100501 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100502 } else {
Yann Collet6cacd342016-07-15 17:58:13 +0200503 cLitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11)
504 : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11);
Yann Colletb923f652016-01-26 03:14:20 +0100505 }
Yann Collet14983e72015-11-11 21:38:21 +0100506
Yann Collet98c88842016-07-15 16:12:38 +0200507 if ((cLitSize==0) | (cLitSize >= srcSize - minGain))
Yann Colleta910dc82016-03-18 12:37:45 +0100508 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
509 if (cLitSize==1)
510 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100511
512 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100513 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100514 {
Yann Collet59d1f792016-01-23 19:28:41 +0100515 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200516 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200517 MEM_writeLE24(ostart, lhc);
518 break;
519 }
Yann Collet59d1f792016-01-23 19:28:41 +0100520 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200521 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200522 MEM_writeLE32(ostart, lhc);
523 break;
524 }
Yann Colleta910dc82016-03-18 12:37:45 +0100525 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100526 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200527 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200528 MEM_writeLE32(ostart, lhc);
529 ostart[4] = (BYTE)(cLitSize >> 10);
530 break;
531 }
Yann Collet14983e72015-11-11 21:38:21 +0100532 }
Yann Colleta910dc82016-03-18 12:37:45 +0100533 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100534}
535
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200536static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
537 8, 9, 10, 11, 12, 13, 14, 15,
538 16, 16, 17, 17, 18, 18, 19, 19,
539 20, 20, 20, 20, 21, 21, 21, 21,
540 22, 22, 22, 22, 22, 22, 22, 22,
541 23, 23, 23, 23, 23, 23, 23, 23,
542 24, 24, 24, 24, 24, 24, 24, 24,
543 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100544
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200545static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
546 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
547 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
548 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
549 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
550 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
551 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
552 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200553
554
555void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100556{
Yann Colleted57d852016-07-29 21:22:17 +0200557 BYTE const LL_deltaCode = 19;
558 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200559 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200560 BYTE* const llCodeTable = seqStorePtr->llCode;
561 BYTE* const ofCodeTable = seqStorePtr->ofCode;
562 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200563 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200564 U32 u;
565 for (u=0; u<nbSeq; u++) {
566 U32 const llv = sequences[u].litLength;
567 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200568 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200569 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200570 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200571 }
Yann Colleted57d852016-07-29 21:22:17 +0200572 if (seqStorePtr->longLengthID==1)
573 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
574 if (seqStorePtr->longLengthID==2)
575 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100576}
577
578
Yann Colletb923f652016-01-26 03:14:20 +0100579size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100580 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100581 size_t srcSize)
582{
Yann Colletb923f652016-01-26 03:14:20 +0100583 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100584 U32 count[MaxSeq+1];
585 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100586 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
587 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
588 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100589 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200590 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200591 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
592 const BYTE* const llCodeTable = seqStorePtr->llCode;
593 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +0100594 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100595 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100596 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200597 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +0100598 BYTE* seqHead;
599
Yann Collet14983e72015-11-11 21:38:21 +0100600 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100601 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100602 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100603 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100604 if (ZSTD_isError(cSize)) return cSize;
605 op += cSize;
606 }
607
608 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100609 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100610 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
611 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
612 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100613 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100614
Yann Colletbe391432016-03-22 23:19:28 +0100615 /* seqHead : flags for FSE encoding type */
616 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100617
Yann Colletfb810d62016-01-28 00:18:06 +0100618#define MIN_SEQ_FOR_DYNAMIC_FSE 64
619#define MAX_SEQ_FOR_STATIC_FSE 1000
620
Yann Colletb44be742016-03-26 20:52:14 +0100621 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +0200622 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +0100623
Yann Collet14983e72015-11-11 21:38:21 +0100624 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100625 { U32 max = MaxLL;
626 size_t const mostFrequent = FSE_countFast(count, &max, llCodeTable, nbSeq);
627 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
628 *op++ = llCodeTable[0];
629 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200630 LLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100631 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200632 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100633 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
634 FSE_buildCTable(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog);
Yann Colletf8e7b532016-07-23 16:31:49 +0200635 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100636 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100637 size_t nbSeq_1 = nbSeq;
638 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
639 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
640 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100641 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
642 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
643 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100644 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
Yann Colletf8e7b532016-07-23 16:31:49 +0200645 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100646 } }
Yann Collet14983e72015-11-11 21:38:21 +0100647
Yann Colletb44be742016-03-26 20:52:14 +0100648 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100649 { U32 max = MaxOff;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100650 size_t const mostFrequent = FSE_countFast(count, &max, ofCodeTable, nbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100651 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100652 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100653 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200654 Offtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100655 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200656 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +0200657 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
658 FSE_buildCTable(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog);
Yann Colletf8e7b532016-07-23 16:31:49 +0200659 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100660 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100661 size_t nbSeq_1 = nbSeq;
662 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100663 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100664 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100665 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
666 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
667 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100668 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
Yann Colletf8e7b532016-07-23 16:31:49 +0200669 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100670 } }
671
Yann Collet14983e72015-11-11 21:38:21 +0100672 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100673 { U32 max = MaxML;
674 size_t const mostFrequent = FSE_countFast(count, &max, mlCodeTable, nbSeq);
675 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100676 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100677 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200678 MLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100679 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200680 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100681 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
682 FSE_buildCTable(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog);
Yann Colletf8e7b532016-07-23 16:31:49 +0200683 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100684 } else {
685 size_t nbSeq_1 = nbSeq;
686 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
687 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
688 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
689 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
690 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
691 op += NCountSize; }
692 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
Yann Colletf8e7b532016-07-23 16:31:49 +0200693 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100694 } }
Yann Collet14983e72015-11-11 21:38:21 +0100695
Yann Colletbe391432016-03-22 23:19:28 +0100696 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100697 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100698
699 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100700 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100701 FSE_CState_t stateMatchLength;
702 FSE_CState_t stateOffsetBits;
703 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100704
Yann Colleta910dc82016-03-18 12:37:45 +0100705 { size_t const errorCode = BIT_initCStream(&blockStream, op, oend-op);
Yann Collet597847a2016-03-20 19:14:22 +0100706 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100707
Yann Collet597847a2016-03-20 19:14:22 +0100708 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100709 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100710 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100711 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +0200712 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100713 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200714 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100715 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200716 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100717 BIT_flushBits(&blockStream);
718
Yann Colletfadda6c2016-03-22 12:14:26 +0100719 { size_t n;
720 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +0200721 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200722 BYTE const ofCode = ofCodeTable[n];
723 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200724 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +0200725 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200726 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +0100727 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100728 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
729 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
730 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
731 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200732 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100733 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +0200734 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100735 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200736 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100737 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200738 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
Yann Colletb9151402016-03-26 17:18:11 +0100739 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100740 } }
Yann Collet14983e72015-11-11 21:38:21 +0100741
742 FSE_flushCState(&blockStream, &stateMatchLength);
743 FSE_flushCState(&blockStream, &stateOffsetBits);
744 FSE_flushCState(&blockStream, &stateLitLength);
745
Yann Colletb9151402016-03-26 17:18:11 +0100746 { size_t const streamSize = BIT_closeCStream(&blockStream);
747 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
748 op += streamSize;
749 } }
Yann Collet14983e72015-11-11 21:38:21 +0100750
751 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100752_check_compressibility:
Yann Colletfadda6c2016-03-22 12:14:26 +0100753 { size_t const minGain = ZSTD_minGain(srcSize);
754 size_t const maxCSize = srcSize - minGain;
755 if ((size_t)(op-ostart) >= maxCSize) return 0; }
Yann Collet14983e72015-11-11 21:38:21 +0100756
Yann Collet4266c0a2016-06-14 01:49:25 +0200757 /* confirm repcodes */
758 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->savedRep[i]; }
759
Yann Collet5054ee02015-11-23 13:34:21 +0100760 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100761}
762
763
Yann Collet95cd0c22016-03-08 18:24:21 +0100764/*! ZSTD_storeSeq() :
765 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
766 `offsetCode` : distance to match, or 0 == repCode.
767 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100768*/
Yann Colletd57dffb2016-07-03 01:48:26 +0200769MEM_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 +0100770{
Yann Collet45c03c52016-06-14 13:46:11 +0200771#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100772 static const BYTE* g_start = NULL;
Yann Colletb0aec172016-03-21 13:24:16 +0100773 const U32 pos = (U32)(literals - g_start);
Yann Collet14983e72015-11-11 21:38:21 +0100774 if (g_start==NULL) g_start = literals;
Yann Collet4266c0a2016-06-14 01:49:25 +0200775 //if ((pos > 1) && (pos < 50000))
Yann Colletb9151402016-03-26 17:18:11 +0100776 printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
Yann Collet433a5cc2016-03-25 11:43:48 +0100777 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +0100778#endif
Yann Collet14983e72015-11-11 21:38:21 +0100779 /* copy Literals */
780 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
781 seqStorePtr->lit += litLength;
782
783 /* literal Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200784 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
785 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100786
787 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200788 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100789
790 /* match Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200791 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
792 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +0200793
Yann Colletc0ce4f12016-07-30 00:55:13 +0200794 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +0100795}
796
797
Yann Collet7d360282016-02-12 00:07:30 +0100798/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100799* Match length counter
800***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100801static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100802{
Yann Collet863ec402016-01-28 17:56:33 +0100803 if (MEM_isLittleEndian()) {
804 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100805# if defined(_MSC_VER) && defined(_WIN64)
806 unsigned long r = 0;
807 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100808 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100809# elif defined(__GNUC__) && (__GNUC__ >= 3)
810 return (__builtin_ctzll((U64)val) >> 3);
811# else
812 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 };
813 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
814# endif
Yann Collet863ec402016-01-28 17:56:33 +0100815 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100816# if defined(_MSC_VER)
817 unsigned long r=0;
818 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100819 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100820# elif defined(__GNUC__) && (__GNUC__ >= 3)
821 return (__builtin_ctz((U32)val) >> 3);
822# else
823 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 };
824 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
825# endif
826 }
Yann Collet863ec402016-01-28 17:56:33 +0100827 } else { /* Big Endian CPU */
828 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100829# if defined(_MSC_VER) && defined(_WIN64)
830 unsigned long r = 0;
831 _BitScanReverse64( &r, val );
832 return (unsigned)(r>>3);
833# elif defined(__GNUC__) && (__GNUC__ >= 3)
834 return (__builtin_clzll(val) >> 3);
835# else
836 unsigned r;
837 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
838 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
839 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
840 r += (!val);
841 return r;
842# endif
Yann Collet863ec402016-01-28 17:56:33 +0100843 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100844# if defined(_MSC_VER)
845 unsigned long r = 0;
846 _BitScanReverse( &r, (unsigned long)val );
847 return (unsigned)(r>>3);
848# elif defined(__GNUC__) && (__GNUC__ >= 3)
849 return (__builtin_clz((U32)val) >> 3);
850# else
851 unsigned r;
852 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
853 r += (!val);
854 return r;
855# endif
Yann Collet863ec402016-01-28 17:56:33 +0100856 } }
Yann Collet14983e72015-11-11 21:38:21 +0100857}
858
859
Yann Colleta436a522016-06-20 23:34:04 +0200860static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100861{
862 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +0200863 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +0100864
Yann Colleta436a522016-06-20 23:34:04 +0200865 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +0200866 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100867 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
868 pIn += ZSTD_NbCommonBytes(diff);
869 return (size_t)(pIn - pStart);
870 }
Yann Collet14983e72015-11-11 21:38:21 +0100871 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
872 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
873 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
874 return (size_t)(pIn - pStart);
875}
876
Yann Collet04b12d82016-02-11 06:23:24 +0100877/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100878* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100879* convention : on reaching mEnd, match count continue starting from iStart
880*/
881static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
882{
Yann Collet7591a7f2016-05-20 11:44:43 +0200883 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +0200884 size_t const matchLength = ZSTD_count(ip, match, vEnd);
885 if (match + matchLength != mEnd) return matchLength;
886 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +0100887}
888
Yann Collet14983e72015-11-11 21:38:21 +0100889
Yann Collet863ec402016-01-28 17:56:33 +0100890/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100891* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100892***************************************/
inikepcc52a972016-02-19 10:09:35 +0100893static const U32 prime3bytes = 506832829U;
894static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Colletd4f4e582016-06-27 01:31:35 +0200895MEM_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 +0100896
Yann Collet4b100f42015-10-30 15:49:48 +0100897static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100898static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100899static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100900
Yann Collet4b100f42015-10-30 15:49:48 +0100901static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100902static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100903static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100904
905static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100906static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100907static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100908
Yann Collet14983e72015-11-11 21:38:21 +0100909static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100910static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100911static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100912
Yann Collet45dc3562016-07-12 09:47:31 +0200913static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
914static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
915static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
916
Yann Collet5be2dd22015-11-11 13:43:58 +0100917static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100918{
919 switch(mls)
920 {
921 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100922 case 4: return ZSTD_hash4Ptr(p, hBits);
923 case 5: return ZSTD_hash5Ptr(p, hBits);
924 case 6: return ZSTD_hash6Ptr(p, hBits);
925 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +0200926 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100927 }
928}
Yann Collet2acb5d32015-10-29 16:49:43 +0100929
Yann Collet863ec402016-01-28 17:56:33 +0100930
Yann Collet2ce49232016-02-02 14:36:49 +0100931/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +0100932* Fast Scan
933***************************************/
Yann Collet417890c2015-12-04 17:16:37 +0100934static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
935{
936 U32* const hashTable = zc->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200937 U32 const hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +0100938 const BYTE* const base = zc->base;
939 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +0200940 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +0100941 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +0100942
Yann Colletfb810d62016-01-28 00:18:06 +0100943 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +0100944 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +0100945 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +0100946 }
947}
948
949
Yann Collet1f44b3f2015-11-05 17:32:18 +0100950FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +0200951void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +0200952 const void* src, size_t srcSize,
953 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100954{
Yann Collet4266c0a2016-06-14 01:49:25 +0200955 U32* const hashTable = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200956 U32 const hBits = cctx->params.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +0200957 seqStore_t* seqStorePtr = &(cctx->seqStore);
958 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100959 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100960 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100961 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +0200962 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +0200963 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100964 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +0200965 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +0200966 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
967 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100968
Yann Collet1f44b3f2015-11-05 17:32:18 +0100969 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +0200970 ip += (ip==lowest);
971 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +0200972 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
973 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +0200974 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100975
976 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +0200977 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +0200978 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +0200979 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
980 U32 const current = (U32)(ip-base);
981 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +0100982 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +0100983 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100984
Yann Collet280f9a82016-08-08 00:44:00 +0200985 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +0200986 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +0100987 ip++;
Yann Colleta436a522016-06-20 23:34:04 +0200988 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
989 } else {
Yann Collet92d75662016-07-03 01:10:53 +0200990 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +0200991 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +0100992 ip += ((ip-anchor) >> g_searchStrength) + 1;
993 continue;
994 }
Yann Collet45dc3562016-07-12 09:47:31 +0200995 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +0200996 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +0200997 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +0100998 offset_2 = offset_1;
999 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001000
Yann Colleta436a522016-06-20 23:34:04 +02001001 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001002 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001003
Yann Collet402fdcf2015-11-20 12:46:08 +01001004 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001005 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001006 anchor = ip;
1007
Yann Colletfb810d62016-01-28 00:18:06 +01001008 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001009 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001010 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 +01001011 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1012 /* check immediate repcode */
1013 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001014 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001015 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001016 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001017 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001018 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001019 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001020 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1021 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001022 anchor = ip;
1023 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001024 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001025
Yann Collet4266c0a2016-06-14 01:49:25 +02001026 /* save reps for next block */
Yann Collet92d75662016-07-03 01:10:53 +02001027 cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved;
1028 cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001029
Yann Collet70e45772016-03-19 18:08:32 +01001030 /* Last Literals */
1031 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001032 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1033 seqStorePtr->lit += lastLLSize;
1034 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001035}
1036
1037
Yann Collet82260dd2016-02-11 07:14:25 +01001038static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001039 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001040{
Yann Collet3b719252016-03-30 19:48:05 +02001041 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001042 switch(mls)
1043 {
1044 default:
1045 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001046 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001047 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001048 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001049 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001050 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001051 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001052 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001053 }
1054}
Yann Colletf3eca252015-10-22 15:31:46 +01001055
Yann Colletf3eca252015-10-22 15:31:46 +01001056
Yann Collet82260dd2016-02-11 07:14:25 +01001057static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001058 const void* src, size_t srcSize,
1059 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001060{
1061 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001062 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001063 seqStore_t* seqStorePtr = &(ctx->seqStore);
1064 const BYTE* const base = ctx->base;
1065 const BYTE* const dictBase = ctx->dictBase;
1066 const BYTE* const istart = (const BYTE*)src;
1067 const BYTE* ip = istart;
1068 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001069 const U32 lowestIndex = ctx->lowLimit;
1070 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001071 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001072 const BYTE* const lowPrefixPtr = base + dictLimit;
1073 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001074 const BYTE* const iend = istart + srcSize;
1075 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001076 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001077
Yann Colleta436a522016-06-20 23:34:04 +02001078 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001079 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001080 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001081 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001082 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001083 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001084 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001085 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001086 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001087 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001088 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001089 hashTable[h] = current; /* update hash table */
1090
Yann Colleta436a522016-06-20 23:34:04 +02001091 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001092 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001093 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Colleta436a522016-06-20 23:34:04 +02001094 mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001095 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001096 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001097 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001098 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001099 (MEM_read32(match) != MEM_read32(ip)) ) {
1100 ip += ((ip-anchor) >> g_searchStrength) + 1;
1101 continue;
1102 }
1103 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001104 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001105 U32 offset;
1106 mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
1107 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001108 offset = current - matchIndex;
1109 offset_2 = offset_1;
1110 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001111 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001112 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001113
Yann Collet5054ee02015-11-23 13:34:21 +01001114 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001115 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001116 anchor = ip;
1117
Yann Colletfb810d62016-01-28 00:18:06 +01001118 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001119 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001120 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001121 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1122 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001123 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001124 U32 const current2 = (U32)(ip-base);
1125 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001126 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001127 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1128 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001129 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001130 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001131 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001132 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001133 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001134 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001135 anchor = ip;
1136 continue;
1137 }
Yann Collet743402c2015-11-20 12:03:53 +01001138 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001139 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001140
Yann Collet4266c0a2016-06-14 01:49:25 +02001141 /* save reps for next block */
1142 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
1143
Yann Collet89db5e02015-11-13 11:27:46 +01001144 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001145 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001146 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1147 seqStorePtr->lit += lastLLSize;
1148 }
Yann Collet89db5e02015-11-13 11:27:46 +01001149}
1150
1151
Yann Collet82260dd2016-02-11 07:14:25 +01001152static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001153 const void* src, size_t srcSize)
1154{
Yann Collet731ef162016-07-27 21:05:12 +02001155 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001156 switch(mls)
1157 {
1158 default:
1159 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001160 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001161 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001162 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001163 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001164 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001165 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001166 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001167 }
1168}
1169
1170
Yann Collet04b12d82016-02-11 06:23:24 +01001171/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001172* Double Fast
1173***************************************/
1174static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1175{
1176 U32* const hashLarge = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001177 U32 const hBitsL = cctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001178 U32* const hashSmall = cctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001179 U32 const hBitsS = cctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001180 const BYTE* const base = cctx->base;
1181 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001182 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001183 const size_t fastHashFillStep = 3;
1184
1185 while(ip <= iend) {
1186 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1187 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1188 ip += fastHashFillStep;
1189 }
1190}
1191
1192
1193FORCE_INLINE
1194void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1195 const void* src, size_t srcSize,
1196 const U32 mls)
1197{
1198 U32* const hashLong = cctx->hashTable;
1199 const U32 hBitsL = cctx->params.cParams.hashLog;
1200 U32* const hashSmall = cctx->chainTable;
1201 const U32 hBitsS = cctx->params.cParams.chainLog;
1202 seqStore_t* seqStorePtr = &(cctx->seqStore);
1203 const BYTE* const base = cctx->base;
1204 const BYTE* const istart = (const BYTE*)src;
1205 const BYTE* ip = istart;
1206 const BYTE* anchor = istart;
1207 const U32 lowestIndex = cctx->dictLimit;
1208 const BYTE* const lowest = base + lowestIndex;
1209 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001210 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001211 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1212 U32 offsetSaved = 0;
1213
1214 /* init */
1215 ip += (ip==lowest);
1216 { U32 const maxRep = (U32)(ip-lowest);
1217 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1218 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1219 }
1220
1221 /* Main Search Loop */
1222 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1223 size_t mLength;
1224 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1225 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1226 U32 const current = (U32)(ip-base);
1227 U32 const matchIndexL = hashLong[h2];
1228 U32 const matchIndexS = hashSmall[h];
1229 const BYTE* matchLong = base + matchIndexL;
1230 const BYTE* match = base + matchIndexS;
1231 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1232
1233 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1234 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1235 ip++;
1236 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1237 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001238 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001239 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1240 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001241 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001242 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1243 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Colletc54692f2016-08-24 01:10:42 +02001244 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1245 U32 const matchIndex3 = hashLong[h3];
1246 const BYTE* match3 = base + matchIndex3;
1247 hashLong[h3] = current + 1;
1248 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1249 mLength = ZSTD_count(ip+9, match3+8, iend) + 8;
1250 ip++;
1251 offset = (U32)(ip-match3);
1252 while (((ip>anchor) & (match3>lowest)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1253 } else {
1254 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1255 offset = (U32)(ip-match);
1256 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1257 }
Yann Collet45dc3562016-07-12 09:47:31 +02001258 } else {
1259 ip += ((ip-anchor) >> g_searchStrength) + 1;
1260 continue;
1261 }
1262
1263 offset_2 = offset_1;
1264 offset_1 = offset;
1265
1266 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1267 }
1268
1269 /* match found */
1270 ip += mLength;
1271 anchor = ip;
1272
1273 if (ip <= ilimit) {
1274 /* Fill Table */
1275 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1276 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1277 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1278 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1279
1280 /* check immediate repcode */
1281 while ( (ip <= ilimit)
1282 && ( (offset_2>0)
1283 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1284 /* store sequence */
1285 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001286 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001287 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1288 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1289 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1290 ip += rLength;
1291 anchor = ip;
1292 continue; /* faster when present ... (?) */
1293 } } }
1294
1295 /* save reps for next block */
1296 cctx->savedRep[0] = offset_1 ? offset_1 : offsetSaved;
1297 cctx->savedRep[1] = offset_2 ? offset_2 : offsetSaved;
1298
1299 /* Last Literals */
1300 { size_t const lastLLSize = iend - anchor;
1301 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1302 seqStorePtr->lit += lastLLSize;
1303 }
1304}
1305
1306
1307static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1308{
1309 const U32 mls = ctx->params.cParams.searchLength;
1310 switch(mls)
1311 {
1312 default:
1313 case 4 :
1314 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1315 case 5 :
1316 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1317 case 6 :
1318 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1319 case 7 :
1320 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1321 }
1322}
1323
1324
1325static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1326 const void* src, size_t srcSize,
1327 const U32 mls)
1328{
1329 U32* const hashLong = ctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001330 U32 const hBitsL = ctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001331 U32* const hashSmall = ctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001332 U32 const hBitsS = ctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001333 seqStore_t* seqStorePtr = &(ctx->seqStore);
1334 const BYTE* const base = ctx->base;
1335 const BYTE* const dictBase = ctx->dictBase;
1336 const BYTE* const istart = (const BYTE*)src;
1337 const BYTE* ip = istart;
1338 const BYTE* anchor = istart;
1339 const U32 lowestIndex = ctx->lowLimit;
1340 const BYTE* const dictStart = dictBase + lowestIndex;
1341 const U32 dictLimit = ctx->dictLimit;
1342 const BYTE* const lowPrefixPtr = base + dictLimit;
1343 const BYTE* const dictEnd = dictBase + dictLimit;
1344 const BYTE* const iend = istart + srcSize;
1345 const BYTE* const ilimit = iend - 8;
1346 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1347
1348 /* Search Loop */
1349 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1350 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1351 const U32 matchIndex = hashSmall[hSmall];
1352 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1353 const BYTE* match = matchBase + matchIndex;
1354
1355 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1356 const U32 matchLongIndex = hashLong[hLong];
1357 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1358 const BYTE* matchLong = matchLongBase + matchLongIndex;
1359
1360 const U32 current = (U32)(ip-base);
1361 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1362 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1363 const BYTE* repMatch = repBase + repIndex;
1364 size_t mLength;
1365 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1366
1367 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1368 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1369 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1370 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1371 ip++;
1372 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1373 } else {
1374 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1375 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1376 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1377 U32 offset;
1378 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1379 offset = current - matchLongIndex;
1380 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1381 offset_2 = offset_1;
1382 offset_1 = offset;
1383 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001384
Yann Collet73d74a02016-07-12 13:03:48 +02001385 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001386 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1387 U32 const matchIndex3 = hashLong[h3];
1388 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1389 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001390 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001391 hashLong[h3] = current + 1;
1392 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1393 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1394 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1395 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1396 ip++;
1397 offset = current+1 - matchIndex3;
1398 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1399 } else {
1400 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1401 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1402 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1403 offset = current - matchIndex;
1404 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1405 }
Yann Collet45dc3562016-07-12 09:47:31 +02001406 offset_2 = offset_1;
1407 offset_1 = offset;
1408 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001409
Yann Collet45dc3562016-07-12 09:47:31 +02001410 } else {
1411 ip += ((ip-anchor) >> g_searchStrength) + 1;
1412 continue;
1413 } }
1414
1415 /* found a match : store it */
1416 ip += mLength;
1417 anchor = ip;
1418
1419 if (ip <= ilimit) {
1420 /* Fill Table */
1421 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1422 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
1423 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1424 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1425 /* check immediate repcode */
1426 while (ip <= ilimit) {
1427 U32 const current2 = (U32)(ip-base);
1428 U32 const repIndex2 = current2 - offset_2;
1429 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1430 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1431 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1432 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1433 size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1434 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1435 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1436 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1437 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1438 ip += repLength2;
1439 anchor = ip;
1440 continue;
1441 }
1442 break;
1443 } } }
1444
1445 /* save reps for next block */
1446 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
1447
1448 /* Last Literals */
1449 { size_t const lastLLSize = iend - anchor;
1450 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1451 seqStorePtr->lit += lastLLSize;
1452 }
1453}
1454
1455
1456static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1457 const void* src, size_t srcSize)
1458{
Yann Collet731ef162016-07-27 21:05:12 +02001459 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001460 switch(mls)
1461 {
1462 default:
1463 case 4 :
1464 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1465 case 5 :
1466 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1467 case 6 :
1468 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1469 case 7 :
1470 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1471 }
1472}
1473
1474
1475/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001476* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001477***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001478/** ZSTD_insertBt1() : add one or multiple positions to tree.
1479* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001480* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001481static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1482 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001483{
Yann Collet731ef162016-07-27 21:05:12 +02001484 U32* const hashTable = zc->hashTable;
1485 U32 const hashLog = zc->params.cParams.hashLog;
1486 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1487 U32* const bt = zc->chainTable;
1488 U32 const btLog = zc->params.cParams.chainLog - 1;
1489 U32 const btMask = (1 << btLog) - 1;
1490 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001491 size_t commonLengthSmaller=0, commonLengthLarger=0;
1492 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001493 const BYTE* const dictBase = zc->dictBase;
1494 const U32 dictLimit = zc->dictLimit;
1495 const BYTE* const dictEnd = dictBase + dictLimit;
1496 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001497 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001498 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001499 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001500 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001501 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001502 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001503 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001504 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001505 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001506#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001507 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1508 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1509 predictedSmall += (predictedSmall>0);
1510 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001511#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001512
Yann Collet6c3e2e72015-12-11 10:44:07 +01001513 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001514
Yann Colletfb810d62016-01-28 00:18:06 +01001515 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001516 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001517 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Colletc0932082016-06-30 14:07:30 +02001518#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001519 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001520 if (matchIndex == predictedSmall) {
1521 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001522 *smallerPtr = matchIndex;
1523 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1524 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1525 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001526 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001527 continue;
1528 }
Yann Colletfb810d62016-01-28 00:18:06 +01001529 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001530 *largerPtr = matchIndex;
1531 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1532 largerPtr = nextPtr;
1533 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001534 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001535 continue;
1536 }
Yann Collet04b12d82016-02-11 06:23:24 +01001537#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001538 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001539 match = base + matchIndex;
1540 if (match[matchLength] == ip[matchLength])
1541 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001542 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001543 match = dictBase + matchIndex;
1544 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1545 if (matchIndex+matchLength >= dictLimit)
1546 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1547 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001548
Yann Colletb8a6f682016-02-15 17:06:29 +01001549 if (matchLength > bestLength) {
1550 bestLength = matchLength;
1551 if (matchLength > matchEndIdx - matchIndex)
1552 matchEndIdx = matchIndex + (U32)matchLength;
1553 }
Yann Colletee3f4512015-12-29 22:26:09 +01001554
Yann Collet59d70632015-11-04 12:05:27 +01001555 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001556 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001557
Yann Colletfb810d62016-01-28 00:18:06 +01001558 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001559 /* match is smaller than current */
1560 *smallerPtr = matchIndex; /* update smaller idx */
1561 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001562 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001563 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001564 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001565 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001566 /* match is larger than current */
1567 *largerPtr = matchIndex;
1568 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001569 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001570 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001571 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001572 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001573
Yann Collet59d70632015-11-04 12:05:27 +01001574 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02001575 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01001576 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1577 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001578}
1579
1580
Yann Collet82260dd2016-02-11 07:14:25 +01001581static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001582 ZSTD_CCtx* zc,
1583 const BYTE* const ip, const BYTE* const iend,
1584 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001585 U32 nbCompares, const U32 mls,
1586 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001587{
Yann Collet731ef162016-07-27 21:05:12 +02001588 U32* const hashTable = zc->hashTable;
1589 U32 const hashLog = zc->params.cParams.hashLog;
1590 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1591 U32* const bt = zc->chainTable;
1592 U32 const btLog = zc->params.cParams.chainLog - 1;
1593 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001594 U32 matchIndex = hashTable[h];
1595 size_t commonLengthSmaller=0, commonLengthLarger=0;
1596 const BYTE* const base = zc->base;
1597 const BYTE* const dictBase = zc->dictBase;
1598 const U32 dictLimit = zc->dictLimit;
1599 const BYTE* const dictEnd = dictBase + dictLimit;
1600 const BYTE* const prefixStart = base + dictLimit;
1601 const U32 current = (U32)(ip-base);
1602 const U32 btLow = btMask >= current ? 0 : current - btMask;
1603 const U32 windowLow = zc->lowLimit;
1604 U32* smallerPtr = bt + 2*(current&btMask);
1605 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001606 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001607 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001608 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001609
Yann Collet6c3e2e72015-12-11 10:44:07 +01001610 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001611
Yann Colletfb810d62016-01-28 00:18:06 +01001612 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001613 U32* nextPtr = bt + 2*(matchIndex & btMask);
1614 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1615 const BYTE* match;
1616
Yann Colletfb810d62016-01-28 00:18:06 +01001617 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001618 match = base + matchIndex;
1619 if (match[matchLength] == ip[matchLength])
1620 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001621 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001622 match = dictBase + matchIndex;
1623 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001624 if (matchIndex+matchLength >= dictLimit)
1625 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001626 }
1627
Yann Colletfb810d62016-01-28 00:18:06 +01001628 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001629 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001630 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02001631 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001632 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001633 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1634 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1635 }
1636
Yann Colletfb810d62016-01-28 00:18:06 +01001637 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001638 /* match is smaller than current */
1639 *smallerPtr = matchIndex; /* update smaller idx */
1640 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1641 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1642 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1643 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001644 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001645 /* match is larger than current */
1646 *largerPtr = matchIndex;
1647 commonLengthLarger = matchLength;
1648 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1649 largerPtr = nextPtr;
1650 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001651 } }
Yann Collet03526e12015-11-23 15:29:15 +01001652
1653 *smallerPtr = *largerPtr = 0;
1654
Yann Collet72e84cf2015-12-31 19:08:44 +01001655 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001656 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001657}
1658
Yann Collet2cc12cb2016-01-01 07:47:58 +01001659
Yann Colletb8a6f682016-02-15 17:06:29 +01001660static 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 +01001661{
1662 const BYTE* const base = zc->base;
1663 const U32 target = (U32)(ip - base);
1664 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001665
1666 while(idx < target)
1667 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001668}
1669
Yann Collet52447382016-03-20 16:00:00 +01001670/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001671static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001672 ZSTD_CCtx* zc,
1673 const BYTE* const ip, const BYTE* const iLimit,
1674 size_t* offsetPtr,
1675 const U32 maxNbAttempts, const U32 mls)
1676{
1677 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001678 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001679 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1680}
1681
1682
Yann Collet768c6bc2016-02-10 14:01:49 +01001683static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001684 ZSTD_CCtx* zc, /* Index table will be updated */
1685 const BYTE* ip, const BYTE* const iLimit,
1686 size_t* offsetPtr,
1687 const U32 maxNbAttempts, const U32 matchLengthSearch)
1688{
1689 switch(matchLengthSearch)
1690 {
1691 default :
1692 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1693 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1694 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1695 }
1696}
1697
1698
Yann Colletb8a6f682016-02-15 17:06:29 +01001699static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1700{
1701 const BYTE* const base = zc->base;
1702 const U32 target = (U32)(ip - base);
1703 U32 idx = zc->nextToUpdate;
1704
1705 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1706}
1707
inikep64d7bcb2016-04-07 19:14:09 +02001708
Yann Collet03526e12015-11-23 15:29:15 +01001709/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001710static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001711 ZSTD_CCtx* zc,
1712 const BYTE* const ip, const BYTE* const iLimit,
1713 size_t* offsetPtr,
1714 const U32 maxNbAttempts, const U32 mls)
1715{
Yann Colletee3f4512015-12-29 22:26:09 +01001716 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001717 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001718 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001719}
1720
1721
Yann Collet82260dd2016-02-11 07:14:25 +01001722static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001723 ZSTD_CCtx* zc, /* Index table will be updated */
1724 const BYTE* ip, const BYTE* const iLimit,
1725 size_t* offsetPtr,
1726 const U32 maxNbAttempts, const U32 matchLengthSearch)
1727{
1728 switch(matchLengthSearch)
1729 {
1730 default :
1731 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1732 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1733 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1734 }
1735}
1736
1737
Yann Collet5106a762015-11-05 15:00:24 +01001738
Yann Collet731ef162016-07-27 21:05:12 +02001739/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02001740* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02001741***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02001742#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1743
1744/* Update chains up to ip (excluded)
1745 Assumption : always within prefix (ie. not within extDict) */
1746FORCE_INLINE
1747U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1748{
1749 U32* const hashTable = zc->hashTable;
1750 const U32 hashLog = zc->params.cParams.hashLog;
1751 U32* const chainTable = zc->chainTable;
1752 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1753 const BYTE* const base = zc->base;
1754 const U32 target = (U32)(ip - base);
1755 U32 idx = zc->nextToUpdate;
1756
Yann Collet22d76322016-06-21 08:01:51 +02001757 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001758 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1759 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1760 hashTable[h] = idx;
1761 idx++;
1762 }
1763
1764 zc->nextToUpdate = target;
1765 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1766}
1767
1768
1769
1770FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1771size_t ZSTD_HcFindBestMatch_generic (
1772 ZSTD_CCtx* zc, /* Index table will be updated */
1773 const BYTE* const ip, const BYTE* const iLimit,
1774 size_t* offsetPtr,
1775 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1776{
1777 U32* const chainTable = zc->chainTable;
1778 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1779 const U32 chainMask = chainSize-1;
1780 const BYTE* const base = zc->base;
1781 const BYTE* const dictBase = zc->dictBase;
1782 const U32 dictLimit = zc->dictLimit;
1783 const BYTE* const prefixStart = base + dictLimit;
1784 const BYTE* const dictEnd = dictBase + dictLimit;
1785 const U32 lowLimit = zc->lowLimit;
1786 const U32 current = (U32)(ip-base);
1787 const U32 minChain = current > chainSize ? current - chainSize : 0;
1788 int nbAttempts=maxNbAttempts;
1789 size_t ml=EQUAL_READ32-1;
1790
1791 /* HC4 match finder */
1792 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1793
Yann Collet22d76322016-06-21 08:01:51 +02001794 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02001795 const BYTE* match;
1796 size_t currentMl=0;
1797 if ((!extDict) || matchIndex >= dictLimit) {
1798 match = base + matchIndex;
1799 if (match[ml] == ip[ml]) /* potentially better */
1800 currentMl = ZSTD_count(ip, match, iLimit);
1801 } else {
1802 match = dictBase + matchIndex;
1803 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1804 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1805 }
1806
1807 /* save best solution */
Yann Collet22d76322016-06-21 08:01:51 +02001808 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 +02001809
1810 if (matchIndex <= minChain) break;
1811 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1812 }
1813
1814 return ml;
1815}
1816
1817
1818FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1819 ZSTD_CCtx* zc,
1820 const BYTE* ip, const BYTE* const iLimit,
1821 size_t* offsetPtr,
1822 const U32 maxNbAttempts, const U32 matchLengthSearch)
1823{
1824 switch(matchLengthSearch)
1825 {
1826 default :
1827 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1828 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1829 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1830 }
1831}
1832
1833
1834FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1835 ZSTD_CCtx* zc,
1836 const BYTE* ip, const BYTE* const iLimit,
1837 size_t* offsetPtr,
1838 const U32 maxNbAttempts, const U32 matchLengthSearch)
1839{
1840 switch(matchLengthSearch)
1841 {
1842 default :
1843 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1844 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1845 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1846 }
1847}
1848
inikep64d7bcb2016-04-07 19:14:09 +02001849
Yann Collet287b7d92015-11-22 13:24:05 +01001850/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001851* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001852*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001853FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001854void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1855 const void* src, size_t srcSize,
1856 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001857{
inikepfaa8d8a2016-04-05 19:01:10 +02001858 seqStore_t* seqStorePtr = &(ctx->seqStore);
1859 const BYTE* const istart = (const BYTE*)src;
1860 const BYTE* ip = istart;
1861 const BYTE* anchor = istart;
1862 const BYTE* const iend = istart + srcSize;
1863 const BYTE* const ilimit = iend - 8;
1864 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001865
Yann Collet793c6492016-04-09 20:32:00 +02001866 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1867 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001868
inikep64d7bcb2016-04-07 19:14:09 +02001869 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1870 size_t* offsetPtr,
1871 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02001872 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02001873 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02001874
inikepfaa8d8a2016-04-05 19:01:10 +02001875 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001876 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02001877 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02001878 { U32 const maxRep = (U32)(ip-base);
1879 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
1880 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
1881 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001882
inikepfaa8d8a2016-04-05 19:01:10 +02001883 /* Match Loop */
1884 while (ip < ilimit) {
1885 size_t matchLength=0;
1886 size_t offset=0;
1887 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001888
inikepfaa8d8a2016-04-05 19:01:10 +02001889 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02001890 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02001891 /* repcode : we take it */
Yann Collet9634f672016-07-03 01:23:58 +02001892 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001893 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001894 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001895
inikepfaa8d8a2016-04-05 19:01:10 +02001896 /* first search (depth 0) */
1897 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001898 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001899 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001900 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001901 }
Yann Collet5106a762015-11-05 15:00:24 +01001902
inikep7bc19b62016-04-06 09:46:01 +02001903 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001904 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1905 continue;
1906 }
1907
inikep64d7bcb2016-04-07 19:14:09 +02001908 /* let's try to find a better solution */
1909 if (depth>=1)
1910 while (ip<ilimit) {
1911 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001912 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1913 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001914 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02001915 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001916 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1917 matchLength = mlRep, offset = 0, start = ip;
1918 }
1919 { size_t offset2=99999999;
1920 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001921 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1922 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02001923 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1924 matchLength = ml2, offset = offset2, start = ip;
1925 continue; /* search a better one */
1926 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001927
inikep64d7bcb2016-04-07 19:14:09 +02001928 /* let's find an even better one */
1929 if ((depth==2) && (ip<ilimit)) {
1930 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001931 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1932 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001933 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02001934 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001935 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1936 matchLength = ml2, offset = 0, start = ip;
1937 }
1938 { size_t offset2=99999999;
1939 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001940 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1941 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02001942 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1943 matchLength = ml2, offset = offset2, start = ip;
1944 continue;
1945 } } }
1946 break; /* nothing found : store previous solution */
1947 }
1948
1949 /* catch up */
1950 if (offset) {
1951 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1952 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02001953 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02001954 }
1955
inikepfaa8d8a2016-04-05 19:01:10 +02001956 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001957_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001958 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02001959 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02001960 anchor = ip = start + matchLength;
1961 }
Yann Collet48537162016-04-07 15:24:29 +02001962
inikepfaa8d8a2016-04-05 19:01:10 +02001963 /* check immediate repcode */
1964 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02001965 && ((offset_2>0)
1966 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02001967 /* store sequence */
Yann Collet9634f672016-07-03 01:23:58 +02001968 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
1969 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02001970 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1971 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02001972 anchor = ip;
1973 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02001974 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001975
Yann Collet4266c0a2016-06-14 01:49:25 +02001976 /* Save reps for next block */
Yann Collet9634f672016-07-03 01:23:58 +02001977 ctx->savedRep[0] = offset_1 ? offset_1 : savedOffset;
1978 ctx->savedRep[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02001979
inikepfaa8d8a2016-04-05 19:01:10 +02001980 /* Last Literals */
1981 { size_t const lastLLSize = iend - anchor;
1982 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1983 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01001984 }
Yann Collet5106a762015-11-05 15:00:24 +01001985}
1986
Yann Collet5be2dd22015-11-11 13:43:58 +01001987
inikep64d7bcb2016-04-07 19:14:09 +02001988static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1989{
1990 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
1991}
1992
1993static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1994{
1995 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
1996}
1997
1998static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1999{
2000 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2001}
2002
2003static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2004{
2005 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2006}
2007
2008
inikepfaa8d8a2016-04-05 19:01:10 +02002009FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002010void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2011 const void* src, size_t srcSize,
2012 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002013{
inikepfaa8d8a2016-04-05 19:01:10 +02002014 seqStore_t* seqStorePtr = &(ctx->seqStore);
2015 const BYTE* const istart = (const BYTE*)src;
2016 const BYTE* ip = istart;
2017 const BYTE* anchor = istart;
2018 const BYTE* const iend = istart + srcSize;
2019 const BYTE* const ilimit = iend - 8;
2020 const BYTE* const base = ctx->base;
2021 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002022 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002023 const BYTE* const prefixStart = base + dictLimit;
2024 const BYTE* const dictBase = ctx->dictBase;
2025 const BYTE* const dictEnd = dictBase + dictLimit;
2026 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2027
2028 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2029 const U32 mls = ctx->params.cParams.searchLength;
2030
inikep64d7bcb2016-04-07 19:14:09 +02002031 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2032 size_t* offsetPtr,
2033 U32 maxNbAttempts, U32 matchLengthSearch);
2034 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2035
Yann Collet302ff032016-07-03 01:28:16 +02002036 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002037
Yann Collet302ff032016-07-03 01:28:16 +02002038 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002039 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002040 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002041
2042 /* Match Loop */
2043 while (ip < ilimit) {
2044 size_t matchLength=0;
2045 size_t offset=0;
2046 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002047 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002048
2049 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002050 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002051 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2052 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002053 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002054 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002055 /* repcode detected we should take it */
2056 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02002057 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2058 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002059 } }
2060
2061 /* first search (depth 0) */
2062 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002063 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002064 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002065 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002066 }
2067
inikep7bc19b62016-04-06 09:46:01 +02002068 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02002069 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2070 continue;
2071 }
2072
inikep64d7bcb2016-04-07 19:14:09 +02002073 /* let's try to find a better solution */
2074 if (depth>=1)
2075 while (ip<ilimit) {
2076 ip ++;
2077 current++;
2078 /* check repCode */
2079 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002080 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002081 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2082 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002083 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002084 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2085 /* repcode detected */
2086 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2087 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2088 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002089 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002090 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2091 matchLength = repLength, offset = 0, start = ip;
2092 } }
2093
2094 /* search match, depth 1 */
2095 { size_t offset2=99999999;
2096 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002097 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2098 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02002099 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2100 matchLength = ml2, offset = offset2, start = ip;
2101 continue; /* search a better one */
2102 } }
2103
2104 /* let's find an even better one */
2105 if ((depth==2) && (ip<ilimit)) {
2106 ip ++;
2107 current++;
2108 /* check repCode */
2109 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002110 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002111 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2112 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002113 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002114 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2115 /* repcode detected */
2116 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2117 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2118 int gain2 = (int)(repLength * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002119 int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002120 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2121 matchLength = repLength, offset = 0, start = ip;
2122 } }
2123
2124 /* search match, depth 2 */
2125 { size_t offset2=99999999;
2126 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002127 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2128 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02002129 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2130 matchLength = ml2, offset = offset2, start = ip;
2131 continue;
2132 } } }
2133 break; /* nothing found : store previous solution */
2134 }
2135
inikepfaa8d8a2016-04-05 19:01:10 +02002136 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002137 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002138 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002139 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2140 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002141 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002142 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002143 }
inikepfaa8d8a2016-04-05 19:01:10 +02002144
inikepfaa8d8a2016-04-05 19:01:10 +02002145 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002146_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002147 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002148 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002149 anchor = ip = start + matchLength;
2150 }
2151
2152 /* check immediate repcode */
2153 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002154 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002155 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2156 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002157 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002158 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2159 /* repcode detected we should take it */
2160 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02002161 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
Yann Collet302ff032016-07-03 01:28:16 +02002162 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002163 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2164 ip += matchLength;
2165 anchor = ip;
2166 continue; /* faster when present ... (?) */
2167 }
2168 break;
2169 } }
2170
Yann Collet4266c0a2016-06-14 01:49:25 +02002171 /* Save reps for next block */
Yann Collet302ff032016-07-03 01:28:16 +02002172 ctx->savedRep[0] = offset_1; ctx->savedRep[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002173
inikepfaa8d8a2016-04-05 19:01:10 +02002174 /* Last Literals */
2175 { size_t const lastLLSize = iend - anchor;
2176 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2177 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002178 }
2179}
2180
2181
Yann Collet59d1f792016-01-23 19:28:41 +01002182void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002183{
inikep64d7bcb2016-04-07 19:14:09 +02002184 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002185}
2186
Yann Collet59d1f792016-01-23 19:28:41 +01002187static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002188{
Yann Colleta1249dc2016-01-25 04:22:03 +01002189 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002190}
Yann Collet9a24e592015-11-22 02:53:43 +01002191
Yann Collet59d1f792016-01-23 19:28:41 +01002192static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002193{
Yann Colleta1249dc2016-01-25 04:22:03 +01002194 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002195}
2196
Yann Collet59d1f792016-01-23 19:28:41 +01002197static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002198{
Yann Colleta1249dc2016-01-25 04:22:03 +01002199 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002200}
2201
inikepef519412016-04-21 11:08:43 +02002202
inikepef519412016-04-21 11:08:43 +02002203/* The optimal parser */
2204#include "zstd_opt.h"
2205
2206static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2207{
Yann Colletd4f4e582016-06-27 01:31:35 +02002208#ifdef ZSTD_OPT_H_91842398743
inikepef519412016-04-21 11:08:43 +02002209 ZSTD_compressBlock_opt_generic(ctx, src, srcSize);
Yann Colletd4f4e582016-06-27 01:31:35 +02002210#else
2211 (void)ctx; (void)src; (void)srcSize;
2212 return;
2213#endif
inikepef519412016-04-21 11:08:43 +02002214}
2215
inikepd3b8d7a2016-02-22 10:06:17 +01002216static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002217{
Yann Colletd4f4e582016-06-27 01:31:35 +02002218#ifdef ZSTD_OPT_H_91842398743
inikep5ce00ae2016-04-05 21:03:43 +02002219 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize);
Yann Colletd4f4e582016-06-27 01:31:35 +02002220#else
2221 (void)ctx; (void)src; (void)srcSize;
2222 return;
2223#endif
inikepe2bfe242016-01-31 11:25:48 +01002224}
2225
Yann Collet7a231792015-11-21 15:27:35 +01002226
Yann Collet59d1f792016-01-23 19:28:41 +01002227typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002228
Yann Colletb923f652016-01-26 03:14:20 +01002229static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002230{
Yann Collet45dc3562016-07-12 09:47:31 +02002231 static const ZSTD_blockCompressor blockCompressor[2][7] = {
2232 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt },
2233 { 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 +01002234 };
2235
2236 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002237}
2238
2239
Yann Colletd1b26842016-03-15 01:24:33 +01002240static 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 +01002241{
Yann Collet19cab462016-06-17 12:54:52 +02002242 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002243 const BYTE* const base = zc->base;
2244 const BYTE* const istart = (const BYTE*)src;
2245 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002246 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 +02002247 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002248 if (current > zc->nextToUpdate + 384)
2249 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 +01002250 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002251 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002252}
2253
2254
Yann Colletc991cc12016-07-28 00:55:43 +02002255/*! ZSTD_compress_generic() :
2256* Compress a chunk of data into one or multiple blocks.
2257* All blocks will be terminated, all input will be consumed.
2258* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2259* Frame is supposed already started (header already produced)
2260* @return : compressed size, or an error code
2261*/
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002262static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2263 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002264 const void* src, size_t srcSize,
2265 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002266{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002267 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002268 size_t remaining = srcSize;
2269 const BYTE* ip = (const BYTE*)src;
2270 BYTE* const ostart = (BYTE*)dst;
2271 BYTE* op = ostart;
Yann Colletd4180ca2016-07-27 21:21:36 +02002272 U32 const maxDist = 1 << cctx->params.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002273
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002274 if (cctx->params.fParams.checksumFlag)
2275 XXH64_update(&cctx->xxhState, src, srcSize);
2276
Yann Collet2ce49232016-02-02 14:36:49 +01002277 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002278 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002279 size_t cSize;
2280
inikepfb5df612016-05-24 15:36:37 +02002281 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 +01002282 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002283
Yann Collet346efcc2016-08-02 14:26:00 +02002284 /* preemptive overflow correction */
2285 if (cctx->lowLimit > (1<<30)) {
2286 U32 const btplus = (cctx->params.cParams.strategy == ZSTD_btlazy2) | (cctx->params.cParams.strategy == ZSTD_btopt);
2287 U32 const chainMask = (1 << (cctx->params.cParams.chainLog - btplus)) - 1;
Yann Collet5a02b692016-08-25 22:24:59 +02002288 U32 const supLog = MAX(cctx->params.cParams.chainLog, 17 /* blockSize */);
2289 U32 const newLowLimit = (cctx->lowLimit & chainMask) + (1 << supLog); /* preserve position % chainSize, ensure current-repcode doesn't underflow */
Yann Collet346efcc2016-08-02 14:26:00 +02002290 U32 const correction = cctx->lowLimit - newLowLimit;
2291 ZSTD_reduceIndex(cctx, correction);
2292 cctx->base += correction;
2293 cctx->dictBase += correction;
2294 cctx->lowLimit = newLowLimit;
2295 cctx->dictLimit -= correction;
2296 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2297 else cctx->nextToUpdate -= correction;
2298 }
2299
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002300 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002301 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002302 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2303 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2304 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002305 }
Yann Collet89db5e02015-11-13 11:27:46 +01002306
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002307 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002308 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002309
Yann Collet2ce49232016-02-02 14:36:49 +01002310 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002311 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2312 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2313 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2314 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2315 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002316 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002317 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002318 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002319 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002320 }
2321
2322 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002323 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002324 ip += blockSize;
2325 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002326 }
2327
Yann Collet62470b42016-07-28 15:29:08 +02002328 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002329 return op-ostart;
2330}
2331
2332
Yann Collet6236eba2016-04-12 15:52:33 +02002333static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002334 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002335{ BYTE* const op = (BYTE*)dst;
Yann Collet731ef162016-07-27 21:05:12 +02002336 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2337 U32 const checksumFlag = params.fParams.checksumFlag>0;
2338 U32 const windowSize = 1U << params.cParams.windowLog;
2339 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize > (pledgedSrcSize-1));
2340 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2341 U32 const fcsCode = params.fParams.contentSizeFlag ?
Yann Collet673f0d72016-06-06 00:26:38 +02002342 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
2343 0;
Yann Collet731ef162016-07-27 21:05:12 +02002344 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002345 size_t pos;
2346
2347 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet6236eba2016-04-12 15:52:33 +02002348
2349 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002350 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002351 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002352 switch(dictIDSizeCode)
2353 {
2354 default: /* impossible */
2355 case 0 : break;
2356 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002357 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002358 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2359 }
Yann Collet673f0d72016-06-06 00:26:38 +02002360 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002361 {
2362 default: /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002363 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002364 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2365 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002366 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002367 }
Yann Colletc46fb922016-05-29 05:01:04 +02002368 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002369}
2370
2371
Yann Collet346efcc2016-08-02 14:26:00 +02002372static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002373 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002374 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002375 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002376{
Yann Collet2acb5d32015-10-29 16:49:43 +01002377 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002378 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002379
Yann Collet346efcc2016-08-02 14:26:00 +02002380 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002381
Yann Collet346efcc2016-08-02 14:26:00 +02002382 if (frame && (cctx->stage==ZSTDcs_init)) {
2383 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002384 if (ZSTD_isError(fhSize)) return fhSize;
2385 dstCapacity -= fhSize;
2386 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002387 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002388 }
Yann Colletf3eca252015-10-22 15:31:46 +01002389
Yann Collet417890c2015-12-04 17:16:37 +01002390 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002391 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002392 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002393 ptrdiff_t const delta = cctx->nextSrc - ip;
2394 cctx->lowLimit = cctx->dictLimit;
2395 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2396 cctx->dictBase = cctx->base;
2397 cctx->base -= delta;
2398 cctx->nextToUpdate = cctx->dictLimit;
2399 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002400 }
2401
Yann Collet346efcc2016-08-02 14:26:00 +02002402 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2403 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2404 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2405 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2406 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002407 }
2408
Yann Collet346efcc2016-08-02 14:26:00 +02002409 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002410
Yann Collet70e45772016-03-19 18:08:32 +01002411 { size_t const cSize = frame ?
Yann Collet346efcc2016-08-02 14:26:00 +02002412 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2413 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002414 if (ZSTD_isError(cSize)) return cSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002415 return cSize + fhSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002416 }
Yann Colletf3eca252015-10-22 15:31:46 +01002417}
2418
Yann Colletbf42c8e2016-01-09 01:08:23 +01002419
Yann Collet5b567392016-07-28 01:17:22 +02002420size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002421 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002422 const void* src, size_t srcSize)
2423{
Yann Collet5b567392016-07-28 01:17:22 +02002424 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 0);
2425}
2426
2427
Yann Colletcf05b9d2016-07-18 16:52:10 +02002428size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002429{
Yann Colletcf05b9d2016-07-18 16:52:10 +02002430 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
2431}
2432
2433size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2434{
2435 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002436 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Colletc991cc12016-07-28 00:55:43 +02002437 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002438}
2439
2440
Yann Colletb923f652016-01-26 03:14:20 +01002441static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002442{
2443 const BYTE* const ip = (const BYTE*) src;
2444 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002445
Yann Collet417890c2015-12-04 17:16:37 +01002446 /* input becomes current prefix */
2447 zc->lowLimit = zc->dictLimit;
2448 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2449 zc->dictBase = zc->base;
2450 zc->base += ip - zc->nextSrc;
2451 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002452 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002453
2454 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002455 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002456
Yann Collet3b719252016-03-30 19:48:05 +02002457 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002458 {
2459 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002460 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002461 break;
2462
Yann Collet45dc3562016-07-12 09:47:31 +02002463 case ZSTD_dfast:
2464 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2465 break;
2466
Yann Collet417890c2015-12-04 17:16:37 +01002467 case ZSTD_greedy:
2468 case ZSTD_lazy:
2469 case ZSTD_lazy2:
Yann Collet731ef162016-07-27 21:05:12 +02002470 ZSTD_insertAndFindFirstIndex (zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002471 break;
2472
2473 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002474 case ZSTD_btopt:
Yann Collet731ef162016-07-27 21:05:12 +02002475 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002476 break;
2477
2478 default:
2479 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2480 }
2481
Yann Collet2ce49232016-02-02 14:36:49 +01002482 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002483 return 0;
2484}
2485
2486
Yann Colletb923f652016-01-26 03:14:20 +01002487/* Dictionary format :
2488 Magic == ZSTD_DICT_MAGIC (4 bytes)
Yann Colletfb797352016-03-13 11:08:40 +01002489 HUF_writeCTable(256)
Yann Collet736d4192016-06-15 18:48:51 +02002490 FSE_writeNCount(off)
Yann Collet731ef162016-07-27 21:05:12 +02002491 FSE_writeNCount(ml)
Yann Collet736d4192016-06-15 18:48:51 +02002492 FSE_writeNCount(ll)
2493 RepOffsets
Yann Colletb923f652016-01-26 03:14:20 +01002494 Dictionary content
2495*/
Yann Colletfb797352016-03-13 11:08:40 +01002496/*! ZSTD_loadDictEntropyStats() :
Yann Collet736d4192016-06-15 18:48:51 +02002497 @return : size read from dictionary
2498 note : magic number supposed already checked */
2499static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002500{
Yann Collet52a06222016-06-15 13:53:34 +02002501 const BYTE* dictPtr = (const BYTE*)dict;
2502 const BYTE* const dictEnd = dictPtr + dictSize;
Yann Colletfb810d62016-01-28 00:18:06 +01002503
Yann Collet736d4192016-06-15 18:48:51 +02002504 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dict, dictSize);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002505 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002506 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002507 }
Yann Colletfb810d62016-01-28 00:18:06 +01002508
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002509 { short offcodeNCount[MaxOff+1];
2510 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
Yann Collet52a06222016-06-15 13:53:34 +02002511 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002512 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet736d4192016-06-15 18:48:51 +02002513 { size_t const errorCode = FSE_buildCTable(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002514 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
Yann Collet52a06222016-06-15 13:53:34 +02002515 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002516 }
Yann Colletfb810d62016-01-28 00:18:06 +01002517
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002518 { short matchlengthNCount[MaxML+1];
2519 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
Yann Collet52a06222016-06-15 13:53:34 +02002520 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002521 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet736d4192016-06-15 18:48:51 +02002522 { size_t const errorCode = FSE_buildCTable(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002523 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
Yann Collet52a06222016-06-15 13:53:34 +02002524 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002525 }
Yann Colletfb810d62016-01-28 00:18:06 +01002526
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002527 { short litlengthNCount[MaxLL+1];
2528 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
Yann Collet52a06222016-06-15 13:53:34 +02002529 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002530 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet736d4192016-06-15 18:48:51 +02002531 { size_t const errorCode = FSE_buildCTable(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002532 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted); }
Yann Collet52a06222016-06-15 13:53:34 +02002533 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002534 }
Yann Colletfb810d62016-01-28 00:18:06 +01002535
Yann Collet52a06222016-06-15 13:53:34 +02002536 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Yann Collet736d4192016-06-15 18:48:51 +02002537 cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);
2538 cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);
2539 cctx->rep[2] = MEM_readLE32(dictPtr+8); if (cctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002540 dictPtr += 12;
2541
Yann Collet736d4192016-06-15 18:48:51 +02002542 cctx->flagStaticTables = 1;
Yann Collet52a06222016-06-15 13:53:34 +02002543 return dictPtr - (const BYTE*)dict;
Yann Colletb923f652016-01-26 03:14:20 +01002544}
2545
Yann Colletd1b26842016-03-15 01:24:33 +01002546/** ZSTD_compress_insertDictionary() :
2547* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002548static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002549{
Yann Colletc46fb922016-05-29 05:01:04 +02002550 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002551
Yann Colletd1b26842016-03-15 01:24:33 +01002552 /* default : dict is pure content */
2553 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletc46fb922016-05-29 05:01:04 +02002554 zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4);
Yann Colletd1b26842016-03-15 01:24:33 +01002555
2556 /* known magic number : dict is parsed for entropy stats and content */
Yann Collet14200a22016-08-30 06:51:00 -07002557 { size_t const eSize_8 = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8);
2558 size_t const eSize = eSize_8 + 8;
2559 if (ZSTD_isError(eSize_8)) return eSize_8;
Yann Collet21588e32016-03-30 16:50:44 +02002560 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002561 }
Yann Colletecd651b2016-01-07 15:35:18 +01002562}
2563
Yann Collet0085cd32016-04-12 14:14:10 +02002564
Yann Collet27caf2a2016-04-01 15:48:48 +02002565/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002566* @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02002567static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01002568 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002569 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002570{
Yann Colleta7737f62016-09-06 09:44:59 +02002571 ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
2572 size_t const resetError = ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp);
Yann Collet673f0d72016-06-06 00:26:38 +02002573 if (ZSTD_isError(resetError)) return resetError;
Yann Collet89db5e02015-11-13 11:27:46 +01002574
Yann Colleta7737f62016-09-06 09:44:59 +02002575 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002576}
2577
2578
Yann Collet27caf2a2016-04-01 15:48:48 +02002579/*! ZSTD_compressBegin_advanced() :
2580* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002581size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002582 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02002583 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02002584{
2585 /* compression parameters verification and optimization */
Yann Colleta7737f62016-09-06 09:44:59 +02002586 size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize);
2587 if (ZSTD_isError(errorCode)) return errorCode;
Yann Collet27caf2a2016-04-01 15:48:48 +02002588
Yann Collet81e13ef2016-06-07 00:51:51 +02002589 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002590}
2591
2592
Yann Collet81e13ef2016-06-07 00:51:51 +02002593size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002594{
Yann Collet6c6e1752016-06-27 15:28:45 +02002595 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002596 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002597}
Yann Collet083fcc82015-10-25 14:06:35 +01002598
inikep19bd48f2016-04-04 12:10:00 +02002599
Yann Collet1c8e1942016-01-26 16:31:22 +01002600size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002601{
Yann Collet3b719252016-03-30 19:48:05 +02002602 return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002603}
2604
2605
Yann Collet62470b42016-07-28 15:29:08 +02002606/*! ZSTD_writeEpilogue() :
2607* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01002608* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02002609static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002610{
Yann Colletc991cc12016-07-28 00:55:43 +02002611 BYTE* const ostart = (BYTE*)dst;
2612 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02002613 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002614
Yann Collet87c18b22016-08-26 01:43:47 +02002615 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02002616
2617 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02002618 if (cctx->stage == ZSTDcs_init) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002619 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002620 if (ZSTD_isError(fhSize)) return fhSize;
2621 dstCapacity -= fhSize;
2622 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02002623 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002624 }
2625
Yann Colletc991cc12016-07-28 00:55:43 +02002626 if (cctx->stage != ZSTDcs_ending) {
2627 /* write one last empty block, make it the "last" block */
2628 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2629 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2630 MEM_writeLE32(op, cBlockHeader24);
2631 op += ZSTD_blockHeaderSize;
2632 dstCapacity -= ZSTD_blockHeaderSize;
2633 }
2634
2635 if (cctx->params.fParams.checksumFlag) {
2636 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2637 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2638 MEM_writeLE32(op, checksum);
2639 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002640 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002641
Yann Collet731ef162016-07-27 21:05:12 +02002642 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02002643 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01002644}
2645
Yann Colletfd416f12016-01-30 03:14:15 +01002646
Yann Collet62470b42016-07-28 15:29:08 +02002647size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2648 void* dst, size_t dstCapacity,
2649 const void* src, size_t srcSize)
2650{
2651 size_t endResult;
2652 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 1);
2653 if (ZSTD_isError(cSize)) return cSize;
2654 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2655 if (ZSTD_isError(endResult)) return endResult;
2656 return cSize + endResult;
2657}
2658
2659
Yann Collet19c10022016-07-28 01:25:46 +02002660static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002661 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002662 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002663 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002664 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002665{
Yann Collet62470b42016-07-28 15:29:08 +02002666 size_t const errorCode = ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize);
2667 if(ZSTD_isError(errorCode)) return errorCode;
Yann Colletf3eca252015-10-22 15:31:46 +01002668
Yann Collet62470b42016-07-28 15:29:08 +02002669 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002670}
2671
Yann Collet21588e32016-03-30 16:50:44 +02002672size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2673 void* dst, size_t dstCapacity,
2674 const void* src, size_t srcSize,
2675 const void* dict,size_t dictSize,
2676 ZSTD_parameters params)
2677{
Yann Collet3b719252016-03-30 19:48:05 +02002678 size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, srcSize);
Yann Collet21588e32016-03-30 16:50:44 +02002679 if (ZSTD_isError(errorCode)) return errorCode;
2680 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2681}
2682
Yann Colletd1b26842016-03-15 01:24:33 +01002683size_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 +01002684{
Yann Collet6c6e1752016-06-27 15:28:45 +02002685 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dictSize);
Yann Collet3b719252016-03-30 19:48:05 +02002686 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002687 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002688}
2689
Yann Colletd1b26842016-03-15 01:24:33 +01002690size_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 +01002691{
Yann Collet21588e32016-03-30 16:50:44 +02002692 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002693}
2694
Yann Colletd1b26842016-03-15 01:24:33 +01002695size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002696{
Yann Collet44fe9912015-10-29 22:02:40 +01002697 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002698 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002699 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002700 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002701 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Collet23b6e052016-08-28 21:05:43 -07002702 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 +01002703 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002704}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002705
Yann Colletfd416f12016-01-30 03:14:15 +01002706
Yann Collet81e13ef2016-06-07 00:51:51 +02002707/* ===== Dictionary API ===== */
2708
2709struct ZSTD_CDict_s {
2710 void* dictContent;
2711 size_t dictContentSize;
2712 ZSTD_CCtx* refContext;
David Lamda9d3b72016-08-29 09:03:12 -07002713}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
Yann Collet81e13ef2016-06-07 00:51:51 +02002714
2715ZSTD_CDict* ZSTD_createCDict_advanced(const void* dict, size_t dictSize, ZSTD_parameters params, ZSTD_customMem customMem)
2716{
Yann Collet23b6e052016-08-28 21:05:43 -07002717 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2718 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02002719
Yann Collet23b6e052016-08-28 21:05:43 -07002720 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
2721 void* const dictContent = ZSTD_malloc(dictSize, customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002722 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2723
2724 if (!dictContent || !cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07002725 ZSTD_free(dictContent, customMem);
2726 ZSTD_free(cdict, customMem);
2727 ZSTD_free(cctx, customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002728 return NULL;
2729 }
2730
2731 memcpy(dictContent, dict, dictSize);
2732 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, dictContent, dictSize, params, 0);
2733 if (ZSTD_isError(errorCode)) {
Yann Collet23b6e052016-08-28 21:05:43 -07002734 ZSTD_free(dictContent, customMem);
2735 ZSTD_free(cdict, customMem);
2736 ZSTD_free(cctx, customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002737 return NULL;
2738 } }
2739
2740 cdict->dictContent = dictContent;
2741 cdict->dictContentSize = dictSize;
2742 cdict->refContext = cctx;
2743 return cdict;
2744 }
2745}
2746
2747ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2748{
2749 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet07639052016-08-03 01:57:57 +02002750 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002751 params.fParams.contentSizeFlag = 1;
2752 return ZSTD_createCDict_advanced(dict, dictSize, params, allocator);
2753}
2754
2755size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2756{
Yann Collet23b6e052016-08-28 21:05:43 -07002757 if (cdict==NULL) return 0; /* support free on NULL */
2758 { ZSTD_customMem cMem = cdict->refContext->customMem;
2759 ZSTD_freeCCtx(cdict->refContext);
2760 ZSTD_free(cdict->dictContent, cMem);
2761 ZSTD_free(cdict, cMem);
2762 return 0;
2763 }
Yann Collet81e13ef2016-06-07 00:51:51 +02002764}
2765
Yann Collet07639052016-08-03 01:57:57 +02002766/*! ZSTD_compress_usingCDict() :
2767* Compression using a digested Dictionary.
2768* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
2769* Note that compression level is decided during dictionary creation */
Yann Collet81e13ef2016-06-07 00:51:51 +02002770ZSTDLIB_API size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2771 void* dst, size_t dstCapacity,
2772 const void* src, size_t srcSize,
2773 const ZSTD_CDict* cdict)
2774{
Yann Collet7ae67bb2016-09-06 06:28:05 +02002775 if (cdict->dictContentSize) {
2776 size_t const errorCode = ZSTD_copyCCtx(cctx, cdict->refContext);
2777 if (ZSTD_isError(errorCode)) return errorCode;
2778 } else {
2779 size_t const errorCode = ZSTD_compressBegin_advanced(cctx, NULL, 0, cdict->refContext->params, srcSize);
2780 if (ZSTD_isError(errorCode)) return errorCode;
2781 }
Yann Collet07639052016-08-03 01:57:57 +02002782
2783 if (cdict->refContext->params.fParams.contentSizeFlag==1) {
2784 cctx->params.fParams.contentSizeFlag = 1;
2785 cctx->frameContentSize = srcSize;
2786 }
2787
2788 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002789}
2790
2791
2792
Yann Collet104e5b02016-08-12 13:04:27 +02002793/* ******************************************************************
2794* Streaming
2795********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002796
2797typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
2798
2799struct ZSTD_CStream_s {
2800 ZSTD_CCtx* zc;
2801 char* inBuff;
2802 size_t inBuffSize;
2803 size_t inToCompress;
2804 size_t inBuffPos;
2805 size_t inBuffTarget;
2806 size_t blockSize;
2807 char* outBuff;
2808 size_t outBuffSize;
2809 size_t outBuffContentSize;
2810 size_t outBuffFlushedSize;
2811 ZSTD_cStreamStage stage;
2812 U32 checksum;
2813 U32 frameEnded;
2814 ZSTD_customMem customMem;
2815}; /* typedef'd to ZSTD_CStream within "zstd.h" */
2816
2817ZSTD_CStream* ZSTD_createCStream(void)
2818{
2819 return ZSTD_createCStream_advanced(defaultCustomMem);
2820}
2821
2822ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
2823{
2824 ZSTD_CStream* zcs;
2825
Yann Collet23b6e052016-08-28 21:05:43 -07002826 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2827 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002828
Yann Collet23b6e052016-08-28 21:05:43 -07002829 zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002830 if (zcs==NULL) return NULL;
2831 memset(zcs, 0, sizeof(ZSTD_CStream));
2832 memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
2833 zcs->zc = ZSTD_createCCtx_advanced(customMem);
2834 if (zcs->zc == NULL) { ZSTD_freeCStream(zcs); return NULL; }
2835 return zcs;
2836}
2837
2838size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
2839{
2840 if (zcs==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -07002841 { ZSTD_customMem const cMem = zcs->customMem;
2842 ZSTD_freeCCtx(zcs->zc);
2843 ZSTD_free(zcs->inBuff, cMem);
2844 ZSTD_free(zcs->outBuff, cMem);
2845 ZSTD_free(zcs, cMem);
2846 return 0;
2847 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002848}
2849
2850
Yann Collet104e5b02016-08-12 13:04:27 +02002851/*====== Initialization ======*/
2852
2853size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
2854size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002855
2856size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
2857 const void* dict, size_t dictSize,
2858 ZSTD_parameters params, unsigned long long pledgedSrcSize)
2859{
2860 /* allocate buffers */
2861 { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
2862 if (zcs->inBuffSize < neededInBuffSize) {
2863 zcs->inBuffSize = neededInBuffSize;
Yann Collet23b6e052016-08-28 21:05:43 -07002864 ZSTD_free(zcs->inBuff, zcs->customMem); /* should not be necessary */
2865 zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002866 if (zcs->inBuff == NULL) return ERROR(memory_allocation);
2867 }
2868 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
2869 }
2870 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
2871 zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
Yann Collet23b6e052016-08-28 21:05:43 -07002872 ZSTD_free(zcs->outBuff, zcs->customMem); /* should not be necessary */
2873 zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002874 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
2875 }
2876
2877 { size_t const errorCode = ZSTD_compressBegin_advanced(zcs->zc, dict, dictSize, params, pledgedSrcSize);
2878 if (ZSTD_isError(errorCode)) return errorCode; }
2879
2880 zcs->inToCompress = 0;
2881 zcs->inBuffPos = 0;
2882 zcs->inBuffTarget = zcs->blockSize;
2883 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
2884 zcs->stage = zcss_load;
2885 zcs->checksum = params.fParams.checksumFlag > 0;
2886 zcs->frameEnded = 0;
2887 return 0; /* ready to go */
2888}
2889
2890size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
2891{
2892 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
2893 return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0);
2894}
2895
2896size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
2897{
2898 return ZSTD_initCStream_usingDict(zcs, NULL, 0, compressionLevel);
2899}
2900
Yann Collet70e3b312016-08-23 01:18:06 +02002901size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
Yann Colletcb327632016-08-23 00:30:31 +02002902{
Yann Collet70e3b312016-08-23 01:18:06 +02002903 return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->zc) + zcs->outBuffSize + zcs->inBuffSize;
Yann Colletcb327632016-08-23 00:30:31 +02002904}
Yann Collet5a0c8e22016-08-12 01:20:36 +02002905
Yann Collet104e5b02016-08-12 13:04:27 +02002906/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002907
2908typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
2909
2910MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2911{
2912 size_t const length = MIN(dstCapacity, srcSize);
2913 memcpy(dst, src, length);
2914 return length;
2915}
2916
2917static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
2918 void* dst, size_t* dstCapacityPtr,
2919 const void* src, size_t* srcSizePtr,
2920 ZSTD_flush_e const flush)
2921{
2922 U32 someMoreWork = 1;
2923 const char* const istart = (const char*)src;
2924 const char* const iend = istart + *srcSizePtr;
2925 const char* ip = istart;
2926 char* const ostart = (char*)dst;
2927 char* const oend = ostart + *dstCapacityPtr;
2928 char* op = ostart;
2929
2930 while (someMoreWork) {
2931 switch(zcs->stage)
2932 {
2933 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
2934
2935 case zcss_load:
2936 /* complete inBuffer */
2937 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
2938 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
2939 zcs->inBuffPos += loaded;
2940 ip += loaded;
2941 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
2942 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
2943 } }
2944 /* compress current block (note : this stage cannot be stopped in the middle) */
2945 { void* cDst;
2946 size_t cSize;
2947 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
2948 size_t oSize = oend-op;
2949 if (oSize >= ZSTD_compressBound(iSize))
2950 cDst = op; /* compress directly into output buffer (avoid flush stage) */
2951 else
2952 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
2953 cSize = (flush == zsf_end) ?
2954 ZSTD_compressEnd(zcs->zc, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
2955 ZSTD_compressContinue(zcs->zc, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
2956 if (ZSTD_isError(cSize)) return cSize;
2957 if (flush == zsf_end) zcs->frameEnded = 1;
2958 /* prepare next block */
2959 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
2960 if (zcs->inBuffTarget > zcs->inBuffSize)
2961 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
2962 zcs->inToCompress = zcs->inBuffPos;
2963 if (cDst == op) { op += cSize; break; } /* no need to flush */
2964 zcs->outBuffContentSize = cSize;
2965 zcs->outBuffFlushedSize = 0;
2966 zcs->stage = zcss_flush; /* pass-through to flush stage */
2967 }
2968
2969 case zcss_flush:
2970 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
2971 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
2972 op += flushed;
2973 zcs->outBuffFlushedSize += flushed;
2974 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
2975 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
2976 zcs->stage = zcss_load;
2977 break;
2978 }
2979
2980 case zcss_final:
2981 someMoreWork = 0; /* do nothing */
2982 break;
2983
2984 default:
2985 return ERROR(GENERIC); /* impossible */
2986 }
2987 }
2988
2989 *srcSizePtr = ip - istart;
2990 *dstCapacityPtr = op - ostart;
2991 if (zcs->frameEnded) return 0;
2992 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
2993 if (hintInSize==0) hintInSize = zcs->blockSize;
2994 return hintInSize;
2995 }
2996}
2997
Yann Collet53e17fb2016-08-17 01:39:22 +02002998size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02002999{
Yann Collet53e17fb2016-08-17 01:39:22 +02003000 size_t sizeRead = input->size - input->pos;
3001 size_t sizeWritten = output->size - output->pos;
3002 size_t const result = ZSTD_compressStream_generic(zcs,
3003 (char*)(output->dst) + output->pos, &sizeWritten,
3004 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
3005 input->pos += sizeRead;
3006 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003007 return result;
3008}
3009
3010
Yann Collet104e5b02016-08-12 13:04:27 +02003011/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003012
3013/*! ZSTD_flushStream() :
3014* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003015size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003016{
3017 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003018 size_t sizeWritten = output->size - output->pos;
Yann Colletc4119022016-08-17 01:50:54 +02003019 size_t const result = ZSTD_compressStream_generic(zcs,
3020 (char*)(output->dst) + output->pos, &sizeWritten,
3021 &srcSize, &srcSize, /* use a valid src address instead of NULL */
3022 zsf_flush);
Yann Collet53e17fb2016-08-17 01:39:22 +02003023 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003024 if (ZSTD_isError(result)) return result;
3025 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3026}
3027
3028
Yann Collet53e17fb2016-08-17 01:39:22 +02003029size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003030{
Yann Collet53e17fb2016-08-17 01:39:22 +02003031 BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
3032 BYTE* const oend = (BYTE*)(output->dst) + output->size;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003033 BYTE* op = ostart;
3034
3035 if (zcs->stage != zcss_final) {
3036 /* flush whatever remains */
3037 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003038 size_t sizeWritten = output->size - output->pos;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003039 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
3040 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3041 op += sizeWritten;
3042 if (remainingToFlush) {
Yann Collet53e17fb2016-08-17 01:39:22 +02003043 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003044 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4);
3045 }
3046 /* create epilogue */
3047 zcs->stage = zcss_final;
3048 zcs->outBuffContentSize = !notEnded ? 0 :
3049 ZSTD_compressEnd(zcs->zc, zcs->outBuff, zcs->outBuffSize, NULL, 0); /* write epilogue, including final empty block, into outBuff */
3050 }
3051
3052 /* flush epilogue */
3053 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3054 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3055 op += flushed;
3056 zcs->outBuffFlushedSize += flushed;
Yann Collet53e17fb2016-08-17 01:39:22 +02003057 output->pos += op-ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003058 if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */
3059 return toFlush - flushed;
3060 }
3061}
3062
3063
3064
Yann Collet70e8c382016-02-10 13:37:52 +01003065/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003066
Yann Collet236d94f2016-05-18 12:06:33 +02003067#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02003068#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003069int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003070
Yann Collet3b719252016-03-30 19:48:05 +02003071static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003072{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003073 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003074 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003075 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3076 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003077 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3078 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003079 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3080 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3081 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003082 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003083 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3084 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3085 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3086 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3087 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3088 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3089 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3090 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003091 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
3092 { 23, 23, 22, 6, 5, 32, ZSTD_btopt }, /* level 18 */
3093 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
3094 { 25, 25, 23, 7, 3, 64, ZSTD_btopt }, /* level 20 */
3095 { 26, 26, 23, 7, 3,256, ZSTD_btopt }, /* level 21 */
3096 { 27, 27, 25, 9, 3,512, ZSTD_btopt }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003097},
3098{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003099 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003100 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003101 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003102 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3103 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3104 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3105 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3106 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3107 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3108 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3109 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3110 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3111 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3112 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3113 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003114 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003115 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3116 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3117 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003118 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3119 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
3120 { 18, 19, 18, 11, 3,512, ZSTD_btopt }, /* level 20.*/
3121 { 18, 19, 18, 12, 3,512, ZSTD_btopt }, /* level 21.*/
3122 { 18, 19, 18, 13, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003123},
3124{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003125 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003126 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3127 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3128 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3129 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3130 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3131 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3132 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3133 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3134 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3135 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3136 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3137 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3138 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3139 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003140 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3141 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3142 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3143 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3144 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3145 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
3146 { 17, 18, 17, 9, 3,256, ZSTD_btopt }, /* level 20.*/
3147 { 17, 18, 17, 10, 3,256, ZSTD_btopt }, /* level 21.*/
Yann Collet5894ea82016-07-22 14:36:46 +02003148 { 17, 18, 17, 11, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003149},
3150{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003151 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003152 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003153 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003154 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3155 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3156 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3157 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3158 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3159 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3160 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3161 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003162 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3163 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3164 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3165 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3166 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3167 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3168 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3169 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3170 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3171 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
3172 { 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 20.*/
3173 { 14, 15, 15, 9, 3,256, ZSTD_btopt }, /* level 21.*/
3174 { 14, 15, 15, 10, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003175},
3176};
3177
Yann Collet236d94f2016-05-18 12:06:33 +02003178/*! ZSTD_getCParams() :
3179* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3180* Size values are optional, provide 0 if not known or unused */
Yann Collet52c04fe2016-07-07 11:53:18 +02003181ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003182{
Yann Collet15354142016-04-04 04:22:53 +02003183 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02003184 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02003185 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003186 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02003187 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003188 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003189 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003190 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3191 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003192 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003193 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3194 }
Yann Collet70d13012016-06-01 18:45:34 +02003195 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003196 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003197}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003198
3199/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003200* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003201* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet52c04fe2016-07-07 11:53:18 +02003202ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003203 ZSTD_parameters params;
3204 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3205 memset(&params, 0, sizeof(params));
3206 params.cParams = cParams;
3207 return params;
3208}