blob: 966d9acbdf2caa35bb6fad030ea46fe1d2a2393c [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
inikep107e2432016-05-23 16:24:52 +0200131 if (!customMem.customAlloc || !customMem.customFree)
132 {
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
141 ctx = (ZSTD_CCtx*) customMem.customAlloc(sizeof(ZSTD_CCtx));
inikep50e82c02016-05-23 15:49:09 +0200142 if (!ctx) return NULL;
143
144 memset(ctx, 0, sizeof(ZSTD_CCtx));
145 ctx->customAlloc = customMem.customAlloc;
146 ctx->customFree = customMem.customFree;
147 return ctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100148}
149
Yann Collet5be2dd22015-11-11 13:43:58 +0100150size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100151{
inikep50e82c02016-05-23 15:49:09 +0200152 cctx->customFree(cctx->workSpace);
153 cctx->customFree(cctx);
Yann Collet982ffc72016-02-05 02:33:10 +0100154 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100155}
156
Yann Colletb44be742016-03-26 20:52:14 +0100157const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100158{
Yann Colletb44be742016-03-26 20:52:14 +0100159 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100160}
161
Yann Collet59d70632015-11-04 12:05:27 +0100162
Yann Collet21588e32016-03-30 16:50:44 +0200163#define CLAMP(val,min,max) { if (val<min) val=min; else if (val>max) val=max; }
164#define CLAMPCHECK(val,min,max) { if ((val<min) || (val>max)) return ERROR(compressionParameter_unsupported); }
165
166/** ZSTD_checkParams() :
167 ensure param values remain within authorized range.
168 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200169size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200170{
Yann Collet15354142016-04-04 04:22:53 +0200171 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200172 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200173 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
174 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
inikep75716852016-04-06 12:34:42 +0200175 { 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 +0200176 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
177 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
178 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Collet9bb87e52016-03-30 21:28:15 +0200179 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200180 return 0;
181}
182
183
Yann Collet14983e72015-11-11 21:38:21 +0100184static unsigned ZSTD_highbit(U32 val);
185
Yann Collet3b719252016-03-30 19:48:05 +0200186/** ZSTD_checkCParams_advanced() :
187 temporary work-around, while the compressor compatibility remains limited regarding windowLog < 18 */
188size_t ZSTD_checkCParams_advanced(ZSTD_compressionParameters cParams, U64 srcSize)
189{
Yann Colletefb18302016-04-01 18:54:13 +0200190 if (srcSize > (1ULL << ZSTD_WINDOWLOG_MIN)) return ZSTD_checkCParams(cParams);
Yann Collet3b719252016-03-30 19:48:05 +0200191 if (cParams.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) return ERROR(compressionParameter_unsupported);
Yann Collet8a57b922016-04-04 13:49:18 +0200192 if (srcSize <= (1ULL << cParams.windowLog)) cParams.windowLog = ZSTD_WINDOWLOG_MIN; /* fake value - temporary work around */
193 if (srcSize <= (1ULL << cParams.chainLog)) cParams.chainLog = ZSTD_CHAINLOG_MIN; /* fake value - temporary work around */
Yann Colletef363902016-04-02 00:46:40 +0200194 if ((srcSize <= (1ULL << cParams.hashLog)) && ((U32)cParams.strategy < (U32)ZSTD_btlazy2)) cParams.hashLog = ZSTD_HASHLOG_MIN; /* fake value - temporary work around */
Yann Collet3b719252016-03-30 19:48:05 +0200195 return ZSTD_checkCParams(cParams);
196}
197
198
Yann Collet21588e32016-03-30 16:50:44 +0200199/** ZSTD_adjustParams() :
200 optimize params for q given input (`srcSize` and `dictSize`).
201 mostly downsizing to reduce memory consumption and initialization.
202 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
203 but if both are 0, no optimization can be done.
204 Note : params is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Colletdd6466a2016-03-30 20:06:26 +0200205void ZSTD_adjustCParams(ZSTD_compressionParameters* params, U64 srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100206{
Yann Collet21588e32016-03-30 16:50:44 +0200207 if (srcSize+dictSize == 0) return; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100208
Yann Collet70e45772016-03-19 18:08:32 +0100209 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200210 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
211 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200212 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Collet21588e32016-03-30 16:50:44 +0200213 U32 const srcLog = ZSTD_highbit((U32)(rSize)-1) + 1;
214 if (params->windowLog > srcLog) params->windowLog = srcLog;
215 } }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100216 if (params->hashLog > params->windowLog) params->hashLog = params->windowLog;
Yann Collet21588e32016-03-30 16:50:44 +0200217 { U32 const btPlus = (params->strategy == ZSTD_btlazy2) || (params->strategy == ZSTD_btopt);
Yann Collet8a57b922016-04-04 13:49:18 +0200218 U32 const maxChainLog = params->windowLog+btPlus;
219 if (params->chainLog > maxChainLog) params->chainLog = maxChainLog; } /* <= ZSTD_CHAINLOG_MAX */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100220
221 if (params->windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) params->windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet40358d02016-04-02 00:40:09 +0200222 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 +0100223}
224
225
Yann Collet51d50042016-03-30 20:42:19 +0200226size_t ZSTD_sizeofCCtx(ZSTD_compressionParameters cParams) /* hidden interface, for paramagrill */
Yann Collete74215e2016-03-19 16:09:09 +0100227{
228 ZSTD_CCtx* zc = ZSTD_createCCtx();
Yann Collet51d50042016-03-30 20:42:19 +0200229 ZSTD_parameters params;
230 params.cParams = cParams;
231 params.fParams.contentSizeFlag = 1;
Yann Collet3b719252016-03-30 19:48:05 +0200232 ZSTD_compressBegin_advanced(zc, NULL, 0, params, 0);
Yann Colletd64f4352016-03-21 00:07:42 +0100233 { size_t const ccsize = sizeof(*zc) + zc->workSpaceSize;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100234 ZSTD_freeCCtx(zc);
Yann Colletd64f4352016-03-21 00:07:42 +0100235 return ccsize; }
Yann Collet2e91dde2016-03-08 12:22:11 +0100236}
237
Yann Collet27caf2a2016-04-01 15:48:48 +0200238/*! ZSTD_resetCCtx_advanced() :
239 note : 'params' is expected to be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100240static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Colletabb5c652016-04-11 20:42:31 +0200241 ZSTD_parameters params, U32 reset)
Yann Collet863ec402016-01-28 17:56:33 +0100242{ /* note : params considered validated here */
Yann Collet3b719252016-03-30 19:48:05 +0200243 const size_t blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
244 const U32 divider = (params.cParams.searchLength==3) ? 3 : 4;
Yann Colletdd54bbc2016-03-08 02:35:34 +0100245 const size_t maxNbSeq = blockSize / divider;
Yann Colletbe391432016-03-22 23:19:28 +0100246 const size_t tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet8a57b922016-04-04 13:49:18 +0200247 const size_t chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
inikep1007a1f2016-04-25 15:23:09 +0200248 const size_t hSize = ((size_t)1) << params.cParams.hashLog;
inikep7adceef2016-03-23 15:53:38 +0100249 const size_t h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Collet8a57b922016-04-04 13:49:18 +0200250 const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
inikep87d4f3d2016-03-02 15:56:24 +0100251
Yann Collete74215e2016-03-19 16:09:09 +0100252 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Collet48537162016-04-07 15:24:29 +0200253 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
Yann Collete74215e2016-03-19 16:09:09 +0100254 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
255 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Yann Collet1005fc12016-04-04 13:28:28 +0200256 + ((params.cParams.strategy == ZSTD_btopt) ? optSpace : 0);
Yann Collete74215e2016-03-19 16:09:09 +0100257 if (zc->workSpaceSize < neededSpace) {
inikep50e82c02016-05-23 15:49:09 +0200258 zc->customFree(zc->workSpace);
259 zc->workSpace = zc->customAlloc(neededSpace);
Yann Collete74215e2016-03-19 16:09:09 +0100260 if (zc->workSpace == NULL) return ERROR(memory_allocation);
261 zc->workSpaceSize = neededSpace;
Yann Colletc6eea2b2016-03-19 17:18:00 +0100262 } }
Yann Collete74215e2016-03-19 16:09:09 +0100263
Yann Colletabb5c652016-04-11 20:42:31 +0200264 if (reset) memset(zc->workSpace, 0, tableSpace ); /* reset only tables */
inikepcc52a972016-02-19 10:09:35 +0100265 zc->hashTable3 = (U32*)(zc->workSpace);
Yann Collete74215e2016-03-19 16:09:09 +0100266 zc->hashTable = zc->hashTable3 + h3Size;
Yann Collet8a57b922016-04-04 13:49:18 +0200267 zc->chainTable = zc->hashTable + hSize;
268 zc->seqStore.buffer = zc->chainTable + chainSize;
Yann Collet863ec402016-01-28 17:56:33 +0100269 zc->hufTable = (HUF_CElt*)zc->seqStore.buffer;
270 zc->flagStaticTables = 0;
Yann Collet597847a2016-03-20 19:14:22 +0100271 zc->seqStore.buffer = ((U32*)(zc->seqStore.buffer)) + 256;
Yann Collet083fcc82015-10-25 14:06:35 +0100272
Yann Colletf48e35c2015-11-07 01:13:31 +0100273 zc->nextToUpdate = 1;
Yann Collet89db5e02015-11-13 11:27:46 +0100274 zc->nextSrc = NULL;
Yann Collet2acb5d32015-10-29 16:49:43 +0100275 zc->base = NULL;
276 zc->dictBase = NULL;
277 zc->dictLimit = 0;
278 zc->lowLimit = 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100279 zc->params = params;
Yann Collet120230b2015-12-02 14:00:45 +0100280 zc->blockSize = blockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100281
Yann Collet3b719252016-03-30 19:48:05 +0200282 if (params.cParams.strategy == ZSTD_btopt) {
Yann Collet72d706a2016-03-23 20:44:12 +0100283 zc->seqStore.litFreq = (U32*)(zc->seqStore.buffer);
284 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
285 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
286 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
Yann Collet48537162016-04-07 15:24:29 +0200287 zc->seqStore.matchTable = (ZSTD_match_t*)((void*)(zc->seqStore.offCodeFreq + (MaxOff+1)));
Yann Collet72d706a2016-03-23 20:44:12 +0100288 zc->seqStore.priceTable = (ZSTD_optimal_t*)((void*)(zc->seqStore.matchTable + ZSTD_OPT_NUM+1));
289 zc->seqStore.buffer = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
290 zc->seqStore.litLengthSum = 0;
291 }
inikep87d4f3d2016-03-02 15:56:24 +0100292 zc->seqStore.offsetStart = (U32*) (zc->seqStore.buffer);
Yann Collet597847a2016-03-20 19:14:22 +0100293 zc->seqStore.litLengthStart = (U16*) (void*)(zc->seqStore.offsetStart + maxNbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100294 zc->seqStore.matchLengthStart = (U16*) (void*)(zc->seqStore.litLengthStart + maxNbSeq);
295 zc->seqStore.llCodeStart = (BYTE*) (zc->seqStore.matchLengthStart + maxNbSeq);
296 zc->seqStore.mlCodeStart = zc->seqStore.llCodeStart + maxNbSeq;
297 zc->seqStore.offCodeStart = zc->seqStore.mlCodeStart + maxNbSeq;
Yann Colletdd54bbc2016-03-08 02:35:34 +0100298 zc->seqStore.litStart = zc->seqStore.offCodeStart + maxNbSeq;
inikep5cccd772016-03-02 20:37:49 +0100299
Yann Collet887e7da2016-04-11 20:12:27 +0200300 zc->stage = 1;
Yann Collet2ce49232016-02-02 14:36:49 +0100301 zc->loadedDictEnd = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +0100302
Yann Collet4114f952015-10-30 06:40:22 +0100303 return 0;
Yann Colletf3eca252015-10-22 15:31:46 +0100304}
305
Yann Collet083fcc82015-10-25 14:06:35 +0100306
Yann Collet370b08e2016-03-08 00:03:59 +0100307/*! ZSTD_copyCCtx() :
308* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet887e7da2016-04-11 20:12:27 +0200309* Only works during stage 1 (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100310* @return : 0, or an error code */
311size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx)
312{
Yann Collet887e7da2016-04-11 20:12:27 +0200313 if (srcCCtx->stage!=1) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100314
inikep107e2432016-05-23 16:24:52 +0200315 dstCCtx->hashLog3 = srcCCtx->hashLog3; /* must be before ZSTD_resetCCtx_advanced */
316 dstCCtx->customAlloc = srcCCtx->customAlloc;
317 dstCCtx->customFree = srcCCtx->customFree;
Yann Colletabb5c652016-04-11 20:42:31 +0200318 ZSTD_resetCCtx_advanced(dstCCtx, srcCCtx->params, 0);
Yann Collet389648c2016-04-12 19:13:08 +0200319 dstCCtx->params.fParams.contentSizeFlag = 0; /* content size different from the one set during srcCCtx init */
Yann Collet7b51a292016-01-26 15:58:49 +0100320
321 /* copy tables */
inikep0c7456c2016-04-04 14:54:53 +0200322 { const size_t chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
inikep1007a1f2016-04-25 15:23:09 +0200323 const size_t hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
inikep7adceef2016-03-23 15:53:38 +0100324 const size_t h3Size = (srcCCtx->hashLog3) ? 1 << srcCCtx->hashLog3 : 0;
inikep0c7456c2016-04-04 14:54:53 +0200325 const size_t tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100326 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
327 }
Yann Collet7b51a292016-01-26 15:58:49 +0100328
Yann Collet7b51a292016-01-26 15:58:49 +0100329 /* copy dictionary pointers */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100330 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
331 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
332 dstCCtx->nextSrc = srcCCtx->nextSrc;
333 dstCCtx->base = srcCCtx->base;
334 dstCCtx->dictBase = srcCCtx->dictBase;
335 dstCCtx->dictLimit = srcCCtx->dictLimit;
336 dstCCtx->lowLimit = srcCCtx->lowLimit;
337 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Collet7b51a292016-01-26 15:58:49 +0100338
Yann Colletfb810d62016-01-28 00:18:06 +0100339 /* copy entropy tables */
340 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100341 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100342 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100343 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
344 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
345 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
346 }
Yann Collet7b51a292016-01-26 15:58:49 +0100347
348 return 0;
349}
350
351
Yann Colletecabfe32016-03-20 16:20:06 +0100352/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100353* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100354static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100355{
Yann Colletecabfe32016-03-20 16:20:06 +0100356 U32 u;
357 for (u=0 ; u < size ; u++) {
358 if (table[u] < reducerValue) table[u] = 0;
359 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100360 }
361}
362
Yann Colletecabfe32016-03-20 16:20:06 +0100363/*! ZSTD_reduceIndex() :
364* rescale all indexes to avoid future overflow (indexes are U32) */
365static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
366{
Yann Collet3b719252016-03-30 19:48:05 +0200367 { const U32 hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100368 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
369
Yann Collet8a57b922016-04-04 13:49:18 +0200370 { const U32 chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
371 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100372
inikep7adceef2016-03-23 15:53:38 +0100373 { const U32 h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100374 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
375}
376
Yann Collet89db5e02015-11-13 11:27:46 +0100377
Yann Collet863ec402016-01-28 17:56:33 +0100378/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100379* Block entropic compression
380*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100381
Yann Colletfb797352016-03-13 11:08:40 +0100382/* Frame format description
383 Frame Header - [ Block Header - Block ] - Frame End
384 1) Frame Header
385 - 4 bytes - Magic Number : ZSTD_MAGICNUMBER (defined within zstd_static.h)
386 - 1 byte - Frame Descriptor
387 2) Block Header
388 - 3 bytes, starting with a 2-bits descriptor
389 Uncompressed, Compressed, Frame End, unused
390 3) Block
391 See Block Format Description
392 4) Frame End
393 - 3 bytes, compatible with Block Header
394*/
395
396
397/* Frame descriptor
398
399 1 byte, using :
400 bit 0-3 : windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN (see zstd_internal.h)
401 bit 4 : minmatch 4(0) or 3(1)
402 bit 5 : reserved (must be zero)
403 bit 6-7 : Frame content size : unknown, 1 byte, 2 bytes, 8 bytes
404
405 Optional : content size (0, 1, 2 or 8 bytes)
406 0 : unknown
407 1 : 0-255 bytes
408 2 : 256 - 65535+256
409 8 : up to 16 exa
410*/
411
412
Yann Collet59d1f792016-01-23 19:28:41 +0100413/* Block format description
414
415 Block = Literal Section - Sequences Section
416 Prerequisite : size of (compressed) block, maximum size of regenerated data
417
418 1) Literal Section
419
420 1.1) Header : 1-5 bytes
421 flags: 2 bits
422 00 compressed by Huff0
423 01 unused
424 10 is Raw (uncompressed)
425 11 is Rle
426 Note : using 01 => Huff0 with precomputed table ?
427 Note : delta map ? => compressed ?
428
429 1.1.1) Huff0-compressed literal block : 3-5 bytes
Yann Colletafe07092016-01-25 04:10:46 +0100430 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
Yann Collet59d1f792016-01-23 19:28:41 +0100431 srcSize < 1 KB => 3 bytes (2-2-10-10)
Yann Colleta1249dc2016-01-25 04:22:03 +0100432 srcSize < 16KB => 4 bytes (2-2-14-14)
Yann Collet59d1f792016-01-23 19:28:41 +0100433 else => 5 bytes (2-2-18-18)
434 big endian convention
435
436 1.1.2) Raw (uncompressed) literal block header : 1-3 bytes
437 size : 5 bits: (IS_RAW<<6) + (0<<4) + size
438 12 bits: (IS_RAW<<6) + (2<<4) + (size>>8)
439 size&255
440 20 bits: (IS_RAW<<6) + (3<<4) + (size>>16)
441 size>>8&255
442 size&255
443
444 1.1.3) Rle (repeated single byte) literal block header : 1-3 bytes
445 size : 5 bits: (IS_RLE<<6) + (0<<4) + size
446 12 bits: (IS_RLE<<6) + (2<<4) + (size>>8)
447 size&255
448 20 bits: (IS_RLE<<6) + (3<<4) + (size>>16)
449 size>>8&255
450 size&255
451
Yann Colleta1249dc2016-01-25 04:22:03 +0100452 1.1.4) Huff0-compressed literal block, using precomputed CTables : 3-5 bytes
453 srcSize < 1 KB => 3 bytes (2-2-10-10) => single stream
454 srcSize < 1 KB => 3 bytes (2-2-10-10)
455 srcSize < 16KB => 4 bytes (2-2-14-14)
456 else => 5 bytes (2-2-18-18)
457 big endian convention
458
459 1- CTable available (stored into workspace ?)
Yann Colletb923f652016-01-26 03:14:20 +0100460 2- Small input (fast heuristic ? Full comparison ? depend on clevel ?)
Yann Colleta1249dc2016-01-25 04:22:03 +0100461
Yann Collet59d1f792016-01-23 19:28:41 +0100462
463 1.2) Literal block content
464
465 1.2.1) Huff0 block, using sizes from header
466 See Huff0 format
467
Yann Colletfb810d62016-01-28 00:18:06 +0100468 1.2.2) Huff0 block, using prepared table
Yann Collet59d1f792016-01-23 19:28:41 +0100469
Yann Colletfb810d62016-01-28 00:18:06 +0100470 1.2.3) Raw content
Yann Collet59d1f792016-01-23 19:28:41 +0100471
Yann Colletfb810d62016-01-28 00:18:06 +0100472 1.2.4) single byte
Yann Collet59d1f792016-01-23 19:28:41 +0100473
474
475 2) Sequences section
Yann Colletfb810d62016-01-28 00:18:06 +0100476
477 - Nb Sequences : 2 bytes, little endian
478 - Control Token : 1 byte (see below)
479 - Dumps Length : 1 or 2 bytes (depending on control token)
480 - Dumps : as stated by dumps length
481 - Literal Lengths FSE table (as needed depending on encoding method)
482 - Offset Codes FSE table (as needed depending on encoding method)
483 - Match Lengths FSE table (as needed depending on encoding method)
484
485 2.1) Control Token
486 8 bits, divided as :
487 0-1 : dumpsLength
488 2-3 : MatchLength, FSE encoding method
489 4-5 : Offset Codes, FSE encoding method
490 6-7 : Literal Lengths, FSE encoding method
491
492 FSE encoding method :
493 FSE_ENCODING_RAW : uncompressed; no header
494 FSE_ENCODING_RLE : single repeated value; header 1 byte
495 FSE_ENCODING_STATIC : use prepared table; no header
496 FSE_ENCODING_DYNAMIC : read NCount
Yann Collet59d1f792016-01-23 19:28:41 +0100497*/
Yann Collet14983e72015-11-11 21:38:21 +0100498
Yann Colletd1b26842016-03-15 01:24:33 +0100499size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100500{
501 BYTE* const ostart = (BYTE* const)dst;
502
Yann Colletd1b26842016-03-15 01:24:33 +0100503 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100504 memcpy(ostart + ZSTD_blockHeaderSize, src, srcSize);
505
506 /* Build header */
507 ostart[0] = (BYTE)(srcSize>>16);
508 ostart[1] = (BYTE)(srcSize>>8);
509 ostart[2] = (BYTE) srcSize;
510 ostart[0] += (BYTE)(bt_raw<<6); /* is a raw (uncompressed) block */
511
512 return ZSTD_blockHeaderSize+srcSize;
513}
514
515
Yann Colletd1b26842016-03-15 01:24:33 +0100516static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100517{
518 BYTE* const ostart = (BYTE* const)dst;
Yann Colleta910dc82016-03-18 12:37:45 +0100519 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100520
Yann Colletd1b26842016-03-15 01:24:33 +0100521 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100522
Yann Collet59d1f792016-01-23 19:28:41 +0100523 switch(flSize)
524 {
525 case 1: /* 2 - 1 - 5 */
526 ostart[0] = (BYTE)((IS_RAW<<6) + (0<<5) + srcSize);
527 break;
528 case 2: /* 2 - 2 - 12 */
529 ostart[0] = (BYTE)((IS_RAW<<6) + (2<<4) + (srcSize >> 8));
530 ostart[1] = (BYTE)srcSize;
531 break;
532 default: /*note : should not be necessary : flSize is within {1,2,3} */
533 case 3: /* 2 - 2 - 20 */
534 ostart[0] = (BYTE)((IS_RAW<<6) + (3<<4) + (srcSize >> 16));
535 ostart[1] = (BYTE)(srcSize>>8);
536 ostart[2] = (BYTE)srcSize;
537 break;
538 }
539
540 memcpy(ostart + flSize, src, srcSize);
541 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100542}
543
Yann Colletd1b26842016-03-15 01:24:33 +0100544static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100545{
546 BYTE* const ostart = (BYTE* const)dst;
Yann Colleta910dc82016-03-18 12:37:45 +0100547 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100548
Yann Colletd1b26842016-03-15 01:24:33 +0100549 (void)dstCapacity; /* dstCapacity guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100550
551 switch(flSize)
552 {
553 case 1: /* 2 - 1 - 5 */
554 ostart[0] = (BYTE)((IS_RLE<<6) + (0<<5) + srcSize);
555 break;
556 case 2: /* 2 - 2 - 12 */
557 ostart[0] = (BYTE)((IS_RLE<<6) + (2<<4) + (srcSize >> 8));
558 ostart[1] = (BYTE)srcSize;
559 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100560 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100561 case 3: /* 2 - 2 - 20 */
562 ostart[0] = (BYTE)((IS_RLE<<6) + (3<<4) + (srcSize >> 16));
563 ostart[1] = (BYTE)(srcSize>>8);
564 ostart[2] = (BYTE)srcSize;
565 break;
566 }
567
568 ostart[flSize] = *(const BYTE*)src;
569 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100570}
571
Yann Collet59d1f792016-01-23 19:28:41 +0100572
Yann Colleta5c2c082016-03-20 01:09:18 +0100573static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100574
Yann Colletb923f652016-01-26 03:14:20 +0100575static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100576 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100577 const void* src, size_t srcSize)
578{
Yann Colleta910dc82016-03-18 12:37:45 +0100579 size_t const minGain = ZSTD_minGain(srcSize);
580 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet14983e72015-11-11 21:38:21 +0100581 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100582 U32 singleStream = srcSize < 256;
Yann Colletb923f652016-01-26 03:14:20 +0100583 U32 hType = IS_HUF;
Yann Colleta910dc82016-03-18 12:37:45 +0100584 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100585
Yann Collet14983e72015-11-11 21:38:21 +0100586
Yann Colleta5c2c082016-03-20 01:09:18 +0100587 /* small ? don't even attempt compression (speed opt) */
588# define LITERAL_NOENTROPY 63
589 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
590 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
591 }
592
593 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Colletfb810d62016-01-28 00:18:06 +0100594 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletb923f652016-01-26 03:14:20 +0100595 hType = IS_PCH;
596 singleStream = 1;
Yann Colleta910dc82016-03-18 12:37:45 +0100597 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100598 } else {
Yann Colleta910dc82016-03-18 12:37:45 +0100599 cLitSize = singleStream ? HUF_compress1X(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12)
Yann Colletd1b26842016-03-15 01:24:33 +0100600 : HUF_compress2 (ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 12);
Yann Colletb923f652016-01-26 03:14:20 +0100601 }
Yann Collet14983e72015-11-11 21:38:21 +0100602
Yann Colleta910dc82016-03-18 12:37:45 +0100603 if ((cLitSize==0) || (cLitSize >= srcSize - minGain))
604 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
605 if (cLitSize==1)
606 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100607
608 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100609 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100610 {
Yann Collet59d1f792016-01-23 19:28:41 +0100611 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletb923f652016-01-26 03:14:20 +0100612 ostart[0] = (BYTE)((srcSize>>6) + (singleStream << 4) + (hType<<6));
Yann Colleta910dc82016-03-18 12:37:45 +0100613 ostart[1] = (BYTE)((srcSize<<2) + (cLitSize>>8));
614 ostart[2] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100615 break;
616 case 4: /* 2 - 2 - 14 - 14 */
Yann Colletb923f652016-01-26 03:14:20 +0100617 ostart[0] = (BYTE)((srcSize>>10) + (2<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100618 ostart[1] = (BYTE)(srcSize>> 2);
Yann Colleta910dc82016-03-18 12:37:45 +0100619 ostart[2] = (BYTE)((srcSize<<6) + (cLitSize>>8));
620 ostart[3] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100621 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100622 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100623 case 5: /* 2 - 2 - 18 - 18 */
Yann Colletb923f652016-01-26 03:14:20 +0100624 ostart[0] = (BYTE)((srcSize>>14) + (3<<4) + (hType<<6));
Yann Collet59d1f792016-01-23 19:28:41 +0100625 ostart[1] = (BYTE)(srcSize>>6);
Yann Colleta910dc82016-03-18 12:37:45 +0100626 ostart[2] = (BYTE)((srcSize<<2) + (cLitSize>>16));
627 ostart[3] = (BYTE)(cLitSize>>8);
628 ostart[4] = (BYTE)(cLitSize);
Yann Collet59d1f792016-01-23 19:28:41 +0100629 break;
Yann Collet14983e72015-11-11 21:38:21 +0100630 }
Yann Colleta910dc82016-03-18 12:37:45 +0100631 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100632}
633
634
Yann Colletb44be742016-03-26 20:52:14 +0100635void ZSTD_seqToCodes(const seqStore_t* seqStorePtr, size_t const nbSeq)
636{
637 /* LL codes */
638 { static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
639 8, 9, 10, 11, 12, 13, 14, 15,
640 16, 16, 17, 17, 18, 18, 19, 19,
641 20, 20, 20, 20, 21, 21, 21, 21,
642 22, 22, 22, 22, 22, 22, 22, 22,
643 23, 23, 23, 23, 23, 23, 23, 23,
644 24, 24, 24, 24, 24, 24, 24, 24,
645 24, 24, 24, 24, 24, 24, 24, 24 };
646 const BYTE LL_deltaCode = 19;
Yann Collet5d393572016-04-07 17:19:00 +0200647 const U16* const llTable = seqStorePtr->litLengthStart;
Yann Colletb44be742016-03-26 20:52:14 +0100648 BYTE* const llCodeTable = seqStorePtr->llCodeStart;
649 size_t u;
650 for (u=0; u<nbSeq; u++) {
Yann Collet5d393572016-04-07 17:19:00 +0200651 U32 const ll = llTable[u];
Yann Colletb44be742016-03-26 20:52:14 +0100652 llCodeTable[u] = (ll>63) ? (BYTE)ZSTD_highbit(ll) + LL_deltaCode : LL_Code[ll];
Yann Collet5d393572016-04-07 17:19:00 +0200653 }
654 if (seqStorePtr->longLengthID==1)
655 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
656 }
Yann Colletb44be742016-03-26 20:52:14 +0100657
658 /* Offset codes */
659 { const U32* const offsetTable = seqStorePtr->offsetStart;
660 BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
661 size_t u;
662 for (u=0; u<nbSeq; u++) ofCodeTable[u] = (BYTE)ZSTD_highbit(offsetTable[u]);
663 }
664
665 /* ML codes */
666 { static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
667 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
668 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
669 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
670 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
671 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
672 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
673 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
674 const BYTE ML_deltaCode = 36;
Yann Collet5d393572016-04-07 17:19:00 +0200675 const U16* const mlTable = seqStorePtr->matchLengthStart;
Yann Colletb44be742016-03-26 20:52:14 +0100676 BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
677 size_t u;
678 for (u=0; u<nbSeq; u++) {
Yann Collet5d393572016-04-07 17:19:00 +0200679 U32 const ml = mlTable[u];
Yann Colletb44be742016-03-26 20:52:14 +0100680 mlCodeTable[u] = (ml>127) ? (BYTE)ZSTD_highbit(ml) + ML_deltaCode : ML_Code[ml];
Yann Collet5d393572016-04-07 17:19:00 +0200681 }
682 if (seqStorePtr->longLengthID==2)
683 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
684 }
Yann Colletb44be742016-03-26 20:52:14 +0100685}
686
687
Yann Colletb923f652016-01-26 03:14:20 +0100688size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100689 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100690 size_t srcSize)
691{
Yann Colletb923f652016-01-26 03:14:20 +0100692 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100693 U32 count[MaxSeq+1];
694 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100695 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
696 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
697 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100698 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletb0aec172016-03-21 13:24:16 +0100699 U16* const llTable = seqStorePtr->litLengthStart;
Yann Colletfadda6c2016-03-22 12:14:26 +0100700 U16* const mlTable = seqStorePtr->matchLengthStart;
Yann Collet14983e72015-11-11 21:38:21 +0100701 const U32* const offsetTable = seqStorePtr->offsetStart;
Yann Colletd64f4352016-03-21 00:07:42 +0100702 const U32* const offsetTableEnd = seqStorePtr->offset;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100703 BYTE* const ofCodeTable = seqStorePtr->offCodeStart;
Yann Collet597847a2016-03-20 19:14:22 +0100704 BYTE* const llCodeTable = seqStorePtr->llCodeStart;
Yann Colletfadda6c2016-03-22 12:14:26 +0100705 BYTE* const mlCodeTable = seqStorePtr->mlCodeStart;
Yann Collet5054ee02015-11-23 13:34:21 +0100706 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100707 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100708 BYTE* op = ostart;
Yann Colletd64f4352016-03-21 00:07:42 +0100709 size_t const nbSeq = offsetTableEnd - offsetTable;
Yann Collet14983e72015-11-11 21:38:21 +0100710 BYTE* seqHead;
711
Yann Collet14983e72015-11-11 21:38:21 +0100712 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100713 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100714 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100715 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100716 if (ZSTD_isError(cSize)) return cSize;
717 op += cSize;
718 }
719
720 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100721 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100722 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
723 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
724 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100725 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100726
Yann Colletbe391432016-03-22 23:19:28 +0100727 /* seqHead : flags for FSE encoding type */
728 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100729
Yann Colletfb810d62016-01-28 00:18:06 +0100730#define MIN_SEQ_FOR_DYNAMIC_FSE 64
731#define MAX_SEQ_FOR_STATIC_FSE 1000
732
Yann Colletb44be742016-03-26 20:52:14 +0100733 /* convert length/distances into codes */
734 ZSTD_seqToCodes(seqStorePtr, nbSeq);
Yann Collet597847a2016-03-20 19:14:22 +0100735
Yann Collet14983e72015-11-11 21:38:21 +0100736 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100737 { U32 max = MaxLL;
738 size_t const mostFrequent = FSE_countFast(count, &max, llCodeTable, nbSeq);
739 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
740 *op++ = llCodeTable[0];
741 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
742 LLtype = FSE_ENCODING_RLE;
743 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
744 LLtype = FSE_ENCODING_STATIC;
745 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
746 FSE_buildCTable(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog);
747 LLtype = FSE_ENCODING_RAW;
748 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100749 size_t nbSeq_1 = nbSeq;
750 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
751 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
752 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100753 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
754 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
755 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100756 FSE_buildCTable(CTable_LitLength, norm, max, tableLog);
757 LLtype = FSE_ENCODING_DYNAMIC;
758 } }
Yann Collet14983e72015-11-11 21:38:21 +0100759
Yann Colletb44be742016-03-26 20:52:14 +0100760 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100761 { U32 max = MaxOff;
Yann Collet7cbe79a2016-03-23 22:31:57 +0100762 size_t const mostFrequent = FSE_countFast(count, &max, ofCodeTable, nbSeq);
Yann Colletfadda6c2016-03-22 12:14:26 +0100763 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100764 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100765 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
766 Offtype = FSE_ENCODING_RLE;
767 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
768 Offtype = FSE_ENCODING_STATIC;
Yann Collet48537162016-04-07 15:24:29 +0200769 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
770 FSE_buildCTable(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog);
Yann Colletfadda6c2016-03-22 12:14:26 +0100771 Offtype = FSE_ENCODING_RAW;
772 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100773 size_t nbSeq_1 = nbSeq;
774 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100775 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100776 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100777 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
778 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
779 op += NCountSize; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100780 FSE_buildCTable(CTable_OffsetBits, norm, max, tableLog);
781 Offtype = FSE_ENCODING_DYNAMIC;
782 } }
783
Yann Collet14983e72015-11-11 21:38:21 +0100784 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100785 { U32 max = MaxML;
786 size_t const mostFrequent = FSE_countFast(count, &max, mlCodeTable, nbSeq);
787 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100788 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100789 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
790 MLtype = FSE_ENCODING_RLE;
791 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
792 MLtype = FSE_ENCODING_STATIC;
793 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
794 FSE_buildCTable(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog);
795 MLtype = FSE_ENCODING_RAW;
796 } else {
797 size_t nbSeq_1 = nbSeq;
798 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
799 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
800 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
801 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
802 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
803 op += NCountSize; }
804 FSE_buildCTable(CTable_MatchLength, norm, max, tableLog);
805 MLtype = FSE_ENCODING_DYNAMIC;
806 } }
Yann Collet14983e72015-11-11 21:38:21 +0100807
Yann Colletbe391432016-03-22 23:19:28 +0100808 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100809 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100810
811 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100812 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100813 FSE_CState_t stateMatchLength;
814 FSE_CState_t stateOffsetBits;
815 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100816
Yann Colleta910dc82016-03-18 12:37:45 +0100817 { size_t const errorCode = BIT_initCStream(&blockStream, op, oend-op);
Yann Collet597847a2016-03-20 19:14:22 +0100818 if (ERR_isError(errorCode)) return ERROR(dstSize_tooSmall); } /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100819
Yann Collet597847a2016-03-20 19:14:22 +0100820 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100821 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100822 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100823 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colletb0aec172016-03-21 13:24:16 +0100824 BIT_addBits(&blockStream, llTable[nbSeq-1], LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100825 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Collet25125972016-03-23 14:00:09 +0100826 BIT_addBits(&blockStream, mlTable[nbSeq-1], ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100827 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Collet646693e2016-03-24 02:31:27 +0100828 BIT_addBits(&blockStream, offsetTable[nbSeq-1], ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100829 BIT_flushBits(&blockStream);
830
Yann Colletfadda6c2016-03-22 12:14:26 +0100831 { size_t n;
832 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Colletb9151402016-03-26 17:18:11 +0100833 const BYTE ofCode = ofCodeTable[n];
Yann Collet7cbe79a2016-03-23 22:31:57 +0100834 const BYTE mlCode = mlCodeTable[n];
835 const BYTE llCode = llCodeTable[n];
836 const U32 llBits = LL_bits[llCode];
837 const U32 mlBits = ML_bits[mlCode];
Yann Colletb9151402016-03-26 17:18:11 +0100838 const U32 ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100839 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100840 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
841 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
842 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
843 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200844 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100845 BIT_flushBits(&blockStream); /* (7)*/
Yann Collet7cbe79a2016-03-23 22:31:57 +0100846 BIT_addBits(&blockStream, llTable[n], llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100847 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100848 BIT_addBits(&blockStream, mlTable[n], mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100849 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
850 BIT_addBits(&blockStream, offsetTable[n], ofBits); /* 31 */
851 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100852 } }
Yann Collet14983e72015-11-11 21:38:21 +0100853
854 FSE_flushCState(&blockStream, &stateMatchLength);
855 FSE_flushCState(&blockStream, &stateOffsetBits);
856 FSE_flushCState(&blockStream, &stateLitLength);
857
Yann Colletb9151402016-03-26 17:18:11 +0100858 { size_t const streamSize = BIT_closeCStream(&blockStream);
859 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
860 op += streamSize;
861 } }
Yann Collet14983e72015-11-11 21:38:21 +0100862
863 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100864_check_compressibility:
Yann Colletfadda6c2016-03-22 12:14:26 +0100865 { size_t const minGain = ZSTD_minGain(srcSize);
866 size_t const maxCSize = srcSize - minGain;
867 if ((size_t)(op-ostart) >= maxCSize) return 0; }
Yann Collet14983e72015-11-11 21:38:21 +0100868
Yann Collet5054ee02015-11-23 13:34:21 +0100869 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100870}
871
872
Yann Collet95cd0c22016-03-08 18:24:21 +0100873/*! ZSTD_storeSeq() :
874 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
875 `offsetCode` : distance to match, or 0 == repCode.
876 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100877*/
878MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const BYTE* literals, size_t offsetCode, size_t matchCode)
879{
Yann Collet7d8e6bd2016-02-02 17:30:37 +0100880#if 0 /* for debug */
Yann Collet14983e72015-11-11 21:38:21 +0100881 static const BYTE* g_start = NULL;
Yann Colletb0aec172016-03-21 13:24:16 +0100882 const U32 pos = (U32)(literals - g_start);
Yann Collet14983e72015-11-11 21:38:21 +0100883 if (g_start==NULL) g_start = literals;
Yann Collet3f8ed502016-05-05 03:01:13 +0200884 if ((pos > 2587900) && (pos < 2588050))
Yann Colletb9151402016-03-26 17:18:11 +0100885 printf("Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
Yann Collet433a5cc2016-03-25 11:43:48 +0100886 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +0100887#endif
inikep35b891c2016-05-20 19:42:20 +0200888 ZSTD_statsUpdatePrices(seqStorePtr->stats, litLength, literals, offsetCode, matchCode);
Yann Collet14983e72015-11-11 21:38:21 +0100889
890 /* copy Literals */
891 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
892 seqStorePtr->lit += litLength;
893
894 /* literal Length */
Yann Collet5d393572016-04-07 17:19:00 +0200895 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->litLength - seqStorePtr->litLengthStart); }
896 *seqStorePtr->litLength++ = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100897
898 /* match offset */
Yann Collet646693e2016-03-24 02:31:27 +0100899 *(seqStorePtr->offset++) = (U32)offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100900
901 /* match Length */
Yann Collet5d393572016-04-07 17:19:00 +0200902 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->matchLength - seqStorePtr->matchLengthStart); }
903 *seqStorePtr->matchLength++ = (U16)matchCode;
Yann Collet14983e72015-11-11 21:38:21 +0100904}
905
906
Yann Collet7d360282016-02-12 00:07:30 +0100907/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100908* Match length counter
909***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100910static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100911{
Yann Collet863ec402016-01-28 17:56:33 +0100912 if (MEM_isLittleEndian()) {
913 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100914# if defined(_MSC_VER) && defined(_WIN64)
915 unsigned long r = 0;
916 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100917 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100918# elif defined(__GNUC__) && (__GNUC__ >= 3)
919 return (__builtin_ctzll((U64)val) >> 3);
920# else
921 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 };
922 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
923# endif
Yann Collet863ec402016-01-28 17:56:33 +0100924 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100925# if defined(_MSC_VER)
926 unsigned long r=0;
927 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100928 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100929# elif defined(__GNUC__) && (__GNUC__ >= 3)
930 return (__builtin_ctz((U32)val) >> 3);
931# else
932 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 };
933 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
934# endif
935 }
Yann Collet863ec402016-01-28 17:56:33 +0100936 } else { /* Big Endian CPU */
937 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100938# if defined(_MSC_VER) && defined(_WIN64)
939 unsigned long r = 0;
940 _BitScanReverse64( &r, val );
941 return (unsigned)(r>>3);
942# elif defined(__GNUC__) && (__GNUC__ >= 3)
943 return (__builtin_clzll(val) >> 3);
944# else
945 unsigned r;
946 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
947 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
948 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
949 r += (!val);
950 return r;
951# endif
Yann Collet863ec402016-01-28 17:56:33 +0100952 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100953# if defined(_MSC_VER)
954 unsigned long r = 0;
955 _BitScanReverse( &r, (unsigned long)val );
956 return (unsigned)(r>>3);
957# elif defined(__GNUC__) && (__GNUC__ >= 3)
958 return (__builtin_clz((U32)val) >> 3);
959# else
960 unsigned r;
961 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
962 r += (!val);
963 return r;
964# endif
Yann Collet863ec402016-01-28 17:56:33 +0100965 } }
Yann Collet14983e72015-11-11 21:38:21 +0100966}
967
968
Yann Collet5054ee02015-11-23 13:34:21 +0100969static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100970{
971 const BYTE* const pStart = pIn;
972
Yann Colletfb810d62016-01-28 00:18:06 +0100973 while ((pIn<pInLimit-(sizeof(size_t)-1))) {
Yann Collet7d360282016-02-12 00:07:30 +0100974 size_t diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100975 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
976 pIn += ZSTD_NbCommonBytes(diff);
977 return (size_t)(pIn - pStart);
978 }
Yann Collet14983e72015-11-11 21:38:21 +0100979 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
980 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
981 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
982 return (size_t)(pIn - pStart);
983}
984
Yann Collet04b12d82016-02-11 06:23:24 +0100985/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100986* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100987* convention : on reaching mEnd, match count continue starting from iStart
988*/
989static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
990{
991 size_t matchLength;
992 const BYTE* vEnd = ip + (mEnd - match);
993 if (vEnd > iEnd) vEnd = iEnd;
994 matchLength = ZSTD_count(ip, match, vEnd);
995 if (match + matchLength == mEnd)
996 matchLength += ZSTD_count(ip+matchLength, iStart, iEnd);
997 return matchLength;
998}
999
Yann Collet14983e72015-11-11 21:38:21 +01001000
Yann Collet863ec402016-01-28 17:56:33 +01001001/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001002* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +01001003***************************************/
inikepcc52a972016-02-19 10:09:35 +01001004static const U32 prime3bytes = 506832829U;
1005static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
inikepe2446b02016-03-07 10:07:08 +01001006static size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); }
inikepcc52a972016-02-19 10:09:35 +01001007
Yann Collet4b100f42015-10-30 15:49:48 +01001008static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +01001009static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +01001010static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +01001011
Yann Collet4b100f42015-10-30 15:49:48 +01001012static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001013static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001014static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001015
1016static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001017static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001018static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001019
Yann Collet14983e72015-11-11 21:38:21 +01001020static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001021static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001022static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001023
Yann Collet5be2dd22015-11-11 13:43:58 +01001024static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001025{
1026 switch(mls)
1027 {
1028 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001029 case 4: return ZSTD_hash4Ptr(p, hBits);
1030 case 5: return ZSTD_hash5Ptr(p, hBits);
1031 case 6: return ZSTD_hash6Ptr(p, hBits);
1032 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001033 }
1034}
Yann Collet2acb5d32015-10-29 16:49:43 +01001035
Yann Collet863ec402016-01-28 17:56:33 +01001036
Yann Collet2ce49232016-02-02 14:36:49 +01001037/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001038* Fast Scan
1039***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001040static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1041{
1042 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001043 const U32 hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001044 const BYTE* const base = zc->base;
1045 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet2ce49232016-02-02 14:36:49 +01001046 const BYTE* const iend = ((const BYTE*)end) - 8;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001047 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001048
Yann Colletfb810d62016-01-28 00:18:06 +01001049 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001050 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001051 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001052 }
1053}
1054
1055
Yann Collet1f44b3f2015-11-05 17:32:18 +01001056FORCE_INLINE
Yann Collet59d1f792016-01-23 19:28:41 +01001057void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* zc,
Yann Collet89db5e02015-11-13 11:27:46 +01001058 const void* src, size_t srcSize,
1059 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001060{
Yann Collet417890c2015-12-04 17:16:37 +01001061 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001062 const U32 hBits = zc->params.cParams.hashLog;
Yann Colletc3652152015-11-24 14:06:07 +01001063 seqStore_t* seqStorePtr = &(zc->seqStore);
1064 const BYTE* const base = zc->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001065 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001066 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001067 const BYTE* anchor = istart;
Yann Colletd94efbf2015-12-29 14:29:08 +01001068 const U32 lowIndex = zc->dictLimit;
1069 const BYTE* const lowest = base + lowIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001070 const BYTE* const iend = istart + srcSize;
1071 const BYTE* const ilimit = iend - 8;
Yann Collet89db5e02015-11-13 11:27:46 +01001072 size_t offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001073
Yann Collet1f44b3f2015-11-05 17:32:18 +01001074 /* init */
Yann Collet743402c2015-11-20 12:03:53 +01001075 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001076 if (ip < lowest+REPCODE_STARTVALUE) ip = lowest+REPCODE_STARTVALUE;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001077
1078 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001079 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Collet5054ee02015-11-23 13:34:21 +01001080 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001081 size_t offset;
Yann Collet5be2dd22015-11-11 13:43:58 +01001082 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Colletd94efbf2015-12-29 14:29:08 +01001083 const U32 matchIndex = hashTable[h];
1084 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001085 const U32 current = (U32)(ip-base);
1086 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001087
Yann Colletfb810d62016-01-28 00:18:06 +01001088 if (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1)) { /* note : by construction, offset_1 <= current */
inikep7bc19b62016-04-06 09:46:01 +02001089 mlCode = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
Yann Collet402fdcf2015-11-20 12:46:08 +01001090 ip++;
inikep7bc19b62016-04-06 09:46:01 +02001091 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mlCode-MINMATCH);
inikep59453082016-03-16 15:35:14 +01001092 } else {
Yann Colletd94efbf2015-12-29 14:29:08 +01001093 if ( (matchIndex <= lowIndex) ||
Yann Colletfb810d62016-01-28 00:18:06 +01001094 (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001095 ip += ((ip-anchor) >> g_searchStrength) + 1;
1096 continue;
1097 }
inikep7bc19b62016-04-06 09:46:01 +02001098 mlCode = ZSTD_count(ip+EQUAL_READ32, match+EQUAL_READ32, iend) + EQUAL_READ32;
Yann Collet402fdcf2015-11-20 12:46:08 +01001099 offset = ip-match;
Yann Collet5054ee02015-11-23 13:34:21 +01001100 while ((ip>anchor) && (match>lowest) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001101 offset_2 = offset_1;
1102 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001103
inikep7bc19b62016-04-06 09:46:01 +02001104 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mlCode-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001105 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001106
Yann Collet402fdcf2015-11-20 12:46:08 +01001107 /* match found */
inikep7bc19b62016-04-06 09:46:01 +02001108 ip += mlCode;
Yann Collet402fdcf2015-11-20 12:46:08 +01001109 anchor = ip;
1110
Yann Colletfb810d62016-01-28 00:18:06 +01001111 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001112 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001113 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 +01001114 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1115 /* check immediate repcode */
1116 while ( (ip <= ilimit)
Yann Colletfb810d62016-01-28 00:18:06 +01001117 && (MEM_read32(ip) == MEM_read32(ip - offset_2)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001118 /* store sequence */
inikep7bc19b62016-04-06 09:46:01 +02001119 size_t const rlCode = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
Yann Collet70e45772016-03-19 18:08:32 +01001120 { 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 +01001121 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
inikep7bc19b62016-04-06 09:46:01 +02001122 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rlCode-MINMATCH);
1123 ip += rlCode;
Yann Collet402fdcf2015-11-20 12:46:08 +01001124 anchor = ip;
1125 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001126 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001127
Yann Collet70e45772016-03-19 18:08:32 +01001128 /* Last Literals */
1129 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001130 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1131 seqStorePtr->lit += lastLLSize;
1132 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001133}
1134
1135
Yann Collet82260dd2016-02-11 07:14:25 +01001136static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001137 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001138{
Yann Collet3b719252016-03-30 19:48:05 +02001139 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001140 switch(mls)
1141 {
1142 default:
1143 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001144 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001145 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001146 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001147 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001148 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001149 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001150 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001151 }
1152}
Yann Colletf3eca252015-10-22 15:31:46 +01001153
Yann Colletf3eca252015-10-22 15:31:46 +01001154
Yann Collet82260dd2016-02-11 07:14:25 +01001155static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001156 const void* src, size_t srcSize,
1157 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001158{
1159 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001160 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001161 seqStore_t* seqStorePtr = &(ctx->seqStore);
1162 const BYTE* const base = ctx->base;
1163 const BYTE* const dictBase = ctx->dictBase;
1164 const BYTE* const istart = (const BYTE*)src;
1165 const BYTE* ip = istart;
1166 const BYTE* anchor = istart;
1167 const U32 lowLimit = ctx->lowLimit;
Yann Collet5054ee02015-11-23 13:34:21 +01001168 const BYTE* const dictStart = dictBase + lowLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001169 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001170 const BYTE* const lowPrefixPtr = base + dictLimit;
1171 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001172 const BYTE* const iend = istart + srcSize;
1173 const BYTE* const ilimit = iend - 8;
1174
Yann Collet138e89c2015-11-17 14:26:54 +01001175 U32 offset_2=REPCODE_STARTVALUE, offset_1=REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001176
1177
1178 /* init */
1179 ZSTD_resetSeqStore(seqStorePtr);
Yann Collet61e16ce2016-01-31 02:04:15 +01001180 /* skip first position to avoid read overflow during repcode match check */
Yann Colletfb810d62016-01-28 00:18:06 +01001181 hashTable[ZSTD_hashPtr(ip+0, hBits, mls)] = (U32)(ip-base+0);
Yann Collet61e16ce2016-01-31 02:04:15 +01001182 ip += REPCODE_STARTVALUE;
Yann Collet89db5e02015-11-13 11:27:46 +01001183
1184 /* Main Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001185 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001186 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001187 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001188 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001189 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001190 const U32 current = (U32)(ip-base);
Yann Collet743402c2015-11-20 12:03:53 +01001191 const U32 repIndex = current + 1 - offset_1;
Yann Collet402fdcf2015-11-20 12:46:08 +01001192 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001193 const BYTE* repMatch = repBase + repIndex;
Yann Collet5054ee02015-11-23 13:34:21 +01001194 size_t mlCode;
Yann Collet743402c2015-11-20 12:03:53 +01001195 U32 offset;
Yann Collet89db5e02015-11-13 11:27:46 +01001196 hashTable[h] = current; /* update hash table */
1197
Yann Collet52447382016-03-20 16:00:00 +01001198 if ( ((repIndex >= dictLimit) || (repIndex <= dictLimit-4))
Yann Colletfb810d62016-01-28 00:18:06 +01001199 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001200 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001201 mlCode = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001202 ip++;
inikep7bc19b62016-04-06 09:46:01 +02001203 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mlCode-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001204 } else {
Yann Collet402fdcf2015-11-20 12:46:08 +01001205 if ( (matchIndex < lowLimit) ||
Yann Collet52447382016-03-20 16:00:00 +01001206 (MEM_read32(match) != MEM_read32(ip)) ) {
1207 ip += ((ip-anchor) >> g_searchStrength) + 1;
1208 continue;
1209 }
1210 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001211 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
inikep7bc19b62016-04-06 09:46:01 +02001212 mlCode = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Colletfb810d62016-01-28 00:18:06 +01001213 while ((ip>anchor) && (match>lowMatchPtr) && (ip[-1] == match[-1])) { ip--; match--; mlCode++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001214 offset = current - matchIndex;
1215 offset_2 = offset_1;
1216 offset_1 = offset;
inikep7bc19b62016-04-06 09:46:01 +02001217 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mlCode-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001218 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001219
Yann Collet5054ee02015-11-23 13:34:21 +01001220 /* found a match : store it */
inikep7bc19b62016-04-06 09:46:01 +02001221 ip += mlCode;
Yann Collet402fdcf2015-11-20 12:46:08 +01001222 anchor = ip;
1223
Yann Colletfb810d62016-01-28 00:18:06 +01001224 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001225 /* Fill Table */
Yann Collet239cc282015-11-23 16:17:21 +01001226 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001227 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1228 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001229 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001230 U32 const current2 = (U32)(ip-base);
1231 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001232 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet743402c2015-11-20 12:03:53 +01001233 if ( ((repIndex2 <= dictLimit-4) || (repIndex2 >= dictLimit))
Yann Colletfb810d62016-01-28 00:18:06 +01001234 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001235 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001236 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001237 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001238 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001239 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001240 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001241 anchor = ip;
1242 continue;
1243 }
Yann Collet743402c2015-11-20 12:03:53 +01001244 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001245 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001246
1247 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001248 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001249 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1250 seqStorePtr->lit += lastLLSize;
1251 }
Yann Collet89db5e02015-11-13 11:27:46 +01001252}
1253
1254
Yann Collet82260dd2016-02-11 07:14:25 +01001255static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001256 const void* src, size_t srcSize)
1257{
Yann Collet3b719252016-03-30 19:48:05 +02001258 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001259 switch(mls)
1260 {
1261 default:
1262 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001263 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001264 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001265 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001266 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001267 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001268 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001269 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001270 }
1271}
1272
1273
inikep75716852016-04-06 12:34:42 +02001274
inikep2db1eb72016-04-06 17:14:19 +02001275
Yann Collet04b12d82016-02-11 06:23:24 +01001276/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001277* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001278***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001279/** ZSTD_insertBt1() : add one or multiple positions to tree.
1280* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001281* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001282static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1283 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001284{
1285 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001286 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet5be2dd22015-11-11 13:43:58 +01001287 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet8a57b922016-04-04 13:49:18 +02001288 U32* const bt = zc->chainTable;
1289 const U32 btLog = zc->params.cParams.chainLog - 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001290 const U32 btMask= (1 << btLog) - 1;
1291 U32 matchIndex = hashTable[h];
1292 size_t commonLengthSmaller=0, commonLengthLarger=0;
1293 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001294 const BYTE* const dictBase = zc->dictBase;
1295 const U32 dictLimit = zc->dictLimit;
1296 const BYTE* const dictEnd = dictBase + dictLimit;
1297 const BYTE* const prefixStart = base + dictLimit;
Yann Colletf48e35c2015-11-07 01:13:31 +01001298 const BYTE* match = base + matchIndex;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001299 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001300 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001301 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001302 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001303 U32 dummy32; /* to be nullified at the end */
Yann Collet03526e12015-11-23 15:29:15 +01001304 const U32 windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001305 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001306 size_t bestLength = 8;
Yann Collet7beaa052016-01-21 11:57:45 +01001307 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1308 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1309 predictedSmall += (predictedSmall>0);
1310 predictedLarge += (predictedLarge>0);
Yann Colletf48e35c2015-11-07 01:13:31 +01001311
Yann Collet6c3e2e72015-12-11 10:44:07 +01001312 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001313
Yann Colletfb810d62016-01-28 00:18:06 +01001314 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001315 U32* nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001316 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet793c6492016-04-09 20:32:00 +02001317#if 0 /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001318 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001319 if (matchIndex == predictedSmall) {
1320 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001321 *smallerPtr = matchIndex;
1322 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1323 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1324 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001325 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001326 continue;
1327 }
Yann Colletfb810d62016-01-28 00:18:06 +01001328 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001329 *largerPtr = matchIndex;
1330 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1331 largerPtr = nextPtr;
1332 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001333 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001334 continue;
1335 }
Yann Collet04b12d82016-02-11 06:23:24 +01001336#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001337 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001338 match = base + matchIndex;
1339 if (match[matchLength] == ip[matchLength])
1340 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001341 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001342 match = dictBase + matchIndex;
1343 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1344 if (matchIndex+matchLength >= dictLimit)
1345 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1346 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001347
Yann Colletb8a6f682016-02-15 17:06:29 +01001348 if (matchLength > bestLength) {
1349 bestLength = matchLength;
1350 if (matchLength > matchEndIdx - matchIndex)
1351 matchEndIdx = matchIndex + (U32)matchLength;
1352 }
Yann Colletee3f4512015-12-29 22:26:09 +01001353
Yann Collet59d70632015-11-04 12:05:27 +01001354 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001355 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001356
Yann Colletfb810d62016-01-28 00:18:06 +01001357 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001358 /* match is smaller than current */
1359 *smallerPtr = matchIndex; /* update smaller idx */
1360 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001361 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001362 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001363 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001364 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001365 /* match is larger than current */
1366 *largerPtr = matchIndex;
1367 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001368 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001369 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001370 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001371 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001372
Yann Collet59d70632015-11-04 12:05:27 +01001373 *smallerPtr = *largerPtr = 0;
Yann Colletb8a6f682016-02-15 17:06:29 +01001374 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384));
1375 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1376 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001377}
1378
1379
Yann Collet82260dd2016-02-11 07:14:25 +01001380static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001381 ZSTD_CCtx* zc,
1382 const BYTE* const ip, const BYTE* const iend,
1383 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001384 U32 nbCompares, const U32 mls,
1385 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001386{
1387 U32* const hashTable = zc->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001388 const U32 hashLog = zc->params.cParams.hashLog;
Yann Collet03526e12015-11-23 15:29:15 +01001389 const size_t h = ZSTD_hashPtr(ip, hashLog, mls);
Yann Collet8a57b922016-04-04 13:49:18 +02001390 U32* const bt = zc->chainTable;
1391 const U32 btLog = zc->params.cParams.chainLog - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001392 const U32 btMask= (1 << btLog) - 1;
1393 U32 matchIndex = hashTable[h];
1394 size_t commonLengthSmaller=0, commonLengthLarger=0;
1395 const BYTE* const base = zc->base;
1396 const BYTE* const dictBase = zc->dictBase;
1397 const U32 dictLimit = zc->dictLimit;
1398 const BYTE* const dictEnd = dictBase + dictLimit;
1399 const BYTE* const prefixStart = base + dictLimit;
1400 const U32 current = (U32)(ip-base);
1401 const U32 btLow = btMask >= current ? 0 : current - btMask;
1402 const U32 windowLow = zc->lowLimit;
1403 U32* smallerPtr = bt + 2*(current&btMask);
1404 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001405 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001406 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001407 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001408
Yann Collet6c3e2e72015-12-11 10:44:07 +01001409 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001410
Yann Colletfb810d62016-01-28 00:18:06 +01001411 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet03526e12015-11-23 15:29:15 +01001412 U32* nextPtr = bt + 2*(matchIndex & btMask);
1413 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1414 const BYTE* match;
1415
Yann Colletfb810d62016-01-28 00:18:06 +01001416 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001417 match = base + matchIndex;
1418 if (match[matchLength] == ip[matchLength])
1419 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001420 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001421 match = dictBase + matchIndex;
1422 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001423 if (matchIndex+matchLength >= dictLimit)
1424 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001425 }
1426
Yann Colletfb810d62016-01-28 00:18:06 +01001427 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001428 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001429 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet03526e12015-11-23 15:29:15 +01001430 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit(current-matchIndex+1) - ZSTD_highbit((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001431 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001432 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1433 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1434 }
1435
Yann Colletfb810d62016-01-28 00:18:06 +01001436 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001437 /* match is smaller than current */
1438 *smallerPtr = matchIndex; /* update smaller idx */
1439 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1440 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1441 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1442 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001443 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001444 /* match is larger than current */
1445 *largerPtr = matchIndex;
1446 commonLengthLarger = matchLength;
1447 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1448 largerPtr = nextPtr;
1449 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001450 } }
Yann Collet03526e12015-11-23 15:29:15 +01001451
1452 *smallerPtr = *largerPtr = 0;
1453
Yann Collet72e84cf2015-12-31 19:08:44 +01001454 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001455 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001456}
1457
Yann Collet2cc12cb2016-01-01 07:47:58 +01001458
Yann Colletb8a6f682016-02-15 17:06:29 +01001459static 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 +01001460{
1461 const BYTE* const base = zc->base;
1462 const U32 target = (U32)(ip - base);
1463 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001464
1465 while(idx < target)
1466 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001467}
1468
Yann Collet52447382016-03-20 16:00:00 +01001469/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001470static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001471 ZSTD_CCtx* zc,
1472 const BYTE* const ip, const BYTE* const iLimit,
1473 size_t* offsetPtr,
1474 const U32 maxNbAttempts, const U32 mls)
1475{
1476 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001477 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001478 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1479}
1480
1481
Yann Collet768c6bc2016-02-10 14:01:49 +01001482static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001483 ZSTD_CCtx* zc, /* Index table will be updated */
1484 const BYTE* ip, const BYTE* const iLimit,
1485 size_t* offsetPtr,
1486 const U32 maxNbAttempts, const U32 matchLengthSearch)
1487{
1488 switch(matchLengthSearch)
1489 {
1490 default :
1491 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1492 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1493 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1494 }
1495}
1496
1497
Yann Colletb8a6f682016-02-15 17:06:29 +01001498static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1499{
1500 const BYTE* const base = zc->base;
1501 const U32 target = (U32)(ip - base);
1502 U32 idx = zc->nextToUpdate;
1503
1504 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1505}
1506
inikep64d7bcb2016-04-07 19:14:09 +02001507
1508
Yann Collet03526e12015-11-23 15:29:15 +01001509/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001510static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001511 ZSTD_CCtx* zc,
1512 const BYTE* const ip, const BYTE* const iLimit,
1513 size_t* offsetPtr,
1514 const U32 maxNbAttempts, const U32 mls)
1515{
Yann Colletee3f4512015-12-29 22:26:09 +01001516 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001517 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001518 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001519}
1520
1521
Yann Collet82260dd2016-02-11 07:14:25 +01001522static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001523 ZSTD_CCtx* zc, /* Index table will be updated */
1524 const BYTE* ip, const BYTE* const iLimit,
1525 size_t* offsetPtr,
1526 const U32 maxNbAttempts, const U32 matchLengthSearch)
1527{
1528 switch(matchLengthSearch)
1529 {
1530 default :
1531 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1532 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1533 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1534 }
1535}
1536
1537
Yann Collet5106a762015-11-05 15:00:24 +01001538
inikep64d7bcb2016-04-07 19:14:09 +02001539/* ***********************
1540* Hash Chain
1541*************************/
1542
1543#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1544
inikepafe1f792016-04-07 19:50:03 +02001545
inikep64d7bcb2016-04-07 19:14:09 +02001546/* Update chains up to ip (excluded)
1547 Assumption : always within prefix (ie. not within extDict) */
1548FORCE_INLINE
1549U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1550{
1551 U32* const hashTable = zc->hashTable;
1552 const U32 hashLog = zc->params.cParams.hashLog;
1553 U32* const chainTable = zc->chainTable;
1554 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1555 const BYTE* const base = zc->base;
1556 const U32 target = (U32)(ip - base);
1557 U32 idx = zc->nextToUpdate;
1558
1559 while(idx < target) {
1560 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1561 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1562 hashTable[h] = idx;
1563 idx++;
1564 }
1565
1566 zc->nextToUpdate = target;
1567 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1568}
1569
1570
1571
1572FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1573size_t ZSTD_HcFindBestMatch_generic (
1574 ZSTD_CCtx* zc, /* Index table will be updated */
1575 const BYTE* const ip, const BYTE* const iLimit,
1576 size_t* offsetPtr,
1577 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1578{
1579 U32* const chainTable = zc->chainTable;
1580 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1581 const U32 chainMask = chainSize-1;
1582 const BYTE* const base = zc->base;
1583 const BYTE* const dictBase = zc->dictBase;
1584 const U32 dictLimit = zc->dictLimit;
1585 const BYTE* const prefixStart = base + dictLimit;
1586 const BYTE* const dictEnd = dictBase + dictLimit;
1587 const U32 lowLimit = zc->lowLimit;
1588 const U32 current = (U32)(ip-base);
1589 const U32 minChain = current > chainSize ? current - chainSize : 0;
1590 int nbAttempts=maxNbAttempts;
1591 size_t ml=EQUAL_READ32-1;
1592
1593 /* HC4 match finder */
1594 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1595
1596 for ( ; (matchIndex>lowLimit) && (nbAttempts) ; nbAttempts--) {
1597 const BYTE* match;
1598 size_t currentMl=0;
1599 if ((!extDict) || matchIndex >= dictLimit) {
1600 match = base + matchIndex;
1601 if (match[ml] == ip[ml]) /* potentially better */
1602 currentMl = ZSTD_count(ip, match, iLimit);
1603 } else {
1604 match = dictBase + matchIndex;
1605 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1606 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1607 }
1608
1609 /* save best solution */
1610 if (currentMl > ml) { ml = currentMl; *offsetPtr = ZSTD_REP_MOVE + current - matchIndex; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }
1611
1612 if (matchIndex <= minChain) break;
1613 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1614 }
1615
1616 return ml;
1617}
1618
1619
1620FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1621 ZSTD_CCtx* zc,
1622 const BYTE* ip, const BYTE* const iLimit,
1623 size_t* offsetPtr,
1624 const U32 maxNbAttempts, const U32 matchLengthSearch)
1625{
1626 switch(matchLengthSearch)
1627 {
1628 default :
1629 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1630 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1631 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1632 }
1633}
1634
1635
1636FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1637 ZSTD_CCtx* zc,
1638 const BYTE* ip, const BYTE* const iLimit,
1639 size_t* offsetPtr,
1640 const U32 maxNbAttempts, const U32 matchLengthSearch)
1641{
1642 switch(matchLengthSearch)
1643 {
1644 default :
1645 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1646 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1647 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1648 }
1649}
1650
inikep64d7bcb2016-04-07 19:14:09 +02001651
Yann Collet287b7d92015-11-22 13:24:05 +01001652/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001653* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001654*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001655FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001656void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1657 const void* src, size_t srcSize,
1658 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001659{
inikepfaa8d8a2016-04-05 19:01:10 +02001660 seqStore_t* seqStorePtr = &(ctx->seqStore);
1661 const BYTE* const istart = (const BYTE*)src;
1662 const BYTE* ip = istart;
1663 const BYTE* anchor = istart;
1664 const BYTE* const iend = istart + srcSize;
1665 const BYTE* const ilimit = iend - 8;
1666 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001667
Yann Collet793c6492016-04-09 20:32:00 +02001668 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1669 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001670
inikep64d7bcb2016-04-07 19:14:09 +02001671 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1672 size_t* offsetPtr,
1673 U32 maxNbAttempts, U32 matchLengthSearch);
1674 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
1675
inikepfaa8d8a2016-04-05 19:01:10 +02001676 /* init */
1677 U32 rep[ZSTD_REP_INIT];
Yann Colletea63bb72016-04-08 15:25:32 +02001678 { U32 i ; for (i=0; i<ZSTD_REP_INIT; i++) rep[i]=REPCODE_STARTVALUE; }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001679
inikep64d7bcb2016-04-07 19:14:09 +02001680 ctx->nextToUpdate3 = ctx->nextToUpdate;
inikepfaa8d8a2016-04-05 19:01:10 +02001681 ZSTD_resetSeqStore(seqStorePtr);
1682 if ((ip-base) < REPCODE_STARTVALUE) ip = base + REPCODE_STARTVALUE;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001683
inikepfaa8d8a2016-04-05 19:01:10 +02001684 /* Match Loop */
1685 while (ip < ilimit) {
1686 size_t matchLength=0;
1687 size_t offset=0;
1688 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001689
inikepfaa8d8a2016-04-05 19:01:10 +02001690 /* check repCode */
inikep64d7bcb2016-04-07 19:14:09 +02001691 if (MEM_read32(ip+1) == MEM_read32(ip+1 - rep[0])) {
inikepfaa8d8a2016-04-05 19:01:10 +02001692 /* repcode : we take it */
inikep64d7bcb2016-04-07 19:14:09 +02001693 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-rep[0], iend) + EQUAL_READ32;
1694 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001695 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001696
inikepfaa8d8a2016-04-05 19:01:10 +02001697 /* first search (depth 0) */
1698 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001699 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001700 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001701 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001702 }
Yann Collet5106a762015-11-05 15:00:24 +01001703
inikep7bc19b62016-04-06 09:46:01 +02001704 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001705 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1706 continue;
1707 }
1708
inikep64d7bcb2016-04-07 19:14:09 +02001709 /* let's try to find a better solution */
1710 if (depth>=1)
1711 while (ip<ilimit) {
1712 ip ++;
1713 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - rep[0]))) {
1714 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-rep[0], iend) + EQUAL_READ32;
1715 int const gain2 = (int)(mlRep * 3);
1716 int const gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1717 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1718 matchLength = mlRep, offset = 0, start = ip;
1719 }
1720 { size_t offset2=99999999;
1721 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1722 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1723 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
1724 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1725 matchLength = ml2, offset = offset2, start = ip;
1726 continue; /* search a better one */
1727 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001728
inikep64d7bcb2016-04-07 19:14:09 +02001729 /* let's find an even better one */
1730 if ((depth==2) && (ip<ilimit)) {
1731 ip ++;
1732 if ((offset) && (MEM_read32(ip) == MEM_read32(ip - rep[0]))) {
1733 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-rep[0], iend) + EQUAL_READ32;
1734 int const gain2 = (int)(ml2 * 4);
1735 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1736 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1737 matchLength = ml2, offset = 0, start = ip;
1738 }
1739 { size_t offset2=99999999;
1740 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1741 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1742 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
1743 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1744 matchLength = ml2, offset = offset2, start = ip;
1745 continue;
1746 } } }
1747 break; /* nothing found : store previous solution */
1748 }
1749
1750 /* catch up */
1751 if (offset) {
1752 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1753 { start--; matchLength++; }
1754 rep[1] = rep[0]; rep[0] = (U32)(offset - ZSTD_REP_MOVE);
1755 }
1756
inikepfaa8d8a2016-04-05 19:01:10 +02001757 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001758_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001759 { size_t const litLength = start - anchor;
1760 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1761 anchor = ip = start + matchLength;
1762 }
Yann Collet48537162016-04-07 15:24:29 +02001763
inikepfaa8d8a2016-04-05 19:01:10 +02001764 /* check immediate repcode */
1765 while ( (ip <= ilimit)
1766 && (MEM_read32(ip) == MEM_read32(ip - rep[1])) ) {
1767 /* store sequence */
inikep7bc19b62016-04-06 09:46:01 +02001768 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-rep[1], iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001769 offset = rep[1]; rep[1] = rep[0]; rep[0] = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02001770 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1771 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02001772 anchor = ip;
1773 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02001774 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001775
1776 /* Last Literals */
1777 { size_t const lastLLSize = iend - anchor;
1778 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1779 seqStorePtr->lit += lastLLSize;
inikep35b891c2016-05-20 19:42:20 +02001780 ZSTD_statsUpdatePrices(seqStorePtr->stats, lastLLSize, anchor, 0, 0);
Yann Collet5106a762015-11-05 15:00:24 +01001781 }
Yann Collet5106a762015-11-05 15:00:24 +01001782}
1783
Yann Collet5be2dd22015-11-11 13:43:58 +01001784
inikep64d7bcb2016-04-07 19:14:09 +02001785static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1786{
1787 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
1788}
1789
1790static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1791{
1792 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
1793}
1794
1795static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1796{
1797 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
1798}
1799
1800static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1801{
1802 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
1803}
1804
1805
inikepfaa8d8a2016-04-05 19:01:10 +02001806FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001807void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
1808 const void* src, size_t srcSize,
1809 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01001810{
inikepfaa8d8a2016-04-05 19:01:10 +02001811 seqStore_t* seqStorePtr = &(ctx->seqStore);
1812 const BYTE* const istart = (const BYTE*)src;
1813 const BYTE* ip = istart;
1814 const BYTE* anchor = istart;
1815 const BYTE* const iend = istart + srcSize;
1816 const BYTE* const ilimit = iend - 8;
1817 const BYTE* const base = ctx->base;
1818 const U32 dictLimit = ctx->dictLimit;
1819 const BYTE* const prefixStart = base + dictLimit;
1820 const BYTE* const dictBase = ctx->dictBase;
1821 const BYTE* const dictEnd = dictBase + dictLimit;
1822 const BYTE* const dictStart = dictBase + ctx->lowLimit;
1823
1824 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
1825 const U32 mls = ctx->params.cParams.searchLength;
1826
inikep64d7bcb2016-04-07 19:14:09 +02001827 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1828 size_t* offsetPtr,
1829 U32 maxNbAttempts, U32 matchLengthSearch);
1830 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
1831
inikepfaa8d8a2016-04-05 19:01:10 +02001832 /* init */
1833 U32 rep[ZSTD_REP_INIT];
Yann Colletea63bb72016-04-08 15:25:32 +02001834 { U32 i; for (i=0; i<ZSTD_REP_INIT; i++) rep[i]=REPCODE_STARTVALUE; }
inikepfaa8d8a2016-04-05 19:01:10 +02001835
inikep64d7bcb2016-04-07 19:14:09 +02001836 ctx->nextToUpdate3 = ctx->nextToUpdate;
inikepfaa8d8a2016-04-05 19:01:10 +02001837 ZSTD_resetSeqStore(seqStorePtr);
1838 if ((ip - prefixStart) < REPCODE_STARTVALUE) ip += REPCODE_STARTVALUE;
1839
1840 /* Match Loop */
1841 while (ip < ilimit) {
1842 size_t matchLength=0;
1843 size_t offset=0;
1844 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02001845 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02001846
1847 /* check repCode */
1848 {
inikep64d7bcb2016-04-07 19:14:09 +02001849 const U32 repIndex = (U32)(current+1 - rep[0]);
inikepfaa8d8a2016-04-05 19:01:10 +02001850 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1851 const BYTE* const repMatch = repBase + repIndex;
1852 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02001853 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02001854 /* repcode detected we should take it */
1855 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02001856 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1857 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02001858 } }
1859
1860 /* first search (depth 0) */
1861 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001862 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001863 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001864 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001865 }
1866
inikep7bc19b62016-04-06 09:46:01 +02001867 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001868 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1869 continue;
1870 }
1871
inikep64d7bcb2016-04-07 19:14:09 +02001872 /* let's try to find a better solution */
1873 if (depth>=1)
1874 while (ip<ilimit) {
1875 ip ++;
1876 current++;
1877 /* check repCode */
1878 if (offset) {
1879 const U32 repIndex = (U32)(current - rep[0]);
1880 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1881 const BYTE* const repMatch = repBase + repIndex;
1882 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
1883 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1884 /* repcode detected */
1885 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
1886 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1887 int const gain2 = (int)(repLength * 3);
1888 int const gain1 = (int)(matchLength*3 - ZSTD_highbit((U32)offset+1) + 1);
1889 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
1890 matchLength = repLength, offset = 0, start = ip;
1891 } }
1892
1893 /* search match, depth 1 */
1894 { size_t offset2=99999999;
1895 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1896 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1897 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 4);
1898 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1899 matchLength = ml2, offset = offset2, start = ip;
1900 continue; /* search a better one */
1901 } }
1902
1903 /* let's find an even better one */
1904 if ((depth==2) && (ip<ilimit)) {
1905 ip ++;
1906 current++;
1907 /* check repCode */
1908 if (offset) {
1909 const U32 repIndex = (U32)(current - rep[0]);
1910 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1911 const BYTE* const repMatch = repBase + repIndex;
1912 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
1913 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1914 /* repcode detected */
1915 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
1916 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
1917 int gain2 = (int)(repLength * 4);
1918 int gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 1);
1919 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
1920 matchLength = repLength, offset = 0, start = ip;
1921 } }
1922
1923 /* search match, depth 2 */
1924 { size_t offset2=99999999;
1925 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
1926 int const gain2 = (int)(ml2*4 - ZSTD_highbit((U32)offset2+1)); /* raw approx */
1927 int const gain1 = (int)(matchLength*4 - ZSTD_highbit((U32)offset+1) + 7);
1928 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1929 matchLength = ml2, offset = offset2, start = ip;
1930 continue;
1931 } } }
1932 break; /* nothing found : store previous solution */
1933 }
1934
inikepfaa8d8a2016-04-05 19:01:10 +02001935 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001936 if (offset) {
inikepfaa8d8a2016-04-05 19:01:10 +02001937 U32 matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
1938 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
1939 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02001940 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
inikep5ce00ae2016-04-05 21:03:43 +02001941 rep[1] = rep[0]; rep[0] = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02001942 }
inikepfaa8d8a2016-04-05 19:01:10 +02001943
inikepfaa8d8a2016-04-05 19:01:10 +02001944 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001945_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001946 { size_t const litLength = start - anchor;
1947 ZSTD_storeSeq(seqStorePtr, litLength, anchor, offset, matchLength-MINMATCH);
1948 anchor = ip = start + matchLength;
1949 }
1950
1951 /* check immediate repcode */
1952 while (ip <= ilimit) {
1953 const U32 repIndex = (U32)((ip-base) - rep[1]);
1954 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
1955 const BYTE* const repMatch = repBase + repIndex;
1956 if ((U32)((dictLimit-1) - repIndex) >= 3) /* intentional overflow */
1957 if (MEM_read32(ip) == MEM_read32(repMatch)) {
1958 /* repcode detected we should take it */
1959 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001960 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
inikep5ce00ae2016-04-05 21:03:43 +02001961 offset = rep[1]; rep[1] = rep[0]; rep[0] = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02001962 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1963 ip += matchLength;
1964 anchor = ip;
1965 continue; /* faster when present ... (?) */
1966 }
1967 break;
1968 } }
1969
1970 /* Last Literals */
1971 { size_t const lastLLSize = iend - anchor;
1972 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1973 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01001974 }
1975}
1976
1977
Yann Collet59d1f792016-01-23 19:28:41 +01001978void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01001979{
inikep64d7bcb2016-04-07 19:14:09 +02001980 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01001981}
1982
Yann Collet59d1f792016-01-23 19:28:41 +01001983static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01001984{
Yann Colleta1249dc2016-01-25 04:22:03 +01001985 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01001986}
Yann Collet9a24e592015-11-22 02:53:43 +01001987
Yann Collet59d1f792016-01-23 19:28:41 +01001988static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01001989{
Yann Colleta1249dc2016-01-25 04:22:03 +01001990 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01001991}
1992
Yann Collet59d1f792016-01-23 19:28:41 +01001993static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01001994{
Yann Colleta1249dc2016-01-25 04:22:03 +01001995 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01001996}
1997
inikepef519412016-04-21 11:08:43 +02001998
1999
2000/* The optimal parser */
2001#include "zstd_opt.h"
2002
2003static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2004{
2005 ZSTD_compressBlock_opt_generic(ctx, src, srcSize);
2006}
2007
inikepd3b8d7a2016-02-22 10:06:17 +01002008static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002009{
inikep5ce00ae2016-04-05 21:03:43 +02002010 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize);
inikepe2bfe242016-01-31 11:25:48 +01002011}
2012
Yann Collet7a231792015-11-21 15:27:35 +01002013
Yann Collet59d1f792016-01-23 19:28:41 +01002014typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002015
Yann Colletb923f652016-01-26 03:14:20 +01002016static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002017{
inikepd3b8d7a2016-02-22 10:06:17 +01002018 static const ZSTD_blockCompressor blockCompressor[2][6] = {
inikepf8a339d2016-04-05 23:58:51 +02002019#if 1
inikepd3b8d7a2016-02-22 10:06:17 +01002020 { ZSTD_compressBlock_fast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt },
inikep908fcb32016-04-05 18:16:38 +02002021#else
2022 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict },
2023#endif
inikepd3b8d7a2016-02-22 10:06:17 +01002024 { 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 +01002025 };
2026
2027 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002028}
2029
2030
Yann Colletd1b26842016-03-15 01:24:33 +01002031static 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 +01002032{
Yann Collet3b719252016-03-30 19:48:05 +02002033 ZSTD_blockCompressor blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
Yann Collet2ce49232016-02-02 14:36:49 +01002034 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 +01002035 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002036 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002037}
2038
2039
inikep5cc4efd2016-03-25 10:52:25 +01002040
2041
Yann Collet2ce49232016-02-02 14:36:49 +01002042static size_t ZSTD_compress_generic (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +01002043 void* dst, size_t dstCapacity,
Yann Colletf3eca252015-10-22 15:31:46 +01002044 const void* src, size_t srcSize)
2045{
Yann Collet2ce49232016-02-02 14:36:49 +01002046 size_t blockSize = zc->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002047 size_t remaining = srcSize;
2048 const BYTE* ip = (const BYTE*)src;
2049 BYTE* const ostart = (BYTE*)dst;
2050 BYTE* op = ostart;
Yann Collet3b719252016-03-30 19:48:05 +02002051 const U32 maxDist = 1 << zc->params.cParams.windowLog;
inikep50e82c02016-05-23 15:49:09 +02002052 ZSTD_stats_t* stats = (ZSTD_stats_t*) zc->customAlloc(sizeof(ZSTD_stats_t));
inikep35b891c2016-05-20 19:42:20 +02002053 if (!stats) return ERROR(memory_allocation);
2054 zc->seqStore.stats = stats;
inikep5cc4efd2016-03-25 10:52:25 +01002055 ZSTD_statsInit(stats);
Yann Collet9b11b462015-11-01 12:40:22 +01002056
Yann Collet2ce49232016-02-02 14:36:49 +01002057 while (remaining) {
Yann Collet3e358272015-11-04 18:19:39 +01002058 size_t cSize;
inikep5cc4efd2016-03-25 10:52:25 +01002059 ZSTD_statsResetFreqs(stats);
Yann Collet3e358272015-11-04 18:19:39 +01002060
inikep50e82c02016-05-23 15:49:09 +02002061 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 +01002062 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002063
Yann Collet70e45772016-03-19 18:08:32 +01002064 if ((U32)(ip+blockSize - zc->base) > zc->loadedDictEnd + maxDist) {
2065 /* enforce maxDist */
2066 U32 const newLowLimit = (U32)(ip+blockSize - zc->base) - maxDist;
Yann Collet7a6343f2016-02-02 16:00:50 +01002067 if (zc->lowLimit < newLowLimit) zc->lowLimit = newLowLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002068 if (zc->dictLimit < zc->lowLimit) zc->dictLimit = zc->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002069 }
Yann Collet89db5e02015-11-13 11:27:46 +01002070
Yann Colletd1b26842016-03-15 01:24:33 +01002071 cSize = ZSTD_compressBlock_internal(zc, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikep50e82c02016-05-23 15:49:09 +02002072 if (ZSTD_isError(cSize)) { zc->customFree(stats); return cSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002073
Yann Collet2ce49232016-02-02 14:36:49 +01002074 if (cSize == 0) { /* block is not compressible */
Yann Colletd1b26842016-03-15 01:24:33 +01002075 cSize = ZSTD_noCompressBlock(op, dstCapacity, ip, blockSize);
inikep50e82c02016-05-23 15:49:09 +02002076 if (ZSTD_isError(cSize)) { zc->customFree(stats); return cSize; }
Yann Collet2ce49232016-02-02 14:36:49 +01002077 } else {
Yann Colletf3eca252015-10-22 15:31:46 +01002078 op[0] = (BYTE)(cSize>>16);
2079 op[1] = (BYTE)(cSize>>8);
2080 op[2] = (BYTE)cSize;
Yann Colletc95f8992015-11-19 17:28:35 +01002081 op[0] += (BYTE)(bt_compressed << 6); /* is a compressed block */
Yann Colletf3eca252015-10-22 15:31:46 +01002082 cSize += 3;
2083 }
2084
2085 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002086 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002087 ip += blockSize;
2088 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002089 }
2090
inikep19bd48f2016-04-04 12:10:00 +02002091 ZSTD_statsPrint(stats, zc->params.cParams.searchLength);
inikep50e82c02016-05-23 15:49:09 +02002092 zc->customFree(stats);
Yann Colletf3eca252015-10-22 15:31:46 +01002093 return op-ostart;
2094}
2095
2096
Yann Collet6236eba2016-04-12 15:52:33 +02002097static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
2098 ZSTD_parameters params, U64 pledgedSrcSize)
2099{ BYTE* const op = (BYTE*)dst;
2100 U32 const fcsId = params.fParams.contentSizeFlag ?
2101 (pledgedSrcSize>0) + (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) : /* 0-3 */
2102 0;
2103 BYTE const fdescriptor = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) /* windowLog : 4 KB - 128 MB */
2104 | (fcsId << 6) );
2105 size_t const hSize = ZSTD_frameHeaderSize_min + ZSTD_fcs_fieldSize[fcsId];
2106 if (hSize > dstCapacity) return ERROR(dstSize_tooSmall);
2107
2108 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
2109 op[4] = fdescriptor;
2110 switch(fcsId)
2111 {
2112 default: /* impossible */
2113 case 0 : break;
2114 case 1 : op[5] = (BYTE)(pledgedSrcSize); break;
2115 case 2 : MEM_writeLE16(op+5, (U16)(pledgedSrcSize-256)); break;
2116 case 3 : MEM_writeLE64(op+5, (U64)(pledgedSrcSize)); break;
2117 }
2118 return hSize;
2119}
2120
2121
Yann Colletbf42c8e2016-01-09 01:08:23 +01002122static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* zc,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002123 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002124 const void* src, size_t srcSize,
2125 U32 frame)
Yann Colletf3eca252015-10-22 15:31:46 +01002126{
Yann Collet2acb5d32015-10-29 16:49:43 +01002127 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002128 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002129
Yann Collet887e7da2016-04-11 20:12:27 +02002130 if (zc->stage==0) return ERROR(stage_wrong);
2131 if (frame && (zc->stage==1)) { /* copy saved header */
Yann Collet6236eba2016-04-12 15:52:33 +02002132 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, zc->params, srcSize);
2133 if (ZSTD_isError(fhSize)) return fhSize;
2134 dstCapacity -= fhSize;
2135 dst = (char*)dst + fhSize;
Yann Collet887e7da2016-04-11 20:12:27 +02002136 zc->stage = 2;
Yann Colletecd651b2016-01-07 15:35:18 +01002137 }
Yann Colletf3eca252015-10-22 15:31:46 +01002138
Yann Collet417890c2015-12-04 17:16:37 +01002139 /* Check if blocks follow each other */
Yann Collet2ce49232016-02-02 14:36:49 +01002140 if (src != zc->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002141 /* not contiguous */
Yann Collet70e45772016-03-19 18:08:32 +01002142 size_t const delta = zc->nextSrc - ip;
Yann Collet417890c2015-12-04 17:16:37 +01002143 zc->lowLimit = zc->dictLimit;
2144 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2145 zc->dictBase = zc->base;
Yann Collet417890c2015-12-04 17:16:37 +01002146 zc->base -= delta;
2147 zc->nextToUpdate = zc->dictLimit;
Yann Collete47c4e52015-12-05 09:23:53 +01002148 if (zc->dictLimit - zc->lowLimit < 8) zc->lowLimit = zc->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002149 }
2150
Yann Collet89db5e02015-11-13 11:27:46 +01002151 /* preemptive overflow correction */
Yann Collet2ce49232016-02-02 14:36:49 +01002152 if (zc->lowLimit > (1<<30)) {
Yann Collet3b719252016-03-30 19:48:05 +02002153 U32 const btplus = (zc->params.cParams.strategy == ZSTD_btlazy2) || (zc->params.cParams.strategy == ZSTD_btopt);
Yann Collet8a57b922016-04-04 13:49:18 +02002154 U32 const chainMask = (1 << (zc->params.cParams.chainLog - btplus)) - 1;
2155 U32 const newLowLimit = zc->lowLimit & chainMask; /* preserve position % chainSize */
Yann Collet70e45772016-03-19 18:08:32 +01002156 U32 const correction = zc->lowLimit - newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002157 ZSTD_reduceIndex(zc, correction);
2158 zc->base += correction;
2159 zc->dictBase += correction;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002160 zc->lowLimit = newLowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002161 zc->dictLimit -= correction;
2162 if (zc->nextToUpdate < correction) zc->nextToUpdate = 0;
2163 else zc->nextToUpdate -= correction;
Yann Colletf3eca252015-10-22 15:31:46 +01002164 }
2165
Yann Colletbf42c8e2016-01-09 01:08:23 +01002166 /* if input and dictionary overlap : reduce dictionary (presumed modified by input) */
Yann Collet2ce49232016-02-02 14:36:49 +01002167 if ((ip+srcSize > zc->dictBase + zc->lowLimit) && (ip < zc->dictBase + zc->dictLimit)) {
Yann Colletc3652152015-11-24 14:06:07 +01002168 zc->lowLimit = (U32)(ip + srcSize - zc->dictBase);
2169 if (zc->lowLimit > zc->dictLimit) zc->lowLimit = zc->dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01002170 }
2171
Yann Colletc3652152015-11-24 14:06:07 +01002172 zc->nextSrc = ip + srcSize;
Yann Collet70e45772016-03-19 18:08:32 +01002173 { size_t const cSize = frame ?
Yann Collet7cbe79a2016-03-23 22:31:57 +01002174 ZSTD_compress_generic (zc, dst, dstCapacity, src, srcSize) :
2175 ZSTD_compressBlock_internal (zc, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002176 if (ZSTD_isError(cSize)) return cSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002177 return cSize + fhSize;
Yann Colletecd651b2016-01-07 15:35:18 +01002178 }
Yann Colletf3eca252015-10-22 15:31:46 +01002179}
2180
Yann Colletbf42c8e2016-01-09 01:08:23 +01002181
2182size_t ZSTD_compressContinue (ZSTD_CCtx* zc,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002183 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002184 const void* src, size_t srcSize)
2185{
Yann Collet7cbe79a2016-03-23 22:31:57 +01002186 return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 1);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002187}
2188
2189
Yann Colletd1b26842016-03-15 01:24:33 +01002190size_t ZSTD_compressBlock(ZSTD_CCtx* zc, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002191{
Yann Collet569b81a2016-03-16 15:26:51 +01002192 if (srcSize > ZSTD_BLOCKSIZE_MAX) return ERROR(srcSize_wrong);
inikepd6f208b2016-04-04 21:15:23 +02002193 ZSTD_LOG_BLOCK("%p: ZSTD_compressBlock searchLength=%d\n", zc->base, zc->params.cParams.searchLength);
Yann Colletd1b26842016-03-15 01:24:33 +01002194 return ZSTD_compressContinue_internal(zc, dst, dstCapacity, src, srcSize, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002195}
2196
2197
Yann Colletb923f652016-01-26 03:14:20 +01002198static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002199{
2200 const BYTE* const ip = (const BYTE*) src;
2201 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002202
Yann Collet417890c2015-12-04 17:16:37 +01002203 /* input becomes current prefix */
2204 zc->lowLimit = zc->dictLimit;
2205 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2206 zc->dictBase = zc->base;
2207 zc->base += ip - zc->nextSrc;
2208 zc->nextToUpdate = zc->dictLimit;
Yann Collet2ce49232016-02-02 14:36:49 +01002209 zc->loadedDictEnd = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002210
2211 zc->nextSrc = iend;
2212 if (srcSize <= 8) return 0;
2213
Yann Collet3b719252016-03-30 19:48:05 +02002214 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002215 {
2216 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002217 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002218 break;
2219
2220 case ZSTD_greedy:
2221 case ZSTD_lazy:
2222 case ZSTD_lazy2:
Yann Collet3b719252016-03-30 19:48:05 +02002223 ZSTD_insertAndFindFirstIndex (zc, iend-8, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002224 break;
2225
2226 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002227 case ZSTD_btopt:
Yann Collet3b719252016-03-30 19:48:05 +02002228 ZSTD_updateTree(zc, iend-8, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002229 break;
2230
2231 default:
2232 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2233 }
2234
Yann Collet2ce49232016-02-02 14:36:49 +01002235 zc->nextToUpdate = zc->loadedDictEnd;
Yann Collet417890c2015-12-04 17:16:37 +01002236 return 0;
2237}
2238
2239
Yann Colletb923f652016-01-26 03:14:20 +01002240/* Dictionary format :
2241 Magic == ZSTD_DICT_MAGIC (4 bytes)
Yann Colletfb797352016-03-13 11:08:40 +01002242 HUF_writeCTable(256)
Yann Colletb923f652016-01-26 03:14:20 +01002243 Dictionary content
2244*/
Yann Colletfb797352016-03-13 11:08:40 +01002245/*! ZSTD_loadDictEntropyStats() :
Yann Colletb923f652016-01-26 03:14:20 +01002246 @return : size read from dictionary */
2247static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
2248{
2249 /* note : magic number already checked */
Yann Colletfb810d62016-01-28 00:18:06 +01002250 size_t offcodeHeaderSize, matchlengthHeaderSize, litlengthHeaderSize, errorCode;
2251 short offcodeNCount[MaxOff+1];
2252 unsigned offcodeMaxValue = MaxOff, offcodeLog = OffFSELog;
2253 short matchlengthNCount[MaxML+1];
2254 unsigned matchlengthMaxValue = MaxML, matchlengthLog = MLFSELog;
2255 short litlengthNCount[MaxLL+1];
2256 unsigned litlengthMaxValue = MaxLL, litlengthLog = LLFSELog;
2257
Yann Collet70e45772016-03-19 18:08:32 +01002258 size_t const hufHeaderSize = HUF_readCTable(zc->hufTable, 255, dict, dictSize);
Yann Colletb923f652016-01-26 03:14:20 +01002259 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Colletfb810d62016-01-28 00:18:06 +01002260 zc->flagStaticTables = 1;
2261 dict = (const char*)dict + hufHeaderSize;
2262 dictSize -= hufHeaderSize;
2263
2264 offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dict, dictSize);
2265 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
2266 errorCode = FSE_buildCTable(zc->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog);
2267 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2268 dict = (const char*)dict + offcodeHeaderSize;
2269 dictSize -= offcodeHeaderSize;
2270
2271 matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dict, dictSize);
2272 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
2273 errorCode = FSE_buildCTable(zc->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog);
2274 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2275 dict = (const char*)dict + matchlengthHeaderSize;
2276 dictSize -= matchlengthHeaderSize;
2277
2278 litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dict, dictSize);
2279 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
2280 errorCode = FSE_buildCTable(zc->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog);
2281 if (FSE_isError(errorCode)) return ERROR(dictionary_corrupted);
2282
2283 return hufHeaderSize + offcodeHeaderSize + matchlengthHeaderSize + litlengthHeaderSize;
Yann Colletb923f652016-01-26 03:14:20 +01002284}
2285
Yann Colletd1b26842016-03-15 01:24:33 +01002286/** ZSTD_compress_insertDictionary() :
2287* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002288static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002289{
Yann Colletd1b26842016-03-15 01:24:33 +01002290 if ((dict==NULL) || (dictSize<=4)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002291
Yann Colletd1b26842016-03-15 01:24:33 +01002292 /* default : dict is pure content */
2293 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) return ZSTD_loadDictionaryContent(zc, dict, dictSize);
2294
2295 /* known magic number : dict is parsed for entropy stats and content */
Yann Collet21588e32016-03-30 16:50:44 +02002296 { size_t const eSize = ZSTD_loadDictEntropyStats(zc, (const char*)dict+4 /* skip magic */, dictSize-4) + 4;
2297 if (ZSTD_isError(eSize)) return eSize;
2298 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002299 }
Yann Colletecd651b2016-01-07 15:35:18 +01002300}
2301
Yann Collet0085cd32016-04-12 14:14:10 +02002302
Yann Collet27caf2a2016-04-01 15:48:48 +02002303/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002304* @return : 0, or an error code */
Yann Collet27caf2a2016-04-01 15:48:48 +02002305static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* zc,
Yann Collet1c8e1942016-01-26 16:31:22 +01002306 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002307 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002308{
Yann Collet6236eba2016-04-12 15:52:33 +02002309 { U32 const hashLog3 = (pledgedSrcSize || pledgedSrcSize >= 8192) ? ZSTD_HASHLOG3_MAX : ((pledgedSrcSize >= 2048) ? ZSTD_HASHLOG3_MIN + 1 : ZSTD_HASHLOG3_MIN);
2310 zc->hashLog3 = (params.cParams.searchLength==3) ? hashLog3 : 0; }
Yann Collet88fcd292015-11-25 14:42:45 +01002311
Yann Colletabb5c652016-04-11 20:42:31 +02002312 { size_t const resetError = ZSTD_resetCCtx_advanced(zc, params, 1);
2313 if (ZSTD_isError(resetError)) return resetError; }
Yann Collet89db5e02015-11-13 11:27:46 +01002314
Yann Collet1c8e1942016-01-26 16:31:22 +01002315 return ZSTD_compress_insertDictionary(zc, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002316}
2317
2318
Yann Collet27caf2a2016-04-01 15:48:48 +02002319/*! ZSTD_compressBegin_advanced() :
2320* @return : 0, or an error code */
2321size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* zc,
2322 const void* dict, size_t dictSize,
2323 ZSTD_parameters params, U64 pledgedSrcSize)
2324{
2325 /* compression parameters verification and optimization */
2326 { size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, pledgedSrcSize);
2327 if (ZSTD_isError(errorCode)) return errorCode; }
2328
2329 return ZSTD_compressBegin_internal(zc, dict, dictSize, params, pledgedSrcSize);
2330}
2331
2332
Yann Collet1c8e1942016-01-26 16:31:22 +01002333size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* zc, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002334{
Yann Collet3b719252016-03-30 19:48:05 +02002335 ZSTD_parameters params;
2336 params.cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
2337 params.fParams.contentSizeFlag = 0;
Yann Collet27caf2a2016-04-01 15:48:48 +02002338 ZSTD_adjustCParams(&params.cParams, 0, dictSize);
inikepa4dde252016-03-01 14:14:35 +01002339 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin_usingDict compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet27caf2a2016-04-01 15:48:48 +02002340 return ZSTD_compressBegin_internal(zc, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002341}
Yann Collet083fcc82015-10-25 14:06:35 +01002342
inikep19bd48f2016-04-04 12:10:00 +02002343
Yann Collet1c8e1942016-01-26 16:31:22 +01002344size_t ZSTD_compressBegin(ZSTD_CCtx* zc, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002345{
inikepa4dde252016-03-01 14:14:35 +01002346 ZSTD_LOG_BLOCK("%p: ZSTD_compressBegin compressionLevel=%d\n", zc->base, compressionLevel);
Yann Collet3b719252016-03-30 19:48:05 +02002347 return ZSTD_compressBegin_usingDict(zc, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002348}
2349
2350
Yann Colletfb797352016-03-13 11:08:40 +01002351/*! ZSTD_compressEnd() :
2352* Write frame epilogue.
Yann Collet88fcd292015-11-25 14:42:45 +01002353* @return : nb of bytes written into dst (or an error code) */
Yann Colletd1b26842016-03-15 01:24:33 +01002354size_t ZSTD_compressEnd(ZSTD_CCtx* zc, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002355{
2356 BYTE* op = (BYTE*)dst;
Yann Collet6236eba2016-04-12 15:52:33 +02002357 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002358
Yann Collet887e7da2016-04-11 20:12:27 +02002359 /* not even init ! */
2360 if (zc->stage==0) return ERROR(stage_wrong);
2361
2362 /* special case : empty frame */
2363 if (zc->stage==1) {
Yann Collet6236eba2016-04-12 15:52:33 +02002364 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, zc->params, 0);
2365 if (ZSTD_isError(fhSize)) return fhSize;
2366 dstCapacity -= fhSize;
2367 op += fhSize;
Yann Collet887e7da2016-04-11 20:12:27 +02002368 zc->stage = 2;
Yann Colletecd651b2016-01-07 15:35:18 +01002369 }
2370
2371 /* frame epilogue */
Yann Colletd1b26842016-03-15 01:24:33 +01002372 if (dstCapacity < 3) return ERROR(dstSize_tooSmall);
Yann Collet2acb5d32015-10-29 16:49:43 +01002373 op[0] = (BYTE)(bt_end << 6);
2374 op[1] = 0;
2375 op[2] = 0;
2376
Yann Collet887e7da2016-04-11 20:12:27 +02002377 zc->stage = 0; /* return to "created by not init" status */
Yann Collet6236eba2016-04-12 15:52:33 +02002378 return 3+fhSize;
Yann Collet2acb5d32015-10-29 16:49:43 +01002379}
2380
Yann Colletfd416f12016-01-30 03:14:15 +01002381
2382size_t ZSTD_compress_usingPreparedCCtx(ZSTD_CCtx* cctx, const ZSTD_CCtx* preparedCCtx,
Yann Colletd1b26842016-03-15 01:24:33 +01002383 void* dst, size_t dstCapacity,
Yann Colletfd416f12016-01-30 03:14:15 +01002384 const void* src, size_t srcSize)
2385{
Yann Collet70e45772016-03-19 18:08:32 +01002386 { size_t const errorCode = ZSTD_copyCCtx(cctx, preparedCCtx);
2387 if (ZSTD_isError(errorCode)) return errorCode;
2388 }
2389 { size_t const cSize = ZSTD_compressContinue(cctx, dst, dstCapacity, src, srcSize);
2390 if (ZSTD_isError(cSize)) return cSize;
Yann Collet0dbf2872016-04-08 02:02:12 +02002391
Yann Collet70e45772016-03-19 18:08:32 +01002392 { size_t const endSize = ZSTD_compressEnd(cctx, (char*)dst+cSize, dstCapacity-cSize);
2393 if (ZSTD_isError(endSize)) return endSize;
2394 return cSize + endSize;
2395 } }
Yann Colletfd416f12016-01-30 03:14:15 +01002396}
2397
2398
Yann Collet21588e32016-03-30 16:50:44 +02002399static size_t ZSTD_compress_internal (ZSTD_CCtx* ctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002400 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002401 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002402 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002403 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002404{
2405 BYTE* const ostart = (BYTE*)dst;
2406 BYTE* op = ostart;
2407
Yann Collet1c8e1942016-01-26 16:31:22 +01002408 /* Init */
Yann Collet27caf2a2016-04-01 15:48:48 +02002409 { size_t const errorCode = ZSTD_compressBegin_internal(ctx, dict, dictSize, params, srcSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002410 if(ZSTD_isError(errorCode)) return errorCode; }
Yann Colletf3eca252015-10-22 15:31:46 +01002411
2412 /* body (compression) */
Yann Colletd1b26842016-03-15 01:24:33 +01002413 { size_t const oSize = ZSTD_compressContinue (ctx, op, dstCapacity, src, srcSize);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002414 if(ZSTD_isError(oSize)) return oSize;
2415 op += oSize;
2416 dstCapacity -= oSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002417
2418 /* Close frame */
Yann Colletd1b26842016-03-15 01:24:33 +01002419 { size_t const oSize = ZSTD_compressEnd(ctx, op, dstCapacity);
Yann Collet7cbe79a2016-03-23 22:31:57 +01002420 if(ZSTD_isError(oSize)) return oSize;
2421 op += oSize; }
Yann Colletf3eca252015-10-22 15:31:46 +01002422
2423 return (op - ostart);
2424}
2425
Yann Collet21588e32016-03-30 16:50:44 +02002426size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2427 void* dst, size_t dstCapacity,
2428 const void* src, size_t srcSize,
2429 const void* dict,size_t dictSize,
2430 ZSTD_parameters params)
2431{
Yann Collet3b719252016-03-30 19:48:05 +02002432 size_t const errorCode = ZSTD_checkCParams_advanced(params.cParams, srcSize);
Yann Collet21588e32016-03-30 16:50:44 +02002433 if (ZSTD_isError(errorCode)) return errorCode;
2434 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2435}
2436
Yann Colletd1b26842016-03-15 01:24:33 +01002437size_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 +01002438{
Yann Collet3b719252016-03-30 19:48:05 +02002439 ZSTD_parameters params;
inikepa4dde252016-03-01 14:14:35 +01002440 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 +02002441 params.cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
2442 params.fParams.contentSizeFlag = 1;
2443 ZSTD_adjustCParams(&params.cParams, srcSize, dictSize);
Yann Collet21588e32016-03-30 16:50:44 +02002444 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002445}
2446
Yann Colletd1b26842016-03-15 01:24:33 +01002447size_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 +01002448{
inikepa4dde252016-03-01 14:14:35 +01002449 ZSTD_LOG_BLOCK("%p: ZSTD_compressCCtx srcSize=%d compressionLevel=%d\n", ctx->base, (int)srcSize, compressionLevel);
Yann Collet21588e32016-03-30 16:50:44 +02002450 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002451}
2452
Yann Colletd1b26842016-03-15 01:24:33 +01002453size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002454{
Yann Collet44fe9912015-10-29 22:02:40 +01002455 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002456 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002457 memset(&ctxBody, 0, sizeof(ctxBody));
inikep50e82c02016-05-23 15:49:09 +02002458 ctxBody.customAlloc = malloc;
2459 ctxBody.customFree = free;
Yann Colletd1b26842016-03-15 01:24:33 +01002460 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
inikep50e82c02016-05-23 15:49:09 +02002461 ctxBody.customFree(ctxBody.workSpace); /* can't free ctxBody, since it's on stack; just free heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002462 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002463}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002464
Yann Colletfd416f12016-01-30 03:14:15 +01002465
Yann Collet70e8c382016-02-10 13:37:52 +01002466/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01002467
inikep3c7c3522016-04-22 13:59:05 +02002468#define ZSTD_DEFAULT_CLEVEL 5
inikep2c5eeea2016-04-15 13:44:46 +02002469#define ZSTD_MAX_CLEVEL 22
Yann Collet7d968c72016-02-03 02:11:32 +01002470unsigned ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
2471
Yann Collet3b719252016-03-30 19:48:05 +02002472static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01002473{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02002474 /* W, C, H, S, L, TL, strat */
Yann Collet3b719252016-03-30 19:48:05 +02002475 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2476 { 19, 13, 14, 1, 7, 4, ZSTD_fast }, /* level 1 */
2477 { 19, 15, 16, 1, 6, 4, ZSTD_fast }, /* level 2 */
2478 { 20, 18, 20, 1, 6, 4, ZSTD_fast }, /* level 3 */
2479 { 20, 13, 17, 2, 5, 4, ZSTD_greedy }, /* level 4.*/
2480 { 20, 15, 18, 3, 5, 4, ZSTD_greedy }, /* level 5 */
2481 { 21, 16, 19, 2, 5, 4, ZSTD_lazy }, /* level 6 */
2482 { 21, 17, 20, 3, 5, 4, ZSTD_lazy }, /* level 7 */
2483 { 21, 18, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 8.*/
2484 { 21, 20, 20, 3, 5, 4, ZSTD_lazy2 }, /* level 9 */
2485 { 21, 19, 21, 4, 5, 4, ZSTD_lazy2 }, /* level 10 */
2486 { 22, 20, 22, 4, 5, 4, ZSTD_lazy2 }, /* level 11 */
2487 { 22, 20, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 12 */
2488 { 22, 21, 22, 5, 5, 4, ZSTD_lazy2 }, /* level 13 */
2489 { 22, 21, 22, 6, 5, 4, ZSTD_lazy2 }, /* level 14 */
2490 { 22, 21, 21, 5, 5, 4, ZSTD_btlazy2 }, /* level 15 */
2491 { 23, 22, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 16 */
Yann Collet793c6492016-04-09 20:32:00 +02002492 { 23, 23, 22, 5, 5, 4, ZSTD_btlazy2 }, /* level 17.*/
2493 { 23, 23, 22, 6, 5, 24, ZSTD_btopt }, /* level 18.*/
2494 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19.*/
2495 { 25, 26, 23, 7, 3, 64, ZSTD_btopt }, /* level 20.*/
2496 { 26, 26, 23, 7, 3,256, ZSTD_btopt }, /* level 21.*/
2497 { 27, 27, 25, 9, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002498},
2499{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002500 /* W, C, H, S, L, T, strat */
2501 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 */
Yann Collet0dbf2872016-04-08 02:02:12 +02002502 { 18, 13, 14, 1, 6, 4, ZSTD_fast }, /* level 1 */
Yann Collet78267d12016-04-08 12:36:19 +02002503 { 18, 15, 17, 1, 5, 4, ZSTD_fast }, /* level 2 */
2504 { 18, 13, 15, 1, 5, 4, ZSTD_greedy }, /* level 3.*/
2505 { 18, 15, 17, 1, 5, 4, ZSTD_greedy }, /* level 4.*/
2506 { 18, 16, 17, 4, 5, 4, ZSTD_greedy }, /* level 5 */
2507 { 18, 17, 17, 5, 5, 4, ZSTD_greedy }, /* level 6 */
Yann Collet3b719252016-03-30 19:48:05 +02002508 { 18, 17, 17, 4, 4, 4, ZSTD_lazy }, /* level 7 */
2509 { 18, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2510 { 18, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2511 { 18, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
Yann Collet78267d12016-04-08 12:36:19 +02002512 { 18, 18, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 11.*/
2513 { 18, 18, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 12.*/
2514 { 18, 19, 17, 7, 4, 4, ZSTD_btlazy2 }, /* level 13 */
2515 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
2516 { 18, 18, 18, 8, 4, 24, ZSTD_btopt }, /* level 15.*/
2517 { 18, 19, 18, 8, 3, 48, ZSTD_btopt }, /* level 16.*/
2518 { 18, 19, 18, 8, 3, 96, ZSTD_btopt }, /* level 17.*/
2519 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
2520 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
2521 { 18, 19, 18, 11, 3,512, ZSTD_btopt }, /* level 20.*/
2522 { 18, 19, 18, 12, 3,512, ZSTD_btopt }, /* level 21.*/
2523 { 18, 19, 18, 13, 3,512, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002524},
2525{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002526 /* W, C, H, S, L, T, strat */
2527 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - never used */
2528 { 17, 12, 13, 1, 6, 4, ZSTD_fast }, /* level 1 */
2529 { 17, 13, 16, 1, 5, 4, ZSTD_fast }, /* level 2 */
2530 { 17, 13, 14, 2, 5, 4, ZSTD_greedy }, /* level 3 */
2531 { 17, 13, 15, 3, 4, 4, ZSTD_greedy }, /* level 4 */
2532 { 17, 15, 17, 4, 4, 4, ZSTD_greedy }, /* level 5 */
2533 { 17, 16, 17, 3, 4, 4, ZSTD_lazy }, /* level 6 */
2534 { 17, 15, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 7 */
2535 { 17, 17, 17, 4, 4, 4, ZSTD_lazy2 }, /* level 8 */
2536 { 17, 17, 17, 5, 4, 4, ZSTD_lazy2 }, /* level 9 */
2537 { 17, 17, 17, 6, 4, 4, ZSTD_lazy2 }, /* level 10 */
2538 { 17, 17, 17, 7, 4, 4, ZSTD_lazy2 }, /* level 11 */
2539 { 17, 17, 17, 8, 4, 4, ZSTD_lazy2 }, /* level 12 */
2540 { 17, 18, 17, 6, 4, 4, ZSTD_btlazy2 }, /* level 13.*/
2541 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
2542 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
2543 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
2544 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
2545 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
2546 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
2547 { 17, 18, 17, 9, 3,256, ZSTD_btopt }, /* level 20.*/
2548 { 17, 18, 17, 10, 3,256, ZSTD_btopt }, /* level 21.*/
2549 { 17, 18, 17, 11, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002550},
2551{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02002552 /* W, C, H, S, L, T, strat */
2553 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 -- never used */
2554 { 14, 14, 14, 1, 4, 4, ZSTD_fast }, /* level 1 */
2555 { 14, 14, 15, 1, 4, 4, ZSTD_fast }, /* level 2 */
2556 { 14, 14, 14, 4, 4, 4, ZSTD_greedy }, /* level 3.*/
2557 { 14, 14, 14, 3, 4, 4, ZSTD_lazy }, /* level 4.*/
2558 { 14, 14, 14, 4, 4, 4, ZSTD_lazy2 }, /* level 5 */
2559 { 14, 14, 14, 5, 4, 4, ZSTD_lazy2 }, /* level 6 */
2560 { 14, 14, 14, 6, 4, 4, ZSTD_lazy2 }, /* level 7.*/
2561 { 14, 14, 14, 7, 4, 4, ZSTD_lazy2 }, /* level 8.*/
2562 { 14, 15, 14, 6, 4, 4, ZSTD_btlazy2 }, /* level 9.*/
2563 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
2564 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
2565 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
2566 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
2567 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
2568 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
2569 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
2570 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
2571 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
2572 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
2573 { 14, 15, 15, 8, 3,256, ZSTD_btopt }, /* level 20.*/
2574 { 14, 15, 15, 9, 3,256, ZSTD_btopt }, /* level 21.*/
2575 { 14, 15, 15, 10, 3,256, ZSTD_btopt }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01002576},
2577};
2578
Yann Collet1df25942016-03-05 18:43:21 +01002579/*! ZSTD_getParams() :
Yann Colletfd416f12016-01-30 03:14:15 +01002580* @return ZSTD_parameters structure for a selected compression level and srcSize.
Yann Colletde406ee2016-03-20 15:46:10 +01002581* `srcSize` value is optional, select 0 if not known */
Yann Collet3b719252016-03-30 19:48:05 +02002582ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, U64 srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01002583{
Yann Collet15354142016-04-04 04:22:53 +02002584 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02002585 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02002586 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02002587 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
inikep3c7c3522016-04-22 13:59:05 +02002588 if (compressionLevel < 0) compressionLevel = ZSTD_DEFAULT_CLEVEL;
inikep2c5eeea2016-04-15 13:44:46 +02002589 if (compressionLevel==0) compressionLevel = 1;
Yann Colletfd416f12016-01-30 03:14:15 +01002590 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02002591 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02002592 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
2593 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02002594 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02002595 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
2596 }
Yann Collet15354142016-04-04 04:22:53 +02002597 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01002598}