blob: bca725f545ea081ec9ff565794a4eb813aa650e1 [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"
inikep23a08892016-04-22 12:43:18 +020058#include "huf_static.h"
Yann Collet3d9cf7a2015-10-29 17:15:14 +010059#include "zstd_internal.h"
inikep35b891c2016-05-20 19:42:20 +020060#include ".debug/zstd_stats.h"
Yann Colletf3eca252015-10-22 15:31:46 +010061
62
Yann Collet7d360282016-02-12 00:07:30 +010063/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010064* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010065***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010066static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Colletf3eca252015-10-22 15:31:46 +010067
Yann Colletf3eca252015-10-22 15:31:46 +010068
Yann Collet7d360282016-02-12 00:07:30 +010069/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010070* Helper functions
71***************************************/
Yann Collet59d1f792016-01-23 19:28:41 +010072size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
73
74
Yann Collet7d360282016-02-12 00:07:30 +010075/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010076* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010077***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010078static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
79{
80 ssPtr->offset = ssPtr->offsetStart;
81 ssPtr->lit = ssPtr->litStart;
82 ssPtr->litLength = ssPtr->litLengthStart;
83 ssPtr->matchLength = ssPtr->matchLengthStart;
Yann Collet5d393572016-04-07 17:19:00 +020084 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010085}
86
87
Yann Collet7d360282016-02-12 00:07:30 +010088/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010089* Context memory management
90***************************************/
Yann Collet5be2dd22015-11-11 13:43:58 +010091struct ZSTD_CCtx_s
Yann Colletf3eca252015-10-22 15:31:46 +010092{
Yann Collet89db5e02015-11-13 11:27:46 +010093 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010094 const BYTE* base; /* All regular indexes relative to this position */
95 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010096 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010097 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010098 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010099 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +0100100 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Collet2ce49232016-02-02 14:36:49 +0100101 U32 loadedDictEnd;
Yann Collet887e7da2016-04-11 20:12:27 +0200102 U32 stage; /* 0: created; 1: init,dictLoad; 2:started */
Yann Collet5be2dd22015-11-11 13:43:58 +0100103 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +0100104 void* workSpace;
105 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100106 size_t blockSize;
inikep50e82c02016-05-23 15:49:09 +0200107 ZSTD_allocFunction customAlloc;
108 ZSTD_freeFunction customFree;
Yann Colletecd651b2016-01-07 15:35:18 +0100109
Yann Collet712def92015-10-29 18:41:45 +0100110 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100111 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +0100112 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +0200113 U32* chainTable;
Yann Colletb923f652016-01-26 03:14:20 +0100114 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +0100115 U32 flagStaticTables;
116 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
117 FSE_CTable matchlengthCTable [FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
118 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Colletf3eca252015-10-22 15:31:46 +0100119};
120
Yann Collet5be2dd22015-11-11 13:43:58 +0100121ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100122{
inikep107e2432016-05-23 16:24:52 +0200123 ZSTD_customMem customMem = { NULL, NULL };
124 return ZSTD_createCCtx_advanced(customMem);
inikep50e82c02016-05-23 15:49:09 +0200125}
126
127ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
128{
inikep107e2432016-05-23 16:24:52 +0200129 ZSTD_CCtx* ctx;
inikep50e82c02016-05-23 15:49:09 +0200130
inikep13ba8802016-05-23 17:04:23 +0200131 if (!customMem.customAlloc && !customMem.customFree)
inikep107e2432016-05-23 16:24:52 +0200132 {
133 ctx = (ZSTD_CCtx*) calloc(1, sizeof(ZSTD_CCtx));
134 if (!ctx) return NULL;
135
136 ctx->customAlloc = malloc;
137 ctx->customFree = free;
138 return ctx;
139 }
140
inikep13ba8802016-05-23 17:04:23 +0200141 if (!customMem.customAlloc || !customMem.customFree)
142 return NULL;
143
inikep107e2432016-05-23 16:24:52 +0200144 ctx = (ZSTD_CCtx*) customMem.customAlloc(sizeof(ZSTD_CCtx));
inikep50e82c02016-05-23 15:49:09 +0200145 if (!ctx) return NULL;
146
147 memset(ctx, 0, sizeof(ZSTD_CCtx));
148 ctx->customAlloc = customMem.customAlloc;
149 ctx->customFree = customMem.customFree;
150 return ctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100151}
152
Yann Collet5be2dd22015-11-11 13:43:58 +0100153size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100154{
inikep50e82c02016-05-23 15:49:09 +0200155 cctx->customFree(cctx->workSpace);
156 cctx->customFree(cctx);
Yann Collet982ffc72016-02-05 02:33:10 +0100157 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100158}
159
Yann Colletb44be742016-03-26 20:52:14 +0100160const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100161{
Yann Colletb44be742016-03-26 20:52:14 +0100162 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100163}
164
Yann Collet59d70632015-11-04 12:05:27 +0100165
Yann Collet21588e32016-03-30 16:50:44 +0200166#define CLAMP(val,min,max) { if (val<min) val=min; else if (val>max) val=max; }
167#define CLAMPCHECK(val,min,max) { if ((val<min) || (val>max)) return ERROR(compressionParameter_unsupported); }
168
169/** ZSTD_checkParams() :
170 ensure param values remain within authorized range.
171 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200172size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200173{
Yann Collet15354142016-04-04 04:22:53 +0200174 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200175 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200176 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
177 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
inikep75716852016-04-06 12:34:42 +0200178 { U32 const searchLengthMin = (cParams.strategy == ZSTD_fast || cParams.strategy == ZSTD_greedy) ? ZSTD_SEARCHLENGTH_MIN+1 : ZSTD_SEARCHLENGTH_MIN;
Yann Collet3b719252016-03-30 19:48:05 +0200179 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
180 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
181 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Collet9bb87e52016-03-30 21:28:15 +0200182 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200183 return 0;
184}
185
186
Yann Collet14983e72015-11-11 21:38:21 +0100187static unsigned ZSTD_highbit(U32 val);
188
Yann Collet3b719252016-03-30 19:48:05 +0200189/** ZSTD_checkCParams_advanced() :
190 temporary work-around, while the compressor compatibility remains limited regarding windowLog < 18 */
191size_t ZSTD_checkCParams_advanced(ZSTD_compressionParameters cParams, U64 srcSize)
192{
Yann Colletefb18302016-04-01 18:54:13 +0200193 if (srcSize > (1ULL << ZSTD_WINDOWLOG_MIN)) return ZSTD_checkCParams(cParams);
Yann Collet3b719252016-03-30 19:48:05 +0200194 if (cParams.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) return ERROR(compressionParameter_unsupported);
Yann Collet8a57b922016-04-04 13:49:18 +0200195 if (srcSize <= (1ULL << cParams.windowLog)) cParams.windowLog = ZSTD_WINDOWLOG_MIN; /* fake value - temporary work around */
196 if (srcSize <= (1ULL << cParams.chainLog)) cParams.chainLog = ZSTD_CHAINLOG_MIN; /* fake value - temporary work around */
Yann Colletef363902016-04-02 00:46:40 +0200197 if ((srcSize <= (1ULL << cParams.hashLog)) && ((U32)cParams.strategy < (U32)ZSTD_btlazy2)) cParams.hashLog = ZSTD_HASHLOG_MIN; /* fake value - temporary work around */
Yann Collet3b719252016-03-30 19:48:05 +0200198 return ZSTD_checkCParams(cParams);
199}
200
201
Yann Collet21588e32016-03-30 16:50:44 +0200202/** ZSTD_adjustParams() :
203 optimize params for q given input (`srcSize` and `dictSize`).
204 mostly downsizing to reduce memory consumption and initialization.
205 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
206 but if both are 0, no optimization can be done.
207 Note : params is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Colletdd6466a2016-03-30 20:06:26 +0200208void ZSTD_adjustCParams(ZSTD_compressionParameters* params, U64 srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100209{
Yann Collet21588e32016-03-30 16:50:44 +0200210 if (srcSize+dictSize == 0) return; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100211
Yann Collet70e45772016-03-19 18:08:32 +0100212 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200213 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
214 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200215 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Collet21588e32016-03-30 16:50:44 +0200216 U32 const srcLog = ZSTD_highbit((U32)(rSize)-1) + 1;
217 if (params->windowLog > srcLog) params->windowLog = srcLog;
218 } }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100219 if (params->hashLog > params->windowLog) params->hashLog = params->windowLog;
Yann Collet21588e32016-03-30 16:50:44 +0200220 { U32 const btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_btopt);
Yann Collet8a57b922016-04-04 13:49:18 +0200221 U32 const maxChainLog = params->windowLog+btPlus;
222 if (params->chainLog > maxChainLog) params->chainLog = maxChainLog; } /* <= ZSTD_CHAINLOG_MAX */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100223
224 if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet40358d02016-04-02 00:40:09 +0200225 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 +0100226}
227
228
Yann Collet51d50042016-03-30 20:42:19 +0200229size_t ZSTD_sizeofCCtx(ZSTD_compressionParameters cParams) /* hidden interface, for paramagrill */
Yann Collete74215e2016-03-19 16:09:09 +0100230{
231 ZSTD_CCtx* zc = ZSTD_createCCtx();
Yann Collet51d50042016-03-30 20:42:19 +0200232 ZSTD_parameters params;
233 params.cParams = cParams;
234 params.fParams.contentSizeFlag = 1;
Yann Collet3b719252016-03-30 19:48:05 +0200235 ZSTD_compressBegin_advanced(zc, NULL, 0, params, 0);
Yann Colletd64f4352016-03-21 00:07:42 +0100236 { size_t const ccsize = sizeof(*zc) + zc->workSpaceSize;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100237 ZSTD_freeCCtx(zc);
Yann Colletd64f4352016-03-21 00:07:42 +0100238 return ccsize; }
Yann Collet2e91dde2016-03-08 12:22:11 +0100239}
240
Yann Collet27caf2a2016-04-01 15:48:48 +0200241/*! ZSTD_resetCCtx_advanced() :
242 note : 'params' is expected to be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100243static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Colletabb5c652016-04-11 20:42:31 +0200244 ZSTD_parameters params, U32 reset)
Yann Collet863ec402016-01-28 17:56:33 +0100245{ /* note : params considered validated here */
Yann Collet3b719252016-03-30 19:48:05 +0200246 const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
247 const U32 divider = (params.cParams.searchLength==3) ? 3 : 4;
Yann Colletdd54bbc2016-03-08 02:35:34 +0100248 const size_t maxNbSeq = blockSize / divider;
Yann Colletbe391432016-03-22 23:19:28 +0100249 const size_t tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet8a57b922016-04-04 13:49:18 +0200250 const size_t chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
inikep1007a1f2016-04-25 15:23:09 +0200251 const size_t hSize = ((size_t)1) << params.cParams.hashLog;
inikep7adceef2016-03-23 15:53:38 +0100252 const size_t h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Collet8a57b922016-04-04 13:49:18 +0200253 const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
inikep87d4f3d2016-03-02 15:56:24 +0100254
Yann Collete74215e2016-03-19 16:09:09 +0100255 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Collet48537162016-04-07 15:24:29 +0200256 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
Yann Collete74215e2016-03-19 16:09:09 +0100257 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
258 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Yann Collet1005fc12016-04-04 13:28:28 +0200259 + ((params.cParams.strategy == ZSTD_btopt) ? optSpace : 0);
Yann Collete74215e2016-03-19 16:09:09 +0100260 if (zc->workSpaceSize < neededSpace) {
inikep50e82c02016-05-23 15:49:09 +0200261 zc->customFree(zc->workSpace);
262 zc->workSpace = zc->customAlloc(neededSpace);
Yann Collete74215e2016-03-19 16:09:09 +0100263 if (zc->workSpace == NULL) return ERROR(memory_allocation);
264 zc->workSpaceSize = neededSpace;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100265 } }
Yann Collete74215e2016-03-19 16:09:09 +0100266
Yann Colletabb5c652016-04-11 20:42:31 +0200267 if (reset) memset(zc->workSpace, 0, tableSpace ); /* reset only tables */
inikepcc52a972016-02-19 10:09:35 +0100268 zc->hashTable3 = (U32*)(zc->workSpace);
Yann Collete74215e2016-03-19 16:09:09 +0100269 zc->hashTable = zc->hashTable3 + h3Size;
Yann Collet8a57b922016-04-04 13:49:18 +0200270 zc->chainTable = zc->hashTable + hSize;
271 zc->seqStore.buffer = zc->chainTable + chainSize;
Yann Collet863ec402016-01-28 17:56:33 +0100272 zc->hufTable = (HUF_CElt*)zc->seqStore.buffer;
273 zc->flagStaticTables = 0;
Yann Collet597847a2016-03-20 19:14:22 +0100274 zc->seqStore.buffer = ((U32*)(zc->seqStore.buffer)) + 256;
Yann Collet083fcc82015-10-25 14:06:35 +0100275
Yann Colletf48e35c2015-11-07 01:13:31 +0100276 zc->nextToUpdate = 1;
Yann Collet89db5e02015-11-13 11:27:46 +0100277 zc->nextSrc = NULL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100278 zc->base = NULL;
279 zc->dictBase = NULL;
280 zc->dictLimit = 0;
281 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100282 zc->params = params;
Yann Collet120230b2015-12-02 14:00:45 +0100283 zc->blockSize = blockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100284
Yann Collet3b719252016-03-30 19:48:05 +0200285 if (params.cParams.strategy == ZSTD_btopt) {
Yann Collet72d706a2016-03-23 20:44:12 +0100286 zc->seqStore.litFreq = (U32*)(zc->seqStore.buffer);
287 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
288 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
289 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
Yann Collet48537162016-04-07 15:24:29 +0200290 zc->seqStore.matchTable = (ZSTD_match_t*)((void*)(zc->seqStore.offCodeFreq + (MaxOff+1)));
Yann Collet72d706a2016-03-23 20:44:12 +0100291 zc->seqStore.priceTable = (ZSTD_optimal_t*)((void*)(zc->seqStore.matchTable + ZSTD_OPT_NUM+1));
292 zc->seqStore.buffer = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
293 zc->seqStore.litLengthSum = 0;
294 }
inikep87d4f3d2016-03-02 15:56:24 +0100295 zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer);
Yann Collet597847a2016-03-20 19:14:22 +0100296 zc->seqStore.litLengthStart = (U16*) (void*)(zc->seqStore.offsetStart + maxNbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100297 zc->seqStore.matchLengthStart = (U16*) (void*)(zc->seqStore.litLengthStart + maxNbSeq);
298 zc->seqStore.llCodeStart = (BYTE*) (zc->seqStore.matchLengthStart + maxNbSeq);
299 zc->seqStore.mlCodeStart = zc->seqStore.llCodeStart + maxNbSeq;
300 zc->seqStore.offCodeStart = zc->seqStore.mlCodeStart + maxNbSeq;
Yann Colletdd54bbc2016-03-08 02:35:34 +0100301 zc->seqStore.litStart = zc->seqStore.offCodeStart + maxNbSeq;
inikep5cccd772016-03-02 20:37:49 +0100302
Yann Collet887e7da2016-04-11 20:12:27 +0200303 zc->stage = 1;
Yann Collet2ce49232016-02-02 14:36:49 +0100304 zc->loadedDictEnd = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +0100305
Yann Collet4114f952015-10-30 06:40:22 +0100306 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100307}
308
Yann Collet083fcc82015-10-25 14:06:35 +0100309
Yann Collet370b08e2016-03-08 00:03:59 +0100310/*! ZSTD_copyCCtx() :
311* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet887e7da2016-04-11 20:12:27 +0200312* Only works during stage 1 (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100313* @return : 0, or an error code */
314size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
315{
Yann Collet887e7da2016-04-11 20:12:27 +0200316 if (srcCCtx->stage!=1) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100317
inikep107e2432016-05-23 16:24:52 +0200318 dstCCtx->hashLog3 = srcCCtx->hashLog3; /* must be before ZSTD_resetCCtx_advanced */
319 dstCCtx->customAlloc = srcCCtx->customAlloc;
320 dstCCtx->customFree = srcCCtx->customFree;
Yann Colletabb5c652016-04-11 20:42:31 +0200321 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, 0);
Yann Collet389648c2016-04-12 19:13:08 +0200322 dstCCtx->params.fParams.contentSizeFlag = 0; /* content size different from the one set during srcCCtx init */
Yann Collet7b51a292016-01-26 15:58:49 +0100323
324 /* copy tables */
inikep0c7456c2016-04-04 14:54:53 +0200325 { const size_t chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
inikep1007a1f2016-04-25 15:23:09 +0200326 const size_t hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
inikep7adceef2016-03-23 15:53:38 +0100327 const size_t h3Size = (srcCCtx->hashLog3) ? 1 << srcCCtx->hashLog3 : 0;
inikep0c7456c2016-04-04 14:54:53 +0200328 const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100329 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
330 }
Yann Collet7b51a292016-01-26 15:58:49 +0100331
Yann Collet7b51a292016-01-26 15:58:49 +0100332 /* copy dictionary pointers */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100333 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
334 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
335 dstCCtx->nextSrc = srcCCtx->nextSrc;
336 dstCCtx->base = srcCCtx->base;
337 dstCCtx->dictBase = srcCCtx->dictBase;
338 dstCCtx->dictLimit = srcCCtx->dictLimit;
339 dstCCtx->lowLimit = srcCCtx->lowLimit;
340 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Collet7b51a292016-01-26 15:58:49 +0100341
Yann Colletfb810d62016-01-28 00:18:06 +0100342 /* copy entropy tables */
343 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100344 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100345 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100346 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
347 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
348 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
349 }
Yann Collet7b51a292016-01-26 15:58:49 +0100350
351 return 0;
352}
353
354
Yann Colletecabfe32016-03-20 16:20:06 +0100355/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100356* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100357static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100358{
Yann Colletecabfe32016-03-20 16:20:06 +0100359 U32 u;
360 for (u=0 ; u < size ; u++) {
361 if (table[u] < reducerValue) table[u] = 0;
362 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100363 }
364}
365
Yann Colletecabfe32016-03-20 16:20:06 +0100366/*! ZSTD_reduceIndex() :
367* rescale all indexes to avoid future overflow (indexes are U32) */
368static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
369{
Yann Collet3b719252016-03-30 19:48:05 +0200370 { const U32 hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100371 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
372
Yann Collet8a57b922016-04-04 13:49:18 +0200373 { const U32 chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
374 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100375
inikep7adceef2016-03-23 15:53:38 +0100376 { const U32 h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100377 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
378}
379
Yann Collet89db5e02015-11-13 11:27:46 +0100380
Yann Collet863ec402016-01-28 17:56:33 +0100381/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100382* Block entropic compression
383*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100384
Yann Colletfb797352016-03-13 11:08:40 +0100385/* Frame format description
386 Frame Header - [ Block Header - Block ] - Frame End
387 1) Frame Header
388 - 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_static.h)
389 - 1 byte - Frame Descriptor
390 2) Block Header
391 - 3 bytes, starting with a 2-bits descriptor
392 Uncompressed, Compressed, Frame End, unused
393 3) Block
394 See Block Format Description
395 4) Frame End
396 - 3 bytes, compatible with Block Header
397*/
398
399
400/* Frame descriptor
401
402 1 byte, using :
403 bit 0-3 : windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN (see zstd_internal.h)
404 bit 4 : minmatch 4(0) or 3(1)
405 bit 5 : reserved (must be zero)
406 bit 6-7 : Frame content size : unknown, 1 byte, 2 bytes, 8 bytes
407
408 Optional : content size (0, 1, 2 or 8 bytes)
409 0 : unknown
410 1 : 0-255 bytes
411 2 : 256 - 65535+256
412 8 : up to 16 exa
413*/
414
415
Yann Collet59d1f792016-01-23 19:28:41 +0100416/* Block format description
417
418 Block = Literal Section - Sequences Section
419 Prerequisite : size of (compressed) block, maximum size of regenerated data
420
421 1) Literal Section
422
423 1.1) Header : 1-5 bytes
424 flags: 2 bits
425 00 compressed by Huff0
426 01 unused
427 10 is Raw (uncompressed)
428 11 is Rle
429 Note : using 01 => Huff0 with precomputed table ?
430 Note : delta map ? => compressed ?
431
432 1.1.1) Huff0-compressed literal block : 3-5 bytes
Yann Colletafe07092016-01-25 04:10:46 +0100433 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
Yann Collet59d1f792016-01-23 19:28:41 +0100434 srcSize < 1 KB => 3 bytes (2-2-10-10)
Yann Colleta1249dc2016-01-25 04:22:03 +0100435 srcSize < 16KB => 4 bytes (2-2-14-14)
Yann Collet59d1f792016-01-23 19:28:41 +0100436 else => 5 bytes (2-2-18-18)
437 big endian convention
438
439 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
440 size : 5 bits: (IS_RAW<<6) + (0<<4) + size
441 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
442 size&255
443 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
444 size>>8&255
445 size&255
446
447 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
448 size : 5 bits: (IS_RLE<<6) + (0<<4) + size
449 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
450 size&255
451 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
452 size>>8&255
453 size&255
454
Yann Colleta1249dc2016-01-25 04:22:03 +0100455 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
456 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
457 srcSize < 1 KB => 3 bytes (2-2-10-10)
458 srcSize < 16KB => 4 bytes (2-2-14-14)
459 else => 5 bytes (2-2-18-18)
460 big endian convention
461
462 1- CTable available (stored into workspace ?)
Yann Colletb923f652016-01-26 03:14:20 +0100463 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
Yann Colleta1249dc2016-01-25 04:22:03 +0100464
Yann Collet59d1f792016-01-23 19:28:41 +0100465
466 1.2) Literal block content
467
468 1.2.1) Huff0 block, using sizes from header
469 See Huff0 format
470
Yann Colletfb810d62016-01-28 00:18:06 +0100471 1.2.2) Huff0 block, using prepared table
Yann Collet59d1f792016-01-23 19:28:41 +0100472
Yann Colletfb810d62016-01-28 00:18:06 +0100473 1.2.3) Raw content
Yann Collet59d1f792016-01-23 19:28:41 +0100474
Yann Colletfb810d62016-01-28 00:18:06 +0100475 1.2.4) single byte
Yann Collet59d1f792016-01-23 19:28:41 +0100476
477
478 2) Sequences section
Yann Colletfb810d62016-01-28 00:18:06 +0100479
480 - Nb Sequences : 2 bytes, little endian
481 - Control Token : 1 byte (see below)
482 - Dumps Length : 1 or 2 bytes (depending on control token)
483 - Dumps : as stated by dumps length
484 - Literal Lengths FSE table (as needed depending on encoding method)
485 - Offset Codes FSE table (as needed depending on encoding method)
486 - Match Lengths FSE table (as needed depending on encoding method)
487
488 2.1) Control Token
489 8 bits, divided as :
490 0-1 : dumpsLength
491 2-3 : MatchLength, FSE encoding method
492 4-5 : Offset Codes, FSE encoding method
493 6-7 : Literal Lengths, FSE encoding method
494
495 FSE encoding method :
496 FSE_ENCODING_RAW : uncompressed; no header
497 FSE_ENCODING_RLE : single repeated value; header 1 byte
498 FSE_ENCODING_STATIC : use prepared table; no header
499 FSE_ENCODING_DYNAMIC : read NCount
Yann Collet59d1f792016-01-23 19:28:41 +0100500*/
Yann Collet14983e72015-11-11 21:38:21 +0100501
Yann Colletd1b26842016-03-15 01:24:33 +0100502size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100503{
504 BYTE* const ostart = (BYTE* const)dst;
505
Yann Colletd1b26842016-03-15 01:24:33 +0100506 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100507 memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
508
509 /* Build header */
510 ostart[0] = (BYTE)(srcSize>>16);
511 ostart[1] = (BYTE)(srcSize>>8);
512 ostart[2] = (BYTE) srcSize;
513 ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
514
515 return ZSTD_blockHeaderSize+srcSize;
516}
517
518
Yann Colletd1b26842016-03-15 01:24:33 +0100519static size_t ZSTD_noCompressLiterals (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 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100525
Yann Collet59d1f792016-01-23 19:28:41 +0100526 switch(flSize)
527 {
528 case 1: /* 2 - 1 - 5 */
529 ostart[0] = (BYTE)((IS_RAW<<6) + (0<<5) + srcSize);
530 break;
531 case 2: /* 2 - 2 - 12 */
532 ostart[0] = (BYTE)((IS_RAW<<6) + (2<<4) + (srcSize >> 8));
533 ostart[1] = (BYTE)srcSize;
534 break;
535 default: /*note : should not be necessary : flSize is within {1,2,3} */
536 case 3: /* 2 - 2 - 20 */
537 ostart[0] = (BYTE)((IS_RAW<<6) + (3<<4) + (srcSize >> 16));
538 ostart[1] = (BYTE)(srcSize>>8);
539 ostart[2] = (BYTE)srcSize;
540 break;
541 }
542
543 memcpy(ostart + flSize, src, srcSize);
544 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100545}
546
Yann Colletd1b26842016-03-15 01:24:33 +0100547static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100548{
549 BYTE* const ostart = (BYTE* const)dst;
Yann Colleta910dc82016-03-18 12:37:45 +0100550 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100551
Yann Colletd1b26842016-03-15 01:24:33 +0100552 (void)dstCapacity; /* dstCapacity guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100553
554 switch(flSize)
555 {
556 case 1: /* 2 - 1 - 5 */
557 ostart[0] = (BYTE)((IS_RLE<<6) + (0<<5) + srcSize);
558 break;
559 case 2: /* 2 - 2 - 12 */
560 ostart[0] = (BYTE)((IS_RLE<<6) + (2<<4) + (srcSize >> 8));
561 ostart[1] = (BYTE)srcSize;
562 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100563 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100564 case 3: /* 2 - 2 - 20 */
565 ostart[0] = (BYTE)((IS_RLE<<6) + (3<<4) + (srcSize >> 16));
566 ostart[1] = (BYTE)(srcSize>>8);
567 ostart[2] = (BYTE)srcSize;
568 break;
569 }
570
571 ostart[flSize] = *(const BYTE*)src;
572 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100573}
574
Yann Collet59d1f792016-01-23 19:28:41 +0100575
Yann Colleta5c2c082016-03-20 01:09:18 +0100576static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100577
Yann Colletb923f652016-01-26 03:14:20 +0100578static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100579 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100580 const void* src, size_t srcSize)
581{
Yann Colleta910dc82016-03-18 12:37:45 +0100582 size_t const minGain = ZSTD_minGain(srcSize);
583 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet14983e72015-11-11 21:38:21 +0100584 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100585 U32 singleStream = srcSize < 256;
Yann Colletb923f652016-01-26 03:14:20 +0100586 U32 hType = IS_HUF;
Yann Colleta910dc82016-03-18 12:37:45 +0100587 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100588
Yann Collet14983e72015-11-11 21:38:21 +0100589
Yann Colleta5c2c082016-03-20 01:09:18 +0100590 /* small ? don't even attempt compression (speed opt) */
591# define LITERAL_NOENTROPY 63
592 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
593 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
594 }
595
596 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Colletfb810d62016-01-28 00:18:06 +0100597 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletb923f652016-01-26 03:14:20 +0100598 hType = IS_PCH;
599 singleStream = 1;
Yann Colleta910dc82016-03-18 12:37:45 +0100600 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100601 } else {
Yann Colleta910dc82016-03-18 12:37:45 +0100602 cLitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12)
Yann Colletd1b26842016-03-15 01:24:33 +0100603 : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12);
Yann Colletb923f652016-01-26 03:14:20 +0100604 }
Yann Collet14983e72015-11-11 21:38:21 +0100605
Yann Colleta910dc82016-03-18 12:37:45 +0100606 if ((cLitSize==0) || (cLitSize >= srcSize - minGain))
607 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
608 if (cLitSize==1)
609 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100610
611 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100612 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100613 {
Yann Collet59d1f792016-01-23 19:28:41 +0100614 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletb923f652016-01-26 03:14:20 +0100615 ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6));
Yann Colleta910dc82016-03-18 12:37:45 +0100616 ostart[1] = (BYTE)((srcSize<<2) + (cLitSize>>8));
617 ostart[2] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100618 break;
619 case 4: /* 2 - 2 - 14 - 14 */
Yann Colletb923f652016-01-26 03:14:20 +0100620 ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100621 ostart[1] = (BYTE)(srcSize>> 2);
Yann Colleta910dc82016-03-18 12:37:45 +0100622 ostart[2] = (BYTE)((srcSize<<6) + (cLitSize>>8));
623 ostart[3] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100624 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100625 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100626 case 5: /* 2 - 2 - 18 - 18 */
Yann Colletb923f652016-01-26 03:14:20 +0100627 ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100628 ostart[1] = (BYTE)(srcSize>>6);
Yann Colleta910dc82016-03-18 12:37:45 +0100629 ostart[2] = (BYTE)((srcSize<<2) + (cLitSize>>16));
630 ostart[3] = (BYTE)(cLitSize>>8);
631 ostart[4] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100632 break;
Yann Collet14983e72015-11-11 21:38:21 +0100633 }
Yann Colleta910dc82016-03-18 12:37:45 +0100634 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100635}
636
637
Yann Colletb44be742016-03-26 20:52:14 +0100638void ZSTD_seqToCodes(const seqStore_t* seqStorePtr, size_t const nbSeq)
639{
640 /* LL codes */
641 { static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
642 8, 9, 10, 11, 12, 13, 14, 15,
643 16, 16, 17, 17, 18, 18, 19, 19,
644 20, 20, 20, 20, 21, 21, 21, 21,
645 22, 22, 22, 22, 22, 22, 22, 22,
646 23, 23, 23, 23, 23, 23, 23, 23,
647 24, 24, 24, 24, 24, 24, 24, 24,
648 24, 24, 24, 24, 24, 24, 24, 24 };
649 const BYTE LL_deltaCode = 19;
Yann Collet5d393572016-04-07 17:19:00 +0200650 const U16* const llTable = seqStorePtr->litLengthStart;
Yann Colletb44be742016-03-26 20:52:14 +0100651 BYTE* const llCodeTable = seqStorePtr->llCodeStart;
652 size_t u;
653 for (u=0; u<nbSeq; u++) {
Yann Collet5d393572016-04-07 17:19:00 +0200654 U32 const ll = llTable[u];
Yann Colletb44be742016-03-26 20:52:14 +0100655 llCodeTable[u] = (ll>63) ? (BYTE)ZSTD_highbit(ll) + LL_deltaCode : LL_Code[ll];
Yann Collet5d393572016-04-07 17:19:00 +0200656 }
657 if (seqStorePtr->longLengthID==1)
658 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
659 }
Yann Colletb44be742016-03-26 20:52:14 +0100660
661 /* Offset codes */
662 { const U32* const offsetTable = seqStorePtr->offsetStart;
663 BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
664 size_t u;
665 for (u=0; u<nbSeq; u++) ofCodeTable[u] = (BYTE)ZSTD_highbit(offsetTable[u]);
666 }
667
668 /* ML codes */
669 { static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
670 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
671 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
672 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
673 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
674 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
675 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
676 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
677 const BYTE ML_deltaCode = 36;
Yann Collet5d393572016-04-07 17:19:00 +0200678 const U16* const mlTable = seqStorePtr->matchLengthStart;
Yann Colletb44be742016-03-26 20:52:14 +0100679 BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
680 size_t u;
681 for (u=0; u<nbSeq; u++) {
Yann Collet5d393572016-04-07 17:19:00 +0200682 U32 const ml = mlTable[u];
Yann Colletb44be742016-03-26 20:52:14 +0100683 mlCodeTable[u] = (ml>127) ? (BYTE)ZSTD_highbit(ml) + ML_deltaCode : ML_Code[ml];
Yann Collet5d393572016-04-07 17:19:00 +0200684 }
685 if (seqStorePtr->longLengthID==2)
686 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
687 }
Yann Colletb44be742016-03-26 20:52:14 +0100688}
689
690
Yann Colletb923f652016-01-26 03:14:20 +0100691size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100692 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100693 size_t srcSize)
694{
Yann Colletb923f652016-01-26 03:14:20 +0100695 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100696 U32 count[MaxSeq+1];
697 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100698 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
699 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
700 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100701 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletb0aec172016-03-21 13:24:16 +0100702 U16* const llTable = seqStorePtr->litLengthStart;
Yann Colletfadda6c2016-03-22 12:14:26 +0100703 U16* const mlTable = seqStorePtr->matchLengthStart;
Yann Collet14983e72015-11-11 21:38:21 +0100704 const U32* const offsetTable = seqStorePtr->offsetStart;
Yann Colletd64f4352016-03-21 00:07:42 +0100705 const U32* const offsetTableEnd = seqStorePtr->offset;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100706 BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
Yann Collet597847a2016-03-20 19:14:22 +0100707 BYTE* const llCodeTable = seqStorePtr->llCodeStart;
Yann Colletfadda6c2016-03-22 12:14:26 +0100708 BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
Yann Collet5054ee02015-11-23 13:34:21 +0100709 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100710 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100711 BYTE* op = ostart;
Yann Colletd64f4352016-03-21 00:07:42 +0100712 size_t const nbSeq = offsetTableEnd - offsetTable;
Yann Collet14983e72015-11-11 21:38:21 +0100713 BYTE* seqHead;
714
Yann Collet14983e72015-11-11 21:38:21 +0100715 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100716 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100717 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100718 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100719 if (ZSTD_isError(cSize)) return cSize;
720 op += cSize;
721 }
722
723 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100724 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100725 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
726 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
727 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100728 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100729
Yann Colletbe391432016-03-22 23:19:28 +0100730 /* seqHead : flags for FSE encoding type */
731 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100732
Yann Colletfb810d62016-01-28 00:18:06 +0100733#define MIN_SEQ_FOR_DYNAMIC_FSE 64
734#define MAX_SEQ_FOR_STATIC_FSE 1000
735
Yann Colletb44be742016-03-26 20:52:14 +0100736 /* convert length/distances into codes */
737 ZSTD_seqToCodes(seqStorePtr, nbSeq);
Yann Collet597847a2016-03-20 19:14:22 +0100738
Yann Collet14983e72015-11-11 21:38:21 +0100739 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100740 { U32 max = MaxLL;
741 size_t const mostFrequent = FSE_countFast(count, &max, llCodeTable, nbSeq);
742 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
743 *op++ = llCodeTable[0];
744 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
745 LLtype = FSE_ENCODING_RLE;
746 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
747 LLtype = FSE_ENCODING_STATIC;
748 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
749 FSE_buildCTable(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog);
750 LLtype = FSE_ENCODING_RAW;
751 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100752 size_t nbSeq_1 = nbSeq;
753 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
754 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
755 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100756 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
757 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
758 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100759 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
760 LLtype = FSE_ENCODING_DYNAMIC;
761 } }
Yann Collet14983e72015-11-11 21:38:21 +0100762
Yann Colletb44be742016-03-26 20:52:14 +0100763 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100764 { U32 max = MaxOff;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100765 size_t const mostFrequent = FSE_countFast(count, &max, ofCodeTable, nbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100766 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100767 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100768 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
769 Offtype = FSE_ENCODING_RLE;
770 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
771 Offtype = FSE_ENCODING_STATIC;
Yann Collet48537162016-04-07 15:24:29 +0200772 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
773 FSE_buildCTable(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog);
Yann Colletfadda6c2016-03-22 12:14:26 +0100774 Offtype = FSE_ENCODING_RAW;
775 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100776 size_t nbSeq_1 = nbSeq;
777 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100778 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100779 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100780 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
781 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
782 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100783 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
784 Offtype = FSE_ENCODING_DYNAMIC;
785 } }
786
Yann Collet14983e72015-11-11 21:38:21 +0100787 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100788 { U32 max = MaxML;
789 size_t const mostFrequent = FSE_countFast(count, &max, mlCodeTable, nbSeq);
790 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100791 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100792 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
793 MLtype = FSE_ENCODING_RLE;
794 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
795 MLtype = FSE_ENCODING_STATIC;
796 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
797 FSE_buildCTable(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog);
798 MLtype = FSE_ENCODING_RAW;
799 } else {
800 size_t nbSeq_1 = nbSeq;
801 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
802 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
803 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
804 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
805 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
806 op += NCountSize; }
807 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
808 MLtype = FSE_ENCODING_DYNAMIC;
809 } }
Yann Collet14983e72015-11-11 21:38:21 +0100810
Yann Colletbe391432016-03-22 23:19:28 +0100811 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100812 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100813
814 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100815 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100816 FSE_CState_t stateMatchLength;
817 FSE_CState_t stateOffsetBits;
818 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100819
Yann Colleta910dc82016-03-18 12:37:45 +0100820 { size_t const errorCode = BIT_initCStream(&blockStream, op, oend-op);
Yann Collet597847a2016-03-20 19:14:22 +0100821 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100822
Yann Collet597847a2016-03-20 19:14:22 +0100823 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100824 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100825 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100826 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colletb0aec172016-03-21 13:24:16 +0100827 BIT_addBits(&blockStream, llTable[nbSeq-1], LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100828 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Collet25125972016-03-23 14:00:09 +0100829 BIT_addBits(&blockStream, mlTable[nbSeq-1], ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100830 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Collet646693e2016-03-24 02:31:27 +0100831 BIT_addBits(&blockStream, offsetTable[nbSeq-1], ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100832 BIT_flushBits(&blockStream);
833
Yann Colletfadda6c2016-03-22 12:14:26 +0100834 { size_t n;
835 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Colletb9151402016-03-26 17:18:11 +0100836 const BYTE ofCode = ofCodeTable[n];
Yann Collet7cbe79a2016-03-23 22:31:57 +0100837 const BYTE mlCode = mlCodeTable[n];
838 const BYTE llCode = llCodeTable[n];
839 const U32 llBits = LL_bits[llCode];
840 const U32 mlBits = ML_bits[mlCode];
Yann Colletb9151402016-03-26 17:18:11 +0100841 const U32 ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100842 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100843 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
844 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
845 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
846 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200847 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100848 BIT_flushBits(&blockStream); /* (7)*/
Yann Collet7cbe79a2016-03-23 22:31:57 +0100849 BIT_addBits(&blockStream, llTable[n], llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100850 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100851 BIT_addBits(&blockStream, mlTable[n], mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100852 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
853 BIT_addBits(&blockStream, offsetTable[n], ofBits); /* 31 */
854 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100855 } }
Yann Collet14983e72015-11-11 21:38:21 +0100856
857 FSE_flushCState(&blockStream, &stateMatchLength);
858 FSE_flushCState(&blockStream, &stateOffsetBits);
859 FSE_flushCState(&blockStream, &stateLitLength);
860
Yann Colletb9151402016-03-26 17:18:11 +0100861 { size_t const streamSize = BIT_closeCStream(&blockStream);
862 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
863 op += streamSize;
864 } }
Yann Collet14983e72015-11-11 21:38:21 +0100865
866 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100867_check_compressibility:
Yann Colletfadda6c2016-03-22 12:14:26 +0100868 { size_t const minGain = ZSTD_minGain(srcSize);
869 size_t const maxCSize = srcSize - minGain;
870 if ((size_t)(op-ostart) >= maxCSize) return 0; }
Yann Collet14983e72015-11-11 21:38:21 +0100871
Yann Collet5054ee02015-11-23 13:34:21 +0100872 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100873}
874
875
Yann Collet95cd0c22016-03-08 18:24:21 +0100876/*! ZSTD_storeSeq() :
877 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
878 `offsetCode` : distance to match, or 0 == repCode.
879 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100880*/
881MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode)
882{
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100883#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100884 static const BYTE* g_start = NULL;
Yann Colletb0aec172016-03-21 13:24:16 +0100885 const U32 pos = (U32)(literals - g_start);
Yann Collet14983e72015-11-11 21:38:21 +0100886 if (g_start==NULL) g_start = literals;
Yann Collet3f8ed502016-05-05 03:01:13 +0200887 if ((pos > 2587900) && (pos < 2588050))
Yann Colletb9151402016-03-26 17:18:11 +0100888 printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
Yann Collet433a5cc2016-03-25 11:43:48 +0100889 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +0100890#endif
inikep35b891c2016-05-20 19:42:20 +0200891 ZSTD_statsUpdatePrices(seqStorePtr->stats, litLength, literals, offsetCode, matchCode);
Yann Collet14983e72015-11-11 21:38:21 +0100892
893 /* copy Literals */
894 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
895 seqStorePtr->lit += litLength;
896
897 /* literal Length */
Yann Collet5d393572016-04-07 17:19:00 +0200898 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->litLength - seqStorePtr->litLengthStart); }
899 *seqStorePtr->litLength++ = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100900
901 /* match offset */
Yann Collet646693e2016-03-24 02:31:27 +0100902 *(seqStorePtr->offset++) = (U32)offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100903
904 /* match Length */
Yann Collet5d393572016-04-07 17:19:00 +0200905 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->matchLength - seqStorePtr->matchLengthStart); }
906 *seqStorePtr->matchLength++ = (U16)matchCode;
Yann Collet14983e72015-11-11 21:38:21 +0100907}
908
909
Yann Collet7d360282016-02-12 00:07:30 +0100910/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100911* Match length counter
912***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100913static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100914{
Yann Collet863ec402016-01-28 17:56:33 +0100915 if (MEM_isLittleEndian()) {
916 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100917# if defined(_MSC_VER) && defined(_WIN64)
918 unsigned long r = 0;
919 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100920 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100921# elif defined(__GNUC__) && (__GNUC__ >= 3)
922 return (__builtin_ctzll((U64)val) >> 3);
923# else
924 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 };
925 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
926# endif
Yann Collet863ec402016-01-28 17:56:33 +0100927 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100928# if defined(_MSC_VER)
929 unsigned long r=0;
930 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100931 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100932# elif defined(__GNUC__) && (__GNUC__ >= 3)
933 return (__builtin_ctz((U32)val) >> 3);
934# else
935 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 };
936 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
937# endif
938 }
Yann Collet863ec402016-01-28 17:56:33 +0100939 } else { /* Big Endian CPU */
940 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100941# if defined(_MSC_VER) && defined(_WIN64)
942 unsigned long r = 0;
943 _BitScanReverse64( &r, val );
944 return (unsigned)(r>>3);
945# elif defined(__GNUC__) && (__GNUC__ >= 3)
946 return (__builtin_clzll(val) >> 3);
947# else
948 unsigned r;
949 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
950 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
951 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
952 r += (!val);
953 return r;
954# endif
Yann Collet863ec402016-01-28 17:56:33 +0100955 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100956# if defined(_MSC_VER)
957 unsigned long r = 0;
958 _BitScanReverse( &r, (unsigned long)val );
959 return (unsigned)(r>>3);
960# elif defined(__GNUC__) && (__GNUC__ >= 3)
961 return (__builtin_clz((U32)val) >> 3);
962# else
963 unsigned r;
964 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
965 r += (!val);
966 return r;
967# endif
Yann Collet863ec402016-01-28 17:56:33 +0100968 } }
Yann Collet14983e72015-11-11 21:38:21 +0100969}
970
971
Yann Collet5054ee02015-11-23 13:34:21 +0100972static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100973{
974 const BYTE* const pStart = pIn;
975
Yann Colletfb810d62016-01-28 00:18:06 +0100976 while ((pIn<pInLimit-(sizeof(size_t)-1))) {
Yann Collet7d360282016-02-12 00:07:30 +0100977 size_t diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100978 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
979 pIn += ZSTD_NbCommonBytes(diff);
980 return (size_t)(pIn - pStart);
981 }
Yann Collet14983e72015-11-11 21:38:21 +0100982 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
983 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
984 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
985 return (size_t)(pIn - pStart);
986}
987
Yann Collet04b12d82016-02-11 06:23:24 +0100988/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100989* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100990* convention : on reaching mEnd, match count continue starting from iStart
991*/
992static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
993{
994 size_t matchLength;
995 const BYTE* vEnd = ip + (mEnd - match);
996 if (vEnd > iEnd) vEnd = iEnd;
997 matchLength = ZSTD_count(ip, match, vEnd);
998 if (match + matchLength == mEnd)
999 matchLength += ZSTD_count(ip+matchLength, iStart, iEnd);
1000 return matchLength;
1001}
1002
Yann Collet14983e72015-11-11 21:38:21 +01001003
Yann Collet863ec402016-01-28 17:56:33 +01001004/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001005* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +01001006***************************************/
inikepcc52a972016-02-19 10:09:35 +01001007static const U32 prime3bytes = 506832829U;
1008static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
inikepe2446b02016-03-07 10:07:08 +01001009static size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); }
inikepcc52a972016-02-19 10:09:35 +01001010
Yann Collet4b100f42015-10-30 15:49:48 +01001011static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +01001012static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +01001013static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +01001014
Yann Collet4b100f42015-10-30 15:49:48 +01001015static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001016static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001017static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001018
1019static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001020static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001021static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001022
Yann Collet14983e72015-11-11 21:38:21 +01001023static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001024static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001025static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001026
Yann Collet5be2dd22015-11-11 13:43:58 +01001027static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001028{
1029 switch(mls)
1030 {
1031 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001032 case 4: return ZSTD_hash4Ptr(p, hBits);
1033 case 5: return ZSTD_hash5Ptr(p, hBits);
1034 case 6: return ZSTD_hash6Ptr(p, hBits);
1035 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001036 }
1037}
Yann Collet2acb5d32015-10-29 16:49:43 +01001038
Yann Collet863ec402016-01-28 17:56:33 +01001039
Yann Collet2ce49232016-02-02 14:36:49 +01001040/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001041* Fast Scan
1042***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001043static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1044{
1045 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001046 const U32 hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001047 const BYTE* const base = zc->base;
1048 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet2ce49232016-02-02 14:36:49 +01001049 const BYTE* const iend = ((const BYTE*)end) - 8;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001050 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001051
Yann Colletfb810d62016-01-28 00:18:06 +01001052 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001053 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001054 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001055 }
1056}
1057
1058
Yann Collet1f44b3f2015-11-05 17:32:18 +01001059FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001060void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc,
Yann Collet89db5e02015-11-13 11:27:46 +01001061 const void* src, size_t srcSize,
1062 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001063{
Yann Collet417890c2015-12-04 17:16:37 +01001064 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001065 const U32 hBits = zc->params.cParams.hashLog;
Yann Colletc3652152015-11-24 14:06:07 +01001066 seqStore_t* seqStorePtr = &(zc->seqStore);
1067 const BYTE* const base = zc->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001068 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001069 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001070 const BYTE* anchor = istart;
Yann Colletd94efbf2015-12-29 14:29:08 +01001071 const U32 lowIndex = zc->dictLimit;
1072 const BYTE* const lowest = base + lowIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001073 const BYTE* const iend = istart + srcSize;
1074 const BYTE* const ilimit = iend - 8;
Yann Collet89db5e02015-11-13 11:27:46 +01001075 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001076
Yann Collet1f44b3f2015-11-05 17:32:18 +01001077 /* init */
Yann Collet743402c2015-11-20 12:03:53 +01001078 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001079 if (ip < lowest+REPCODE_STARTVALUE) ip = lowest+REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001080
1081 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001082 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Collet5054ee02015-11-23 13:34:21 +01001083 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001084 size_t offset;
Yann Collet5be2dd22015-11-11 13:43:58 +01001085 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Colletd94efbf2015-12-29 14:29:08 +01001086 const U32 matchIndex = hashTable[h];
1087 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001088 const U32 current = (U32)(ip-base);
1089 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001090
Yann Colletfb810d62016-01-28 00:18:06 +01001091 if (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)) { /* note : by construction, offset_1 <= current */
inikep7bc19b62016-04-06 09:46:01 +02001092 mlCode = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
Yann Collet402fdcf2015-11-20 12:46:08 +01001093 ip++;
inikep7bc19b62016-04-06 09:46:01 +02001094 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mlCode-MINMATCH);
inikep59453082016-03-16 15:35:14 +01001095 } else {
Yann Colletd94efbf2015-12-29 14:29:08 +01001096 if ( (matchIndex <= lowIndex) ||
Yann Colletfb810d62016-01-28 00:18:06 +01001097 (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001098 ip += ((ip-anchor) >> g_searchStrength) + 1;
1099 continue;
1100 }
inikep7bc19b62016-04-06 09:46:01 +02001101 mlCode = ZSTD_count(ip+EQUAL_READ32, match+EQUAL_READ32, iend) + EQUAL_READ32;
Yann Collet402fdcf2015-11-20 12:46:08 +01001102 offset = ip-match;
Yann Collet5054ee02015-11-23 13:34:21 +01001103 while ((ip>anchor) && (match>lowest) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001104 offset_2 = offset_1;
1105 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001106
inikep7bc19b62016-04-06 09:46:01 +02001107 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mlCode-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001108 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001109
Yann Collet402fdcf2015-11-20 12:46:08 +01001110 /* match found */
inikep7bc19b62016-04-06 09:46:01 +02001111 ip += mlCode;
Yann Collet402fdcf2015-11-20 12:46:08 +01001112 anchor = ip;
1113
Yann Colletfb810d62016-01-28 00:18:06 +01001114 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001115 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001116 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 +01001117 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1118 /* check immediate repcode */
1119 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001120 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001121 /* store sequence */
inikep7bc19b62016-04-06 09:46:01 +02001122 size_t const rlCode = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
Yann Collet70e45772016-03-19 18:08:32 +01001123 { 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 +01001124 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
inikep7bc19b62016-04-06 09:46:01 +02001125 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rlCode-MINMATCH);
1126 ip += rlCode;
Yann Collet402fdcf2015-11-20 12:46:08 +01001127 anchor = ip;
1128 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001129 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001130
Yann Collet70e45772016-03-19 18:08:32 +01001131 /* Last Literals */
1132 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001133 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1134 seqStorePtr->lit += lastLLSize;
1135 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001136}
1137
1138
Yann Collet82260dd2016-02-11 07:14:25 +01001139static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001140 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001141{
Yann Collet3b719252016-03-30 19:48:05 +02001142 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001143 switch(mls)
1144 {
1145 default:
1146 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001147 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001148 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001149 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001150 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001151 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001152 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001153 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001154 }
1155}
Yann Colletf3eca252015-10-22 15:31:46 +01001156
Yann Colletf3eca252015-10-22 15:31:46 +01001157
Yann Collet82260dd2016-02-11 07:14:25 +01001158static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001159 const void* src, size_t srcSize,
1160 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001161{
1162 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001163 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001164 seqStore_t* seqStorePtr = &(ctx->seqStore);
1165 const BYTE* const base = ctx->base;
1166 const BYTE* const dictBase = ctx->dictBase;
1167 const BYTE* const istart = (const BYTE*)src;
1168 const BYTE* ip = istart;
1169 const BYTE* anchor = istart;
1170 const U32 lowLimit = ctx->lowLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001171 const BYTE* const dictStart = dictBase + lowLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001172 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001173 const BYTE* const lowPrefixPtr = base + dictLimit;
1174 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001175 const BYTE* const iend = istart + srcSize;
1176 const BYTE* const ilimit = iend - 8;
1177
Yann Collet138e89c2015-11-17 14:26:54 +01001178 U32 offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001179
1180
1181 /* init */
1182 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001183 /* skip first position to avoid read overflow during repcode match check */
Yann Colletfb810d62016-01-28 00:18:06 +01001184 hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0);
Yann Collet61e16ce2016-01-31 02:04:15 +01001185 ip += REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001186
1187 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001188 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001189 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001190 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001191 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001192 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001193 const U32 current = (U32)(ip-base);
Yann Collet743402c2015-11-20 12:03:53 +01001194 const U32 repIndex = current + 1 - offset_1;
Yann Collet402fdcf2015-11-20 12:46:08 +01001195 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001196 const BYTE* repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001197 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001198 U32 offset;
Yann Collet89db5e02015-11-13 11:27:46 +01001199 hashTable[h] = current; /* update hash table */
1200
Yann Collet52447382016-03-20 16:00:00 +01001201 if ( ((repIndex >= dictLimit) || (repIndex <= dictLimit-4))
Yann Colletfb810d62016-01-28 00:18:06 +01001202 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001203 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001204 mlCode = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001205 ip++;
inikep7bc19b62016-04-06 09:46:01 +02001206 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mlCode-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001207 } else {
Yann Collet402fdcf2015-11-20 12:46:08 +01001208 if ( (matchIndex < lowLimit) ||
Yann Collet52447382016-03-20 16:00:00 +01001209 (MEM_read32(match) != MEM_read32(ip)) ) {
1210 ip += ((ip-anchor) >> g_searchStrength) + 1;
1211 continue;
1212 }
1213 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001214 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
inikep7bc19b62016-04-06 09:46:01 +02001215 mlCode = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Colletfb810d62016-01-28 00:18:06 +01001216 while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001217 offset = current - matchIndex;
1218 offset_2 = offset_1;
1219 offset_1 = offset;
inikep7bc19b62016-04-06 09:46:01 +02001220 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mlCode-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001221 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001222
Yann Collet5054ee02015-11-23 13:34:21 +01001223 /* found a match : store it */
inikep7bc19b62016-04-06 09:46:01 +02001224 ip += mlCode;
Yann Collet402fdcf2015-11-20 12:46:08 +01001225 anchor = ip;
1226
Yann Colletfb810d62016-01-28 00:18:06 +01001227 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001228 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001229 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001230 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1231 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001232 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001233 U32 const current2 = (U32)(ip-base);
1234 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001235 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet743402c2015-11-20 12:03:53 +01001236 if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001237 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001238 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001239 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001240 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001241 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001242 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001243 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001244 anchor = ip;
1245 continue;
1246 }
Yann Collet743402c2015-11-20 12:03:53 +01001247 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001248 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001249
1250 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001251 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001252 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1253 seqStorePtr->lit += lastLLSize;
1254 }
Yann Collet89db5e02015-11-13 11:27:46 +01001255}
1256
1257
Yann Collet82260dd2016-02-11 07:14:25 +01001258static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001259 const void* src, size_t srcSize)
1260{
Yann Collet3b719252016-03-30 19:48:05 +02001261 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001262 switch(mls)
1263 {
1264 default:
1265 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001266 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001267 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001268 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001269 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001270 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001271 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001272 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001273 }
1274}
1275
1276
inikep75716852016-04-06 12:34:42 +02001277
inikep2db1eb72016-04-06 17:14:19 +02001278
Yann Collet04b12d82016-02-11 06:23:24 +01001279/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001280* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001281***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001282/** ZSTD_insertBt1() : add one or multiple positions to tree.
1283* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001284* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001285static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1286 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001287{
1288 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001289 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet5be2dd22015-11-11 13:43:58 +01001290 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet8a57b922016-04-04 13:49:18 +02001291 U32* const bt = zc->chainTable;
1292 const U32 btLog = zc->params.cParams.chainLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001293 const U32 btMask= (1 << btLog) - 1;
1294 U32 matchIndex = hashTable[h];
1295 size_t commonLengthSmaller=0, commonLengthLarger=0;
1296 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001297 const BYTE* const dictBase = zc->dictBase;
1298 const U32 dictLimit = zc->dictLimit;
1299 const BYTE* const dictEnd = dictBase + dictLimit;
1300 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001301 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001302 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001303 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001304 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001305 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001306 U32 dummy32; /* to be nullified at the end */
Yann Collet03526e12015-11-23 15:29:15 +01001307 const U32 windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001308 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001309 size_t bestLength = 8;
Yann Collet7beaa052016-01-21 11:57:45 +01001310 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1311 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1312 predictedSmall += (predictedSmall>0);
1313 predictedLarge += (predictedLarge>0);
Yann Colletf48e35c2015-11-07 01:13:31 +01001314
Yann Collet6c3e2e72015-12-11 10:44:07 +01001315 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001316
Yann Colletfb810d62016-01-28 00:18:06 +01001317 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001318 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001319 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet793c6492016-04-09 20:32:00 +02001320#if 0 /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001321 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001322 if (matchIndex == predictedSmall) {
1323 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001324 *smallerPtr = matchIndex;
1325 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1326 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1327 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001328 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001329 continue;
1330 }
Yann Colletfb810d62016-01-28 00:18:06 +01001331 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001332 *largerPtr = matchIndex;
1333 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1334 largerPtr = nextPtr;
1335 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001336 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001337 continue;
1338 }
Yann Collet04b12d82016-02-11 06:23:24 +01001339#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001340 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001341 match = base + matchIndex;
1342 if (match[matchLength] == ip[matchLength])
1343 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001344 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001345 match = dictBase + matchIndex;
1346 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1347 if (matchIndex+matchLength >= dictLimit)
1348 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1349 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001350
Yann Colletb8a6f682016-02-15 17:06:29 +01001351 if (matchLength > bestLength) {
1352 bestLength = matchLength;
1353 if (matchLength > matchEndIdx - matchIndex)
1354 matchEndIdx = matchIndex + (U32)matchLength;
1355 }
Yann Colletee3f4512015-12-29 22:26:09 +01001356
Yann Collet59d70632015-11-04 12:05:27 +01001357 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001358 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001359
Yann Colletfb810d62016-01-28 00:18:06 +01001360 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001361 /* match is smaller than current */
1362 *smallerPtr = matchIndex; /* update smaller idx */
1363 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001364 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001365 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001366 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001367 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001368 /* match is larger than current */
1369 *largerPtr = matchIndex;
1370 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001371 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001372 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001373 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001374 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001375
Yann Collet59d70632015-11-04 12:05:27 +01001376 *smallerPtr = *largerPtr = 0;
Yann Colletb8a6f682016-02-15 17:06:29 +01001377 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384));
1378 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1379 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001380}
1381
1382
Yann Collet82260dd2016-02-11 07:14:25 +01001383static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001384 ZSTD_CCtx* zc,
1385 const BYTE* const ip, const BYTE* const iend,
1386 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001387 U32 nbCompares, const U32 mls,
1388 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001389{
1390 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001391 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet03526e12015-11-23 15:29:15 +01001392 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet8a57b922016-04-04 13:49:18 +02001393 U32* const bt = zc->chainTable;
1394 const U32 btLog = zc->params.cParams.chainLog - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001395 const U32 btMask= (1 << btLog) - 1;
1396 U32 matchIndex = hashTable[h];
1397 size_t commonLengthSmaller=0, commonLengthLarger=0;
1398 const BYTE* const base = zc->base;
1399 const BYTE* const dictBase = zc->dictBase;
1400 const U32 dictLimit = zc->dictLimit;
1401 const BYTE* const dictEnd = dictBase + dictLimit;
1402 const BYTE* const prefixStart = base + dictLimit;
1403 const U32 current = (U32)(ip-base);
1404 const U32 btLow = btMask >= current ? 0 : current - btMask;
1405 const U32 windowLow = zc->lowLimit;
1406 U32* smallerPtr = bt + 2*(current&btMask);
1407 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001408 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001409 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001410 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001411
Yann Collet6c3e2e72015-12-11 10:44:07 +01001412 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001413
Yann Colletfb810d62016-01-28 00:18:06 +01001414 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001415 U32* nextPtr = bt + 2*(matchIndex & btMask);
1416 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1417 const BYTE* match;
1418
Yann Colletfb810d62016-01-28 00:18:06 +01001419 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001420 match = base + matchIndex;
1421 if (match[matchLength] == ip[matchLength])
1422 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001423 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001424 match = dictBase + matchIndex;
1425 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001426 if (matchIndex+matchLength >= dictLimit)
1427 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001428 }
1429
Yann Colletfb810d62016-01-28 00:18:06 +01001430 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001431 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001432 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet03526e12015-11-23 15:29:15 +01001433 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001434 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001435 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1436 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1437 }
1438
Yann Colletfb810d62016-01-28 00:18:06 +01001439 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001440 /* match is smaller than current */
1441 *smallerPtr = matchIndex; /* update smaller idx */
1442 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1443 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1444 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1445 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001446 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001447 /* match is larger than current */
1448 *largerPtr = matchIndex;
1449 commonLengthLarger = matchLength;
1450 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1451 largerPtr = nextPtr;
1452 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001453 } }
Yann Collet03526e12015-11-23 15:29:15 +01001454
1455 *smallerPtr = *largerPtr = 0;
1456
Yann Collet72e84cf2015-12-31 19:08:44 +01001457 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001458 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001459}
1460
Yann Collet2cc12cb2016-01-01 07:47:58 +01001461
Yann Colletb8a6f682016-02-15 17:06:29 +01001462static 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 +01001463{
1464 const BYTE* const base = zc->base;
1465 const U32 target = (U32)(ip - base);
1466 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001467
1468 while(idx < target)
1469 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001470}
1471
Yann Collet52447382016-03-20 16:00:00 +01001472/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001473static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001474 ZSTD_CCtx* zc,
1475 const BYTE* const ip, const BYTE* const iLimit,
1476 size_t* offsetPtr,
1477 const U32 maxNbAttempts, const U32 mls)
1478{
1479 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001480 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001481 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1482}
1483
1484
Yann Collet768c6bc2016-02-10 14:01:49 +01001485static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001486 ZSTD_CCtx* zc, /* Index table will be updated */
1487 const BYTE* ip, const BYTE* const iLimit,
1488 size_t* offsetPtr,
1489 const U32 maxNbAttempts, const U32 matchLengthSearch)
1490{
1491 switch(matchLengthSearch)
1492 {
1493 default :
1494 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1495 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1496 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1497 }
1498}
1499
1500
Yann Colletb8a6f682016-02-15 17:06:29 +01001501static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1502{
1503 const BYTE* const base = zc->base;
1504 const U32 target = (U32)(ip - base);
1505 U32 idx = zc->nextToUpdate;
1506
1507 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1508}
1509
inikep64d7bcb2016-04-07 19:14:09 +02001510
1511
Yann Collet03526e12015-11-23 15:29:15 +01001512/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001513static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001514 ZSTD_CCtx* zc,
1515 const BYTE* const ip, const BYTE* const iLimit,
1516 size_t* offsetPtr,
1517 const U32 maxNbAttempts, const U32 mls)
1518{
Yann Colletee3f4512015-12-29 22:26:09 +01001519 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001520 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001521 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001522}
1523
1524
Yann Collet82260dd2016-02-11 07:14:25 +01001525static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001526 ZSTD_CCtx* zc, /* Index table will be updated */
1527 const BYTE* ip, const BYTE* const iLimit,
1528 size_t* offsetPtr,
1529 const U32 maxNbAttempts, const U32 matchLengthSearch)
1530{
1531 switch(matchLengthSearch)
1532 {
1533 default :
1534 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1535 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1536 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1537 }
1538}
1539
1540
Yann Collet5106a762015-11-05 15:00:24 +01001541
inikep64d7bcb2016-04-07 19:14:09 +02001542/* ***********************
1543* Hash Chain
1544*************************/
1545
1546#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1547
inikepafe1f792016-04-07 19:50:03 +02001548
inikep64d7bcb2016-04-07 19:14:09 +02001549/* Update chains up to ip (excluded)
1550 Assumption : always within prefix (ie. not within extDict) */
1551FORCE_INLINE
1552U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1553{
1554 U32* const hashTable = zc->hashTable;
1555 const U32 hashLog = zc->params.cParams.hashLog;
1556 U32* const chainTable = zc->chainTable;
1557 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1558 const BYTE* const base = zc->base;
1559 const U32 target = (U32)(ip - base);
1560 U32 idx = zc->nextToUpdate;
1561
1562 while(idx < target) {
1563 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1564 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1565 hashTable[h] = idx;
1566 idx++;
1567 }
1568
1569 zc->nextToUpdate = target;
1570 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1571}
1572
1573
1574
1575FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1576size_t ZSTD_HcFindBestMatch_generic (
1577 ZSTD_CCtx* zc, /* Index table will be updated */
1578 const BYTE* const ip, const BYTE* const iLimit,
1579 size_t* offsetPtr,
1580 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1581{
1582 U32* const chainTable = zc->chainTable;
1583 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1584 const U32 chainMask = chainSize-1;
1585 const BYTE* const base = zc->base;
1586 const BYTE* const dictBase = zc->dictBase;
1587 const U32 dictLimit = zc->dictLimit;
1588 const BYTE* const prefixStart = base + dictLimit;
1589 const BYTE* const dictEnd = dictBase + dictLimit;
1590 const U32 lowLimit = zc->lowLimit;
1591 const U32 current = (U32)(ip-base);
1592 const U32 minChain = current > chainSize ? current - chainSize : 0;
1593 int nbAttempts=maxNbAttempts;
1594 size_t ml=EQUAL_READ32-1;
1595
1596 /* HC4 match finder */
1597 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1598
1599 for ( ; (matchIndex>lowLimit) && (nbAttempts) ; nbAttempts--) {
1600 const BYTE* match;
1601 size_t currentMl=0;
1602 if ((!extDict) || matchIndex >= dictLimit) {
1603 match = base + matchIndex;
1604 if (match[ml] == ip[ml]) /* potentially better */
1605 currentMl = ZSTD_count(ip, match, iLimit);
1606 } else {
1607 match = dictBase + matchIndex;
1608 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1609 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1610 }
1611
1612 /* save best solution */
1613 if (currentMl > ml) { ml = currentMl; *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }
1614
1615 if (matchIndex <= minChain) break;
1616 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1617 }
1618
1619 return ml;
1620}
1621
1622
1623FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1624 ZSTD_CCtx* zc,
1625 const BYTE* ip, const BYTE* const iLimit,
1626 size_t* offsetPtr,
1627 const U32 maxNbAttempts, const U32 matchLengthSearch)
1628{
1629 switch(matchLengthSearch)
1630 {
1631 default :
1632 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1633 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1634 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1635 }
1636}
1637
1638
1639FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1640 ZSTD_CCtx* zc,
1641 const BYTE* ip, const BYTE* const iLimit,
1642 size_t* offsetPtr,
1643 const U32 maxNbAttempts, const U32 matchLengthSearch)
1644{
1645 switch(matchLengthSearch)
1646 {
1647 default :
1648 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1649 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1650 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1651 }
1652}
1653
inikep64d7bcb2016-04-07 19:14:09 +02001654
Yann Collet287b7d92015-11-22 13:24:05 +01001655/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001656* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001657*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001658FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001659void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1660 const void* src, size_t srcSize,
1661 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001662{
inikepfaa8d8a2016-04-05 19:01:10 +02001663 seqStore_t* seqStorePtr = &(ctx->seqStore);
1664 const BYTE* const istart = (const BYTE*)src;
1665 const BYTE* ip = istart;
1666 const BYTE* anchor = istart;
1667 const BYTE* const iend = istart + srcSize;
1668 const BYTE* const ilimit = iend - 8;
1669 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001670
Yann Collet793c6492016-04-09 20:32:00 +02001671 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1672 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001673
inikep64d7bcb2016-04-07 19:14:09 +02001674 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1675 size_t* offsetPtr,
1676 U32 maxNbAttempts, U32 matchLengthSearch);
1677 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
1678
inikepfaa8d8a2016-04-05 19:01:10 +02001679 /* init */
1680 U32 rep[ZSTD_REP_INIT];
Yann Colletea63bb72016-04-08 15:25:32 +02001681 { U32 i ; for (i=0; i<ZSTD_REP_INIT; i++) rep[i]=REPCODE_STARTVALUE; }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001682
inikep64d7bcb2016-04-07 19:14:09 +02001683 ctx->nextToUpdate3 = ctx->nextToUpdate;
inikepfaa8d8a2016-04-05 19:01:10 +02001684 ZSTD_resetSeqStore(seqStorePtr);
1685 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001686
inikepfaa8d8a2016-04-05 19:01:10 +02001687 /* Match Loop */
1688 while (ip < ilimit) {
1689 size_t matchLength=0;
1690 size_t offset=0;
1691 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001692
inikepfaa8d8a2016-04-05 19:01:10 +02001693 /* check repCode */
inikep64d7bcb2016-04-07 19:14:09 +02001694 if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep[0])) {
inikepfaa8d8a2016-04-05 19:01:10 +02001695 /* repcode : we take it */
inikep64d7bcb2016-04-07 19:14:09 +02001696 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-rep[0], iend) + EQUAL_READ32;
1697 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001698 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001699
inikepfaa8d8a2016-04-05 19:01:10 +02001700 /* first search (depth 0) */
1701 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001702 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001703 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001704 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001705 }
Yann Collet5106a762015-11-05 15:00:24 +01001706
inikep7bc19b62016-04-06 09:46:01 +02001707 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001708 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1709 continue;
1710 }
1711
inikep64d7bcb2016-04-07 19:14:09 +02001712 /* let's try to find a better solution */
1713 if (depth>=1)
1714 while (ip<ilimit) {
1715 ip ++;
1716 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - rep[0]))) {
1717 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-rep[0], iend) + EQUAL_READ32;
1718 int const gain2 = (int)(mlRep * 3);
1719 int const gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1720 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1721 matchLength = mlRep, offset = 0, start = ip;
1722 }
1723 { size_t offset2=99999999;
1724 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1725 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1726 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
1727 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1728 matchLength = ml2, offset = offset2, start = ip;
1729 continue; /* search a better one */
1730 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001731
inikep64d7bcb2016-04-07 19:14:09 +02001732 /* let's find an even better one */
1733 if ((depth==2) && (ip<ilimit)) {
1734 ip ++;
1735 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - rep[0]))) {
1736 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-rep[0], iend) + EQUAL_READ32;
1737 int const gain2 = (int)(ml2 * 4);
1738 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1739 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1740 matchLength = ml2, offset = 0, start = ip;
1741 }
1742 { size_t offset2=99999999;
1743 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1744 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1745 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
1746 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1747 matchLength = ml2, offset = offset2, start = ip;
1748 continue;
1749 } } }
1750 break; /* nothing found : store previous solution */
1751 }
1752
1753 /* catch up */
1754 if (offset) {
1755 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1756 { start--; matchLength++; }
1757 rep[1] = rep[0]; rep[0] = (U32)(offset - ZSTD_REP_MOVE);
1758 }
1759
inikepfaa8d8a2016-04-05 19:01:10 +02001760 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001761_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001762 { size_t const litLength = start - anchor;
1763 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1764 anchor = ip = start + matchLength;
1765 }
Yann Collet48537162016-04-07 15:24:29 +02001766
inikepfaa8d8a2016-04-05 19:01:10 +02001767 /* check immediate repcode */
1768 while ( (ip <= ilimit)
1769 && (MEM_read32(ip) == MEM_read32(ip - rep[1])) ) {
1770 /* store sequence */
inikep7bc19b62016-04-06 09:46:01 +02001771 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-rep[1], iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001772 offset = rep[1]; rep[1] = rep[0]; rep[0] = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02001773 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1774 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02001775 anchor = ip;
1776 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02001777 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001778
1779 /* Last Literals */
1780 { size_t const lastLLSize = iend - anchor;
1781 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1782 seqStorePtr->lit += lastLLSize;
inikep35b891c2016-05-20 19:42:20 +02001783 ZSTD_statsUpdatePrices(seqStorePtr->stats, lastLLSize, anchor, 0, 0);
Yann Collet5106a762015-11-05 15:00:24 +01001784 }
Yann Collet5106a762015-11-05 15:00:24 +01001785}
1786
Yann Collet5be2dd22015-11-11 13:43:58 +01001787
inikep64d7bcb2016-04-07 19:14:09 +02001788static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1789{
1790 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
1791}
1792
1793static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1794{
1795 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
1796}
1797
1798static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1799{
1800 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
1801}
1802
1803static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1804{
1805 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
1806}
1807
1808
inikepfaa8d8a2016-04-05 19:01:10 +02001809FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001810void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1811 const void* src, size_t srcSize,
1812 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01001813{
inikepfaa8d8a2016-04-05 19:01:10 +02001814 seqStore_t* seqStorePtr = &(ctx->seqStore);
1815 const BYTE* const istart = (const BYTE*)src;
1816 const BYTE* ip = istart;
1817 const BYTE* anchor = istart;
1818 const BYTE* const iend = istart + srcSize;
1819 const BYTE* const ilimit = iend - 8;
1820 const BYTE* const base = ctx->base;
1821 const U32 dictLimit = ctx->dictLimit;
1822 const BYTE* const prefixStart = base + dictLimit;
1823 const BYTE* const dictBase = ctx->dictBase;
1824 const BYTE* const dictEnd = dictBase + dictLimit;
1825 const BYTE* const dictStart = dictBase + ctx->lowLimit;
1826
1827 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
1828 const U32 mls = ctx->params.cParams.searchLength;
1829
inikep64d7bcb2016-04-07 19:14:09 +02001830 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1831 size_t* offsetPtr,
1832 U32 maxNbAttempts, U32 matchLengthSearch);
1833 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
1834
inikepfaa8d8a2016-04-05 19:01:10 +02001835 /* init */
1836 U32 rep[ZSTD_REP_INIT];
Yann Colletea63bb72016-04-08 15:25:32 +02001837 { U32 i; for (i=0; i<ZSTD_REP_INIT; i++) rep[i]=REPCODE_STARTVALUE; }
inikepfaa8d8a2016-04-05 19:01:10 +02001838
inikep64d7bcb2016-04-07 19:14:09 +02001839 ctx->nextToUpdate3 = ctx->nextToUpdate;
inikepfaa8d8a2016-04-05 19:01:10 +02001840 ZSTD_resetSeqStore(seqStorePtr);
1841 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
1842
1843 /* Match Loop */
1844 while (ip < ilimit) {
1845 size_t matchLength=0;
1846 size_t offset=0;
1847 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02001848 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02001849
1850 /* check repCode */
1851 {
inikep64d7bcb2016-04-07 19:14:09 +02001852 const U32 repIndex = (U32)(current+1 - rep[0]);
inikepfaa8d8a2016-04-05 19:01:10 +02001853 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1854 const BYTE* const repMatch = repBase + repIndex;
1855 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02001856 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02001857 /* repcode detected we should take it */
1858 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02001859 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1860 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02001861 } }
1862
1863 /* first search (depth 0) */
1864 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001865 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001866 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001867 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001868 }
1869
inikep7bc19b62016-04-06 09:46:01 +02001870 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001871 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1872 continue;
1873 }
1874
inikep64d7bcb2016-04-07 19:14:09 +02001875 /* let's try to find a better solution */
1876 if (depth>=1)
1877 while (ip<ilimit) {
1878 ip ++;
1879 current++;
1880 /* check repCode */
1881 if (offset) {
1882 const U32 repIndex = (U32)(current - rep[0]);
1883 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1884 const BYTE* const repMatch = repBase + repIndex;
1885 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
1886 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1887 /* repcode detected */
1888 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
1889 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1890 int const gain2 = (int)(repLength * 3);
1891 int const gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1892 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
1893 matchLength = repLength, offset = 0, start = ip;
1894 } }
1895
1896 /* search match, depth 1 */
1897 { size_t offset2=99999999;
1898 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1899 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1900 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
1901 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1902 matchLength = ml2, offset = offset2, start = ip;
1903 continue; /* search a better one */
1904 } }
1905
1906 /* let's find an even better one */
1907 if ((depth==2) && (ip<ilimit)) {
1908 ip ++;
1909 current++;
1910 /* check repCode */
1911 if (offset) {
1912 const U32 repIndex = (U32)(current - rep[0]);
1913 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1914 const BYTE* const repMatch = repBase + repIndex;
1915 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
1916 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1917 /* repcode detected */
1918 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
1919 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1920 int gain2 = (int)(repLength * 4);
1921 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1922 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
1923 matchLength = repLength, offset = 0, start = ip;
1924 } }
1925
1926 /* search match, depth 2 */
1927 { size_t offset2=99999999;
1928 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1929 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1930 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
1931 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1932 matchLength = ml2, offset = offset2, start = ip;
1933 continue;
1934 } } }
1935 break; /* nothing found : store previous solution */
1936 }
1937
inikepfaa8d8a2016-04-05 19:01:10 +02001938 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001939 if (offset) {
inikepfaa8d8a2016-04-05 19:01:10 +02001940 U32 matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
1941 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1942 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02001943 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
inikep5ce00ae2016-04-05 21:03:43 +02001944 rep[1] = rep[0]; rep[0] = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02001945 }
inikepfaa8d8a2016-04-05 19:01:10 +02001946
inikepfaa8d8a2016-04-05 19:01:10 +02001947 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001948_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001949 { size_t const litLength = start - anchor;
1950 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1951 anchor = ip = start + matchLength;
1952 }
1953
1954 /* check immediate repcode */
1955 while (ip <= ilimit) {
1956 const U32 repIndex = (U32)((ip-base) - rep[1]);
1957 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1958 const BYTE* const repMatch = repBase + repIndex;
1959 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
1960 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1961 /* repcode detected we should take it */
1962 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001963 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
inikep5ce00ae2016-04-05 21:03:43 +02001964 offset = rep[1]; rep[1] = rep[0]; rep[0] = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02001965 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1966 ip += matchLength;
1967 anchor = ip;
1968 continue; /* faster when present ... (?) */
1969 }
1970 break;
1971 } }
1972
1973 /* Last Literals */
1974 { size_t const lastLLSize = iend - anchor;
1975 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1976 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01001977 }
1978}
1979
1980
Yann Collet59d1f792016-01-23 19:28:41 +01001981void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01001982{
inikep64d7bcb2016-04-07 19:14:09 +02001983 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01001984}
1985
Yann Collet59d1f792016-01-23 19:28:41 +01001986static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01001987{
Yann Colleta1249dc2016-01-25 04:22:03 +01001988 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01001989}
Yann Collet9a24e592015-11-22 02:53:43 +01001990
Yann Collet59d1f792016-01-23 19:28:41 +01001991static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01001992{
Yann Colleta1249dc2016-01-25 04:22:03 +01001993 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01001994}
1995
Yann Collet59d1f792016-01-23 19:28:41 +01001996static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01001997{
Yann Colleta1249dc2016-01-25 04:22:03 +01001998 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001999}
2000
inikepef519412016-04-21 11:08:43 +02002001
2002
2003/* The optimal parser */
2004#include "zstd_opt.h"
2005
2006static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2007{
2008 ZSTD_compressBlock_opt_generic(ctx, src, srcSize);
2009}
2010
inikepd3b8d7a2016-02-22 10:06:17 +01002011static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002012{
inikep5ce00ae2016-04-05 21:03:43 +02002013 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize);
inikepe2bfe242016-01-31 11:25:48 +01002014}
2015
Yann Collet7a231792015-11-21 15:27:35 +01002016
Yann Collet59d1f792016-01-23 19:28:41 +01002017typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002018
Yann Colletb923f652016-01-26 03:14:20 +01002019static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002020{
inikepd3b8d7a2016-02-22 10:06:17 +01002021 static const ZSTD_blockCompressor blockCompressor[2][6] = {
inikepf8a339d2016-04-05 23:58:51 +02002022#if 1
inikepd3b8d7a2016-02-22 10:06:17 +01002023 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt },
inikep908fcb32016-04-05 18:16:38 +02002024#else
2025 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict },
2026#endif
inikepd3b8d7a2016-02-22 10:06:17 +01002027 { 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 +01002028 };
2029
2030 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002031}
2032
2033
Yann Colletd1b26842016-03-15 01:24:33 +01002034static 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 +01002035{
Yann Collet3b719252016-03-30 19:48:05 +02002036 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01002037 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 +01002038 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002039 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002040}
2041
2042
inikep5cc4efd2016-03-25 10:52:25 +01002043
2044
Yann Collet2ce49232016-02-02 14:36:49 +01002045static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +01002046 void* dst, size_t dstCapacity,
Yann Colletf3eca252015-10-22 15:31:46 +01002047 const void* src, size_t srcSize)
2048{
Yann Collet2ce49232016-02-02 14:36:49 +01002049 size_t blockSize = zc->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002050 size_t remaining = srcSize;
2051 const BYTE* ip = (const BYTE*)src;
2052 BYTE* const ostart = (BYTE*)dst;
2053 BYTE* op = ostart;
Yann Collet3b719252016-03-30 19:48:05 +02002054 const U32 maxDist = 1 << zc->params.cParams.windowLog;
inikep50e82c02016-05-23 15:49:09 +02002055 ZSTD_stats_t* stats = (ZSTD_stats_t*) zc->customAlloc(sizeof(ZSTD_stats_t));
inikep35b891c2016-05-20 19:42:20 +02002056 if (!stats) return ERROR(memory_allocation);
2057 zc->seqStore.stats = stats;
inikep5cc4efd2016-03-25 10:52:25 +01002058 ZSTD_statsInit(stats);
Yann Collet9b11b462015-11-01 12:40:22 +01002059
Yann Collet2ce49232016-02-02 14:36:49 +01002060 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01002061 size_t cSize;
inikep5cc4efd2016-03-25 10:52:25 +01002062 ZSTD_statsResetFreqs(stats);
Yann Collet3e358272015-11-04 18:19:39 +01002063
inikep50e82c02016-05-23 15:49:09 +02002064 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) { zc->customFree(stats); return ERROR(dstSize_tooSmall); } /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01002065 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002066
Yann Collet70e45772016-03-19 18:08:32 +01002067 if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) {
2068 /* enforce maxDist */
2069 U32 const newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist;
Yann Collet7a6343f2016-02-02 16:00:50 +01002070 if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002071 if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002072 }
Yann Collet89db5e02015-11-13 11:27:46 +01002073
Yann Colletd1b26842016-03-15 01:24:33 +01002074 cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikep50e82c02016-05-23 15:49:09 +02002075 if (ZSTD_isError(cSize)) { zc->customFree(stats); return cSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002076
Yann Collet2ce49232016-02-02 14:36:49 +01002077 if (cSize == 0) { /* block is not compressible */
Yann Colletd1b26842016-03-15 01:24:33 +01002078 cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize);
inikep50e82c02016-05-23 15:49:09 +02002079 if (ZSTD_isError(cSize)) { zc->customFree(stats); return cSize; }
Yann Collet2ce49232016-02-02 14:36:49 +01002080 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01002081 op[0] = (BYTE)(cSize>>16);
2082 op[1] = (BYTE)(cSize>>8);
2083 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01002084 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01002085 cSize += 3;
2086 }
2087
2088 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002089 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002090 ip += blockSize;
2091 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002092 }
2093
inikep19bd48f2016-04-04 12:10:00 +02002094 ZSTD_statsPrint(stats, zc->params.cParams.searchLength);
inikep50e82c02016-05-23 15:49:09 +02002095 zc->customFree(stats);
Yann Colletf3eca252015-10-22 15:31:46 +01002096 return op-ostart;
2097}
2098
2099
Yann Collet6236eba2016-04-12 15:52:33 +02002100static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
2101 ZSTD_parameters params, U64 pledgedSrcSize)
2102{ BYTE* const op = (BYTE*)dst;
2103 U32 const fcsId = params.fParams.contentSizeFlag ?
2104 (pledgedSrcSize>0) + (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) : /* 0-3 */
2105 0;
2106 BYTE const fdescriptor = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) /* windowLog : 4 KB - 128 MB */
2107 | (fcsId << 6) );
2108 size_t const hSize = ZSTD_frameHeaderSize_min + ZSTD_fcs_fieldSize[fcsId];
2109 if (hSize > dstCapacity) return ERROR(dstSize_tooSmall);
2110
2111 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
2112 op[4] = fdescriptor;
2113 switch(fcsId)
2114 {
2115 default: /* impossible */
2116 case 0 : break;
2117 case 1 : op[5] = (BYTE)(pledgedSrcSize); break;
2118 case 2 : MEM_writeLE16(op+5, (U16)(pledgedSrcSize-256)); break;
2119 case 3 : MEM_writeLE64(op+5, (U64)(pledgedSrcSize)); break;
2120 }
2121 return hSize;
2122}
2123
2124
Yann Colletbf42c8e2016-01-09 01:08:23 +01002125static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002126 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002127 const void* src, size_t srcSize,
2128 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01002129{
Yann Collet2acb5d32015-10-29 16:49:43 +01002130 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002131 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002132
Yann Collet887e7da2016-04-11 20:12:27 +02002133 if (zc->stage==0) return ERROR(stage_wrong);
2134 if (frame && (zc->stage==1)) { /* copy saved header */
Yann Collet6236eba2016-04-12 15:52:33 +02002135 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, zc->params, srcSize);
2136 if (ZSTD_isError(fhSize)) return fhSize;
2137 dstCapacity -= fhSize;
2138 dst = (char*)dst + fhSize;
Yann Collet887e7da2016-04-11 20:12:27 +02002139 zc->stage = 2;
Yann Colletecd651b2016-01-07 15:35:18 +01002140 }
Yann Colletf3eca252015-10-22 15:31:46 +01002141
Yann Collet417890c2015-12-04 17:16:37 +01002142 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01002143 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002144 /* not contiguous */
Yann Collet70e45772016-03-19 18:08:32 +01002145 size_t const delta = zc->nextSrc - ip;
Yann Collet417890c2015-12-04 17:16:37 +01002146 zc->lowLimit = zc->dictLimit;
2147 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2148 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01002149 zc->base -= delta;
2150 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01002151 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002152 }
2153
Yann Collet89db5e02015-11-13 11:27:46 +01002154 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01002155 if (zc->lowLimit > (1<<30)) {
Yann Collet3b719252016-03-30 19:48:05 +02002156 U32 const btplus = (zc->params.cParams.strategy == ZSTD_btlazy2) || (zc->params.cParams.strategy == ZSTD_btopt);
Yann Collet8a57b922016-04-04 13:49:18 +02002157 U32 const chainMask = (1 << (zc->params.cParams.chainLog - btplus)) - 1;
2158 U32 const newLowLimit = zc->lowLimit & chainMask; /* preserve position % chainSize */
Yann Collet70e45772016-03-19 18:08:32 +01002159 U32 const correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002160 ZSTD_reduceIndex(zc, correction);
2161 zc->base += correction;
2162 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002163 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002164 zc->dictLimit -= correction;
2165 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2166 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01002167 }
2168
Yann Colletbf42c8e2016-01-09 01:08:23 +01002169 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01002170 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01002171 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2172 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002173 }
2174
Yann Colletc3652152015-11-24 14:06:07 +01002175 zc->nextSrc = ip + srcSize;
Yann Collet70e45772016-03-19 18:08:32 +01002176 { size_t const cSize = frame ?
Yann Collet7cbe79a2016-03-23 22:31:57 +01002177 ZSTD_compress_generic (zc, dst, dstCapacity, src, srcSize) :
2178 ZSTD_compressBlock_internal (zc, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002179 if (ZSTD_isError(cSize)) return cSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002180 return cSize + fhSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002181 }
Yann Colletf3eca252015-10-22 15:31:46 +01002182}
2183
Yann Colletbf42c8e2016-01-09 01:08:23 +01002184
2185size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002186 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002187 const void* src, size_t srcSize)
2188{
Yann Collet7cbe79a2016-03-23 22:31:57 +01002189 return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 1);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002190}
2191
2192
Yann Colletd1b26842016-03-15 01:24:33 +01002193size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002194{
Yann Collet569b81a2016-03-16 15:26:51 +01002195 if (srcSize > ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
inikepd6f208b2016-04-04 21:15:23 +02002196 ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.cParams.searchLength);
Yann Colletd1b26842016-03-15 01:24:33 +01002197 return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002198}
2199
2200
Yann Colletb923f652016-01-26 03:14:20 +01002201static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002202{
2203 const BYTE* const ip = (const BYTE*) src;
2204 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002205
Yann Collet417890c2015-12-04 17:16:37 +01002206 /* input becomes current prefix */
2207 zc->lowLimit = zc->dictLimit;
2208 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2209 zc->dictBase = zc->base;
2210 zc->base += ip - zc->nextSrc;
2211 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002212 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002213
2214 zc->nextSrc = iend;
2215 if (srcSize <= 8) return 0;
2216
Yann Collet3b719252016-03-30 19:48:05 +02002217 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002218 {
2219 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002220 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002221 break;
2222
2223 case ZSTD_greedy:
2224 case ZSTD_lazy:
2225 case ZSTD_lazy2:
Yann Collet3b719252016-03-30 19:48:05 +02002226 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002227 break;
2228
2229 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002230 case ZSTD_btopt:
Yann Collet3b719252016-03-30 19:48:05 +02002231 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002232 break;
2233
2234 default:
2235 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2236 }
2237
Yann Collet2ce49232016-02-02 14:36:49 +01002238 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002239 return 0;
2240}
2241
2242
Yann Colletb923f652016-01-26 03:14:20 +01002243/* Dictionary format :
2244 Magic == ZSTD_DICT_MAGIC (4 bytes)
Yann Colletfb797352016-03-13 11:08:40 +01002245 HUF_writeCTable(256)
Yann Colletb923f652016-01-26 03:14:20 +01002246 Dictionary content
2247*/
Yann Colletfb797352016-03-13 11:08:40 +01002248/*! ZSTD_loadDictEntropyStats() :
Yann Colletb923f652016-01-26 03:14:20 +01002249 @return : size read from dictionary */
2250static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2251{
2252 /* note : magic number already checked */
Yann Colletfb810d62016-01-28 00:18:06 +01002253 size_t offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize, errorCode;
2254 short offcodeNCount[MaxOff+1];
2255 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2256 short matchlengthNCount[MaxML+1];
2257 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2258 short litlengthNCount[MaxLL+1];
2259 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2260
Yann Collet70e45772016-03-19 18:08:32 +01002261 size_t const hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize);
Yann Colletb923f652016-01-26 03:14:20 +01002262 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Colletfb810d62016-01-28 00:18:06 +01002263 zc->flagStaticTables = 1;
2264 dict = (const char*)dict + hufHeaderSize;
2265 dictSize -= hufHeaderSize;
2266
2267 offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
2268 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2269 errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2270 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2271 dict = (const char*)dict + offcodeHeaderSize;
2272 dictSize -= offcodeHeaderSize;
2273
2274 matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
2275 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2276 errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2277 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2278 dict = (const char*)dict + matchlengthHeaderSize;
2279 dictSize -= matchlengthHeaderSize;
2280
2281 litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
2282 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2283 errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2284 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2285
2286 return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
Yann Colletb923f652016-01-26 03:14:20 +01002287}
2288
Yann Colletd1b26842016-03-15 01:24:33 +01002289/** ZSTD_compress_insertDictionary() :
2290* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002291static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002292{
Yann Colletd1b26842016-03-15 01:24:33 +01002293 if ((dict==NULL) || (dictSize<=4)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002294
Yann Colletd1b26842016-03-15 01:24:33 +01002295 /* default : dict is pure content */
2296 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
2297
2298 /* known magic number : dict is parsed for entropy stats and content */
Yann Collet21588e32016-03-30 16:50:44 +02002299 { size_t const eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4 /* skip magic */, dictSize-4) + 4;
2300 if (ZSTD_isError(eSize)) return eSize;
2301 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002302 }
Yann Colletecd651b2016-01-07 15:35:18 +01002303}
2304
Yann Collet0085cd32016-04-12 14:14:10 +02002305
Yann Collet27caf2a2016-04-01 15:48:48 +02002306/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002307* @return : 0, or an error code */
Yann Collet27caf2a2016-04-01 15:48:48 +02002308static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* zc,
Yann Collet1c8e1942016-01-26 16:31:22 +01002309 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002310 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002311{
Yann Collet6236eba2016-04-12 15:52:33 +02002312 { U32 const hashLog3 = (pledgedSrcSize || pledgedSrcSize >= 8192) ? ZSTD_HASHLOG3_MAX : ((pledgedSrcSize >= 2048) ? ZSTD_HASHLOG3_MIN + 1 : ZSTD_HASHLOG3_MIN);
2313 zc->hashLog3 = (params.cParams.searchLength==3) ? hashLog3 : 0; }
Yann Collet88fcd292015-11-25 14:42:45 +01002314
Yann Colletabb5c652016-04-11 20:42:31 +02002315 { size_t const resetError = ZSTD_resetCCtx_advanced(zc, params, 1);
2316 if (ZSTD_isError(resetError)) return resetError; }
Yann Collet89db5e02015-11-13 11:27:46 +01002317
Yann Collet1c8e1942016-01-26 16:31:22 +01002318 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002319}
2320
2321
Yann Collet27caf2a2016-04-01 15:48:48 +02002322/*! ZSTD_compressBegin_advanced() :
2323* @return : 0, or an error code */
2324size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
2325 const void* dict, size_t dictSize,
2326 ZSTD_parameters params, U64 pledgedSrcSize)
2327{
2328 /* compression parameters verification and optimization */
2329 { size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize);
2330 if (ZSTD_isError(errorCode)) return errorCode; }
2331
2332 return ZSTD_compressBegin_internal(zc, dict, dictSize, params, pledgedSrcSize);
2333}
2334
2335
Yann Collet1c8e1942016-01-26 16:31:22 +01002336size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002337{
Yann Collet3b719252016-03-30 19:48:05 +02002338 ZSTD_parameters params;
2339 params.cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
2340 params.fParams.contentSizeFlag = 0;
Yann Collet27caf2a2016-04-01 15:48:48 +02002341 ZSTD_adjustCParams(&params.cParams, 0, dictSize);
inikepa4dde252016-03-01 14:14:35 +01002342 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet27caf2a2016-04-01 15:48:48 +02002343 return ZSTD_compressBegin_internal(zc, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002344}
Yann Collet083fcc82015-10-25 14:06:35 +01002345
inikep19bd48f2016-04-04 12:10:00 +02002346
Yann Collet1c8e1942016-01-26 16:31:22 +01002347size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002348{
inikepa4dde252016-03-01 14:14:35 +01002349 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet3b719252016-03-30 19:48:05 +02002350 return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002351}
2352
2353
Yann Colletfb797352016-03-13 11:08:40 +01002354/*! ZSTD_compressEnd() :
2355* Write frame epilogue.
Yann Collet88fcd292015-11-25 14:42:45 +01002356* @return : nb of bytes written into dst (or an error code) */
Yann Colletd1b26842016-03-15 01:24:33 +01002357size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002358{
2359 BYTE* op = (BYTE*)dst;
Yann Collet6236eba2016-04-12 15:52:33 +02002360 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002361
Yann Collet887e7da2016-04-11 20:12:27 +02002362 /* not even init ! */
2363 if (zc->stage==0) return ERROR(stage_wrong);
2364
2365 /* special case : empty frame */
2366 if (zc->stage==1) {
Yann Collet6236eba2016-04-12 15:52:33 +02002367 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, zc->params, 0);
2368 if (ZSTD_isError(fhSize)) return fhSize;
2369 dstCapacity -= fhSize;
2370 op += fhSize;
Yann Collet887e7da2016-04-11 20:12:27 +02002371 zc->stage = 2;
Yann Colletecd651b2016-01-07 15:35:18 +01002372 }
2373
2374 /* frame epilogue */
Yann Colletd1b26842016-03-15 01:24:33 +01002375 if (dstCapacity < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002376 op[0] = (BYTE)(bt_end << 6);
2377 op[1] = 0;
2378 op[2] = 0;
2379
Yann Collet887e7da2016-04-11 20:12:27 +02002380 zc->stage = 0; /* return to "created by not init" status */
Yann Collet6236eba2016-04-12 15:52:33 +02002381 return 3+fhSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002382}
2383
Yann Colletfd416f12016-01-30 03:14:15 +01002384
2385size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
Yann Colletd1b26842016-03-15 01:24:33 +01002386 void* dst, size_t dstCapacity,
Yann Colletfd416f12016-01-30 03:14:15 +01002387 const void* src, size_t srcSize)
2388{
Yann Collet70e45772016-03-19 18:08:32 +01002389 { size_t const errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2390 if (ZSTD_isError(errorCode)) return errorCode;
2391 }
2392 { size_t const cSize = ZSTD_compressContinue(cctx, dst, dstCapacity, src, srcSize);
2393 if (ZSTD_isError(cSize)) return cSize;
Yann Collet0dbf2872016-04-08 02:02:12 +02002394
Yann Collet70e45772016-03-19 18:08:32 +01002395 { size_t const endSize = ZSTD_compressEnd(cctx, (char*)dst+cSize, dstCapacity-cSize);
2396 if (ZSTD_isError(endSize)) return endSize;
2397 return cSize + endSize;
2398 } }
Yann Colletfd416f12016-01-30 03:14:15 +01002399}
2400
2401
Yann Collet21588e32016-03-30 16:50:44 +02002402static size_t ZSTD_compress_internal (ZSTD_CCtx* ctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002403 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002404 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002405 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002406 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002407{
2408 BYTE* const ostart = (BYTE*)dst;
2409 BYTE* op = ostart;
2410
Yann Collet1c8e1942016-01-26 16:31:22 +01002411 /* Init */
Yann Collet27caf2a2016-04-01 15:48:48 +02002412 { size_t const errorCode = ZSTD_compressBegin_internal(ctx, dict, dictSize, params, srcSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002413 if(ZSTD_isError(errorCode)) return errorCode; }
Yann Colletf3eca252015-10-22 15:31:46 +01002414
2415 /* body (compression) */
Yann Colletd1b26842016-03-15 01:24:33 +01002416 { size_t const oSize = ZSTD_compressContinue (ctx, op, dstCapacity, src, srcSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002417 if(ZSTD_isError(oSize)) return oSize;
2418 op += oSize;
2419 dstCapacity -= oSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002420
2421 /* Close frame */
Yann Colletd1b26842016-03-15 01:24:33 +01002422 { size_t const oSize = ZSTD_compressEnd(ctx, op, dstCapacity);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002423 if(ZSTD_isError(oSize)) return oSize;
2424 op += oSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002425
2426 return (op - ostart);
2427}
2428
Yann Collet21588e32016-03-30 16:50:44 +02002429size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2430 void* dst, size_t dstCapacity,
2431 const void* src, size_t srcSize,
2432 const void* dict,size_t dictSize,
2433 ZSTD_parameters params)
2434{
Yann Collet3b719252016-03-30 19:48:05 +02002435 size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, srcSize);
Yann Collet21588e32016-03-30 16:50:44 +02002436 if (ZSTD_isError(errorCode)) return errorCode;
2437 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2438}
2439
Yann Colletd1b26842016-03-15 01:24:33 +01002440size_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 +01002441{
Yann Collet3b719252016-03-30 19:48:05 +02002442 ZSTD_parameters params;
inikepa4dde252016-03-01 14:14:35 +01002443 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 +02002444 params.cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
2445 params.fParams.contentSizeFlag = 1;
2446 ZSTD_adjustCParams(&params.cParams, srcSize, dictSize);
Yann Collet21588e32016-03-30 16:50:44 +02002447 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002448}
2449
Yann Colletd1b26842016-03-15 01:24:33 +01002450size_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 +01002451{
inikepa4dde252016-03-01 14:14:35 +01002452 ZSTD_LOG_BLOCK("%p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, compressionLevel);
Yann Collet21588e32016-03-30 16:50:44 +02002453 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002454}
2455
Yann Colletd1b26842016-03-15 01:24:33 +01002456size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002457{
Yann Collet44fe9912015-10-29 22:02:40 +01002458 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002459 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002460 memset(&ctxBody, 0, sizeof(ctxBody));
inikep50e82c02016-05-23 15:49:09 +02002461 ctxBody.customAlloc = malloc;
2462 ctxBody.customFree = free;
Yann Colletd1b26842016-03-15 01:24:33 +01002463 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
inikep50e82c02016-05-23 15:49:09 +02002464 ctxBody.customFree(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002465 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002466}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002467
Yann Colletfd416f12016-01-30 03:14:15 +01002468
Yann Collet70e8c382016-02-10 13:37:52 +01002469/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01002470
inikep3c7c3522016-04-22 13:59:05 +02002471#define ZSTD_DEFAULT_CLEVEL 5
inikep2c5eeea2016-04-15 13:44:46 +02002472#define ZSTD_MAX_CLEVEL 22
Yann Collet7d968c72016-02-03 02:11:32 +01002473unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2474
Yann Collet3b719252016-03-30 19:48:05 +02002475static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01002476{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02002477 /* W, C, H, S, L, TL, strat */
Yann Collet3b719252016-03-30 19:48:05 +02002478 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2479 { 19, 13, 14, 1, 7, 4, ZSTD_fast }, /* level 1 */
2480 { 19, 15, 16, 1, 6, 4, ZSTD_fast }, /* level 2 */
2481 { 20, 18, 20, 1, 6, 4, ZSTD_fast }, /* level 3 */
2482 { 20, 13, 17, 2, 5, 4, ZSTD_greedy }, /* level 4.*/
2483 { 20, 15, 18, 3, 5, 4, ZSTD_greedy }, /* level 5 */
2484 { 21, 16, 19, 2, 5, 4, ZSTD_lazy }, /* level 6 */
2485 { 21, 17, 20, 3, 5, 4, ZSTD_lazy }, /* level 7 */
2486 { 21, 18, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 8.*/
2487 { 21, 20, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 9 */
2488 { 21, 19, 21, 4, 5, 4, ZSTD_lazy2 }, /* level 10 */
2489 { 22, 20, 22, 4, 5, 4, ZSTD_lazy2 }, /* level 11 */
2490 { 22, 20, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 12 */
2491 { 22, 21, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 13 */
2492 { 22, 21, 22, 6, 5, 4, ZSTD_lazy2 }, /* level 14 */
2493 { 22, 21, 21, 5, 5, 4, ZSTD_btlazy2 }, /* level 15 */
2494 { 23, 22, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */
Yann Collet793c6492016-04-09 20:32:00 +02002495 { 23, 23, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 17.*/
2496 { 23, 23, 22, 6, 5, 24, ZSTD_btopt }, /* level 18.*/
2497 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19.*/
2498 { 25, 26, 23, 7, 3, 64, ZSTD_btopt }, /* level 20.*/
2499 { 26, 26, 23, 7, 3,256, ZSTD_btopt }, /* level 21.*/
2500 { 27, 27, 25, 9, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002501},
2502{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002503 /* W, C, H, S, L, T, strat */
2504 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 */
Yann Collet0dbf2872016-04-08 02:02:12 +02002505 { 18, 13, 14, 1, 6, 4, ZSTD_fast }, /* level 1 */
Yann Collet78267d12016-04-08 12:36:19 +02002506 { 18, 15, 17, 1, 5, 4, ZSTD_fast }, /* level 2 */
2507 { 18, 13, 15, 1, 5, 4, ZSTD_greedy }, /* level 3.*/
2508 { 18, 15, 17, 1, 5, 4, ZSTD_greedy }, /* level 4.*/
2509 { 18, 16, 17, 4, 5, 4, ZSTD_greedy }, /* level 5 */
2510 { 18, 17, 17, 5, 5, 4, ZSTD_greedy }, /* level 6 */
Yann Collet3b719252016-03-30 19:48:05 +02002511 { 18, 17, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */
2512 { 18, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2513 { 18, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2514 { 18, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
Yann Collet78267d12016-04-08 12:36:19 +02002515 { 18, 18, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 11.*/
2516 { 18, 18, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 12.*/
2517 { 18, 19, 17, 7, 4, 4, ZSTD_btlazy2 }, /* level 13 */
2518 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
2519 { 18, 18, 18, 8, 4, 24, ZSTD_btopt }, /* level 15.*/
2520 { 18, 19, 18, 8, 3, 48, ZSTD_btopt }, /* level 16.*/
2521 { 18, 19, 18, 8, 3, 96, ZSTD_btopt }, /* level 17.*/
2522 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
2523 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
2524 { 18, 19, 18, 11, 3,512, ZSTD_btopt }, /* level 20.*/
2525 { 18, 19, 18, 12, 3,512, ZSTD_btopt }, /* level 21.*/
2526 { 18, 19, 18, 13, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002527},
2528{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002529 /* W, C, H, S, L, T, strat */
2530 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2531 { 17, 12, 13, 1, 6, 4, ZSTD_fast }, /* level 1 */
2532 { 17, 13, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */
2533 { 17, 13, 14, 2, 5, 4, ZSTD_greedy }, /* level 3 */
2534 { 17, 13, 15, 3, 4, 4, ZSTD_greedy }, /* level 4 */
2535 { 17, 15, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */
2536 { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
2537 { 17, 15, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 7 */
2538 { 17, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2539 { 17, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2540 { 17, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
2541 { 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */
2542 { 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */
2543 { 17, 18, 17, 6, 4, 4, ZSTD_btlazy2 }, /* level 13.*/
2544 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
2545 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
2546 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
2547 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
2548 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
2549 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
2550 { 17, 18, 17, 9, 3,256, ZSTD_btopt }, /* level 20.*/
2551 { 17, 18, 17, 10, 3,256, ZSTD_btopt }, /* level 21.*/
2552 { 17, 18, 17, 11, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002553},
2554{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002555 /* W, C, H, S, L, T, strat */
2556 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 -- never used */
2557 { 14, 14, 14, 1, 4, 4, ZSTD_fast }, /* level 1 */
2558 { 14, 14, 15, 1, 4, 4, ZSTD_fast }, /* level 2 */
2559 { 14, 14, 14, 4, 4, 4, ZSTD_greedy }, /* level 3.*/
2560 { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 4.*/
2561 { 14, 14, 14, 4, 4, 4, ZSTD_lazy2 }, /* level 5 */
2562 { 14, 14, 14, 5, 4, 4, ZSTD_lazy2 }, /* level 6 */
2563 { 14, 14, 14, 6, 4, 4, ZSTD_lazy2 }, /* level 7.*/
2564 { 14, 14, 14, 7, 4, 4, ZSTD_lazy2 }, /* level 8.*/
2565 { 14, 15, 14, 6, 4, 4, ZSTD_btlazy2 }, /* level 9.*/
2566 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
2567 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
2568 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
2569 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
2570 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
2571 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
2572 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
2573 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
2574 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
2575 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
2576 { 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 20.*/
2577 { 14, 15, 15, 9, 3,256, ZSTD_btopt }, /* level 21.*/
2578 { 14, 15, 15, 10, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002579},
2580};
2581
Yann Collet1df25942016-03-05 18:43:21 +01002582/*! ZSTD_getParams() :
Yann Colletfd416f12016-01-30 03:14:15 +01002583* @return ZSTD_parameters structure for a selected compression level and srcSize.
Yann Colletde406ee2016-03-20 15:46:10 +01002584* `srcSize` value is optional, select 0 if not known */
Yann Collet3b719252016-03-30 19:48:05 +02002585ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, U64 srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01002586{
Yann Collet15354142016-04-04 04:22:53 +02002587 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02002588 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02002589 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02002590 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
inikep3c7c3522016-04-22 13:59:05 +02002591 if (compressionLevel < 0) compressionLevel = ZSTD_DEFAULT_CLEVEL;
inikep2c5eeea2016-04-15 13:44:46 +02002592 if (compressionLevel==0) compressionLevel = 1;
Yann Colletfd416f12016-01-30 03:14:15 +01002593 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02002594 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02002595 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
2596 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02002597 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02002598 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
2599 }
Yann Collet15354142016-04-04 04:22:53 +02002600 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01002601}