blob: 65d7258d9e87158dc51865e52b56cc89e7cc259c [file] [log] [blame]
Yann Colletf3eca252015-10-22 15:31:46 +01001/*
2 ZSTD HC - High Compression Mode of Zstandard
Yann Collet863ec402016-01-28 17:56:33 +01003 Copyright (C) 2015-2016, Yann Collet.
Yann Colletf3eca252015-10-22 15:31:46 +01004
5 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are
9 met:
10
11 * Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13 * Redistributions in binary form must reproduce the above
14 copyright notice, this list of conditions and the following disclaimer
15 in the documentation and/or other materials provided with the
16 distribution.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 You can contact the author at :
31 - Zstd source repository : https://www.zstd.net
32*/
33
34
Yann Collet4b100f42015-10-30 15:49:48 +010035/* *******************************************************
36* Compiler specifics
37*********************************************************/
38#ifdef _MSC_VER /* Visual Studio */
39# define FORCE_INLINE static __forceinline
40# include <intrin.h> /* For Visual 2005 */
41# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
Yann Collet4b100f42015-10-30 15:49:48 +010042#else
Yann Collet4b100f42015-10-30 15:49:48 +010043# ifdef __GNUC__
44# define FORCE_INLINE static inline __attribute__((always_inline))
45# else
46# define FORCE_INLINE static inline
47# endif
48#endif
49
50
Yann Collet7d360282016-02-12 00:07:30 +010051/*-*************************************
Yann Colletae7aa062016-02-03 02:46:46 +010052* Dependencies
Yann Colletf3eca252015-10-22 15:31:46 +010053***************************************/
54#include <stdlib.h> /* malloc */
55#include <string.h> /* memset */
Yann Collet14983e72015-11-11 21:38:21 +010056#include "mem.h"
57#include "fse_static.h"
Yann Colletafe07092016-01-25 04:10:46 +010058#include "huff0_static.h"
Yann Collet3d9cf7a2015-10-29 17:15:14 +010059#include "zstd_internal.h"
Yann Colletf3eca252015-10-22 15:31:46 +010060
61
Yann Collet7d360282016-02-12 00:07:30 +010062/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010063* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010064***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010065static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Colletf3eca252015-10-22 15:31:46 +010066
Yann Colletf3eca252015-10-22 15:31:46 +010067
Yann Collet7d360282016-02-12 00:07:30 +010068/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010069* Helper functions
70***************************************/
Yann Collet59d1f792016-01-23 19:28:41 +010071size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
72
73
Yann Collet7d360282016-02-12 00:07:30 +010074/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010075* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010076***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010077static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
78{
79 ssPtr->offset = ssPtr->offsetStart;
80 ssPtr->lit = ssPtr->litStart;
81 ssPtr->litLength = ssPtr->litLengthStart;
82 ssPtr->matchLength = ssPtr->matchLengthStart;
Yann Collet14983e72015-11-11 21:38:21 +010083}
84
85
Yann Collet7d360282016-02-12 00:07:30 +010086/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010087* Context memory management
88***************************************/
Yann Collet5be2dd22015-11-11 13:43:58 +010089struct ZSTD_CCtx_s
Yann Colletf3eca252015-10-22 15:31:46 +010090{
Yann Collet89db5e02015-11-13 11:27:46 +010091 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010092 const BYTE* base; /* All regular indexes relative to this position */
93 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010094 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010095 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010096 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010097 U32 nextToUpdate3; /* index from which to continue dictionary update */
Yann Collet2ce49232016-02-02 14:36:49 +010098 U32 loadedDictEnd;
Yann Colletecd651b2016-01-07 15:35:18 +010099 U32 stage;
Yann Collet5be2dd22015-11-11 13:43:58 +0100100 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +0100101 void* workSpace;
102 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100103 size_t blockSize;
Yann Colletecd651b2016-01-07 15:35:18 +0100104 size_t hbSize;
Yann Collet0e491c02016-03-11 21:58:04 +0100105 char headerBuffer[ZSTD_FRAMEHEADERSIZE_MAX];
Yann Colletecd651b2016-01-07 15:35:18 +0100106
Yann Collet712def92015-10-29 18:41:45 +0100107 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100108 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +0100109 U32* hashTable3;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100110 U32* contentTable;
Yann Colletb923f652016-01-26 03:14:20 +0100111 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +0100112 U32 flagStaticTables;
113 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
114 FSE_CTable matchlengthCTable [FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
115 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Colletf3eca252015-10-22 15:31:46 +0100116};
117
Yann Collet5be2dd22015-11-11 13:43:58 +0100118ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100119{
Yann Collet5be2dd22015-11-11 13:43:58 +0100120 return (ZSTD_CCtx*) calloc(1, sizeof(ZSTD_CCtx));
Yann Colletf3eca252015-10-22 15:31:46 +0100121}
122
Yann Collet5be2dd22015-11-11 13:43:58 +0100123size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100124{
Yann Collet712def92015-10-29 18:41:45 +0100125 free(cctx->workSpace);
Yann Collet083fcc82015-10-25 14:06:35 +0100126 free(cctx);
Yann Collet982ffc72016-02-05 02:33:10 +0100127 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100128}
129
Yann Colletb44be742016-03-26 20:52:14 +0100130const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100131{
Yann Colletb44be742016-03-26 20:52:14 +0100132 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100133}
134
Yann Collet59d70632015-11-04 12:05:27 +0100135
Yann Collet21588e32016-03-30 16:50:44 +0200136#define CLAMP(val,min,max) { if (val<min) val=min; else if (val>max) val=max; }
137#define CLAMPCHECK(val,min,max) { if ((val<min) || (val>max)) return ERROR(compressionParameter_unsupported); }
138
139/** ZSTD_checkParams() :
140 ensure param values remain within authorized range.
141 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200142size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200143{
144 { U32 const windowLog_max = MEM_32bits() ? 25 : ZSTD_WINDOWLOG_MAX; /* 32 bits mode cannot flush > 24 bits */
Yann Collet3b719252016-03-30 19:48:05 +0200145 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, windowLog_max); }
146 CLAMPCHECK(cParams.contentLog, ZSTD_CONTENTLOG_MIN, ZSTD_CONTENTLOG_MAX);
147 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
148 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
149 { U32 const searchLengthMin = (cParams.strategy == ZSTD_btopt) ? ZSTD_SEARCHLENGTH_MIN : ZSTD_SEARCHLENGTH_MIN+1;
150 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
151 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
152 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Collet9bb87e52016-03-30 21:28:15 +0200153 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200154 return 0;
155}
156
157
Yann Collet14983e72015-11-11 21:38:21 +0100158static unsigned ZSTD_highbit(U32 val);
159
Yann Collet3b719252016-03-30 19:48:05 +0200160/** ZSTD_checkCParams_advanced() :
161 temporary work-around, while the compressor compatibility remains limited regarding windowLog < 18 */
162size_t ZSTD_checkCParams_advanced(ZSTD_compressionParameters cParams, U64 srcSize)
163{
Yann Colletefb18302016-04-01 18:54:13 +0200164 if (srcSize > (1ULL << ZSTD_WINDOWLOG_MIN)) return ZSTD_checkCParams(cParams);
Yann Collet3b719252016-03-30 19:48:05 +0200165 if (cParams.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) return ERROR(compressionParameter_unsupported);
Yann Colletefb18302016-04-01 18:54:13 +0200166 if (srcSize <= (1ULL << cParams.windowLog)) cParams.windowLog = ZSTD_WINDOWLOG_MIN; /* fake value - temporary work around */
167 if (srcSize <= (1ULL << cParams.hashLog)) cParams.hashLog = ZSTD_HASHLOG_MIN; /* fake value - temporary work around */
168 if (srcSize <= (1ULL << cParams.contentLog)) cParams.contentLog = ZSTD_CONTENTLOG_MIN; /* fake value - temporary work around */
Yann Collet3b719252016-03-30 19:48:05 +0200169 return ZSTD_checkCParams(cParams);
170}
171
172
Yann Collet21588e32016-03-30 16:50:44 +0200173/** ZSTD_adjustParams() :
174 optimize params for q given input (`srcSize` and `dictSize`).
175 mostly downsizing to reduce memory consumption and initialization.
176 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
177 but if both are 0, no optimization can be done.
178 Note : params is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Colletdd6466a2016-03-30 20:06:26 +0200179void ZSTD_adjustCParams(ZSTD_compressionParameters* params, U64 srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100180{
Yann Collet21588e32016-03-30 16:50:44 +0200181 if (srcSize+dictSize == 0) return; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100182
Yann Collet70e45772016-03-19 18:08:32 +0100183 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200184 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
185 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Collet21588e32016-03-30 16:50:44 +0200186 if (rSize < (1<<ZSTD_WINDOWLOG_MAX)) {
187 U32 const srcLog = ZSTD_highbit((U32)(rSize)-1) + 1;
188 if (params->windowLog > srcLog) params->windowLog = srcLog;
189 } }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100190 if (params->hashLog > params->windowLog) params->hashLog = params->windowLog;
Yann Collet21588e32016-03-30 16:50:44 +0200191 { U32 const btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_btopt);
192 U32 const maxContentLog = params->windowLog+btPlus;
193 if (params->contentLog > maxContentLog) params->contentLog = maxContentLog; } /* <= ZSTD_CONTENTLOG_MAX */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100194
195 if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet40358d02016-04-02 00:40:09 +0200196 if ((params->hashLog < ZSTD_HASHLOG_MIN) && ((U32)params->strategy >= (U32)ZSTD_btlazy2)) params->hashLog = ZSTD_HASHLOG_MIN; /* required to ensure collision resistance in bt */
Yann Collet59d70632015-11-04 12:05:27 +0100197}
198
199
Yann Collet51d50042016-03-30 20:42:19 +0200200size_t ZSTD_sizeofCCtx(ZSTD_compressionParameters cParams) /* hidden interface, for paramagrill */
Yann Collete74215e2016-03-19 16:09:09 +0100201{
202 ZSTD_CCtx* zc = ZSTD_createCCtx();
Yann Collet51d50042016-03-30 20:42:19 +0200203 ZSTD_parameters params;
204 params.cParams = cParams;
205 params.fParams.contentSizeFlag = 1;
Yann Collet3b719252016-03-30 19:48:05 +0200206 ZSTD_compressBegin_advanced(zc, NULL, 0, params, 0);
Yann Colletd64f4352016-03-21 00:07:42 +0100207 { size_t const ccsize = sizeof(*zc) + zc->workSpaceSize;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100208 ZSTD_freeCCtx(zc);
Yann Colletd64f4352016-03-21 00:07:42 +0100209 return ccsize; }
Yann Collet2e91dde2016-03-08 12:22:11 +0100210}
211
Yann Collet27caf2a2016-04-01 15:48:48 +0200212/*! ZSTD_resetCCtx_advanced() :
213 note : 'params' is expected to be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100214static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Collet88fcd292015-11-25 14:42:45 +0100215 ZSTD_parameters params)
Yann Collet863ec402016-01-28 17:56:33 +0100216{ /* note : params considered validated here */
Yann Collet3b719252016-03-30 19:48:05 +0200217 const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
218 const U32 divider = (params.cParams.searchLength==3) ? 3 : 4;
Yann Colletdd54bbc2016-03-08 02:35:34 +0100219 const size_t maxNbSeq = blockSize / divider;
Yann Colletbe391432016-03-22 23:19:28 +0100220 const size_t tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3b719252016-03-30 19:48:05 +0200221 const size_t contentSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.contentLog);
222 const size_t hSize = 1 << params.cParams.hashLog;
223 const size_t h3Size = (params.cParams.searchLength==3) ? (1 << HASHLOG3) : 0;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100224 const size_t tableSpace = (contentSize + hSize + h3Size) * sizeof(U32);
inikep87d4f3d2016-03-02 15:56:24 +0100225
Yann Collete74215e2016-03-19 16:09:09 +0100226 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Colletbe391432016-03-22 23:19:28 +0100227 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (1<<Offbits) + (1<<Litbits))*sizeof(U32)
Yann Collete74215e2016-03-19 16:09:09 +0100228 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
229 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Yann Collet3b719252016-03-30 19:48:05 +0200230 + ((params.cParams.strategy == ZSTD_btopt) ? optSpace : 0);
Yann Collete74215e2016-03-19 16:09:09 +0100231 if (zc->workSpaceSize < neededSpace) {
232 free(zc->workSpace);
233 zc->workSpace = malloc(neededSpace);
234 if (zc->workSpace == NULL) return ERROR(memory_allocation);
235 zc->workSpaceSize = neededSpace;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100236 } }
Yann Collete74215e2016-03-19 16:09:09 +0100237
Yann Collet863ec402016-01-28 17:56:33 +0100238 memset(zc->workSpace, 0, tableSpace ); /* reset only tables */
inikepcc52a972016-02-19 10:09:35 +0100239 zc->hashTable3 = (U32*)(zc->workSpace);
Yann Collete74215e2016-03-19 16:09:09 +0100240 zc->hashTable = zc->hashTable3 + h3Size;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100241 zc->contentTable = zc->hashTable + hSize;
242 zc->seqStore.buffer = zc->contentTable + contentSize;
Yann Collet863ec402016-01-28 17:56:33 +0100243 zc->hufTable = (HUF_CElt*)zc->seqStore.buffer;
244 zc->flagStaticTables = 0;
Yann Collet597847a2016-03-20 19:14:22 +0100245 zc->seqStore.buffer = ((U32*)(zc->seqStore.buffer)) + 256;
Yann Collet083fcc82015-10-25 14:06:35 +0100246
Yann Colletf48e35c2015-11-07 01:13:31 +0100247 zc->nextToUpdate = 1;
Yann Collet89db5e02015-11-13 11:27:46 +0100248 zc->nextSrc = NULL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100249 zc->base = NULL;
250 zc->dictBase = NULL;
251 zc->dictLimit = 0;
252 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100253 zc->params = params;
Yann Collet120230b2015-12-02 14:00:45 +0100254 zc->blockSize = blockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100255
Yann Collet3b719252016-03-30 19:48:05 +0200256 if (params.cParams.strategy == ZSTD_btopt) {
Yann Collet72d706a2016-03-23 20:44:12 +0100257 zc->seqStore.litFreq = (U32*)(zc->seqStore.buffer);
258 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
259 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
260 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
261 zc->seqStore.matchTable = (ZSTD_match_t*)((void*)(zc->seqStore.offCodeFreq + (1<<Offbits)));
262 zc->seqStore.priceTable = (ZSTD_optimal_t*)((void*)(zc->seqStore.matchTable + ZSTD_OPT_NUM+1));
263 zc->seqStore.buffer = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
264 zc->seqStore.litLengthSum = 0;
265 }
inikep87d4f3d2016-03-02 15:56:24 +0100266 zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer);
Yann Collet597847a2016-03-20 19:14:22 +0100267 zc->seqStore.litLengthStart = (U16*) (void*)(zc->seqStore.offsetStart + maxNbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100268 zc->seqStore.matchLengthStart = (U16*) (void*)(zc->seqStore.litLengthStart + maxNbSeq);
269 zc->seqStore.llCodeStart = (BYTE*) (zc->seqStore.matchLengthStart + maxNbSeq);
270 zc->seqStore.mlCodeStart = zc->seqStore.llCodeStart + maxNbSeq;
271 zc->seqStore.offCodeStart = zc->seqStore.mlCodeStart + maxNbSeq;
Yann Colletdd54bbc2016-03-08 02:35:34 +0100272 zc->seqStore.litStart = zc->seqStore.offCodeStart + maxNbSeq;
inikep5cccd772016-03-02 20:37:49 +0100273
Yann Colletecd651b2016-01-07 15:35:18 +0100274 zc->hbSize = 0;
Yann Collet60096272016-01-08 17:27:50 +0100275 zc->stage = 0;
Yann Collet2ce49232016-02-02 14:36:49 +0100276 zc->loadedDictEnd = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +0100277
Yann Collet4114f952015-10-30 06:40:22 +0100278 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100279}
280
Yann Collet083fcc82015-10-25 14:06:35 +0100281
Yann Collet370b08e2016-03-08 00:03:59 +0100282/*! ZSTD_copyCCtx() :
283* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
284* Only works during stage 0 (i.e. before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100285* @return : 0, or an error code */
286size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
287{
Yann Collet7b51a292016-01-26 15:58:49 +0100288 if (srcCCtx->stage!=0) return ERROR(stage_wrong);
289
290 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params);
291
292 /* copy tables */
Yann Collet3b719252016-03-30 19:48:05 +0200293 { const size_t contentSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.contentLog);
294 const size_t hSize = 1 << srcCCtx->params.cParams.hashLog;
295 const size_t h3Size = (srcCCtx->params.cParams.searchLength == 3) ? (1 << HASHLOG3) : 0;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100296 const size_t tableSpace = (contentSize + hSize + h3Size) * sizeof(U32);
297 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
298 }
Yann Collet7b51a292016-01-26 15:58:49 +0100299
300 /* copy frame header */
301 dstCCtx->hbSize = srcCCtx->hbSize;
302 memcpy(dstCCtx->headerBuffer , srcCCtx->headerBuffer, srcCCtx->hbSize);
303
304 /* copy dictionary pointers */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100305 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
306 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
307 dstCCtx->nextSrc = srcCCtx->nextSrc;
308 dstCCtx->base = srcCCtx->base;
309 dstCCtx->dictBase = srcCCtx->dictBase;
310 dstCCtx->dictLimit = srcCCtx->dictLimit;
311 dstCCtx->lowLimit = srcCCtx->lowLimit;
312 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Collet7b51a292016-01-26 15:58:49 +0100313
Yann Colletfb810d62016-01-28 00:18:06 +0100314 /* copy entropy tables */
315 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100316 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100317 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100318 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
319 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
320 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
321 }
Yann Collet7b51a292016-01-26 15:58:49 +0100322
323 return 0;
324}
325
326
Yann Colletecabfe32016-03-20 16:20:06 +0100327/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100328* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100329static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100330{
Yann Colletecabfe32016-03-20 16:20:06 +0100331 U32 u;
332 for (u=0 ; u < size ; u++) {
333 if (table[u] < reducerValue) table[u] = 0;
334 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100335 }
336}
337
Yann Colletecabfe32016-03-20 16:20:06 +0100338/*! ZSTD_reduceIndex() :
339* rescale all indexes to avoid future overflow (indexes are U32) */
340static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
341{
Yann Collet3b719252016-03-30 19:48:05 +0200342 { const U32 hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100343 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
344
Yann Collet3b719252016-03-30 19:48:05 +0200345 { const U32 contentSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.contentLog);
Yann Colletecabfe32016-03-20 16:20:06 +0100346 ZSTD_reduceTable(zc->contentTable, contentSize, reducerValue); }
347
Yann Collet3b719252016-03-30 19:48:05 +0200348 { const U32 h3Size = (zc->params.cParams.searchLength == 3) ? (1 << HASHLOG3) : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100349 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
350}
351
Yann Collet89db5e02015-11-13 11:27:46 +0100352
Yann Collet863ec402016-01-28 17:56:33 +0100353/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100354* Block entropic compression
355*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100356
Yann Colletfb797352016-03-13 11:08:40 +0100357/* Frame format description
358 Frame Header - [ Block Header - Block ] - Frame End
359 1) Frame Header
360 - 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_static.h)
361 - 1 byte - Frame Descriptor
362 2) Block Header
363 - 3 bytes, starting with a 2-bits descriptor
364 Uncompressed, Compressed, Frame End, unused
365 3) Block
366 See Block Format Description
367 4) Frame End
368 - 3 bytes, compatible with Block Header
369*/
370
371
372/* Frame descriptor
373
374 1 byte, using :
375 bit 0-3 : windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN (see zstd_internal.h)
376 bit 4 : minmatch 4(0) or 3(1)
377 bit 5 : reserved (must be zero)
378 bit 6-7 : Frame content size : unknown, 1 byte, 2 bytes, 8 bytes
379
380 Optional : content size (0, 1, 2 or 8 bytes)
381 0 : unknown
382 1 : 0-255 bytes
383 2 : 256 - 65535+256
384 8 : up to 16 exa
385*/
386
387
Yann Collet59d1f792016-01-23 19:28:41 +0100388/* Block format description
389
390 Block = Literal Section - Sequences Section
391 Prerequisite : size of (compressed) block, maximum size of regenerated data
392
393 1) Literal Section
394
395 1.1) Header : 1-5 bytes
396 flags: 2 bits
397 00 compressed by Huff0
398 01 unused
399 10 is Raw (uncompressed)
400 11 is Rle
401 Note : using 01 => Huff0 with precomputed table ?
402 Note : delta map ? => compressed ?
403
404 1.1.1) Huff0-compressed literal block : 3-5 bytes
Yann Colletafe07092016-01-25 04:10:46 +0100405 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
Yann Collet59d1f792016-01-23 19:28:41 +0100406 srcSize < 1 KB => 3 bytes (2-2-10-10)
Yann Colleta1249dc2016-01-25 04:22:03 +0100407 srcSize < 16KB => 4 bytes (2-2-14-14)
Yann Collet59d1f792016-01-23 19:28:41 +0100408 else => 5 bytes (2-2-18-18)
409 big endian convention
410
411 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
412 size : 5 bits: (IS_RAW<<6) + (0<<4) + size
413 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
414 size&255
415 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
416 size>>8&255
417 size&255
418
419 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
420 size : 5 bits: (IS_RLE<<6) + (0<<4) + size
421 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
422 size&255
423 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
424 size>>8&255
425 size&255
426
Yann Colleta1249dc2016-01-25 04:22:03 +0100427 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
428 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
429 srcSize < 1 KB => 3 bytes (2-2-10-10)
430 srcSize < 16KB => 4 bytes (2-2-14-14)
431 else => 5 bytes (2-2-18-18)
432 big endian convention
433
434 1- CTable available (stored into workspace ?)
Yann Colletb923f652016-01-26 03:14:20 +0100435 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
Yann Colleta1249dc2016-01-25 04:22:03 +0100436
Yann Collet59d1f792016-01-23 19:28:41 +0100437
438 1.2) Literal block content
439
440 1.2.1) Huff0 block, using sizes from header
441 See Huff0 format
442
Yann Colletfb810d62016-01-28 00:18:06 +0100443 1.2.2) Huff0 block, using prepared table
Yann Collet59d1f792016-01-23 19:28:41 +0100444
Yann Colletfb810d62016-01-28 00:18:06 +0100445 1.2.3) Raw content
Yann Collet59d1f792016-01-23 19:28:41 +0100446
Yann Colletfb810d62016-01-28 00:18:06 +0100447 1.2.4) single byte
Yann Collet59d1f792016-01-23 19:28:41 +0100448
449
450 2) Sequences section
Yann Colletfb810d62016-01-28 00:18:06 +0100451
452 - Nb Sequences : 2 bytes, little endian
453 - Control Token : 1 byte (see below)
454 - Dumps Length : 1 or 2 bytes (depending on control token)
455 - Dumps : as stated by dumps length
456 - Literal Lengths FSE table (as needed depending on encoding method)
457 - Offset Codes FSE table (as needed depending on encoding method)
458 - Match Lengths FSE table (as needed depending on encoding method)
459
460 2.1) Control Token
461 8 bits, divided as :
462 0-1 : dumpsLength
463 2-3 : MatchLength, FSE encoding method
464 4-5 : Offset Codes, FSE encoding method
465 6-7 : Literal Lengths, FSE encoding method
466
467 FSE encoding method :
468 FSE_ENCODING_RAW : uncompressed; no header
469 FSE_ENCODING_RLE : single repeated value; header 1 byte
470 FSE_ENCODING_STATIC : use prepared table; no header
471 FSE_ENCODING_DYNAMIC : read NCount
Yann Collet59d1f792016-01-23 19:28:41 +0100472*/
Yann Collet14983e72015-11-11 21:38:21 +0100473
Yann Colletd1b26842016-03-15 01:24:33 +0100474size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100475{
476 BYTE* const ostart = (BYTE* const)dst;
477
Yann Colletd1b26842016-03-15 01:24:33 +0100478 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100479 memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
480
481 /* Build header */
482 ostart[0] = (BYTE)(srcSize>>16);
483 ostart[1] = (BYTE)(srcSize>>8);
484 ostart[2] = (BYTE) srcSize;
485 ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
486
487 return ZSTD_blockHeaderSize+srcSize;
488}
489
490
Yann Colletd1b26842016-03-15 01:24:33 +0100491static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100492{
493 BYTE* const ostart = (BYTE* const)dst;
Yann Colleta910dc82016-03-18 12:37:45 +0100494 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100495
Yann Colletd1b26842016-03-15 01:24:33 +0100496 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100497
Yann Collet59d1f792016-01-23 19:28:41 +0100498 switch(flSize)
499 {
500 case 1: /* 2 - 1 - 5 */
501 ostart[0] = (BYTE)((IS_RAW<<6) + (0<<5) + srcSize);
502 break;
503 case 2: /* 2 - 2 - 12 */
504 ostart[0] = (BYTE)((IS_RAW<<6) + (2<<4) + (srcSize >> 8));
505 ostart[1] = (BYTE)srcSize;
506 break;
507 default: /*note : should not be necessary : flSize is within {1,2,3} */
508 case 3: /* 2 - 2 - 20 */
509 ostart[0] = (BYTE)((IS_RAW<<6) + (3<<4) + (srcSize >> 16));
510 ostart[1] = (BYTE)(srcSize>>8);
511 ostart[2] = (BYTE)srcSize;
512 break;
513 }
514
515 memcpy(ostart + flSize, src, srcSize);
516 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100517}
518
Yann Colletd1b26842016-03-15 01:24:33 +0100519static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100520{
521 BYTE* const ostart = (BYTE* const)dst;
Yann Colleta910dc82016-03-18 12:37:45 +0100522 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100523
Yann Colletd1b26842016-03-15 01:24:33 +0100524 (void)dstCapacity; /* dstCapacity guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100525
526 switch(flSize)
527 {
528 case 1: /* 2 - 1 - 5 */
529 ostart[0] = (BYTE)((IS_RLE<<6) + (0<<5) + srcSize);
530 break;
531 case 2: /* 2 - 2 - 12 */
532 ostart[0] = (BYTE)((IS_RLE<<6) + (2<<4) + (srcSize >> 8));
533 ostart[1] = (BYTE)srcSize;
534 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100535 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100536 case 3: /* 2 - 2 - 20 */
537 ostart[0] = (BYTE)((IS_RLE<<6) + (3<<4) + (srcSize >> 16));
538 ostart[1] = (BYTE)(srcSize>>8);
539 ostart[2] = (BYTE)srcSize;
540 break;
541 }
542
543 ostart[flSize] = *(const BYTE*)src;
544 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100545}
546
Yann Collet59d1f792016-01-23 19:28:41 +0100547
Yann Colleta5c2c082016-03-20 01:09:18 +0100548static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100549
Yann Colletb923f652016-01-26 03:14:20 +0100550static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100551 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100552 const void* src, size_t srcSize)
553{
Yann Colleta910dc82016-03-18 12:37:45 +0100554 size_t const minGain = ZSTD_minGain(srcSize);
555 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet14983e72015-11-11 21:38:21 +0100556 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100557 U32 singleStream = srcSize < 256;
Yann Colletb923f652016-01-26 03:14:20 +0100558 U32 hType = IS_HUF;
Yann Colleta910dc82016-03-18 12:37:45 +0100559 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100560
Yann Collet14983e72015-11-11 21:38:21 +0100561
Yann Colleta5c2c082016-03-20 01:09:18 +0100562 /* small ? don't even attempt compression (speed opt) */
563# define LITERAL_NOENTROPY 63
564 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
565 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
566 }
567
568 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Colletfb810d62016-01-28 00:18:06 +0100569 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletb923f652016-01-26 03:14:20 +0100570 hType = IS_PCH;
571 singleStream = 1;
Yann Colleta910dc82016-03-18 12:37:45 +0100572 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100573 } else {
Yann Colleta910dc82016-03-18 12:37:45 +0100574 cLitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12)
Yann Colletd1b26842016-03-15 01:24:33 +0100575 : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12);
Yann Colletb923f652016-01-26 03:14:20 +0100576 }
Yann Collet14983e72015-11-11 21:38:21 +0100577
Yann Colleta910dc82016-03-18 12:37:45 +0100578 if ((cLitSize==0) || (cLitSize >= srcSize - minGain))
579 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
580 if (cLitSize==1)
581 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100582
583 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100584 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100585 {
Yann Collet59d1f792016-01-23 19:28:41 +0100586 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletb923f652016-01-26 03:14:20 +0100587 ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6));
Yann Colleta910dc82016-03-18 12:37:45 +0100588 ostart[1] = (BYTE)((srcSize<<2) + (cLitSize>>8));
589 ostart[2] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100590 break;
591 case 4: /* 2 - 2 - 14 - 14 */
Yann Colletb923f652016-01-26 03:14:20 +0100592 ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100593 ostart[1] = (BYTE)(srcSize>> 2);
Yann Colleta910dc82016-03-18 12:37:45 +0100594 ostart[2] = (BYTE)((srcSize<<6) + (cLitSize>>8));
595 ostart[3] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100596 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100597 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100598 case 5: /* 2 - 2 - 18 - 18 */
Yann Colletb923f652016-01-26 03:14:20 +0100599 ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100600 ostart[1] = (BYTE)(srcSize>>6);
Yann Colleta910dc82016-03-18 12:37:45 +0100601 ostart[2] = (BYTE)((srcSize<<2) + (cLitSize>>16));
602 ostart[3] = (BYTE)(cLitSize>>8);
603 ostart[4] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100604 break;
Yann Collet14983e72015-11-11 21:38:21 +0100605 }
Yann Colleta910dc82016-03-18 12:37:45 +0100606 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100607}
608
609
Yann Colletb44be742016-03-26 20:52:14 +0100610void ZSTD_seqToCodes(const seqStore_t* seqStorePtr, size_t const nbSeq)
611{
612 /* LL codes */
613 { static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
614 8, 9, 10, 11, 12, 13, 14, 15,
615 16, 16, 17, 17, 18, 18, 19, 19,
616 20, 20, 20, 20, 21, 21, 21, 21,
617 22, 22, 22, 22, 22, 22, 22, 22,
618 23, 23, 23, 23, 23, 23, 23, 23,
619 24, 24, 24, 24, 24, 24, 24, 24,
620 24, 24, 24, 24, 24, 24, 24, 24 };
621 const BYTE LL_deltaCode = 19;
622 U16* const llTable = seqStorePtr->litLengthStart;
623 BYTE* const llCodeTable = seqStorePtr->llCodeStart;
624 size_t u;
625 for (u=0; u<nbSeq; u++) {
626 U32 ll = llTable[u];
627 if (llTable[u] == 65535) { ll = seqStorePtr->longLength; llTable[u] = (U16)ll; }
628 llCodeTable[u] = (ll>63) ? (BYTE)ZSTD_highbit(ll) + LL_deltaCode : LL_Code[ll];
629 } }
630
631 /* Offset codes */
632 { const U32* const offsetTable = seqStorePtr->offsetStart;
633 BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
634 size_t u;
635 for (u=0; u<nbSeq; u++) ofCodeTable[u] = (BYTE)ZSTD_highbit(offsetTable[u]);
636 }
637
638 /* ML codes */
639 { static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
640 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
641 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
642 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
643 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
644 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
645 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
646 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
647 const BYTE ML_deltaCode = 36;
648 U16* const mlTable = seqStorePtr->matchLengthStart;
649 BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
650 size_t u;
651 for (u=0; u<nbSeq; u++) {
652 U32 ml = mlTable[u];
653 if (mlTable[u] == 65535) { ml = seqStorePtr->longLength; mlTable[u] = (U16)ml; }
654 mlCodeTable[u] = (ml>127) ? (BYTE)ZSTD_highbit(ml) + ML_deltaCode : ML_Code[ml];
655 } }
656}
657
658
Yann Colletb923f652016-01-26 03:14:20 +0100659size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100660 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100661 size_t srcSize)
662{
Yann Colletb923f652016-01-26 03:14:20 +0100663 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100664 U32 count[MaxSeq+1];
665 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100666 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
667 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
668 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100669 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletb0aec172016-03-21 13:24:16 +0100670 U16* const llTable = seqStorePtr->litLengthStart;
Yann Colletfadda6c2016-03-22 12:14:26 +0100671 U16* const mlTable = seqStorePtr->matchLengthStart;
Yann Collet14983e72015-11-11 21:38:21 +0100672 const U32* const offsetTable = seqStorePtr->offsetStart;
Yann Colletd64f4352016-03-21 00:07:42 +0100673 const U32* const offsetTableEnd = seqStorePtr->offset;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100674 BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
Yann Collet597847a2016-03-20 19:14:22 +0100675 BYTE* const llCodeTable = seqStorePtr->llCodeStart;
Yann Colletfadda6c2016-03-22 12:14:26 +0100676 BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
Yann Collet5054ee02015-11-23 13:34:21 +0100677 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100678 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100679 BYTE* op = ostart;
Yann Colletd64f4352016-03-21 00:07:42 +0100680 size_t const nbSeq = offsetTableEnd - offsetTable;
Yann Collet14983e72015-11-11 21:38:21 +0100681 BYTE* seqHead;
682
Yann Collet14983e72015-11-11 21:38:21 +0100683 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100684 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100685 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100686 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100687 if (ZSTD_isError(cSize)) return cSize;
688 op += cSize;
689 }
690
691 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100692 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100693 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
694 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
695 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100696 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100697
Yann Colletbe391432016-03-22 23:19:28 +0100698 /* seqHead : flags for FSE encoding type */
699 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100700
Yann Colletfb810d62016-01-28 00:18:06 +0100701#define MIN_SEQ_FOR_DYNAMIC_FSE 64
702#define MAX_SEQ_FOR_STATIC_FSE 1000
703
Yann Colletb44be742016-03-26 20:52:14 +0100704 /* convert length/distances into codes */
705 ZSTD_seqToCodes(seqStorePtr, nbSeq);
Yann Collet597847a2016-03-20 19:14:22 +0100706
Yann Collet14983e72015-11-11 21:38:21 +0100707 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100708 { U32 max = MaxLL;
709 size_t const mostFrequent = FSE_countFast(count, &max, llCodeTable, nbSeq);
710 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
711 *op++ = llCodeTable[0];
712 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
713 LLtype = FSE_ENCODING_RLE;
714 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
715 LLtype = FSE_ENCODING_STATIC;
716 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
717 FSE_buildCTable(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog);
718 LLtype = FSE_ENCODING_RAW;
719 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100720 size_t nbSeq_1 = nbSeq;
721 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
722 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
723 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100724 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
725 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
726 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100727 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
728 LLtype = FSE_ENCODING_DYNAMIC;
729 } }
Yann Collet14983e72015-11-11 21:38:21 +0100730
Yann Colletb44be742016-03-26 20:52:14 +0100731 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100732 { U32 max = MaxOff;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100733 size_t const mostFrequent = FSE_countFast(count, &max, ofCodeTable, nbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100734 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100735 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100736 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
737 Offtype = FSE_ENCODING_RLE;
738 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
739 Offtype = FSE_ENCODING_STATIC;
740 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (Offbits-1)))) {
741 FSE_buildCTable_raw(CTable_OffsetBits, Offbits);
742 Offtype = FSE_ENCODING_RAW;
743 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100744 size_t nbSeq_1 = nbSeq;
745 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100746 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100747 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100748 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
749 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
750 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100751 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
752 Offtype = FSE_ENCODING_DYNAMIC;
753 } }
754
Yann Collet14983e72015-11-11 21:38:21 +0100755 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100756 { U32 max = MaxML;
757 size_t const mostFrequent = FSE_countFast(count, &max, mlCodeTable, nbSeq);
758 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100759 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100760 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
761 MLtype = FSE_ENCODING_RLE;
762 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
763 MLtype = FSE_ENCODING_STATIC;
764 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
765 FSE_buildCTable(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog);
766 MLtype = FSE_ENCODING_RAW;
767 } else {
768 size_t nbSeq_1 = nbSeq;
769 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
770 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
771 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
772 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
773 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
774 op += NCountSize; }
775 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
776 MLtype = FSE_ENCODING_DYNAMIC;
777 } }
Yann Collet14983e72015-11-11 21:38:21 +0100778
Yann Colletbe391432016-03-22 23:19:28 +0100779 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100780 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100781
782 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100783 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100784 FSE_CState_t stateMatchLength;
785 FSE_CState_t stateOffsetBits;
786 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100787
Yann Colleta910dc82016-03-18 12:37:45 +0100788 { size_t const errorCode = BIT_initCStream(&blockStream, op, oend-op);
Yann Collet597847a2016-03-20 19:14:22 +0100789 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100790
Yann Collet597847a2016-03-20 19:14:22 +0100791 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100792 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100793 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100794 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colletb0aec172016-03-21 13:24:16 +0100795 BIT_addBits(&blockStream, llTable[nbSeq-1], LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100796 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Collet25125972016-03-23 14:00:09 +0100797 BIT_addBits(&blockStream, mlTable[nbSeq-1], ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100798 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Collet646693e2016-03-24 02:31:27 +0100799 BIT_addBits(&blockStream, offsetTable[nbSeq-1], ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100800 BIT_flushBits(&blockStream);
801
Yann Colletfadda6c2016-03-22 12:14:26 +0100802 { size_t n;
803 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Colletb9151402016-03-26 17:18:11 +0100804 const BYTE ofCode = ofCodeTable[n];
Yann Collet7cbe79a2016-03-23 22:31:57 +0100805 const BYTE mlCode = mlCodeTable[n];
806 const BYTE llCode = llCodeTable[n];
807 const U32 llBits = LL_bits[llCode];
808 const U32 mlBits = ML_bits[mlCode];
Yann Colletb9151402016-03-26 17:18:11 +0100809 const U32 ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100810 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100811 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
812 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
813 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
814 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
815 if (MEM_32bits() || (ofBits+mlBits+llBits > 64-7-(LLFSELog+MLFSELog+OffFSELog)))
816 BIT_flushBits(&blockStream); /* (7)*/
Yann Collet7cbe79a2016-03-23 22:31:57 +0100817 BIT_addBits(&blockStream, llTable[n], llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100818 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100819 BIT_addBits(&blockStream, mlTable[n], mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100820 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
821 BIT_addBits(&blockStream, offsetTable[n], ofBits); /* 31 */
822 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100823 } }
Yann Collet14983e72015-11-11 21:38:21 +0100824
825 FSE_flushCState(&blockStream, &stateMatchLength);
826 FSE_flushCState(&blockStream, &stateOffsetBits);
827 FSE_flushCState(&blockStream, &stateLitLength);
828
Yann Colletb9151402016-03-26 17:18:11 +0100829 { size_t const streamSize = BIT_closeCStream(&blockStream);
830 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
831 op += streamSize;
832 } }
Yann Collet14983e72015-11-11 21:38:21 +0100833
834 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100835_check_compressibility:
Yann Colletfadda6c2016-03-22 12:14:26 +0100836 { size_t const minGain = ZSTD_minGain(srcSize);
837 size_t const maxCSize = srcSize - minGain;
838 if ((size_t)(op-ostart) >= maxCSize) return 0; }
Yann Collet14983e72015-11-11 21:38:21 +0100839
Yann Collet5054ee02015-11-23 13:34:21 +0100840 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100841}
842
843
Yann Collet95cd0c22016-03-08 18:24:21 +0100844/*! ZSTD_storeSeq() :
845 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
846 `offsetCode` : distance to match, or 0 == repCode.
847 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100848*/
849MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode)
850{
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100851#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100852 static const BYTE* g_start = NULL;
Yann Colletb0aec172016-03-21 13:24:16 +0100853 const U32 pos = (U32)(literals - g_start);
Yann Collet14983e72015-11-11 21:38:21 +0100854 if (g_start==NULL) g_start = literals;
Yann Colletb9151402016-03-26 17:18:11 +0100855 if ((pos > 200000000) && (pos < 200900000))
856 printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
Yann Collet433a5cc2016-03-25 11:43:48 +0100857 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +0100858#endif
inikepe29caf72016-03-04 19:52:23 +0100859#if ZSTD_OPT_DEBUG == 3
inikep15174b02016-02-23 12:41:56 +0100860 if (offsetCode == 0) seqStorePtr->realRepSum++;
861 seqStorePtr->realSeqSum++;
862 seqStorePtr->realMatchSum += matchCode;
863 seqStorePtr->realLitSum += litLength;
864#endif
Yann Collet14983e72015-11-11 21:38:21 +0100865
866 /* copy Literals */
867 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
868 seqStorePtr->lit += litLength;
869
870 /* literal Length */
Yann Colletfadda6c2016-03-22 12:14:26 +0100871 if (litLength>=65535) { *(seqStorePtr->litLength++) = 65535; seqStorePtr->longLength = (U32)litLength; }
Yann Colletd64f4352016-03-21 00:07:42 +0100872 else *seqStorePtr->litLength++ = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100873
874 /* match offset */
Yann Collet646693e2016-03-24 02:31:27 +0100875 *(seqStorePtr->offset++) = (U32)offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100876
877 /* match Length */
Yann Colletfadda6c2016-03-22 12:14:26 +0100878 if (matchCode>=65535) { *(seqStorePtr->matchLength++) = 65535; seqStorePtr->longLength = (U32)matchCode; }
879 else *seqStorePtr->matchLength++ = (U16)matchCode;
Yann Collet14983e72015-11-11 21:38:21 +0100880}
881
882
Yann Collet7d360282016-02-12 00:07:30 +0100883/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100884* Match length counter
885***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100886static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100887{
Yann Collet863ec402016-01-28 17:56:33 +0100888 if (MEM_isLittleEndian()) {
889 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100890# if defined(_MSC_VER) && defined(_WIN64)
891 unsigned long r = 0;
892 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100893 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100894# elif defined(__GNUC__) && (__GNUC__ >= 3)
895 return (__builtin_ctzll((U64)val) >> 3);
896# else
897 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 };
898 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
899# endif
Yann Collet863ec402016-01-28 17:56:33 +0100900 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100901# if defined(_MSC_VER)
902 unsigned long r=0;
903 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100904 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100905# elif defined(__GNUC__) && (__GNUC__ >= 3)
906 return (__builtin_ctz((U32)val) >> 3);
907# else
908 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 };
909 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
910# endif
911 }
Yann Collet863ec402016-01-28 17:56:33 +0100912 } else { /* Big Endian CPU */
913 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100914# if defined(_MSC_VER) && defined(_WIN64)
915 unsigned long r = 0;
916 _BitScanReverse64( &r, val );
917 return (unsigned)(r>>3);
918# elif defined(__GNUC__) && (__GNUC__ >= 3)
919 return (__builtin_clzll(val) >> 3);
920# else
921 unsigned r;
922 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
923 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
924 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
925 r += (!val);
926 return r;
927# endif
Yann Collet863ec402016-01-28 17:56:33 +0100928 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100929# if defined(_MSC_VER)
930 unsigned long r = 0;
931 _BitScanReverse( &r, (unsigned long)val );
932 return (unsigned)(r>>3);
933# elif defined(__GNUC__) && (__GNUC__ >= 3)
934 return (__builtin_clz((U32)val) >> 3);
935# else
936 unsigned r;
937 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
938 r += (!val);
939 return r;
940# endif
Yann Collet863ec402016-01-28 17:56:33 +0100941 } }
Yann Collet14983e72015-11-11 21:38:21 +0100942}
943
944
Yann Collet5054ee02015-11-23 13:34:21 +0100945static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100946{
947 const BYTE* const pStart = pIn;
948
Yann Colletfb810d62016-01-28 00:18:06 +0100949 while ((pIn<pInLimit-(sizeof(size_t)-1))) {
Yann Collet7d360282016-02-12 00:07:30 +0100950 size_t diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100951 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
952 pIn += ZSTD_NbCommonBytes(diff);
953 return (size_t)(pIn - pStart);
954 }
Yann Collet14983e72015-11-11 21:38:21 +0100955 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
956 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
957 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
958 return (size_t)(pIn - pStart);
959}
960
Yann Collet04b12d82016-02-11 06:23:24 +0100961/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100962* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100963* convention : on reaching mEnd, match count continue starting from iStart
964*/
965static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
966{
967 size_t matchLength;
968 const BYTE* vEnd = ip + (mEnd - match);
969 if (vEnd > iEnd) vEnd = iEnd;
970 matchLength = ZSTD_count(ip, match, vEnd);
971 if (match + matchLength == mEnd)
972 matchLength += ZSTD_count(ip+matchLength, iStart, iEnd);
973 return matchLength;
974}
975
Yann Collet14983e72015-11-11 21:38:21 +0100976
Yann Collet863ec402016-01-28 17:56:33 +0100977/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100978* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100979***************************************/
inikepcc52a972016-02-19 10:09:35 +0100980static const U32 prime3bytes = 506832829U;
981static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
inikepe2446b02016-03-07 10:07:08 +0100982static size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); }
inikepcc52a972016-02-19 10:09:35 +0100983
Yann Collet4b100f42015-10-30 15:49:48 +0100984static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100985static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100986static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100987
Yann Collet4b100f42015-10-30 15:49:48 +0100988static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100989static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100990static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100991
992static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100993static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100994static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100995
Yann Collet14983e72015-11-11 21:38:21 +0100996static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100997static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100998static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100999
Yann Collet5be2dd22015-11-11 13:43:58 +01001000static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001001{
1002 switch(mls)
1003 {
1004 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001005 case 4: return ZSTD_hash4Ptr(p, hBits);
1006 case 5: return ZSTD_hash5Ptr(p, hBits);
1007 case 6: return ZSTD_hash6Ptr(p, hBits);
1008 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001009 }
1010}
Yann Collet2acb5d32015-10-29 16:49:43 +01001011
Yann Collet863ec402016-01-28 17:56:33 +01001012
Yann Collet2ce49232016-02-02 14:36:49 +01001013/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001014* Fast Scan
1015***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001016static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1017{
1018 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001019 const U32 hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001020 const BYTE* const base = zc->base;
1021 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet2ce49232016-02-02 14:36:49 +01001022 const BYTE* const iend = ((const BYTE*)end) - 8;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001023 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001024
Yann Colletfb810d62016-01-28 00:18:06 +01001025 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001026 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001027 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001028 }
1029}
1030
1031
Yann Collet1f44b3f2015-11-05 17:32:18 +01001032FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001033void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc,
Yann Collet89db5e02015-11-13 11:27:46 +01001034 const void* src, size_t srcSize,
1035 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001036{
Yann Collet417890c2015-12-04 17:16:37 +01001037 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001038 const U32 hBits = zc->params.cParams.hashLog;
Yann Colletc3652152015-11-24 14:06:07 +01001039 seqStore_t* seqStorePtr = &(zc->seqStore);
1040 const BYTE* const base = zc->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001041 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001042 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001043 const BYTE* anchor = istart;
Yann Colletd94efbf2015-12-29 14:29:08 +01001044 const U32 lowIndex = zc->dictLimit;
1045 const BYTE* const lowest = base + lowIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001046 const BYTE* const iend = istart + srcSize;
1047 const BYTE* const ilimit = iend - 8;
Yann Collet89db5e02015-11-13 11:27:46 +01001048 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001049
Yann Collet1f44b3f2015-11-05 17:32:18 +01001050 /* init */
Yann Collet743402c2015-11-20 12:03:53 +01001051 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001052 if (ip < lowest+REPCODE_STARTVALUE) ip = lowest+REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001053
1054 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001055 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Collet5054ee02015-11-23 13:34:21 +01001056 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001057 size_t offset;
Yann Collet5be2dd22015-11-11 13:43:58 +01001058 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Colletd94efbf2015-12-29 14:29:08 +01001059 const U32 matchIndex = hashTable[h];
1060 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001061 const U32 current = (U32)(ip-base);
1062 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001063
Yann Colletfb810d62016-01-28 00:18:06 +01001064 if (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)) { /* note : by construction, offset_1 <= current */
Yann Collet5054ee02015-11-23 13:34:21 +01001065 mlCode = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +01001066 ip++;
1067 offset = 0;
Yann Colletfb810d62016-01-28 00:18:06 +01001068 } else {
Yann Colletd94efbf2015-12-29 14:29:08 +01001069 if ( (matchIndex <= lowIndex) ||
Yann Colletfb810d62016-01-28 00:18:06 +01001070 (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001071 ip += ((ip-anchor) >> g_searchStrength) + 1;
1072 continue;
1073 }
Yann Collet5054ee02015-11-23 13:34:21 +01001074 mlCode = ZSTD_count(ip+MINMATCH, match+MINMATCH, iend);
Yann Collet402fdcf2015-11-20 12:46:08 +01001075 offset = ip-match;
Yann Collet5054ee02015-11-23 13:34:21 +01001076 while ((ip>anchor) && (match>lowest) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001077 offset_2 = offset_1;
1078 offset_1 = offset;
1079 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001080
Yann Collet402fdcf2015-11-20 12:46:08 +01001081 /* match found */
Yann Collet6bcdeac2015-11-26 11:43:00 +01001082 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +01001083 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001084 anchor = ip;
1085
Yann Colletfb810d62016-01-28 00:18:06 +01001086 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001087 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001088 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 +01001089 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1090 /* check immediate repcode */
1091 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001092 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001093 /* store sequence */
Yann Collet70e45772016-03-19 18:08:32 +01001094 size_t const rlCode = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
1095 { size_t const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001096 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Collet06eade52015-11-23 14:23:47 +01001097 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rlCode);
1098 ip += rlCode+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001099 anchor = ip;
1100 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001101 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001102
Yann Collet70e45772016-03-19 18:08:32 +01001103 /* Last Literals */
1104 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001105 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1106 seqStorePtr->lit += lastLLSize;
1107 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001108}
1109
1110
Yann Collet82260dd2016-02-11 07:14:25 +01001111static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001112 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001113{
Yann Collet3b719252016-03-30 19:48:05 +02001114 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001115 switch(mls)
1116 {
1117 default:
1118 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001119 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001120 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001121 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001122 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001123 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001124 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001125 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001126 }
1127}
Yann Colletf3eca252015-10-22 15:31:46 +01001128
Yann Colletf3eca252015-10-22 15:31:46 +01001129
Yann Collet82260dd2016-02-11 07:14:25 +01001130static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001131 const void* src, size_t srcSize,
1132 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001133{
1134 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001135 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001136 seqStore_t* seqStorePtr = &(ctx->seqStore);
1137 const BYTE* const base = ctx->base;
1138 const BYTE* const dictBase = ctx->dictBase;
1139 const BYTE* const istart = (const BYTE*)src;
1140 const BYTE* ip = istart;
1141 const BYTE* anchor = istart;
1142 const U32 lowLimit = ctx->lowLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001143 const BYTE* const dictStart = dictBase + lowLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001144 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001145 const BYTE* const lowPrefixPtr = base + dictLimit;
1146 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001147 const BYTE* const iend = istart + srcSize;
1148 const BYTE* const ilimit = iend - 8;
1149
Yann Collet138e89c2015-11-17 14:26:54 +01001150 U32 offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001151
1152
1153 /* init */
1154 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001155 /* skip first position to avoid read overflow during repcode match check */
Yann Colletfb810d62016-01-28 00:18:06 +01001156 hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0);
Yann Collet61e16ce2016-01-31 02:04:15 +01001157 ip += REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001158
1159 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001160 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001161 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001162 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001163 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001164 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001165 const U32 current = (U32)(ip-base);
Yann Collet743402c2015-11-20 12:03:53 +01001166 const U32 repIndex = current + 1 - offset_1;
Yann Collet402fdcf2015-11-20 12:46:08 +01001167 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001168 const BYTE* repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001169 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001170 U32 offset;
Yann Collet89db5e02015-11-13 11:27:46 +01001171 hashTable[h] = current; /* update hash table */
1172
Yann Collet52447382016-03-20 16:00:00 +01001173 if ( ((repIndex >= dictLimit) || (repIndex <= dictLimit-4))
Yann Colletfb810d62016-01-28 00:18:06 +01001174 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001175 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001176 mlCode = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repMatchEnd, lowPrefixPtr);
Yann Collet743402c2015-11-20 12:03:53 +01001177 ip++;
Yann Collet402fdcf2015-11-20 12:46:08 +01001178 offset = 0;
Yann Colletfb810d62016-01-28 00:18:06 +01001179 } else {
Yann Collet402fdcf2015-11-20 12:46:08 +01001180 if ( (matchIndex < lowLimit) ||
Yann Collet52447382016-03-20 16:00:00 +01001181 (MEM_read32(match) != MEM_read32(ip)) ) {
1182 ip += ((ip-anchor) >> g_searchStrength) + 1;
1183 continue;
1184 }
1185 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001186 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1187 mlCode = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iend, matchEnd, lowPrefixPtr);
Yann Colletfb810d62016-01-28 00:18:06 +01001188 while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001189 offset = current - matchIndex;
1190 offset_2 = offset_1;
1191 offset_1 = offset;
Yann Colletfb810d62016-01-28 00:18:06 +01001192 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001193
Yann Collet5054ee02015-11-23 13:34:21 +01001194 /* found a match : store it */
1195 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset, mlCode);
Yann Collet5054ee02015-11-23 13:34:21 +01001196 ip += mlCode + MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001197 anchor = ip;
1198
Yann Colletfb810d62016-01-28 00:18:06 +01001199 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001200 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001201 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001202 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1203 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001204 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001205 U32 const current2 = (U32)(ip-base);
1206 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001207 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet743402c2015-11-20 12:03:53 +01001208 if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001209 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001210 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1211 size_t repLength2 = ZSTD_count_2segments(ip+MINMATCH, repMatch2+MINMATCH, iend, repEnd2, lowPrefixPtr);
1212 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1213 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2);
1214 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
1215 ip += repLength2+MINMATCH;
Yann Collet402fdcf2015-11-20 12:46:08 +01001216 anchor = ip;
1217 continue;
1218 }
Yann Collet743402c2015-11-20 12:03:53 +01001219 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001220 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001221
1222 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001223 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001224 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1225 seqStorePtr->lit += lastLLSize;
1226 }
Yann Collet89db5e02015-11-13 11:27:46 +01001227}
1228
1229
Yann Collet82260dd2016-02-11 07:14:25 +01001230static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001231 const void* src, size_t srcSize)
1232{
Yann Collet3b719252016-03-30 19:48:05 +02001233 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001234 switch(mls)
1235 {
1236 default:
1237 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001238 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001239 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001240 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001241 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001242 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001243 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001244 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001245 }
1246}
1247
1248
Yann Collet04b12d82016-02-11 06:23:24 +01001249/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001250* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001251***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001252/** ZSTD_insertBt1() : add one or multiple positions to tree.
1253* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001254* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001255static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1256 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001257{
1258 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001259 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet5be2dd22015-11-11 13:43:58 +01001260 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet1f44b3f2015-11-05 17:32:18 +01001261 U32* const bt = zc->contentTable;
Yann Collet3b719252016-03-30 19:48:05 +02001262 const U32 btLog = zc->params.cParams.contentLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001263 const U32 btMask= (1 << btLog) - 1;
1264 U32 matchIndex = hashTable[h];
1265 size_t commonLengthSmaller=0, commonLengthLarger=0;
1266 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001267 const BYTE* const dictBase = zc->dictBase;
1268 const U32 dictLimit = zc->dictLimit;
1269 const BYTE* const dictEnd = dictBase + dictLimit;
1270 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001271 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001272 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001273 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001274 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001275 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001276 U32 dummy32; /* to be nullified at the end */
Yann Collet03526e12015-11-23 15:29:15 +01001277 const U32 windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001278 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001279 size_t bestLength = 8;
Yann Collet7beaa052016-01-21 11:57:45 +01001280 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1281 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1282 predictedSmall += (predictedSmall>0);
1283 predictedLarge += (predictedLarge>0);
Yann Colletf48e35c2015-11-07 01:13:31 +01001284
Yann Collet6c3e2e72015-12-11 10:44:07 +01001285 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001286
Yann Colletfb810d62016-01-28 00:18:06 +01001287 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001288 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001289 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet04b12d82016-02-11 06:23:24 +01001290#if 1 /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001291 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001292 if (matchIndex == predictedSmall) {
1293 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001294 *smallerPtr = matchIndex;
1295 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1296 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1297 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001298 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001299 continue;
1300 }
Yann Colletfb810d62016-01-28 00:18:06 +01001301 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001302 *largerPtr = matchIndex;
1303 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1304 largerPtr = nextPtr;
1305 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001306 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001307 continue;
1308 }
Yann Collet04b12d82016-02-11 06:23:24 +01001309#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001310 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001311 match = base + matchIndex;
1312 if (match[matchLength] == ip[matchLength])
1313 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001314 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001315 match = dictBase + matchIndex;
1316 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1317 if (matchIndex+matchLength >= dictLimit)
1318 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1319 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001320
Yann Colletb8a6f682016-02-15 17:06:29 +01001321 if (matchLength > bestLength) {
1322 bestLength = matchLength;
1323 if (matchLength > matchEndIdx - matchIndex)
1324 matchEndIdx = matchIndex + (U32)matchLength;
1325 }
Yann Colletee3f4512015-12-29 22:26:09 +01001326
Yann Collet59d70632015-11-04 12:05:27 +01001327 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001328 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001329
Yann Colletfb810d62016-01-28 00:18:06 +01001330 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001331 /* match is smaller than current */
1332 *smallerPtr = matchIndex; /* update smaller idx */
1333 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001334 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001335 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001336 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001337 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001338 /* match is larger than current */
1339 *largerPtr = matchIndex;
1340 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001341 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001342 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001343 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001344 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001345
Yann Collet59d70632015-11-04 12:05:27 +01001346 *smallerPtr = *largerPtr = 0;
Yann Colletb8a6f682016-02-15 17:06:29 +01001347 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384));
1348 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1349 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001350}
1351
1352
Yann Collet82260dd2016-02-11 07:14:25 +01001353static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001354 ZSTD_CCtx* zc,
1355 const BYTE* const ip, const BYTE* const iend,
1356 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001357 U32 nbCompares, const U32 mls,
1358 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001359{
1360 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001361 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet03526e12015-11-23 15:29:15 +01001362 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
1363 U32* const bt = zc->contentTable;
Yann Collet3b719252016-03-30 19:48:05 +02001364 const U32 btLog = zc->params.cParams.contentLog - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001365 const U32 btMask= (1 << btLog) - 1;
1366 U32 matchIndex = hashTable[h];
1367 size_t commonLengthSmaller=0, commonLengthLarger=0;
1368 const BYTE* const base = zc->base;
1369 const BYTE* const dictBase = zc->dictBase;
1370 const U32 dictLimit = zc->dictLimit;
1371 const BYTE* const dictEnd = dictBase + dictLimit;
1372 const BYTE* const prefixStart = base + dictLimit;
1373 const U32 current = (U32)(ip-base);
1374 const U32 btLow = btMask >= current ? 0 : current - btMask;
1375 const U32 windowLow = zc->lowLimit;
1376 U32* smallerPtr = bt + 2*(current&btMask);
1377 U32* largerPtr = bt + 2*(current&btMask) + 1;
1378 size_t bestLength = 0;
Yann Collet72e84cf2015-12-31 19:08:44 +01001379 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001380 U32 dummy32; /* to be nullified at the end */
1381
Yann Collet6c3e2e72015-12-11 10:44:07 +01001382 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001383
Yann Colletfb810d62016-01-28 00:18:06 +01001384 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001385 U32* nextPtr = bt + 2*(matchIndex & btMask);
1386 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1387 const BYTE* match;
1388
Yann Colletfb810d62016-01-28 00:18:06 +01001389 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001390 match = base + matchIndex;
1391 if (match[matchLength] == ip[matchLength])
1392 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001393 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001394 match = dictBase + matchIndex;
1395 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001396 if (matchIndex+matchLength >= dictLimit)
1397 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001398 }
1399
Yann Colletfb810d62016-01-28 00:18:06 +01001400 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001401 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001402 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet03526e12015-11-23 15:29:15 +01001403 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
1404 bestLength = matchLength, *offsetPtr = current - matchIndex;
1405 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1406 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1407 }
1408
Yann Colletfb810d62016-01-28 00:18:06 +01001409 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001410 /* match is smaller than current */
1411 *smallerPtr = matchIndex; /* update smaller idx */
1412 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1413 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1414 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1415 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001416 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001417 /* match is larger than current */
1418 *largerPtr = matchIndex;
1419 commonLengthLarger = matchLength;
1420 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1421 largerPtr = nextPtr;
1422 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001423 } }
Yann Collet03526e12015-11-23 15:29:15 +01001424
1425 *smallerPtr = *largerPtr = 0;
1426
Yann Collet72e84cf2015-12-31 19:08:44 +01001427 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
Yann Collet03526e12015-11-23 15:29:15 +01001428 return bestLength;
1429}
1430
Yann Collet2cc12cb2016-01-01 07:47:58 +01001431
Yann Colletb8a6f682016-02-15 17:06:29 +01001432static 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 +01001433{
1434 const BYTE* const base = zc->base;
1435 const U32 target = (U32)(ip - base);
1436 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001437
1438 while(idx < target)
1439 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001440}
1441
Yann Collet52447382016-03-20 16:00:00 +01001442/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001443static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001444 ZSTD_CCtx* zc,
1445 const BYTE* const ip, const BYTE* const iLimit,
1446 size_t* offsetPtr,
1447 const U32 maxNbAttempts, const U32 mls)
1448{
1449 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001450 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001451 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1452}
1453
1454
Yann Collet768c6bc2016-02-10 14:01:49 +01001455static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001456 ZSTD_CCtx* zc, /* Index table will be updated */
1457 const BYTE* ip, const BYTE* const iLimit,
1458 size_t* offsetPtr,
1459 const U32 maxNbAttempts, const U32 matchLengthSearch)
1460{
1461 switch(matchLengthSearch)
1462 {
1463 default :
1464 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1465 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1466 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1467 }
1468}
1469
1470
Yann Colletb8a6f682016-02-15 17:06:29 +01001471static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1472{
1473 const BYTE* const base = zc->base;
1474 const U32 target = (U32)(ip - base);
1475 U32 idx = zc->nextToUpdate;
1476
1477 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1478}
1479
inikep805d2a72016-03-04 19:31:57 +01001480#include "zstd_opt.h"
Yann Collet2cc12cb2016-01-01 07:47:58 +01001481
Yann Collet03526e12015-11-23 15:29:15 +01001482/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001483static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001484 ZSTD_CCtx* zc,
1485 const BYTE* const ip, const BYTE* const iLimit,
1486 size_t* offsetPtr,
1487 const U32 maxNbAttempts, const U32 mls)
1488{
Yann Colletee3f4512015-12-29 22:26:09 +01001489 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001490 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001491 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001492}
1493
1494
Yann Collet82260dd2016-02-11 07:14:25 +01001495static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001496 ZSTD_CCtx* zc, /* Index table will be updated */
1497 const BYTE* ip, const BYTE* const iLimit,
1498 size_t* offsetPtr,
1499 const U32 maxNbAttempts, const U32 matchLengthSearch)
1500{
1501 switch(matchLengthSearch)
1502 {
1503 default :
1504 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1505 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1506 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1507 }
1508}
1509
1510
Yann Collet5106a762015-11-05 15:00:24 +01001511/* ***********************
1512* Hash Chain
1513*************************/
1514
Yann Collet1f44b3f2015-11-05 17:32:18 +01001515#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1516
Yann Collet6bcdeac2015-11-26 11:43:00 +01001517/* Update chains up to ip (excluded)
Yann Collet06eade52015-11-23 14:23:47 +01001518 Assumption : always within prefix (ie. not within extDict) */
Yann Collet6062b152016-02-16 17:41:03 +01001519FORCE_INLINE
1520U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
Yann Collet5106a762015-11-05 15:00:24 +01001521{
1522 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001523 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001524 U32* const chainTable = zc->contentTable;
Yann Collet3b719252016-03-30 19:48:05 +02001525 const U32 chainMask = (1 << zc->params.cParams.contentLog) - 1;
Yann Collet5106a762015-11-05 15:00:24 +01001526 const BYTE* const base = zc->base;
1527 const U32 target = (U32)(ip - base);
1528 U32 idx = zc->nextToUpdate;
1529
Yann Colletfb810d62016-01-28 00:18:06 +01001530 while(idx < target) {
Yann Collet52447382016-03-20 16:00:00 +01001531 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001532 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1533 hashTable[h] = idx;
1534 idx++;
1535 }
1536
1537 zc->nextToUpdate = target;
Yann Collet5be2dd22015-11-11 13:43:58 +01001538 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
Yann Collet5106a762015-11-05 15:00:24 +01001539}
1540
1541
1542FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
Yann Colletc1e52f02015-11-23 14:37:59 +01001543size_t ZSTD_HcFindBestMatch_generic (
Yann Collet5be2dd22015-11-11 13:43:58 +01001544 ZSTD_CCtx* zc, /* Index table will be updated */
Yann Collet5106a762015-11-05 15:00:24 +01001545 const BYTE* const ip, const BYTE* const iLimit,
1546 size_t* offsetPtr,
Yann Colletc1e52f02015-11-23 14:37:59 +01001547 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
Yann Collet287b7d92015-11-22 13:24:05 +01001548{
Yann Collet1f44b3f2015-11-05 17:32:18 +01001549 U32* const chainTable = zc->contentTable;
Yann Collet3b719252016-03-30 19:48:05 +02001550 const U32 chainSize = (1 << zc->params.cParams.contentLog);
Yann Collet5106a762015-11-05 15:00:24 +01001551 const U32 chainMask = chainSize-1;
1552 const BYTE* const base = zc->base;
1553 const BYTE* const dictBase = zc->dictBase;
1554 const U32 dictLimit = zc->dictLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001555 const BYTE* const prefixStart = base + dictLimit;
1556 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001557 const U32 lowLimit = zc->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001558 const U32 current = (U32)(ip-base);
1559 const U32 minChain = current > chainSize ? current - chainSize : 0;
Yann Collet5106a762015-11-05 15:00:24 +01001560 U32 matchIndex;
1561 const BYTE* match;
1562 int nbAttempts=maxNbAttempts;
Yann Collet5054ee02015-11-23 13:34:21 +01001563 size_t ml=MINMATCH-1;
Yann Collet5106a762015-11-05 15:00:24 +01001564
1565 /* HC4 match finder */
Yann Colletc1e52f02015-11-23 14:37:59 +01001566 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
Yann Collet5106a762015-11-05 15:00:24 +01001567
Yann Collet52447382016-03-20 16:00:00 +01001568 for ( ; (matchIndex>lowLimit) && (nbAttempts) ; nbAttempts--) {
Yann Collet5054ee02015-11-23 13:34:21 +01001569 size_t currentMl=0;
Yann Colletfb810d62016-01-28 00:18:06 +01001570 if ((!extDict) || matchIndex >= dictLimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001571 match = base + matchIndex;
Yann Collet4baee502015-11-09 03:19:33 +01001572 if (match[ml] == ip[ml]) /* potentially better */
Yann Collet5054ee02015-11-23 13:34:21 +01001573 currentMl = ZSTD_count(ip, match, iLimit);
Yann Colletfb810d62016-01-28 00:18:06 +01001574 } else {
Yann Collet5106a762015-11-05 15:00:24 +01001575 match = dictBase + matchIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001576 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1577 currentMl = ZSTD_count_2segments(ip+MINMATCH, match+MINMATCH, iLimit, dictEnd, prefixStart) + MINMATCH;
Yann Collet5106a762015-11-05 15:00:24 +01001578 }
1579
Yann Collet5054ee02015-11-23 13:34:21 +01001580 /* save best solution */
Yann Collet239cc282015-11-23 16:17:21 +01001581 if (currentMl > ml) { ml = currentMl; *offsetPtr = current - matchIndex; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }
Yann Collet5054ee02015-11-23 13:34:21 +01001582
Yann Collet9a24e592015-11-22 02:53:43 +01001583 if (matchIndex <= minChain) break;
Yann Collet5106a762015-11-05 15:00:24 +01001584 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1585 }
1586
1587 return ml;
1588}
1589
1590
Yann Colletc1e52f02015-11-23 14:37:59 +01001591FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1592 ZSTD_CCtx* zc,
Yann Collet5106a762015-11-05 15:00:24 +01001593 const BYTE* ip, const BYTE* const iLimit,
1594 size_t* offsetPtr,
1595 const U32 maxNbAttempts, const U32 matchLengthSearch)
1596{
1597 switch(matchLengthSearch)
1598 {
1599 default :
Yann Colletc1e52f02015-11-23 14:37:59 +01001600 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1601 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1602 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1603 }
1604}
1605
1606
1607FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1608 ZSTD_CCtx* zc,
1609 const BYTE* ip, const BYTE* const iLimit,
1610 size_t* offsetPtr,
1611 const U32 maxNbAttempts, const U32 matchLengthSearch)
1612{
1613 switch(matchLengthSearch)
1614 {
1615 default :
1616 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1617 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1618 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001619 }
1620}
1621
1622
Yann Collet287b7d92015-11-22 13:24:05 +01001623/* *******************************
Yann Collet9a24e592015-11-22 02:53:43 +01001624* Common parser - lazy strategy
Yann Collet287b7d92015-11-22 13:24:05 +01001625*********************************/
Yann Collet5106a762015-11-05 15:00:24 +01001626FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001627void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1628 const void* src, size_t srcSize,
Yann Collet007c1c62015-11-22 02:42:28 +01001629 const U32 searchMethod, const U32 depth)
Yann Collet5106a762015-11-05 15:00:24 +01001630{
1631 seqStore_t* seqStorePtr = &(ctx->seqStore);
1632 const BYTE* const istart = (const BYTE*)src;
1633 const BYTE* ip = istart;
1634 const BYTE* anchor = istart;
1635 const BYTE* const iend = istart + srcSize;
1636 const BYTE* const ilimit = iend - 8;
Yann Collete47c4e52015-12-05 09:23:53 +01001637 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet5106a762015-11-05 15:00:24 +01001638
1639 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet3b719252016-03-30 19:48:05 +02001640 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
1641 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet5106a762015-11-05 15:00:24 +01001642
Yann Collet5be2dd22015-11-11 13:43:58 +01001643 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
Yann Collet5106a762015-11-05 15:00:24 +01001644 size_t* offsetPtr,
1645 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet5be2dd22015-11-11 13:43:58 +01001646 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet5106a762015-11-05 15:00:24 +01001647
1648 /* init */
1649 ZSTD_resetSeqStore(seqStorePtr);
Yann Collete47c4e52015-12-05 09:23:53 +01001650 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet5106a762015-11-05 15:00:24 +01001651
1652 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001653 while (ip < ilimit) {
Yann Collet7a231792015-11-21 15:27:35 +01001654 size_t matchLength=0;
1655 size_t offset=0;
1656 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001657
Yann Collet743402c2015-11-20 12:03:53 +01001658 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001659 if (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1)) {
Yann Collet743402c2015-11-20 12:03:53 +01001660 /* repcode : we take it */
Yann Collet7a231792015-11-21 15:27:35 +01001661 matchLength = ZSTD_count(ip+1+MINMATCH, ip+1+MINMATCH-offset_1, iend) + MINMATCH;
Yann Collet007c1c62015-11-22 02:42:28 +01001662 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001663 }
1664
Yann Collet70e45772016-03-19 18:08:32 +01001665 /* first search (depth 0) */
1666 { size_t offsetFound = 99999999;
1667 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
Yann Collet239cc282015-11-23 16:17:21 +01001668 if (ml2 > matchLength)
1669 matchLength = ml2, start = ip, offset=offsetFound;
1670 }
Yann Collet9a24e592015-11-22 02:53:43 +01001671
Yann Colletfb810d62016-01-28 00:18:06 +01001672 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001673 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1674 continue;
1675 }
Yann Collet5106a762015-11-05 15:00:24 +01001676
1677 /* let's try to find a better solution */
Yann Collet007c1c62015-11-22 02:42:28 +01001678 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001679 while (ip<ilimit) {
Yann Collet5106a762015-11-05 15:00:24 +01001680 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001681 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet70e45772016-03-19 18:08:32 +01001682 size_t const mlRep = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1683 int const gain2 = (int)(mlRep * 3);
1684 int const gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet007c1c62015-11-22 02:42:28 +01001685 if ((mlRep >= MINMATCH) && (gain2 > gain1))
1686 matchLength = mlRep, offset = 0, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001687 }
Yann Collet70e45772016-03-19 18:08:32 +01001688 { size_t offset2=99999999;
1689 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1690 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1691 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001692 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001693 matchLength = ml2, offset = offset2, start = ip;
Yann Collet5106a762015-11-05 15:00:24 +01001694 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001695 } }
Yann Collet5106a762015-11-05 15:00:24 +01001696
1697 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001698 if ((depth==2) && (ip<ilimit)) {
Yann Collet5106a762015-11-05 15:00:24 +01001699 ip ++;
Yann Colletfb810d62016-01-28 00:18:06 +01001700 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - offset_1))) {
Yann Collet70e45772016-03-19 18:08:32 +01001701 size_t const ml2 = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_1, iend) + MINMATCH;
1702 int const gain2 = (int)(ml2 * 4);
1703 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet4baee502015-11-09 03:19:33 +01001704 if ((ml2 >= MINMATCH) && (gain2 > gain1))
Yann Collet5106a762015-11-05 15:00:24 +01001705 matchLength = ml2, offset = 0, start = ip;
1706 }
Yann Collet70e45772016-03-19 18:08:32 +01001707 { size_t offset2=99999999;
1708 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1709 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1710 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001711 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet628065c2015-11-06 18:44:54 +01001712 matchLength = ml2, offset = offset2, start = ip;
1713 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001714 } } }
Yann Collet5106a762015-11-05 15:00:24 +01001715 break; /* nothing found : store previous solution */
1716 }
1717
Yann Collet6062b152016-02-16 17:41:03 +01001718 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001719 if (offset) {
Yann Collete47c4e52015-12-05 09:23:53 +01001720 while ((start>anchor) && (start>base+offset) && (start[-1] == start[-1-offset])) /* only search for offset within prefix */
Yann Collet4baee502015-11-09 03:19:33 +01001721 { start--; matchLength++; }
Yann Collet743402c2015-11-20 12:03:53 +01001722 offset_2 = offset_1; offset_1 = offset;
Yann Collet4baee502015-11-09 03:19:33 +01001723 }
1724
1725 /* store sequence */
Yann Collet7a231792015-11-21 15:27:35 +01001726_storeSequence:
Yann Collet70e45772016-03-19 18:08:32 +01001727 { size_t const litLength = start - anchor;
Yann Collet5106a762015-11-05 15:00:24 +01001728 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
Yann Collet4baee502015-11-09 03:19:33 +01001729 anchor = ip = start + matchLength;
Yann Collet5106a762015-11-05 15:00:24 +01001730 }
1731
Yann Collet743402c2015-11-20 12:03:53 +01001732 /* check immediate repcode */
1733 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001734 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet743402c2015-11-20 12:03:53 +01001735 /* store sequence */
1736 matchLength = ZSTD_count(ip+MINMATCH, ip+MINMATCH-offset_2, iend);
1737 offset = offset_2;
1738 offset_2 = offset_1;
1739 offset_1 = offset;
1740 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength);
1741 ip += matchLength+MINMATCH;
1742 anchor = ip;
1743 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001744 } }
Yann Collet5106a762015-11-05 15:00:24 +01001745
1746 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001747 { size_t const lastLLSize = iend - anchor;
Yann Collet5106a762015-11-05 15:00:24 +01001748 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1749 seqStorePtr->lit += lastLLSize;
1750 }
Yann Collet5106a762015-11-05 15:00:24 +01001751}
1752
inikepe2bfe242016-01-31 11:25:48 +01001753
inikepd3b8d7a2016-02-22 10:06:17 +01001754static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01001755{
inikep4ab9c912016-03-04 19:17:31 +01001756 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 2);
inikepe2bfe242016-01-31 11:25:48 +01001757}
1758
Yann Collet59d1f792016-01-23 19:28:41 +01001759static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001760{
Yann Colleta1249dc2016-01-25 04:22:03 +01001761 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001762}
1763
Yann Collet59d1f792016-01-23 19:28:41 +01001764static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001765{
Yann Colleta1249dc2016-01-25 04:22:03 +01001766 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
Yann Collet5106a762015-11-05 15:00:24 +01001767}
1768
Yann Collet59d1f792016-01-23 19:28:41 +01001769static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5106a762015-11-05 15:00:24 +01001770{
Yann Colleta1249dc2016-01-25 04:22:03 +01001771 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
Yann Collet5106a762015-11-05 15:00:24 +01001772}
1773
Yann Collet59d1f792016-01-23 19:28:41 +01001774static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01001775{
Yann Colleta1249dc2016-01-25 04:22:03 +01001776 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
Yann Colletbe2010e2015-10-31 12:57:14 +01001777}
1778
1779
Yann Collet9a24e592015-11-22 02:53:43 +01001780FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001781void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1782 const void* src, size_t srcSize,
Yann Collet9a24e592015-11-22 02:53:43 +01001783 const U32 searchMethod, const U32 depth)
1784{
1785 seqStore_t* seqStorePtr = &(ctx->seqStore);
1786 const BYTE* const istart = (const BYTE*)src;
1787 const BYTE* ip = istart;
1788 const BYTE* anchor = istart;
1789 const BYTE* const iend = istart + srcSize;
1790 const BYTE* const ilimit = iend - 8;
1791 const BYTE* const base = ctx->base;
1792 const U32 dictLimit = ctx->dictLimit;
1793 const BYTE* const prefixStart = base + dictLimit;
1794 const BYTE* const dictBase = ctx->dictBase;
1795 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Colletc3652152015-11-24 14:06:07 +01001796 const BYTE* const dictStart = dictBase + ctx->lowLimit;
Yann Collet9a24e592015-11-22 02:53:43 +01001797
1798 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet3b719252016-03-30 19:48:05 +02001799 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
1800 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet9a24e592015-11-22 02:53:43 +01001801
1802 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1803 size_t* offsetPtr,
1804 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet03526e12015-11-23 15:29:15 +01001805 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
Yann Collet9a24e592015-11-22 02:53:43 +01001806
1807 /* init */
1808 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet6c3e2e72015-12-11 10:44:07 +01001809 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
Yann Collet9a24e592015-11-22 02:53:43 +01001810
1811 /* Match Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001812 while (ip < ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001813 size_t matchLength=0;
1814 size_t offset=0;
1815 const BYTE* start=ip+1;
1816 U32 current = (U32)(ip-base);
1817
1818 /* check repCode */
1819 {
1820 const U32 repIndex = (U32)(current+1 - offset_1);
1821 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1822 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001823 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001824 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001825 /* repcode detected we should take it */
1826 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001827 matchLength = ZSTD_count_2segments(ip+1+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
Yann Collet9a24e592015-11-22 02:53:43 +01001828 if (depth==0) goto _storeSequence;
Yann Colletfb810d62016-01-28 00:18:06 +01001829 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001830
Yann Collet70e45772016-03-19 18:08:32 +01001831 /* first search (depth 0) */
1832 { size_t offsetFound = 99999999;
1833 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
Yann Collet239cc282015-11-23 16:17:21 +01001834 if (ml2 > matchLength)
1835 matchLength = ml2, start = ip, offset=offsetFound;
1836 }
Yann Collet9a24e592015-11-22 02:53:43 +01001837
Yann Colletfb810d62016-01-28 00:18:06 +01001838 if (matchLength < MINMATCH) {
Yann Collet239cc282015-11-23 16:17:21 +01001839 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1840 continue;
1841 }
Yann Collet9a24e592015-11-22 02:53:43 +01001842
1843 /* let's try to find a better solution */
1844 if (depth>=1)
Yann Colletfb810d62016-01-28 00:18:06 +01001845 while (ip<ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001846 ip ++;
1847 current++;
1848 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001849 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001850 const U32 repIndex = (U32)(current - offset_1);
1851 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1852 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001853 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001854 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001855 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001856 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet70e45772016-03-19 18:08:32 +01001857 size_t const repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1858 int const gain2 = (int)(repLength * 3);
1859 int const gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
Yann Collet5054ee02015-11-23 13:34:21 +01001860 if ((repLength >= MINMATCH) && (gain2 > gain1))
1861 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001862 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001863
1864 /* search match, depth 1 */
Yann Collet70e45772016-03-19 18:08:32 +01001865 { size_t offset2=99999999;
1866 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1867 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1868 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
Yann Colletfb810d62016-01-28 00:18:06 +01001869 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001870 matchLength = ml2, offset = offset2, start = ip;
1871 continue; /* search a better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001872 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001873
1874 /* let's find an even better one */
Yann Colletfb810d62016-01-28 00:18:06 +01001875 if ((depth==2) && (ip<ilimit)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001876 ip ++;
1877 current++;
1878 /* check repCode */
Yann Colletfb810d62016-01-28 00:18:06 +01001879 if (offset) {
Yann Collet9a24e592015-11-22 02:53:43 +01001880 const U32 repIndex = (U32)(current - offset_1);
1881 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1882 const BYTE* const repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001883 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001884 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001885 /* repcode detected */
Yann Collet9a24e592015-11-22 02:53:43 +01001886 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001887 size_t repLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1888 int gain2 = (int)(repLength * 4);
1889 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1890 if ((repLength >= MINMATCH) && (gain2 > gain1))
1891 matchLength = repLength, offset = 0, start = ip;
Yann Colletfb810d62016-01-28 00:18:06 +01001892 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001893
1894 /* search match, depth 2 */
Yann Collet70e45772016-03-19 18:08:32 +01001895 { size_t offset2=99999999;
1896 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1897 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1898 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
Yann Colletfb810d62016-01-28 00:18:06 +01001899 if ((ml2 >= MINMATCH) && (gain2 > gain1)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001900 matchLength = ml2, offset = offset2, start = ip;
1901 continue;
Yann Colletfb810d62016-01-28 00:18:06 +01001902 } } }
Yann Collet9a24e592015-11-22 02:53:43 +01001903 break; /* nothing found : store previous solution */
1904 }
1905
1906 /* catch up */
Yann Colletfb810d62016-01-28 00:18:06 +01001907 if (offset) {
Yann Colletc3652152015-11-24 14:06:07 +01001908 U32 matchIndex = (U32)((start-base) - offset);
1909 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1910 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
1911 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet9a24e592015-11-22 02:53:43 +01001912 offset_2 = offset_1; offset_1 = offset;
1913 }
1914
1915 /* store sequence */
1916_storeSequence:
Yann Collet52447382016-03-20 16:00:00 +01001917 { size_t const litLength = start - anchor;
Yann Collet9a24e592015-11-22 02:53:43 +01001918 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1919 anchor = ip = start + matchLength;
1920 }
1921
1922 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001923 while (ip <= ilimit) {
Yann Collet9a24e592015-11-22 02:53:43 +01001924 const U32 repIndex = (U32)((ip-base) - offset_2);
1925 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1926 const BYTE* const repMatch = repBase + repIndex;
Yann Collet239cc282015-11-23 16:17:21 +01001927 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
Yann Colletfb810d62016-01-28 00:18:06 +01001928 if (MEM_read32(ip) == MEM_read32(repMatch)) {
Yann Collet9a24e592015-11-22 02:53:43 +01001929 /* repcode detected we should take it */
1930 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001931 matchLength = ZSTD_count_2segments(ip+MINMATCH, repMatch+MINMATCH, iend, repEnd, prefixStart) + MINMATCH;
1932 offset = offset_2; offset_2 = offset_1; offset_1 = offset; /* swap offset history */
Yann Collet9a24e592015-11-22 02:53:43 +01001933 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1934 ip += matchLength;
1935 anchor = ip;
1936 continue; /* faster when present ... (?) */
1937 }
1938 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001939 } }
Yann Collet9a24e592015-11-22 02:53:43 +01001940
1941 /* Last Literals */
Yann Collet52447382016-03-20 16:00:00 +01001942 { size_t const lastLLSize = iend - anchor;
Yann Collet9a24e592015-11-22 02:53:43 +01001943 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1944 seqStorePtr->lit += lastLLSize;
1945 }
Yann Collet9a24e592015-11-22 02:53:43 +01001946}
1947
Yann Collet59d1f792016-01-23 19:28:41 +01001948void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01001949{
Yann Colleta1249dc2016-01-25 04:22:03 +01001950 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01001951}
1952
Yann Collet59d1f792016-01-23 19:28:41 +01001953static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01001954{
Yann Colleta1249dc2016-01-25 04:22:03 +01001955 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01001956}
Yann Collet9a24e592015-11-22 02:53:43 +01001957
Yann Collet59d1f792016-01-23 19:28:41 +01001958static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01001959{
Yann Colleta1249dc2016-01-25 04:22:03 +01001960 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01001961}
1962
Yann Collet59d1f792016-01-23 19:28:41 +01001963static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01001964{
Yann Colleta1249dc2016-01-25 04:22:03 +01001965 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001966}
1967
inikepd3b8d7a2016-02-22 10:06:17 +01001968static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01001969{
inikep4ab9c912016-03-04 19:17:31 +01001970 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 2);
inikepe2bfe242016-01-31 11:25:48 +01001971}
1972
Yann Collet7a231792015-11-21 15:27:35 +01001973
Yann Collet59d1f792016-01-23 19:28:41 +01001974typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01001975
Yann Colletb923f652016-01-26 03:14:20 +01001976static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01001977{
inikepd3b8d7a2016-02-22 10:06:17 +01001978 static const ZSTD_blockCompressor blockCompressor[2][6] = {
1979 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt },
1980 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01001981 };
1982
1983 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01001984}
1985
1986
Yann Colletd1b26842016-03-15 01:24:33 +01001987static 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 +01001988{
Yann Collet3b719252016-03-30 19:48:05 +02001989 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01001990 if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */
Yann Collet59d1f792016-01-23 19:28:41 +01001991 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01001992 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01001993}
1994
1995
Yann Collet2ce49232016-02-02 14:36:49 +01001996static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +01001997 void* dst, size_t dstCapacity,
Yann Colletf3eca252015-10-22 15:31:46 +01001998 const void* src, size_t srcSize)
1999{
Yann Collet2ce49232016-02-02 14:36:49 +01002000 size_t blockSize = zc->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002001 size_t remaining = srcSize;
2002 const BYTE* ip = (const BYTE*)src;
2003 BYTE* const ostart = (BYTE*)dst;
2004 BYTE* op = ostart;
Yann Collet3b719252016-03-30 19:48:05 +02002005 const U32 maxDist = 1 << zc->params.cParams.windowLog;
inikepe29caf72016-03-04 19:52:23 +01002006#if ZSTD_OPT_DEBUG == 3
inikep15174b02016-02-23 12:41:56 +01002007 seqStore_t* ssPtr = &zc->seqStore;
inikepe0010e92016-02-23 16:25:04 +01002008 static U32 priceFunc = 0;
inikepe0010e92016-02-23 16:25:04 +01002009 ssPtr->realMatchSum = ssPtr->realLitSum = ssPtr->realSeqSum = ssPtr->realRepSum = 1;
2010 ssPtr->priceFunc = priceFunc;
inikepe29caf72016-03-04 19:52:23 +01002011#endif
Yann Collet9b11b462015-11-01 12:40:22 +01002012
Yann Collet2ce49232016-02-02 14:36:49 +01002013 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01002014 size_t cSize;
2015
Yann Colletd1b26842016-03-15 01:24:33 +01002016 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 +01002017 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002018
Yann Collet70e45772016-03-19 18:08:32 +01002019 if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) {
2020 /* enforce maxDist */
2021 U32 const newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist;
Yann Collet7a6343f2016-02-02 16:00:50 +01002022 if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002023 if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002024 }
Yann Collet89db5e02015-11-13 11:27:46 +01002025
Yann Colletd1b26842016-03-15 01:24:33 +01002026 cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
Yann Collet3e358272015-11-04 18:19:39 +01002027 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002028
Yann Collet2ce49232016-02-02 14:36:49 +01002029 if (cSize == 0) { /* block is not compressible */
Yann Colletd1b26842016-03-15 01:24:33 +01002030 cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize);
Yann Collet523b5942016-01-09 02:10:40 +01002031 if (ZSTD_isError(cSize)) return cSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002032 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01002033 op[0] = (BYTE)(cSize>>16);
2034 op[1] = (BYTE)(cSize>>8);
2035 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01002036 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01002037 cSize += 3;
2038 }
2039
2040 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002041 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002042 ip += blockSize;
2043 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002044 }
2045
inikepf647d992016-02-29 12:33:08 +01002046#if ZSTD_OPT_DEBUG == 3
inikep15174b02016-02-23 12:41:56 +01002047 ssPtr->realMatchSum += ssPtr->realSeqSum * ((zc->params.searchLength == 3) ? 3 : 4);
inikepe0010e92016-02-23 16:25:04 +01002048 printf("avgMatchL=%.2f avgLitL=%.2f match=%.1f%% lit=%.1f%% reps=%d seq=%d priceFunc=%d\n", (float)ssPtr->realMatchSum/ssPtr->realSeqSum, (float)ssPtr->realLitSum/ssPtr->realSeqSum, 100.0*ssPtr->realMatchSum/(ssPtr->realMatchSum+ssPtr->realLitSum), 100.0*ssPtr->realLitSum/(ssPtr->realMatchSum+ssPtr->realLitSum), ssPtr->realRepSum, ssPtr->realSeqSum, ssPtr->priceFunc);
2049 priceFunc++;
inikep15174b02016-02-23 12:41:56 +01002050#endif
2051
Yann Colletf3eca252015-10-22 15:31:46 +01002052 return op-ostart;
2053}
2054
2055
Yann Colletbf42c8e2016-01-09 01:08:23 +01002056static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002057 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002058 const void* src, size_t srcSize,
2059 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01002060{
Yann Collet2acb5d32015-10-29 16:49:43 +01002061 const BYTE* const ip = (const BYTE*) src;
Yann Colletecd651b2016-01-07 15:35:18 +01002062 size_t hbSize = 0;
2063
Yann Collet2ce49232016-02-02 14:36:49 +01002064 if (frame && (zc->stage==0)) {
Yann Colletecd651b2016-01-07 15:35:18 +01002065 hbSize = zc->hbSize;
Yann Collet7cbe79a2016-03-23 22:31:57 +01002066 if (dstCapacity <= hbSize) return ERROR(dstSize_tooSmall);
Yann Colletecd651b2016-01-07 15:35:18 +01002067 zc->stage = 1;
2068 memcpy(dst, zc->headerBuffer, hbSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002069 dstCapacity -= hbSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002070 dst = (char*)dst + hbSize;
2071 }
Yann Colletf3eca252015-10-22 15:31:46 +01002072
Yann Collet417890c2015-12-04 17:16:37 +01002073 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01002074 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002075 /* not contiguous */
Yann Collet70e45772016-03-19 18:08:32 +01002076 size_t const delta = zc->nextSrc - ip;
Yann Collet417890c2015-12-04 17:16:37 +01002077 zc->lowLimit = zc->dictLimit;
2078 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2079 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01002080 zc->base -= delta;
2081 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01002082 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002083 }
2084
Yann Collet89db5e02015-11-13 11:27:46 +01002085 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01002086 if (zc->lowLimit > (1<<30)) {
Yann Collet3b719252016-03-30 19:48:05 +02002087 U32 const btplus = (zc->params.cParams.strategy == ZSTD_btlazy2) || (zc->params.cParams.strategy == ZSTD_btopt);
2088 U32 const contentMask = (1 << (zc->params.cParams.contentLog - btplus)) - 1;
Yann Collet70e45772016-03-19 18:08:32 +01002089 U32 const newLowLimit = zc->lowLimit & contentMask; /* preserve position % contentSize */
2090 U32 const correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002091 ZSTD_reduceIndex(zc, correction);
2092 zc->base += correction;
2093 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002094 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002095 zc->dictLimit -= correction;
2096 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2097 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01002098 }
2099
Yann Colletbf42c8e2016-01-09 01:08:23 +01002100 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01002101 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01002102 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2103 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002104 }
2105
Yann Colletc3652152015-11-24 14:06:07 +01002106 zc->nextSrc = ip + srcSize;
Yann Collet70e45772016-03-19 18:08:32 +01002107 { size_t const cSize = frame ?
Yann Collet7cbe79a2016-03-23 22:31:57 +01002108 ZSTD_compress_generic (zc, dst, dstCapacity, src, srcSize) :
2109 ZSTD_compressBlock_internal (zc, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002110 if (ZSTD_isError(cSize)) return cSize;
2111 return cSize + hbSize;
2112 }
Yann Colletf3eca252015-10-22 15:31:46 +01002113}
2114
Yann Colletbf42c8e2016-01-09 01:08:23 +01002115
2116size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002117 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002118 const void* src, size_t srcSize)
2119{
Yann Collet7cbe79a2016-03-23 22:31:57 +01002120 return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 1);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002121}
2122
2123
Yann Colletd1b26842016-03-15 01:24:33 +01002124size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002125{
Yann Collet569b81a2016-03-16 15:26:51 +01002126 if (srcSize > ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
Yann Collet3b719252016-03-30 19:48:05 +02002127 zc->params.cParams.searchLength = MINMATCH; /* force ZSTD_btopt to MINMATCH in block mode */
inikepa4dde252016-03-01 14:14:35 +01002128 ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.searchLength);
Yann Colletd1b26842016-03-15 01:24:33 +01002129 return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002130}
2131
2132
Yann Colletb923f652016-01-26 03:14:20 +01002133static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002134{
2135 const BYTE* const ip = (const BYTE*) src;
2136 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002137
Yann Collet417890c2015-12-04 17:16:37 +01002138 /* input becomes current prefix */
2139 zc->lowLimit = zc->dictLimit;
2140 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2141 zc->dictBase = zc->base;
2142 zc->base += ip - zc->nextSrc;
2143 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002144 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002145
2146 zc->nextSrc = iend;
2147 if (srcSize <= 8) return 0;
2148
Yann Collet3b719252016-03-30 19:48:05 +02002149 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002150 {
2151 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002152 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002153 break;
2154
2155 case ZSTD_greedy:
2156 case ZSTD_lazy:
2157 case ZSTD_lazy2:
Yann Collet3b719252016-03-30 19:48:05 +02002158 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002159 break;
2160
2161 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002162 case ZSTD_btopt:
Yann Collet3b719252016-03-30 19:48:05 +02002163 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002164 break;
2165
2166 default:
2167 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2168 }
2169
Yann Collet2ce49232016-02-02 14:36:49 +01002170 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002171 return 0;
2172}
2173
2174
Yann Colletb923f652016-01-26 03:14:20 +01002175/* Dictionary format :
2176 Magic == ZSTD_DICT_MAGIC (4 bytes)
Yann Colletfb797352016-03-13 11:08:40 +01002177 HUF_writeCTable(256)
Yann Colletb923f652016-01-26 03:14:20 +01002178 Dictionary content
2179*/
Yann Colletfb797352016-03-13 11:08:40 +01002180/*! ZSTD_loadDictEntropyStats() :
Yann Colletb923f652016-01-26 03:14:20 +01002181 @return : size read from dictionary */
2182static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2183{
2184 /* note : magic number already checked */
Yann Colletfb810d62016-01-28 00:18:06 +01002185 size_t offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize, errorCode;
2186 short offcodeNCount[MaxOff+1];
2187 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2188 short matchlengthNCount[MaxML+1];
2189 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2190 short litlengthNCount[MaxLL+1];
2191 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2192
Yann Collet70e45772016-03-19 18:08:32 +01002193 size_t const hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize);
Yann Colletb923f652016-01-26 03:14:20 +01002194 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Colletfb810d62016-01-28 00:18:06 +01002195 zc->flagStaticTables = 1;
2196 dict = (const char*)dict + hufHeaderSize;
2197 dictSize -= hufHeaderSize;
2198
2199 offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
2200 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2201 errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2202 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2203 dict = (const char*)dict + offcodeHeaderSize;
2204 dictSize -= offcodeHeaderSize;
2205
2206 matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
2207 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2208 errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2209 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2210 dict = (const char*)dict + matchlengthHeaderSize;
2211 dictSize -= matchlengthHeaderSize;
2212
2213 litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
2214 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2215 errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2216 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2217
2218 return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
Yann Colletb923f652016-01-26 03:14:20 +01002219}
2220
Yann Colletd1b26842016-03-15 01:24:33 +01002221/** ZSTD_compress_insertDictionary() :
2222* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002223static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002224{
Yann Colletd1b26842016-03-15 01:24:33 +01002225 if ((dict==NULL) || (dictSize<=4)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002226
Yann Colletd1b26842016-03-15 01:24:33 +01002227 /* default : dict is pure content */
2228 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
2229
2230 /* known magic number : dict is parsed for entropy stats and content */
Yann Collet21588e32016-03-30 16:50:44 +02002231 { size_t const eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4 /* skip magic */, dictSize-4) + 4;
2232 if (ZSTD_isError(eSize)) return eSize;
2233 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002234 }
Yann Colletecd651b2016-01-07 15:35:18 +01002235}
2236
2237
Yann Collet27caf2a2016-04-01 15:48:48 +02002238/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002239* @return : 0, or an error code */
Yann Collet27caf2a2016-04-01 15:48:48 +02002240static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* zc,
Yann Collet1c8e1942016-01-26 16:31:22 +01002241 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002242 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002243{
Yann Colletd1b26842016-03-15 01:24:33 +01002244 { size_t const errorCode = ZSTD_resetCCtx_advanced(zc, params);
Yann Colletb0aec172016-03-21 13:24:16 +01002245 if (ZSTD_isError(errorCode)) return errorCode; }
Yann Collet89db5e02015-11-13 11:27:46 +01002246
Yann Colletd1b26842016-03-15 01:24:33 +01002247 /* Write Frame Header into ctx headerBuffer */
2248 MEM_writeLE32(zc->headerBuffer, ZSTD_MAGICNUMBER);
Yann Collet37f3d1b2016-03-19 15:11:42 +01002249 { BYTE* const op = (BYTE*)zc->headerBuffer;
Yann Collet3b719252016-03-30 19:48:05 +02002250 U32 const fcsId = (pledgedSrcSize>0) + (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256); /* 0-3 */
2251 BYTE fdescriptor = (BYTE)(params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN); /* windowLog : 4 KB - 128 MB */
2252 fdescriptor |= (BYTE)((params.cParams.searchLength==3)<<4); /* mml : 3-4 */
Yann Colletd1b26842016-03-15 01:24:33 +01002253 fdescriptor |= (BYTE)(fcsId << 6);
Yann Collet1c2c2bc2016-03-15 01:33:36 +01002254 op[4] = fdescriptor;
Yann Colletd1b26842016-03-15 01:24:33 +01002255 switch(fcsId)
2256 {
2257 default: /* impossible */
2258 case 0 : break;
Yann Collet3b719252016-03-30 19:48:05 +02002259 case 1 : op[5] = (BYTE)(pledgedSrcSize); break;
2260 case 2 : MEM_writeLE16(op+5, (U16)(pledgedSrcSize-256)); break;
2261 case 3 : MEM_writeLE64(op+5, (U64)(pledgedSrcSize)); break;
Yann Colletd1b26842016-03-15 01:24:33 +01002262 }
Yann Collet37f3d1b2016-03-19 15:11:42 +01002263 zc->hbSize = ZSTD_frameHeaderSize_min + ZSTD_fcs_fieldSize[fcsId];
Yann Colletd1b26842016-03-15 01:24:33 +01002264 }
2265
Yann Collet1c8e1942016-01-26 16:31:22 +01002266 zc->stage = 0;
Yann Collet1c8e1942016-01-26 16:31:22 +01002267 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002268}
2269
2270
Yann Collet27caf2a2016-04-01 15:48:48 +02002271/*! ZSTD_compressBegin_advanced() :
2272* @return : 0, or an error code */
2273size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
2274 const void* dict, size_t dictSize,
2275 ZSTD_parameters params, U64 pledgedSrcSize)
2276{
2277 /* compression parameters verification and optimization */
2278 { size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize);
2279 if (ZSTD_isError(errorCode)) return errorCode; }
2280
2281 return ZSTD_compressBegin_internal(zc, dict, dictSize, params, pledgedSrcSize);
2282}
2283
2284
Yann Collet1c8e1942016-01-26 16:31:22 +01002285size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002286{
Yann Collet3b719252016-03-30 19:48:05 +02002287 ZSTD_parameters params;
2288 params.cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
2289 params.fParams.contentSizeFlag = 0;
Yann Collet27caf2a2016-04-01 15:48:48 +02002290 ZSTD_adjustCParams(&params.cParams, 0, dictSize);
inikepa4dde252016-03-01 14:14:35 +01002291 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet27caf2a2016-04-01 15:48:48 +02002292 return ZSTD_compressBegin_internal(zc, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002293}
Yann Collet083fcc82015-10-25 14:06:35 +01002294
Yann Collet1c8e1942016-01-26 16:31:22 +01002295size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002296{
inikepa4dde252016-03-01 14:14:35 +01002297 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet3b719252016-03-30 19:48:05 +02002298 return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002299}
2300
2301
Yann Colletfb797352016-03-13 11:08:40 +01002302/*! ZSTD_compressEnd() :
2303* Write frame epilogue.
Yann Collet88fcd292015-11-25 14:42:45 +01002304* @return : nb of bytes written into dst (or an error code) */
Yann Colletd1b26842016-03-15 01:24:33 +01002305size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002306{
2307 BYTE* op = (BYTE*)dst;
Yann Colletecd651b2016-01-07 15:35:18 +01002308 size_t hbSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002309
Yann Collet70e45772016-03-19 18:08:32 +01002310 /* special case : empty frame : header still within internal buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01002311 if (zc->stage==0) {
Yann Colletecd651b2016-01-07 15:35:18 +01002312 hbSize = zc->hbSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002313 if (dstCapacity <= hbSize) return ERROR(dstSize_tooSmall);
Yann Colletecd651b2016-01-07 15:35:18 +01002314 zc->stage = 1;
2315 memcpy(dst, zc->headerBuffer, hbSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002316 dstCapacity -= hbSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002317 op += hbSize;
2318 }
2319
2320 /* frame epilogue */
Yann Colletd1b26842016-03-15 01:24:33 +01002321 if (dstCapacity < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002322 op[0] = (BYTE)(bt_end << 6);
2323 op[1] = 0;
2324 op[2] = 0;
2325
Yann Colletecd651b2016-01-07 15:35:18 +01002326 return 3+hbSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002327}
2328
Yann Colletfd416f12016-01-30 03:14:15 +01002329
2330size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
Yann Colletd1b26842016-03-15 01:24:33 +01002331 void* dst, size_t dstCapacity,
Yann Colletfd416f12016-01-30 03:14:15 +01002332 const void* src, size_t srcSize)
2333{
Yann Collet70e45772016-03-19 18:08:32 +01002334 { size_t const errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2335 if (ZSTD_isError(errorCode)) return errorCode;
2336 }
2337 { size_t const cSize = ZSTD_compressContinue(cctx, dst, dstCapacity, src, srcSize);
2338 if (ZSTD_isError(cSize)) return cSize;
2339 { size_t const endSize = ZSTD_compressEnd(cctx, (char*)dst+cSize, dstCapacity-cSize);
2340 if (ZSTD_isError(endSize)) return endSize;
2341 return cSize + endSize;
2342 } }
Yann Colletfd416f12016-01-30 03:14:15 +01002343}
2344
2345
Yann Collet21588e32016-03-30 16:50:44 +02002346static size_t ZSTD_compress_internal (ZSTD_CCtx* ctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002347 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002348 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002349 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002350 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002351{
2352 BYTE* const ostart = (BYTE*)dst;
2353 BYTE* op = ostart;
2354
Yann Collet1c8e1942016-01-26 16:31:22 +01002355 /* Init */
Yann Collet27caf2a2016-04-01 15:48:48 +02002356 { size_t const errorCode = ZSTD_compressBegin_internal(ctx, dict, dictSize, params, srcSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002357 if(ZSTD_isError(errorCode)) return errorCode; }
Yann Colletf3eca252015-10-22 15:31:46 +01002358
2359 /* body (compression) */
Yann Colletd1b26842016-03-15 01:24:33 +01002360 { size_t const oSize = ZSTD_compressContinue (ctx, op, dstCapacity, src, srcSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002361 if(ZSTD_isError(oSize)) return oSize;
2362 op += oSize;
2363 dstCapacity -= oSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002364
2365 /* Close frame */
Yann Colletd1b26842016-03-15 01:24:33 +01002366 { size_t const oSize = ZSTD_compressEnd(ctx, op, dstCapacity);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002367 if(ZSTD_isError(oSize)) return oSize;
2368 op += oSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002369
2370 return (op - ostart);
2371}
2372
Yann Collet21588e32016-03-30 16:50:44 +02002373size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2374 void* dst, size_t dstCapacity,
2375 const void* src, size_t srcSize,
2376 const void* dict,size_t dictSize,
2377 ZSTD_parameters params)
2378{
Yann Collet3b719252016-03-30 19:48:05 +02002379 size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, srcSize);
Yann Collet21588e32016-03-30 16:50:44 +02002380 if (ZSTD_isError(errorCode)) return errorCode;
2381 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2382}
2383
Yann Colletd1b26842016-03-15 01:24:33 +01002384size_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 +01002385{
Yann Collet3b719252016-03-30 19:48:05 +02002386 ZSTD_parameters params;
inikepa4dde252016-03-01 14:14:35 +01002387 ZSTD_LOG_BLOCK("%p: ZSTD_compress_usingDict srcSize=%d dictSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, (int)dictSize, compressionLevel);
Yann Collet3b719252016-03-30 19:48:05 +02002388 params.cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
2389 params.fParams.contentSizeFlag = 1;
2390 ZSTD_adjustCParams(&params.cParams, srcSize, dictSize);
Yann Collet21588e32016-03-30 16:50:44 +02002391 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002392}
2393
Yann Colletd1b26842016-03-15 01:24:33 +01002394size_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 +01002395{
inikepa4dde252016-03-01 14:14:35 +01002396 ZSTD_LOG_BLOCK("%p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, compressionLevel);
Yann Collet21588e32016-03-30 16:50:44 +02002397 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002398}
2399
Yann Colletd1b26842016-03-15 01:24:33 +01002400size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002401{
Yann Collet44fe9912015-10-29 22:02:40 +01002402 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002403 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002404 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Colletd1b26842016-03-15 01:24:33 +01002405 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Colletecd651b2016-01-07 15:35:18 +01002406 free(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002407 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002408}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002409
Yann Colletfd416f12016-01-30 03:14:15 +01002410
Yann Collet70e8c382016-02-10 13:37:52 +01002411/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01002412
Yann Collete3193c42016-03-09 16:57:09 +01002413#define ZSTD_MAX_CLEVEL 22
Yann Collet7d968c72016-02-03 02:11:32 +01002414unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2415
inikepcc52a972016-02-19 10:09:35 +01002416
Yann Collet3b719252016-03-30 19:48:05 +02002417static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01002418{ /* "default" */
Yann Collet3b719252016-03-30 19:48:05 +02002419 /* W, C, H, S, L, SL, strat */
2420 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2421 { 19, 13, 14, 1, 7, 4, ZSTD_fast }, /* level 1 */
2422 { 19, 15, 16, 1, 6, 4, ZSTD_fast }, /* level 2 */
2423 { 20, 18, 20, 1, 6, 4, ZSTD_fast }, /* level 3 */
2424 { 20, 13, 17, 2, 5, 4, ZSTD_greedy }, /* level 4.*/
2425 { 20, 15, 18, 3, 5, 4, ZSTD_greedy }, /* level 5 */
2426 { 21, 16, 19, 2, 5, 4, ZSTD_lazy }, /* level 6 */
2427 { 21, 17, 20, 3, 5, 4, ZSTD_lazy }, /* level 7 */
2428 { 21, 18, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 8.*/
2429 { 21, 20, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 9 */
2430 { 21, 19, 21, 4, 5, 4, ZSTD_lazy2 }, /* level 10 */
2431 { 22, 20, 22, 4, 5, 4, ZSTD_lazy2 }, /* level 11 */
2432 { 22, 20, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 12 */
2433 { 22, 21, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 13 */
2434 { 22, 21, 22, 6, 5, 4, ZSTD_lazy2 }, /* level 14 */
2435 { 22, 21, 21, 5, 5, 4, ZSTD_btlazy2 }, /* level 15 */
2436 { 23, 22, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */
2437 { 23, 22, 22, 6, 5, 22, ZSTD_btopt }, /* level 17 */
2438 { 22, 22, 22, 5, 3, 44, ZSTD_btopt }, /* level 18 */
2439 { 23, 24, 22, 7, 3, 44, ZSTD_btopt }, /* level 19 */
2440 { 25, 26, 22, 7, 3, 71, ZSTD_btopt }, /* level 20 */
2441 { 26, 26, 24, 7, 3,256, ZSTD_btopt }, /* level 21 */
2442 { 27, 28, 26, 9, 3,256, ZSTD_btopt }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01002443},
2444{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002445 /* W, C, H, S, L, T, strat */
2446 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 */
2447 { 18, 14, 15, 1, 6, 4, ZSTD_fast }, /* level 1 */
2448 { 18, 14, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */
2449 { 18, 14, 17, 1, 5, 4, ZSTD_fast }, /* level 3.*/
2450 { 18, 14, 15, 4, 4, 4, ZSTD_greedy }, /* level 4 */
2451 { 18, 16, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */
2452 { 18, 17, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
2453 { 18, 17, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */
2454 { 18, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2455 { 18, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2456 { 18, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
2457 { 18, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */
2458 { 18, 18, 17, 4, 4, 4, ZSTD_btlazy2 }, /* level 12 */
2459 { 18, 19, 17, 7, 4, 4, ZSTD_btlazy2 }, /* level 13.*/
2460 { 18, 17, 19, 8, 4, 24, ZSTD_btopt }, /* level 14.*/
2461 { 18, 19, 19, 8, 4, 48, ZSTD_btopt }, /* level 15.*/
2462 { 18, 19, 18, 9, 4,128, ZSTD_btopt }, /* level 16.*/
2463 { 18, 19, 18, 9, 4,192, ZSTD_btopt }, /* level 17.*/
2464 { 18, 19, 18, 9, 4,256, ZSTD_btopt }, /* level 18.*/
2465 { 18, 19, 18, 10, 4,256, ZSTD_btopt }, /* level 19.*/
2466 { 18, 19, 18, 11, 4,256, ZSTD_btopt }, /* level 20.*/
2467 { 18, 19, 18, 12, 4,256, ZSTD_btopt }, /* level 21.*/
2468 { 18, 19, 18, 12, 4,256, ZSTD_btopt }, /* level 22*/
Yann Colletfd416f12016-01-30 03:14:15 +01002469},
2470{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002471 /* W, C, H, S, L, T, strat */
2472 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2473 { 17, 12, 13, 1, 6, 4, ZSTD_fast }, /* level 1 */
2474 { 17, 13, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */
2475 { 17, 13, 14, 2, 5, 4, ZSTD_greedy }, /* level 3 */
2476 { 17, 13, 15, 3, 4, 4, ZSTD_greedy }, /* level 4 */
2477 { 17, 15, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */
2478 { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
2479 { 17, 15, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 7 */
2480 { 17, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2481 { 17, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2482 { 17, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
2483 { 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */
2484 { 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */
2485 { 17, 18, 17, 6, 4, 4, ZSTD_btlazy2 }, /* level 13.*/
2486 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
2487 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
2488 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
2489 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
2490 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
2491 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
2492 { 17, 18, 17, 9, 3,256, ZSTD_btopt }, /* level 20.*/
2493 { 17, 18, 17, 10, 3,256, ZSTD_btopt }, /* level 21.*/
2494 { 17, 18, 17, 11, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002495},
2496{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002497 /* W, C, H, S, L, T, strat */
2498 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 -- never used */
2499 { 14, 14, 14, 1, 4, 4, ZSTD_fast }, /* level 1 */
2500 { 14, 14, 15, 1, 4, 4, ZSTD_fast }, /* level 2 */
2501 { 14, 14, 14, 4, 4, 4, ZSTD_greedy }, /* level 3.*/
2502 { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 4.*/
2503 { 14, 14, 14, 4, 4, 4, ZSTD_lazy2 }, /* level 5 */
2504 { 14, 14, 14, 5, 4, 4, ZSTD_lazy2 }, /* level 6 */
2505 { 14, 14, 14, 6, 4, 4, ZSTD_lazy2 }, /* level 7.*/
2506 { 14, 14, 14, 7, 4, 4, ZSTD_lazy2 }, /* level 8.*/
2507 { 14, 15, 14, 6, 4, 4, ZSTD_btlazy2 }, /* level 9.*/
2508 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
2509 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
2510 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
2511 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
2512 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
2513 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
2514 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
2515 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
2516 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
2517 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
2518 { 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 20.*/
2519 { 14, 15, 15, 9, 3,256, ZSTD_btopt }, /* level 21.*/
2520 { 14, 15, 15, 10, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002521},
2522};
2523
Yann Collet1df25942016-03-05 18:43:21 +01002524/*! ZSTD_getParams() :
Yann Colletfd416f12016-01-30 03:14:15 +01002525* @return ZSTD_parameters structure for a selected compression level and srcSize.
Yann Colletde406ee2016-03-20 15:46:10 +01002526* `srcSize` value is optional, select 0 if not known */
Yann Collet3b719252016-03-30 19:48:05 +02002527ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, U64 srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01002528{
Yann Collet3b719252016-03-30 19:48:05 +02002529 size_t addedSize = srcSize ? 0 : 500;
2530 U64 rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
2531 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Colletfd416f12016-01-30 03:14:15 +01002532 if (compressionLevel<=0) compressionLevel = 1;
2533 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
inikep3379c5d2016-02-05 09:21:20 +01002534#if ZSTD_OPT_DEBUG >= 1
2535 tableID=0;
2536#endif
Yann Collet3b719252016-03-30 19:48:05 +02002537 return ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Colletfd416f12016-01-30 03:14:15 +01002538}
2539