blob: 9a2d194ad79e9c3f1eeaea728bfe2879be8e8cbf [file] [log] [blame]
Yann Collet4ded9e52016-08-30 10:04:33 -07001/**
2 * Copyright (c) 2016-present, Yann Collet, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 */
Yann Colletf3eca252015-10-22 15:31:46 +01009
Yann Colletf3eca252015-10-22 15:31:46 +010010
Yann Collet7d360282016-02-12 00:07:30 +010011/*-*************************************
Yann Colletae7aa062016-02-03 02:46:46 +010012* Dependencies
Yann Colletf3eca252015-10-22 15:31:46 +010013***************************************/
Yann Colletd3b7f8d2016-06-04 19:47:02 +020014#include <string.h> /* memset */
Yann Collet14983e72015-11-11 21:38:21 +010015#include "mem.h"
Yann Collet5a0c8e22016-08-12 01:20:36 +020016#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
Yann Colletd0e2cd12016-06-05 00:58:01 +020017#include "fse.h"
Yann Collet130fe112016-06-05 00:42:28 +020018#define HUF_STATIC_LINKING_ONLY
19#include "huf.h"
Yann Colletd3b7f8d2016-06-04 19:47:02 +020020#include "zstd_internal.h" /* includes zstd.h */
Yann Colletf3eca252015-10-22 15:31:46 +010021
22
Yann Collet7d360282016-02-12 00:07:30 +010023/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010024* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010025***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010026static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Collet731ef162016-07-27 21:05:12 +020027#define HASH_READ_SIZE 8
28typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
Yann Colletf3eca252015-10-22 15:31:46 +010029
Yann Collet71ddeb62017-04-20 22:54:54 -070030/* entropy tables always have same size */
31static size_t const hufCTable_size = HUF_CTABLE_SIZE(255);
Yann Collete42afbc2017-04-26 11:39:35 -070032static size_t const litlengthCTable_size = FSE_CTABLE_SIZE(LLFSELog, MaxLL);
33static size_t const offcodeCTable_size = FSE_CTABLE_SIZE(OffFSELog, MaxOff);
34static size_t const matchlengthCTable_size = FSE_CTABLE_SIZE(MLFSELog, MaxML);
Yann Collet72712032017-04-20 23:21:19 -070035static size_t const entropyScratchSpace_size = HUF_WORKSPACE_SIZE;
Yann Colleta34a39c2017-04-20 18:17:58 -070036
Yann Colletf3eca252015-10-22 15:31:46 +010037
Yann Collet7d360282016-02-12 00:07:30 +010038/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010039* Helper functions
40***************************************/
Yann Collet4b987ad2017-04-10 17:50:44 -070041#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG==1)
42# include <assert.h>
43#else
44# define assert(condition) ((void)0)
45#endif
46
Yann Colletc261f712016-12-12 00:25:07 +010047#define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; }
Yann Collet4b987ad2017-04-10 17:50:44 -070048
Yann Collet3f75d522017-03-31 17:11:38 -070049size_t ZSTD_compressBound(size_t srcSize) {
Yann Collet30c76982017-03-31 18:27:03 -070050 size_t const lowLimit = 256 KB;
51 size_t const margin = (srcSize < lowLimit) ? (lowLimit-srcSize) >> 12 : 0; /* from 64 to 0 */
Yann Collet3f75d522017-03-31 17:11:38 -070052 return srcSize + (srcSize >> 8) + margin;
53}
Yann Collet59d1f792016-01-23 19:28:41 +010054
55
Yann Collet7d360282016-02-12 00:07:30 +010056/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010057* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010058***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010059static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
60{
Yann Collet14983e72015-11-11 21:38:21 +010061 ssPtr->lit = ssPtr->litStart;
Yann Colletc0ce4f12016-07-30 00:55:13 +020062 ssPtr->sequences = ssPtr->sequencesStart;
Yann Collet5d393572016-04-07 17:19:00 +020063 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010064}
65
66
Yann Collet7d360282016-02-12 00:07:30 +010067/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010068* Context memory management
69***************************************/
Yann Colletaca113f2016-12-23 22:25:03 +010070struct ZSTD_CCtx_s {
Yann Collet89db5e02015-11-13 11:27:46 +010071 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010072 const BYTE* base; /* All regular indexes relative to this position */
73 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010074 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010075 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010076 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010077 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +010078 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Colletbb002742017-01-25 16:25:38 -080079 U32 loadedDictEnd; /* index of end of dictionary */
80 U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
Yann Collet14312d82017-02-23 23:42:12 -080081 U32 forceRawDict; /* Force loading dictionary in "content-only" mode (no header analysis) */
Yann Collet731ef162016-07-27 21:05:12 +020082 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +020083 U32 rep[ZSTD_REP_NUM];
Yann Colletb459aad2017-01-19 17:33:37 -080084 U32 repToConfirm[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +020085 U32 dictID;
Yann Collet5be2dd22015-11-11 13:43:58 +010086 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +010087 void* workSpace;
88 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +010089 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +020090 U64 frameContentSize;
Yann Collet20d5e032017-04-11 18:34:02 -070091 U64 consumedSrcSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +020092 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +020093 ZSTD_customMem customMem;
Yann Colletecd651b2016-01-07 15:35:18 +010094
Yann Collet712def92015-10-29 18:41:45 +010095 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +010096 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +010097 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +020098 U32* chainTable;
Yann Collet71ddeb62017-04-20 22:54:54 -070099 HUF_repeat hufCTable_repeatMode;
100 HUF_CElt* hufCTable;
101 U32 fseCTables_ready;
Yann Collet71aaa322017-04-20 23:03:38 -0700102 FSE_CTable* offcodeCTable;
103 FSE_CTable* matchlengthCTable;
104 FSE_CTable* litlengthCTable;
Yann Collete42afbc2017-04-26 11:39:35 -0700105 unsigned* entropyScratchSpace;
Yann Colletf3eca252015-10-22 15:31:46 +0100106};
107
Yann Collet5be2dd22015-11-11 13:43:58 +0100108ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100109{
inikep3763c772016-06-03 13:28:20 +0200110 return ZSTD_createCCtx_advanced(defaultCustomMem);
inikep50e82c02016-05-23 15:49:09 +0200111}
112
113ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
114{
Yann Collet69c2cdb2016-07-14 16:52:45 +0200115 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +0200116
Yann Collet23b6e052016-08-28 21:05:43 -0700117 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
118 if (!customMem.customAlloc || !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200119
Yann Collet23b6e052016-08-28 21:05:43 -0700120 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200121 if (!cctx) return NULL;
122 memset(cctx, 0, sizeof(ZSTD_CCtx));
Yann Colletbb002742017-01-25 16:25:38 -0800123 cctx->customMem = customMem;
Yann Collet69c2cdb2016-07-14 16:52:45 +0200124 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100125}
126
Yann Collet5be2dd22015-11-11 13:43:58 +0100127size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100128{
inikep36403962016-06-03 16:36:50 +0200129 if (cctx==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -0700130 ZSTD_free(cctx->workSpace, cctx->customMem);
131 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100132 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100133}
134
Yann Collet70e3b312016-08-23 01:18:06 +0200135size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200136{
Yann Colletd7c65892016-09-15 02:50:27 +0200137 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet3ae543c2016-07-11 03:12:17 +0200138 return sizeof(*cctx) + cctx->workSpaceSize;
139}
140
Yann Colletbb002742017-01-25 16:25:38 -0800141size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
142{
143 switch(param)
144 {
Yann Collet06e76972017-01-25 16:39:03 -0800145 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
Yann Collet14312d82017-02-23 23:42:12 -0800146 case ZSTD_p_forceRawDict : cctx->forceRawDict = value>0; return 0;
Yann Colletbb002742017-01-25 16:25:38 -0800147 default: return ERROR(parameter_unknown);
148 }
149}
150
Yann Colletb44be742016-03-26 20:52:14 +0100151const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100152{
Yann Colletb44be742016-03-26 20:52:14 +0100153 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100154}
155
Yann Collet95162342016-10-25 16:19:52 -0700156static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx)
157{
158 return cctx->params;
159}
160
Yann Collet59d70632015-11-04 12:05:27 +0100161
Yann Collet21588e32016-03-30 16:50:44 +0200162/** ZSTD_checkParams() :
163 ensure param values remain within authorized range.
164 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200165size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200166{
Yann Colletac8bace2016-09-07 14:54:23 +0200167# define CLAMPCHECK(val,min,max) { if ((val<min) | (val>max)) return ERROR(compressionParameter_unsupported); }
Yann Collet15354142016-04-04 04:22:53 +0200168 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200169 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200170 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
171 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Collet2e2e78d2017-03-29 16:02:47 -0700172 CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200173 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200174 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200175 return 0;
176}
177
178
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100179/** ZSTD_cycleLog() :
180 * condition for correct operation : hashLog > 1 */
181static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
182{
183 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
184 return hashLog - btScale;
185}
186
Yann Collet70d13012016-06-01 18:45:34 +0200187/** ZSTD_adjustCParams() :
Yann Colletcf409a72016-09-26 16:41:05 +0200188 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200189 mostly downsizing to reduce memory consumption and initialization.
190 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
191 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200192 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200193ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100194{
Yann Collet70d13012016-06-01 18:45:34 +0200195 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100196
Yann Collet70e45772016-03-19 18:08:32 +0100197 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200198 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
199 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200200 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200201 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200202 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200203 } }
Yann Collet70d13012016-06-01 18:45:34 +0200204 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100205 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
206 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
207 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100208
Yann Collet70d13012016-06-01 18:45:34 +0200209 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200210
211 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100212}
213
214
Yann Collet88472382016-07-14 17:05:38 +0200215size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100216{
Yann Collet731ef162016-07-27 21:05:12 +0200217 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
218 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
219 size_t const maxNbSeq = blockSize / divider;
220 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200221
Yann Collet731ef162016-07-27 21:05:12 +0200222 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
223 size_t const hSize = ((size_t)1) << cParams.hashLog;
224 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
225 size_t const h3Size = ((size_t)1) << hashLog3;
Yann Collet71ddeb62017-04-20 22:54:54 -0700226 size_t const entropySpace = hufCTable_size + litlengthCTable_size
Yann Colleta4086452017-04-20 23:09:39 -0700227 + offcodeCTable_size + matchlengthCTable_size
Yann Collet72712032017-04-20 23:21:19 -0700228 + entropyScratchSpace_size;
Yann Collet731ef162016-07-27 21:05:12 +0200229 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200230
231 size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
232 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
Yann Collet71ddeb62017-04-20 22:54:54 -0700233 size_t const neededSpace = entropySpace + tableSpace + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200234 + (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Collet3ae543c2016-07-11 03:12:17 +0200235
236 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100237}
238
Yann Colleta7737f62016-09-06 09:44:59 +0200239
240static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2)
241{
242 return (param1.cParams.hashLog == param2.cParams.hashLog)
243 & (param1.cParams.chainLog == param2.cParams.chainLog)
Yann Colletedbcd9f2016-09-06 14:30:57 +0200244 & (param1.cParams.strategy == param2.cParams.strategy)
245 & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3));
Yann Colleta7737f62016-09-06 09:44:59 +0200246}
247
248/*! ZSTD_continueCCtx() :
249 reuse CCtx without reset (note : requires no dictionary) */
250static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
251{
252 U32 const end = (U32)(cctx->nextSrc - cctx->base);
253 cctx->params = params;
254 cctx->frameContentSize = frameContentSize;
Yann Collet20d5e032017-04-11 18:34:02 -0700255 cctx->consumedSrcSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200256 cctx->lowLimit = end;
257 cctx->dictLimit = end;
258 cctx->nextToUpdate = end+1;
259 cctx->stage = ZSTDcs_init;
260 cctx->dictID = 0;
261 cctx->loadedDictEnd = 0;
262 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200263 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
264 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200265 return 0;
266}
267
268typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e;
269
Yann Collet30fb4992017-04-18 14:08:50 -0700270/*! ZSTD_resetCCtx_internal() :
Sean Purcell3437bf22017-03-01 16:10:26 -0800271 note : `params` must be validated */
Yann Collet30fb4992017-04-18 14:08:50 -0700272static size_t ZSTD_resetCCtx_internal (ZSTD_CCtx* zc,
Yann Colletea2ecdc2016-07-14 22:43:12 +0200273 ZSTD_parameters params, U64 frameContentSize,
Yann Collet4cb21292016-09-15 14:54:07 +0200274 ZSTD_compResetPolicy_e const crp)
Yann Colleta7737f62016-09-06 09:44:59 +0200275{
Yann Collet4cb21292016-09-15 14:54:07 +0200276 if (crp == ZSTDcrp_continue)
Nick Terrella4197772017-03-01 17:51:56 -0800277 if (ZSTD_equivalentParams(params, zc->params)) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700278 zc->fseCTables_ready = 0;
279 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200280 return ZSTD_continueCCtx(zc, params, frameContentSize);
Nick Terrella4197772017-03-01 17:51:56 -0800281 }
inikep87d4f3d2016-03-02 15:56:24 +0100282
Yann Colleta7737f62016-09-06 09:44:59 +0200283 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
284 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
285 size_t const maxNbSeq = blockSize / divider;
286 size_t const tokenSpace = blockSize + 11*maxNbSeq;
287 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
288 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
289 U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
290 size_t const h3Size = ((size_t)1) << hashLog3;
291 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
292 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100293
Yann Colleta7737f62016-09-06 09:44:59 +0200294 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Collet71ddeb62017-04-20 22:54:54 -0700295 { size_t const entropySpace = hufCTable_size + litlengthCTable_size
Yann Colleta4086452017-04-20 23:09:39 -0700296 + offcodeCTable_size + matchlengthCTable_size
Yann Collet72712032017-04-20 23:21:19 -0700297 + entropyScratchSpace_size;
Yann Collet71ddeb62017-04-20 22:54:54 -0700298 size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
Yann Collete6fa70a2017-04-20 17:28:31 -0700299 + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
Yann Collet71ddeb62017-04-20 22:54:54 -0700300 size_t const optSpace = ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) ? optPotentialSpace : 0;
301 size_t const neededSpace = entropySpace + optSpace + tableSpace + tokenSpace;
Yann Colleta7737f62016-09-06 09:44:59 +0200302 if (zc->workSpaceSize < neededSpace) {
Yann Collet0181fef2017-04-06 01:25:26 -0700303 zc->workSpaceSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200304 ZSTD_free(zc->workSpace, zc->customMem);
305 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
306 if (zc->workSpace == NULL) return ERROR(memory_allocation);
307 zc->workSpaceSize = neededSpace;
Yann Collet7bb60b12017-04-20 17:38:56 -0700308 ptr = zc->workSpace;
309
310 /* entropy space */
Yann Collet71ddeb62017-04-20 22:54:54 -0700311 zc->hufCTable = (HUF_CElt*)ptr;
312 ptr = (char*)zc->hufCTable + hufCTable_size; /* note : HUF_CElt* is incomplete type, size is estimated via macro */
Yann Collet71aaa322017-04-20 23:03:38 -0700313 zc->offcodeCTable = (FSE_CTable*) ptr;
314 ptr = (char*)ptr + offcodeCTable_size;
Yann Collet72712032017-04-20 23:21:19 -0700315 zc->matchlengthCTable = (FSE_CTable*) ptr;
Yann Collet71aaa322017-04-20 23:03:38 -0700316 ptr = (char*)ptr + matchlengthCTable_size;
Yann Collet72712032017-04-20 23:21:19 -0700317 zc->litlengthCTable = (FSE_CTable*) ptr;
318 ptr = (char*)ptr + litlengthCTable_size;
319 assert(((size_t)ptr & 3) == 0); /* ensure correct alignment */
Yann Collete42afbc2017-04-26 11:39:35 -0700320 zc->entropyScratchSpace = (unsigned*) ptr;
Yann Colleta7737f62016-09-06 09:44:59 +0200321 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100322
Yann Collete6fa70a2017-04-20 17:28:31 -0700323 /* init params */
324 zc->params = params;
325 zc->blockSize = blockSize;
326 zc->frameContentSize = frameContentSize;
327 zc->consumedSrcSize = 0;
328
Yann Colleta7737f62016-09-06 09:44:59 +0200329 XXH64_reset(&zc->xxhState, 0);
Yann Collete6fa70a2017-04-20 17:28:31 -0700330 zc->stage = ZSTDcs_init;
331 zc->dictID = 0;
332 zc->loadedDictEnd = 0;
Yann Collet71ddeb62017-04-20 22:54:54 -0700333 zc->fseCTables_ready = 0;
334 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200335 zc->nextToUpdate = 1;
336 zc->nextSrc = NULL;
337 zc->base = NULL;
338 zc->dictBase = NULL;
339 zc->dictLimit = 0;
340 zc->lowLimit = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200341 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
Yann Collete6fa70a2017-04-20 17:28:31 -0700342 zc->hashLog3 = hashLog3;
343 zc->seqStore.litLengthSum = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200344
Yann Collet71aaa322017-04-20 23:03:38 -0700345 /* ensure entropy tables are close together at the beginning */
346 assert((void*)zc->hufCTable == zc->workSpace);
347 assert((char*)zc->offcodeCTable == (char*)zc->hufCTable + hufCTable_size);
348 assert((char*)zc->matchlengthCTable == (char*)zc->offcodeCTable + offcodeCTable_size);
349 assert((char*)zc->litlengthCTable == (char*)zc->matchlengthCTable + matchlengthCTable_size);
Yann Collete42afbc2017-04-26 11:39:35 -0700350 assert((char*)zc->entropyScratchSpace == (char*)zc->litlengthCTable + litlengthCTable_size);
351 ptr = (char*)zc->entropyScratchSpace + entropyScratchSpace_size;
Yann Collete6fa70a2017-04-20 17:28:31 -0700352
353 /* opt parser space */
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200354 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) {
Yann Collete6fa70a2017-04-20 17:28:31 -0700355 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
Yann Colleta7737f62016-09-06 09:44:59 +0200356 zc->seqStore.litFreq = (U32*)ptr;
357 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
358 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
359 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
360 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
361 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
362 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
363 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
364 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
Yann Colleta7737f62016-09-06 09:44:59 +0200365 }
Yann Collete6fa70a2017-04-20 17:28:31 -0700366
367 /* table Space */
368 if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
369 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
370 zc->hashTable = (U32*)(ptr);
371 zc->chainTable = zc->hashTable + hSize;
372 zc->hashTable3 = zc->chainTable + chainSize;
373 ptr = zc->hashTable3 + h3Size;
374
375 /* sequences storage */
Yann Colleta7737f62016-09-06 09:44:59 +0200376 zc->seqStore.sequencesStart = (seqDef*)ptr;
377 ptr = zc->seqStore.sequencesStart + maxNbSeq;
378 zc->seqStore.llCode = (BYTE*) ptr;
379 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
380 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
381 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
382
Yann Colleta7737f62016-09-06 09:44:59 +0200383 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100384 }
Yann Colletf3eca252015-10-22 15:31:46 +0100385}
386
Yann Collet32dfae62017-01-19 10:32:55 -0800387/* ZSTD_invalidateRepCodes() :
388 * ensures next compression will not use repcodes from previous block.
389 * Note : only works with regular variant;
390 * do not use with extDict variant ! */
391void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
392 int i;
393 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0;
394}
Yann Collet083fcc82015-10-25 14:06:35 +0100395
Yann Colleta4cab802017-04-18 14:54:54 -0700396
397/*! ZSTD_copyCCtx_internal() :
398 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
399 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
400 * pledgedSrcSize=0 means "empty" if fParams.contentSizeFlag=1
401 * @return : 0, or an error code */
402size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx,
403 ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize)
Yann Collet7b51a292016-01-26 15:58:49 +0100404{
Yann Collet731ef162016-07-27 21:05:12 +0200405 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100406
inikep28669512016-06-02 13:04:18 +0200407 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Sean Purcell2db72492017-02-09 10:50:43 -0800408 { ZSTD_parameters params = srcCCtx->params;
Yann Colleta4cab802017-04-18 14:54:54 -0700409 params.fParams = fParams;
Yann Collet30fb4992017-04-18 14:08:50 -0700410 ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset);
Sean Purcell2db72492017-02-09 10:50:43 -0800411 }
Yann Collet7b51a292016-01-26 15:58:49 +0100412
413 /* copy tables */
Yann Collet731ef162016-07-27 21:05:12 +0200414 { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
Yann Collete6fa70a2017-04-20 17:28:31 -0700415 size_t const hSize = (size_t)1 << srcCCtx->params.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +0200416 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
417 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collete6fa70a2017-04-20 17:28:31 -0700418 assert((U32*)dstCCtx->chainTable == (U32*)dstCCtx->hashTable + hSize); /* chainTable must follow hashTable */
419 assert((U32*)dstCCtx->hashTable3 == (U32*)dstCCtx->chainTable + chainSize);
420 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); /* presumes all tables follow each other */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100421 }
Yann Collet7b51a292016-01-26 15:58:49 +0100422
Yann Colletc46fb922016-05-29 05:01:04 +0200423 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100424 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
425 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
426 dstCCtx->nextSrc = srcCCtx->nextSrc;
427 dstCCtx->base = srcCCtx->base;
428 dstCCtx->dictBase = srcCCtx->dictBase;
429 dstCCtx->dictLimit = srcCCtx->dictLimit;
430 dstCCtx->lowLimit = srcCCtx->lowLimit;
431 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200432 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100433
Yann Colletfb810d62016-01-28 00:18:06 +0100434 /* copy entropy tables */
Yann Collet71ddeb62017-04-20 22:54:54 -0700435 dstCCtx->fseCTables_ready = srcCCtx->fseCTables_ready;
436 if (srcCCtx->fseCTables_ready) {
Yann Colleta34a39c2017-04-20 18:17:58 -0700437 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, litlengthCTable_size);
438 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, matchlengthCTable_size);
439 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, offcodeCTable_size);
Yann Colletfb810d62016-01-28 00:18:06 +0100440 }
Yann Collet71ddeb62017-04-20 22:54:54 -0700441 dstCCtx->hufCTable_repeatMode = srcCCtx->hufCTable_repeatMode;
442 if (srcCCtx->hufCTable_repeatMode) {
443 memcpy(dstCCtx->hufCTable, srcCCtx->hufCTable, hufCTable_size);
Nick Terrella4197772017-03-01 17:51:56 -0800444 }
Yann Collet7b51a292016-01-26 15:58:49 +0100445
446 return 0;
447}
448
Yann Colleta4cab802017-04-18 14:54:54 -0700449/*! ZSTD_copyCCtx() :
450 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
451 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
452 * pledgedSrcSize==0 means "unknown".
453* @return : 0, or an error code */
454size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
455{
456 ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
457 fParams.contentSizeFlag = pledgedSrcSize>0;
458
459 return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, fParams, pledgedSrcSize);
460}
461
Yann Collet7b51a292016-01-26 15:58:49 +0100462
Yann Colletecabfe32016-03-20 16:20:06 +0100463/*! ZSTD_reduceTable() :
Yann Colleta4cab802017-04-18 14:54:54 -0700464 * reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100465static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100466{
Yann Colletecabfe32016-03-20 16:20:06 +0100467 U32 u;
468 for (u=0 ; u < size ; u++) {
469 if (table[u] < reducerValue) table[u] = 0;
470 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100471 }
472}
473
Yann Colletecabfe32016-03-20 16:20:06 +0100474/*! ZSTD_reduceIndex() :
475* rescale all indexes to avoid future overflow (indexes are U32) */
476static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
477{
Yann Collet731ef162016-07-27 21:05:12 +0200478 { U32 const hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100479 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
480
Yann Collet731ef162016-07-27 21:05:12 +0200481 { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200482 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100483
Yann Collet731ef162016-07-27 21:05:12 +0200484 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100485 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
486}
487
Yann Collet89db5e02015-11-13 11:27:46 +0100488
Yann Collet863ec402016-01-28 17:56:33 +0100489/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100490* Block entropic compression
491*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100492
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200493/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100494
Yann Colletd1b26842016-03-15 01:24:33 +0100495size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100496{
Yann Colletd1b26842016-03-15 01:24:33 +0100497 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200498 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
499 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100500 return ZSTD_blockHeaderSize+srcSize;
501}
502
503
Yann Colletd1b26842016-03-15 01:24:33 +0100504static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100505{
506 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200507 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100508
Yann Colletd1b26842016-03-15 01:24:33 +0100509 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100510
Yann Collet59d1f792016-01-23 19:28:41 +0100511 switch(flSize)
512 {
513 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200514 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100515 break;
516 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200517 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100518 break;
519 default: /*note : should not be necessary : flSize is within {1,2,3} */
520 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200521 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100522 break;
523 }
524
525 memcpy(ostart + flSize, src, srcSize);
526 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100527}
528
Yann Colletd1b26842016-03-15 01:24:33 +0100529static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100530{
531 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200532 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100533
Yann Collet198e6aa2016-07-20 20:12:24 +0200534 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100535
536 switch(flSize)
537 {
538 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200539 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100540 break;
541 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200542 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100543 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100544 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100545 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200546 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100547 break;
548 }
549
550 ostart[flSize] = *(const BYTE*)src;
551 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100552}
553
Yann Collet59d1f792016-01-23 19:28:41 +0100554
Yann Colleta5c2c082016-03-20 01:09:18 +0100555static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100556
Yann Colletb923f652016-01-26 03:14:20 +0100557static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100558 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100559 const void* src, size_t srcSize)
560{
Yann Colleta910dc82016-03-18 12:37:45 +0100561 size_t const minGain = ZSTD_minGain(srcSize);
562 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200563 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100564 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200565 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100566 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100567
Yann Collet14983e72015-11-11 21:38:21 +0100568
Yann Colleta5c2c082016-03-20 01:09:18 +0100569 /* small ? don't even attempt compression (speed opt) */
570# define LITERAL_NOENTROPY 63
Yann Collet71ddeb62017-04-20 22:54:54 -0700571 { size_t const minLitSize = zc->hufCTable_repeatMode == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
Yann Colleta5c2c082016-03-20 01:09:18 +0100572 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
573 }
574
575 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Collet71ddeb62017-04-20 22:54:54 -0700576 { HUF_repeat repeat = zc->hufCTable_repeatMode;
Nick Terrell54c4bab2017-03-03 12:30:24 -0800577 int const preferRepeat = zc->params.cParams.strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
Nick Terrella4197772017-03-01 17:51:56 -0800578 if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
Yann Collete348dad2017-04-20 11:14:13 -0700579 cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Yann Collete42afbc2017-04-26 11:39:35 -0700580 zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat)
Yann Collete348dad2017-04-20 11:14:13 -0700581 : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Yann Collete42afbc2017-04-26 11:39:35 -0700582 zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat);
Nick Terrella4197772017-03-01 17:51:56 -0800583 if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
Yann Collet71ddeb62017-04-20 22:54:54 -0700584 else { zc->hufCTable_repeatMode = HUF_repeat_check; } /* now have a table to reuse */
Yann Colletb923f652016-01-26 03:14:20 +0100585 }
Yann Collet14983e72015-11-11 21:38:21 +0100586
Nick Terrella4197772017-03-01 17:51:56 -0800587 if ((cLitSize==0) | (cLitSize >= srcSize - minGain)) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700588 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100589 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800590 }
591 if (cLitSize==1) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700592 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100593 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800594 }
Yann Collet14983e72015-11-11 21:38:21 +0100595
596 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100597 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100598 {
Yann Collet59d1f792016-01-23 19:28:41 +0100599 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200600 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200601 MEM_writeLE24(ostart, lhc);
602 break;
603 }
Yann Collet59d1f792016-01-23 19:28:41 +0100604 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200605 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200606 MEM_writeLE32(ostart, lhc);
607 break;
608 }
Yann Colleta910dc82016-03-18 12:37:45 +0100609 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100610 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200611 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200612 MEM_writeLE32(ostart, lhc);
613 ostart[4] = (BYTE)(cLitSize >> 10);
614 break;
615 }
Yann Collet14983e72015-11-11 21:38:21 +0100616 }
Yann Colleta910dc82016-03-18 12:37:45 +0100617 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100618}
619
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200620static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
621 8, 9, 10, 11, 12, 13, 14, 15,
622 16, 16, 17, 17, 18, 18, 19, 19,
623 20, 20, 20, 20, 21, 21, 21, 21,
624 22, 22, 22, 22, 22, 22, 22, 22,
625 23, 23, 23, 23, 23, 23, 23, 23,
626 24, 24, 24, 24, 24, 24, 24, 24,
627 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100628
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200629static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
630 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
631 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
632 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
633 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
634 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
635 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
636 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200637
638
639void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100640{
Yann Colleted57d852016-07-29 21:22:17 +0200641 BYTE const LL_deltaCode = 19;
642 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200643 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200644 BYTE* const llCodeTable = seqStorePtr->llCode;
645 BYTE* const ofCodeTable = seqStorePtr->ofCode;
646 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200647 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200648 U32 u;
649 for (u=0; u<nbSeq; u++) {
650 U32 const llv = sequences[u].litLength;
651 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200652 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200653 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200654 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200655 }
Yann Colleted57d852016-07-29 21:22:17 +0200656 if (seqStorePtr->longLengthID==1)
657 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
658 if (seqStorePtr->longLengthID==2)
659 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100660}
661
Sean Purcell553f67e2017-03-02 15:15:31 -0800662MEM_STATIC size_t ZSTD_compressSequences (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100663 void* dst, size_t dstCapacity,
Sean Purcell553f67e2017-03-02 15:15:31 -0800664 size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100665{
Sean Purcell553f67e2017-03-02 15:15:31 -0800666 const int longOffsets = zc->params.cParams.windowLog > STREAM_ACCUMULATOR_MIN;
Yann Colletb923f652016-01-26 03:14:20 +0100667 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100668 U32 count[MaxSeq+1];
669 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100670 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
671 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
672 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100673 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200674 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200675 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
676 const BYTE* const llCodeTable = seqStorePtr->llCode;
677 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +0100678 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100679 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100680 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200681 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +0100682 BYTE* seqHead;
Yann Colletd79a9a02016-11-30 15:52:20 -0800683 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Collet14983e72015-11-11 21:38:21 +0100684
Yann Collet14983e72015-11-11 21:38:21 +0100685 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100686 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100687 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100688 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100689 if (ZSTD_isError(cSize)) return cSize;
690 op += cSize;
691 }
692
693 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100694 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100695 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
696 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
697 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100698 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100699
Yann Colletbe391432016-03-22 23:19:28 +0100700 /* seqHead : flags for FSE encoding type */
701 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100702
Yann Colletfb810d62016-01-28 00:18:06 +0100703#define MIN_SEQ_FOR_DYNAMIC_FSE 64
704#define MAX_SEQ_FOR_STATIC_FSE 1000
705
Yann Colletb44be742016-03-26 20:52:14 +0100706 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +0200707 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +0100708
Yann Collet14983e72015-11-11 21:38:21 +0100709 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100710 { U32 max = MaxLL;
Yann Collete42afbc2017-04-26 11:39:35 -0700711 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +0100712 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
713 *op++ = llCodeTable[0];
714 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200715 LLtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -0700716 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200717 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100718 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800719 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200720 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100721 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100722 size_t nbSeq_1 = nbSeq;
723 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
724 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
725 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100726 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -0700727 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +0100728 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800729 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200730 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100731 } }
Yann Collet14983e72015-11-11 21:38:21 +0100732
Yann Colletb44be742016-03-26 20:52:14 +0100733 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100734 { U32 max = MaxOff;
Yann Collete42afbc2017-04-26 11:39:35 -0700735 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +0100736 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100737 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100738 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200739 Offtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -0700740 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200741 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +0200742 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800743 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200744 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100745 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100746 size_t nbSeq_1 = nbSeq;
747 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100748 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100749 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100750 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -0700751 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +0100752 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800753 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200754 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100755 } }
756
Yann Collet14983e72015-11-11 21:38:21 +0100757 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100758 { U32 max = MaxML;
Yann Collete42afbc2017-04-26 11:39:35 -0700759 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +0100760 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100761 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100762 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200763 MLtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -0700764 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200765 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100766 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800767 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200768 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100769 } else {
770 size_t nbSeq_1 = nbSeq;
771 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
772 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
773 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
774 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -0700775 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletfadda6c2016-03-22 12:14:26 +0100776 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800777 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200778 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100779 } }
Yann Collet14983e72015-11-11 21:38:21 +0100780
Yann Colletbe391432016-03-22 23:19:28 +0100781 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Collet71ddeb62017-04-20 22:54:54 -0700782 zc->fseCTables_ready = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100783
784 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100785 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100786 FSE_CState_t stateMatchLength;
787 FSE_CState_t stateOffsetBits;
788 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100789
Yann Collet95d07d72016-09-06 16:38:51 +0200790 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100791
Yann Collet597847a2016-03-20 19:14:22 +0100792 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100793 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100794 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100795 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +0200796 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100797 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200798 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100799 if (MEM_32bits()) BIT_flushBits(&blockStream);
Sean Purcelld44703d2017-03-01 14:36:25 -0800800 if (longOffsets) {
801 U32 const ofBits = ofCodeTable[nbSeq-1];
802 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
803 if (extraBits) {
804 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
805 BIT_flushBits(&blockStream);
806 }
807 BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
808 ofBits - extraBits);
809 } else {
810 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
811 }
Yann Collet597847a2016-03-20 19:14:22 +0100812 BIT_flushBits(&blockStream);
813
Yann Colletfadda6c2016-03-22 12:14:26 +0100814 { size_t n;
815 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +0200816 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200817 BYTE const ofCode = ofCodeTable[n];
818 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200819 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +0200820 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200821 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +0100822 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100823 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
824 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
825 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
826 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200827 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100828 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +0200829 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100830 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200831 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100832 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Sean Purcelld44703d2017-03-01 14:36:25 -0800833 if (longOffsets) {
834 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
835 if (extraBits) {
836 BIT_addBits(&blockStream, sequences[n].offset, extraBits);
837 BIT_flushBits(&blockStream); /* (7)*/
838 }
839 BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
840 ofBits - extraBits); /* 31 */
841 } else {
842 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
843 }
Yann Colletb9151402016-03-26 17:18:11 +0100844 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100845 } }
Yann Collet14983e72015-11-11 21:38:21 +0100846
847 FSE_flushCState(&blockStream, &stateMatchLength);
848 FSE_flushCState(&blockStream, &stateOffsetBits);
849 FSE_flushCState(&blockStream, &stateLitLength);
850
Yann Colletb9151402016-03-26 17:18:11 +0100851 { size_t const streamSize = BIT_closeCStream(&blockStream);
852 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
853 op += streamSize;
854 } }
Yann Collet14983e72015-11-11 21:38:21 +0100855
856 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100857_check_compressibility:
Nick Terrella4197772017-03-01 17:51:56 -0800858 { size_t const minGain = ZSTD_minGain(srcSize);
859 size_t const maxCSize = srcSize - minGain;
860 if ((size_t)(op-ostart) >= maxCSize) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700861 zc->hufCTable_repeatMode = HUF_repeat_none;
Nick Terrella4197772017-03-01 17:51:56 -0800862 return 0;
863 } }
Yann Collet14983e72015-11-11 21:38:21 +0100864
Yann Collet4266c0a2016-06-14 01:49:25 +0200865 /* confirm repcodes */
Yann Colletb459aad2017-01-19 17:33:37 -0800866 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; }
Yann Collet4266c0a2016-06-14 01:49:25 +0200867
Yann Collet5054ee02015-11-23 13:34:21 +0100868 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100869}
870
Yann Colletbb002742017-01-25 16:25:38 -0800871#if 0 /* for debug */
872# define STORESEQ_DEBUG
873#include <stdio.h> /* fprintf */
874U32 g_startDebug = 0;
875const BYTE* g_start = NULL;
876#endif
877
Yann Collet95cd0c22016-03-08 18:24:21 +0100878/*! ZSTD_storeSeq() :
879 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
880 `offsetCode` : distance to match, or 0 == repCode.
881 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100882*/
Yann Colletd57dffb2016-07-03 01:48:26 +0200883MEM_STATIC void ZSTD_storeSeq(seqStore_t* seqStorePtr, size_t litLength, const void* literals, U32 offsetCode, size_t matchCode)
Yann Collet14983e72015-11-11 21:38:21 +0100884{
Yann Colletbb002742017-01-25 16:25:38 -0800885#ifdef STORESEQ_DEBUG
886 if (g_startDebug) {
887 const U32 pos = (U32)((const BYTE*)literals - g_start);
888 if (g_start==NULL) g_start = (const BYTE*)literals;
889 if ((pos > 1895000) && (pos < 1895300))
890 fprintf(stderr, "Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
891 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
892 }
Yann Collet14983e72015-11-11 21:38:21 +0100893#endif
Yann Collet14983e72015-11-11 21:38:21 +0100894 /* copy Literals */
895 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
896 seqStorePtr->lit += litLength;
897
898 /* literal Length */
Yann Collete6fa70a2017-04-20 17:28:31 -0700899 if (litLength>0xFFFF) {
900 seqStorePtr->longLengthID = 1;
901 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
902 }
Yann Colletc0ce4f12016-07-30 00:55:13 +0200903 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100904
905 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200906 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100907
908 /* match Length */
Yann Collete6fa70a2017-04-20 17:28:31 -0700909 if (matchCode>0xFFFF) {
910 seqStorePtr->longLengthID = 2;
911 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
912 }
Yann Colletc0ce4f12016-07-30 00:55:13 +0200913 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +0200914
Yann Colletc0ce4f12016-07-30 00:55:13 +0200915 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +0100916}
917
918
Yann Collet7d360282016-02-12 00:07:30 +0100919/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100920* Match length counter
921***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100922static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100923{
Yann Collet863ec402016-01-28 17:56:33 +0100924 if (MEM_isLittleEndian()) {
925 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100926# if defined(_MSC_VER) && defined(_WIN64)
927 unsigned long r = 0;
928 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100929 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100930# elif defined(__GNUC__) && (__GNUC__ >= 3)
931 return (__builtin_ctzll((U64)val) >> 3);
932# else
Yann Collete348dad2017-04-20 11:14:13 -0700933 static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
934 0, 3, 1, 3, 1, 4, 2, 7,
935 0, 2, 3, 6, 1, 5, 3, 5,
936 1, 3, 4, 4, 2, 5, 6, 7,
937 7, 0, 1, 2, 3, 3, 4, 6,
938 2, 6, 5, 5, 3, 4, 5, 6,
939 7, 1, 2, 4, 6, 4, 4, 5,
940 7, 2, 6, 5, 7, 6, 7, 7 };
Yann Collet14983e72015-11-11 21:38:21 +0100941 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
942# endif
Yann Collet863ec402016-01-28 17:56:33 +0100943 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100944# if defined(_MSC_VER)
945 unsigned long r=0;
946 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100947 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100948# elif defined(__GNUC__) && (__GNUC__ >= 3)
949 return (__builtin_ctz((U32)val) >> 3);
950# else
Yann Collete348dad2017-04-20 11:14:13 -0700951 static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
952 3, 2, 2, 1, 3, 2, 0, 1,
953 3, 3, 1, 2, 2, 2, 2, 0,
954 3, 1, 2, 0, 1, 0, 1, 1 };
Yann Collet14983e72015-11-11 21:38:21 +0100955 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
956# endif
957 }
Yann Collet863ec402016-01-28 17:56:33 +0100958 } else { /* Big Endian CPU */
959 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100960# if defined(_MSC_VER) && defined(_WIN64)
961 unsigned long r = 0;
962 _BitScanReverse64( &r, val );
963 return (unsigned)(r>>3);
964# elif defined(__GNUC__) && (__GNUC__ >= 3)
965 return (__builtin_clzll(val) >> 3);
966# else
967 unsigned r;
968 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
969 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
970 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
971 r += (!val);
972 return r;
973# endif
Yann Collet863ec402016-01-28 17:56:33 +0100974 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100975# if defined(_MSC_VER)
976 unsigned long r = 0;
977 _BitScanReverse( &r, (unsigned long)val );
978 return (unsigned)(r>>3);
979# elif defined(__GNUC__) && (__GNUC__ >= 3)
980 return (__builtin_clz((U32)val) >> 3);
981# else
982 unsigned r;
983 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
984 r += (!val);
985 return r;
986# endif
Yann Collet863ec402016-01-28 17:56:33 +0100987 } }
Yann Collet14983e72015-11-11 21:38:21 +0100988}
989
990
Yann Colleta436a522016-06-20 23:34:04 +0200991static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100992{
993 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +0200994 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +0100995
Yann Colleta436a522016-06-20 23:34:04 +0200996 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +0200997 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100998 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
999 pIn += ZSTD_NbCommonBytes(diff);
1000 return (size_t)(pIn - pStart);
1001 }
Yann Collet14983e72015-11-11 21:38:21 +01001002 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
1003 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
1004 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
1005 return (size_t)(pIn - pStart);
1006}
1007
Yann Collet04b12d82016-02-11 06:23:24 +01001008/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +01001009* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +01001010* convention : on reaching mEnd, match count continue starting from iStart
1011*/
1012static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
1013{
Yann Collet7591a7f2016-05-20 11:44:43 +02001014 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +02001015 size_t const matchLength = ZSTD_count(ip, match, vEnd);
1016 if (match + matchLength != mEnd) return matchLength;
1017 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +01001018}
1019
Yann Collet14983e72015-11-11 21:38:21 +01001020
Yann Collet863ec402016-01-28 17:56:33 +01001021/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001022* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +01001023***************************************/
inikepcc52a972016-02-19 10:09:35 +01001024static const U32 prime3bytes = 506832829U;
1025static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Collete6fa70a2017-04-20 17:28:31 -07001026MEM_STATIC size_t ZSTD_hash3Ptr(const void* ptr, U32 h) { return ZSTD_hash3(MEM_readLE32(ptr), h); } /* only in zstd_opt.h */
inikepcc52a972016-02-19 10:09:35 +01001027
Yann Collet4b100f42015-10-30 15:49:48 +01001028static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +01001029static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +01001030static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +01001031
Yann Collet4b100f42015-10-30 15:49:48 +01001032static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001033static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001034static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001035
1036static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001037static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001038static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001039
Yann Collet14983e72015-11-11 21:38:21 +01001040static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001041static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001042static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001043
Yann Collet45dc3562016-07-12 09:47:31 +02001044static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
1045static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
1046static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
1047
Yann Collet5be2dd22015-11-11 13:43:58 +01001048static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001049{
1050 switch(mls)
1051 {
Yann Collet2e2e78d2017-03-29 16:02:47 -07001052 //case 3: return ZSTD_hash3Ptr(p, hBits);
1053 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001054 case 4: return ZSTD_hash4Ptr(p, hBits);
1055 case 5: return ZSTD_hash5Ptr(p, hBits);
1056 case 6: return ZSTD_hash6Ptr(p, hBits);
1057 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +02001058 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001059 }
1060}
Yann Collet2acb5d32015-10-29 16:49:43 +01001061
Yann Collet863ec402016-01-28 17:56:33 +01001062
Yann Collet2ce49232016-02-02 14:36:49 +01001063/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001064* Fast Scan
1065***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001066static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1067{
1068 U32* const hashTable = zc->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001069 U32 const hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001070 const BYTE* const base = zc->base;
1071 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001072 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001073 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001074
Yann Colletfb810d62016-01-28 00:18:06 +01001075 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001076 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001077 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001078 }
1079}
1080
1081
Yann Collet1f44b3f2015-11-05 17:32:18 +01001082FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +02001083void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +02001084 const void* src, size_t srcSize,
1085 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001086{
Yann Collet4266c0a2016-06-14 01:49:25 +02001087 U32* const hashTable = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001088 U32 const hBits = cctx->params.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +02001089 seqStore_t* seqStorePtr = &(cctx->seqStore);
1090 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001091 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001092 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001093 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +02001094 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +02001095 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001096 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001097 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +02001098 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1099 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001100
Yann Collet1f44b3f2015-11-05 17:32:18 +01001101 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001102 ip += (ip==lowest);
1103 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +02001104 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1105 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +02001106 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001107
1108 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +02001109 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +02001110 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +02001111 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
1112 U32 const current = (U32)(ip-base);
1113 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +01001114 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001115 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001116
Yann Collet280f9a82016-08-08 00:44:00 +02001117 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +02001118 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +01001119 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001120 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1121 } else {
Yann Collet92d75662016-07-03 01:10:53 +02001122 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001123 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001124 ip += ((ip-anchor) >> g_searchStrength) + 1;
1125 continue;
1126 }
Yann Collet45dc3562016-07-12 09:47:31 +02001127 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001128 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001129 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001130 offset_2 = offset_1;
1131 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001132
Yann Colleta436a522016-06-20 23:34:04 +02001133 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001134 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001135
Yann Collet402fdcf2015-11-20 12:46:08 +01001136 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001137 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001138 anchor = ip;
1139
Yann Colletfb810d62016-01-28 00:18:06 +01001140 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001141 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001142 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 +01001143 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1144 /* check immediate repcode */
1145 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001146 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001147 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001148 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001149 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001150 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001151 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001152 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1153 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001154 anchor = ip;
1155 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001156 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001157
Yann Collet4266c0a2016-06-14 01:49:25 +02001158 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001159 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1160 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001161
Yann Collet70e45772016-03-19 18:08:32 +01001162 /* Last Literals */
1163 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001164 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1165 seqStorePtr->lit += lastLLSize;
1166 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001167}
1168
1169
Yann Collet82260dd2016-02-11 07:14:25 +01001170static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001171 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001172{
Yann Collet3b719252016-03-30 19:48:05 +02001173 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001174 switch(mls)
1175 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001176 default: /* includes case 3 */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001177 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001178 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001179 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001180 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001181 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001182 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001183 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001184 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001185 }
1186}
Yann Colletf3eca252015-10-22 15:31:46 +01001187
Yann Colletf3eca252015-10-22 15:31:46 +01001188
Yann Collet82260dd2016-02-11 07:14:25 +01001189static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001190 const void* src, size_t srcSize,
1191 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001192{
1193 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001194 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001195 seqStore_t* seqStorePtr = &(ctx->seqStore);
1196 const BYTE* const base = ctx->base;
1197 const BYTE* const dictBase = ctx->dictBase;
1198 const BYTE* const istart = (const BYTE*)src;
1199 const BYTE* ip = istart;
1200 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001201 const U32 lowestIndex = ctx->lowLimit;
1202 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001203 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001204 const BYTE* const lowPrefixPtr = base + dictLimit;
1205 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001206 const BYTE* const iend = istart + srcSize;
1207 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001208 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001209
Yann Colleta436a522016-06-20 23:34:04 +02001210 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001211 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001212 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001213 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001214 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001215 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001216 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001217 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001218 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001219 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001220 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001221 hashTable[h] = current; /* update hash table */
1222
Yann Colleta436a522016-06-20 23:34:04 +02001223 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001224 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001225 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001226 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
Yann Collet743402c2015-11-20 12:03:53 +01001227 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001228 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001229 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001230 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001231 (MEM_read32(match) != MEM_read32(ip)) ) {
1232 ip += ((ip-anchor) >> g_searchStrength) + 1;
1233 continue;
1234 }
1235 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001236 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001237 U32 offset;
Yann Collete6fa70a2017-04-20 17:28:31 -07001238 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
Yann Colleta436a522016-06-20 23:34:04 +02001239 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001240 offset = current - matchIndex;
1241 offset_2 = offset_1;
1242 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001243 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001244 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001245
Yann Collet5054ee02015-11-23 13:34:21 +01001246 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001247 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001248 anchor = ip;
1249
Yann Colletfb810d62016-01-28 00:18:06 +01001250 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001251 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001252 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001253 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1254 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001255 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001256 U32 const current2 = (U32)(ip-base);
1257 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001258 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001259 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1260 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001261 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001262 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet5054ee02015-11-23 13:34:21 +01001263 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001264 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001265 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001266 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001267 anchor = ip;
1268 continue;
1269 }
Yann Collet743402c2015-11-20 12:03:53 +01001270 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001271 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001272
Yann Collet4266c0a2016-06-14 01:49:25 +02001273 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001274 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001275
Yann Collet89db5e02015-11-13 11:27:46 +01001276 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001277 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001278 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1279 seqStorePtr->lit += lastLLSize;
1280 }
Yann Collet89db5e02015-11-13 11:27:46 +01001281}
1282
1283
Yann Collet82260dd2016-02-11 07:14:25 +01001284static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001285 const void* src, size_t srcSize)
1286{
Yann Collet731ef162016-07-27 21:05:12 +02001287 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001288 switch(mls)
1289 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001290 default: /* includes case 3 */
Yann Collet89db5e02015-11-13 11:27:46 +01001291 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001292 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001293 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001294 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001295 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001296 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001297 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001298 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001299 }
1300}
1301
1302
Yann Collet04b12d82016-02-11 06:23:24 +01001303/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001304* Double Fast
1305***************************************/
1306static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1307{
1308 U32* const hashLarge = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001309 U32 const hBitsL = cctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001310 U32* const hashSmall = cctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001311 U32 const hBitsS = cctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001312 const BYTE* const base = cctx->base;
1313 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001314 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001315 const size_t fastHashFillStep = 3;
1316
1317 while(ip <= iend) {
1318 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1319 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1320 ip += fastHashFillStep;
1321 }
1322}
1323
1324
1325FORCE_INLINE
1326void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1327 const void* src, size_t srcSize,
1328 const U32 mls)
1329{
1330 U32* const hashLong = cctx->hashTable;
1331 const U32 hBitsL = cctx->params.cParams.hashLog;
1332 U32* const hashSmall = cctx->chainTable;
1333 const U32 hBitsS = cctx->params.cParams.chainLog;
1334 seqStore_t* seqStorePtr = &(cctx->seqStore);
1335 const BYTE* const base = cctx->base;
1336 const BYTE* const istart = (const BYTE*)src;
1337 const BYTE* ip = istart;
1338 const BYTE* anchor = istart;
1339 const U32 lowestIndex = cctx->dictLimit;
1340 const BYTE* const lowest = base + lowestIndex;
1341 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001342 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001343 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1344 U32 offsetSaved = 0;
1345
1346 /* init */
1347 ip += (ip==lowest);
1348 { U32 const maxRep = (U32)(ip-lowest);
1349 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1350 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1351 }
1352
1353 /* Main Search Loop */
1354 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1355 size_t mLength;
1356 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1357 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1358 U32 const current = (U32)(ip-base);
1359 U32 const matchIndexL = hashLong[h2];
1360 U32 const matchIndexS = hashSmall[h];
1361 const BYTE* matchLong = base + matchIndexL;
1362 const BYTE* match = base + matchIndexS;
1363 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1364
Yann Colletc17e0202017-04-20 12:50:02 -07001365 assert(offset_1 <= current); /* supposed guaranteed by construction */
1366 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001367 /* favor repcode */
Yann Collet45dc3562016-07-12 09:47:31 +02001368 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1369 ip++;
1370 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1371 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001372 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001373 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1374 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001375 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001376 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1377 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001378 size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1379 U32 const matchIndexL3 = hashLong[hl3];
1380 const BYTE* matchL3 = base + matchIndexL3;
1381 hashLong[hl3] = current + 1;
1382 if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
1383 mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
Yann Colletc54692f2016-08-24 01:10:42 +02001384 ip++;
Yann Collete6fa70a2017-04-20 17:28:31 -07001385 offset = (U32)(ip-matchL3);
1386 while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
Yann Colletc54692f2016-08-24 01:10:42 +02001387 } else {
1388 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1389 offset = (U32)(ip-match);
1390 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1391 }
Yann Collet45dc3562016-07-12 09:47:31 +02001392 } else {
1393 ip += ((ip-anchor) >> g_searchStrength) + 1;
1394 continue;
1395 }
1396
1397 offset_2 = offset_1;
1398 offset_1 = offset;
1399
1400 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1401 }
1402
1403 /* match found */
1404 ip += mLength;
1405 anchor = ip;
1406
1407 if (ip <= ilimit) {
1408 /* Fill Table */
1409 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1410 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1411 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1412 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1413
1414 /* check immediate repcode */
1415 while ( (ip <= ilimit)
1416 && ( (offset_2>0)
1417 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1418 /* store sequence */
1419 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001420 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001421 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1422 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1423 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1424 ip += rLength;
1425 anchor = ip;
1426 continue; /* faster when present ... (?) */
1427 } } }
1428
1429 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001430 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1431 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet45dc3562016-07-12 09:47:31 +02001432
1433 /* Last Literals */
1434 { size_t const lastLLSize = iend - anchor;
1435 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1436 seqStorePtr->lit += lastLLSize;
1437 }
1438}
1439
1440
1441static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1442{
1443 const U32 mls = ctx->params.cParams.searchLength;
1444 switch(mls)
1445 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001446 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001447 case 4 :
1448 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1449 case 5 :
1450 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1451 case 6 :
1452 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1453 case 7 :
1454 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1455 }
1456}
1457
1458
1459static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1460 const void* src, size_t srcSize,
1461 const U32 mls)
1462{
1463 U32* const hashLong = ctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001464 U32 const hBitsL = ctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001465 U32* const hashSmall = ctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001466 U32 const hBitsS = ctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001467 seqStore_t* seqStorePtr = &(ctx->seqStore);
1468 const BYTE* const base = ctx->base;
1469 const BYTE* const dictBase = ctx->dictBase;
1470 const BYTE* const istart = (const BYTE*)src;
1471 const BYTE* ip = istart;
1472 const BYTE* anchor = istart;
1473 const U32 lowestIndex = ctx->lowLimit;
1474 const BYTE* const dictStart = dictBase + lowestIndex;
1475 const U32 dictLimit = ctx->dictLimit;
1476 const BYTE* const lowPrefixPtr = base + dictLimit;
1477 const BYTE* const dictEnd = dictBase + dictLimit;
1478 const BYTE* const iend = istart + srcSize;
1479 const BYTE* const ilimit = iend - 8;
1480 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1481
1482 /* Search Loop */
1483 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1484 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1485 const U32 matchIndex = hashSmall[hSmall];
1486 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1487 const BYTE* match = matchBase + matchIndex;
1488
1489 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1490 const U32 matchLongIndex = hashLong[hLong];
1491 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1492 const BYTE* matchLong = matchLongBase + matchLongIndex;
1493
1494 const U32 current = (U32)(ip-base);
1495 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1496 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1497 const BYTE* repMatch = repBase + repIndex;
1498 size_t mLength;
1499 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1500
1501 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1502 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1503 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1504 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1505 ip++;
1506 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1507 } else {
1508 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1509 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1510 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1511 U32 offset;
1512 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1513 offset = current - matchLongIndex;
1514 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1515 offset_2 = offset_1;
1516 offset_1 = offset;
1517 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001518
Yann Collet73d74a02016-07-12 13:03:48 +02001519 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001520 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1521 U32 const matchIndex3 = hashLong[h3];
1522 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1523 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001524 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001525 hashLong[h3] = current + 1;
1526 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1527 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1528 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1529 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1530 ip++;
1531 offset = current+1 - matchIndex3;
1532 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1533 } else {
1534 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1535 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1536 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1537 offset = current - matchIndex;
1538 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1539 }
Yann Collet45dc3562016-07-12 09:47:31 +02001540 offset_2 = offset_1;
1541 offset_1 = offset;
1542 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001543
Yann Collet45dc3562016-07-12 09:47:31 +02001544 } else {
1545 ip += ((ip-anchor) >> g_searchStrength) + 1;
1546 continue;
1547 } }
1548
1549 /* found a match : store it */
1550 ip += mLength;
1551 anchor = ip;
1552
1553 if (ip <= ilimit) {
1554 /* Fill Table */
Nick Terrell5152fb22017-03-29 18:51:58 -07001555 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1556 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
Yann Collet45dc3562016-07-12 09:47:31 +02001557 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1558 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1559 /* check immediate repcode */
1560 while (ip <= ilimit) {
1561 U32 const current2 = (U32)(ip-base);
1562 U32 const repIndex2 = current2 - offset_2;
1563 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1564 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1565 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1566 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07001567 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet45dc3562016-07-12 09:47:31 +02001568 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1569 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1570 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1571 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1572 ip += repLength2;
1573 anchor = ip;
1574 continue;
1575 }
1576 break;
1577 } } }
1578
1579 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001580 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet45dc3562016-07-12 09:47:31 +02001581
1582 /* Last Literals */
1583 { size_t const lastLLSize = iend - anchor;
1584 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1585 seqStorePtr->lit += lastLLSize;
1586 }
1587}
1588
1589
1590static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1591 const void* src, size_t srcSize)
1592{
Yann Collet731ef162016-07-27 21:05:12 +02001593 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001594 switch(mls)
1595 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001596 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001597 case 4 :
1598 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1599 case 5 :
1600 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1601 case 6 :
1602 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1603 case 7 :
1604 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1605 }
1606}
1607
1608
1609/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001610* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001611***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001612/** ZSTD_insertBt1() : add one or multiple positions to tree.
1613* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001614* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001615static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1616 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001617{
Yann Collet731ef162016-07-27 21:05:12 +02001618 U32* const hashTable = zc->hashTable;
1619 U32 const hashLog = zc->params.cParams.hashLog;
1620 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1621 U32* const bt = zc->chainTable;
1622 U32 const btLog = zc->params.cParams.chainLog - 1;
1623 U32 const btMask = (1 << btLog) - 1;
1624 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001625 size_t commonLengthSmaller=0, commonLengthLarger=0;
1626 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001627 const BYTE* const dictBase = zc->dictBase;
1628 const U32 dictLimit = zc->dictLimit;
1629 const BYTE* const dictEnd = dictBase + dictLimit;
1630 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07001631 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001632 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001633 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001634 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001635 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001636 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001637 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001638 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001639 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001640#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001641 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1642 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1643 predictedSmall += (predictedSmall>0);
1644 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001645#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001646
Yann Collet6c3e2e72015-12-11 10:44:07 +01001647 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001648
Yann Colletfb810d62016-01-28 00:18:06 +01001649 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001650 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001651 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08001652
Yann Colletc0932082016-06-30 14:07:30 +02001653#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001654 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001655 if (matchIndex == predictedSmall) {
1656 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001657 *smallerPtr = matchIndex;
1658 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1659 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1660 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001661 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001662 continue;
1663 }
Yann Colletfb810d62016-01-28 00:18:06 +01001664 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001665 *largerPtr = matchIndex;
1666 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1667 largerPtr = nextPtr;
1668 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001669 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001670 continue;
1671 }
Yann Collet04b12d82016-02-11 06:23:24 +01001672#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001673 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001674 match = base + matchIndex;
1675 if (match[matchLength] == ip[matchLength])
1676 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001677 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001678 match = dictBase + matchIndex;
1679 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1680 if (matchIndex+matchLength >= dictLimit)
Nick Terrell5152fb22017-03-29 18:51:58 -07001681 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet1358f912016-01-01 07:29:39 +01001682 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001683
Yann Colletb8a6f682016-02-15 17:06:29 +01001684 if (matchLength > bestLength) {
1685 bestLength = matchLength;
1686 if (matchLength > matchEndIdx - matchIndex)
1687 matchEndIdx = matchIndex + (U32)matchLength;
1688 }
Yann Colletee3f4512015-12-29 22:26:09 +01001689
Yann Collet59d70632015-11-04 12:05:27 +01001690 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001691 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001692
Yann Colletfb810d62016-01-28 00:18:06 +01001693 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001694 /* match is smaller than current */
1695 *smallerPtr = matchIndex; /* update smaller idx */
1696 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001697 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001698 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001699 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001700 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001701 /* match is larger than current */
1702 *largerPtr = matchIndex;
1703 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001704 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001705 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001706 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001707 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001708
Yann Collet59d70632015-11-04 12:05:27 +01001709 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02001710 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01001711 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1712 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001713}
1714
1715
Yann Collet82260dd2016-02-11 07:14:25 +01001716static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001717 ZSTD_CCtx* zc,
1718 const BYTE* const ip, const BYTE* const iend,
1719 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001720 U32 nbCompares, const U32 mls,
1721 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001722{
Yann Collet731ef162016-07-27 21:05:12 +02001723 U32* const hashTable = zc->hashTable;
1724 U32 const hashLog = zc->params.cParams.hashLog;
1725 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1726 U32* const bt = zc->chainTable;
1727 U32 const btLog = zc->params.cParams.chainLog - 1;
1728 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001729 U32 matchIndex = hashTable[h];
1730 size_t commonLengthSmaller=0, commonLengthLarger=0;
1731 const BYTE* const base = zc->base;
1732 const BYTE* const dictBase = zc->dictBase;
1733 const U32 dictLimit = zc->dictLimit;
1734 const BYTE* const dictEnd = dictBase + dictLimit;
1735 const BYTE* const prefixStart = base + dictLimit;
1736 const U32 current = (U32)(ip-base);
1737 const U32 btLow = btMask >= current ? 0 : current - btMask;
1738 const U32 windowLow = zc->lowLimit;
1739 U32* smallerPtr = bt + 2*(current&btMask);
1740 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001741 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001742 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001743 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001744
Yann Collet6c3e2e72015-12-11 10:44:07 +01001745 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001746
Yann Colletfb810d62016-01-28 00:18:06 +01001747 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001748 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01001749 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1750 const BYTE* match;
1751
Yann Colletfb810d62016-01-28 00:18:06 +01001752 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001753 match = base + matchIndex;
1754 if (match[matchLength] == ip[matchLength])
1755 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001756 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001757 match = dictBase + matchIndex;
1758 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001759 if (matchIndex+matchLength >= dictLimit)
Nick Terrell5152fb22017-03-29 18:51:58 -07001760 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001761 }
1762
Yann Colletfb810d62016-01-28 00:18:06 +01001763 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001764 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001765 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02001766 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001767 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001768 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1769 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1770 }
1771
Yann Colletfb810d62016-01-28 00:18:06 +01001772 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001773 /* match is smaller than current */
1774 *smallerPtr = matchIndex; /* update smaller idx */
1775 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1776 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1777 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1778 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001779 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001780 /* match is larger than current */
1781 *largerPtr = matchIndex;
1782 commonLengthLarger = matchLength;
1783 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1784 largerPtr = nextPtr;
1785 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001786 } }
Yann Collet03526e12015-11-23 15:29:15 +01001787
1788 *smallerPtr = *largerPtr = 0;
1789
Yann Collet72e84cf2015-12-31 19:08:44 +01001790 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001791 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001792}
1793
Yann Collet2cc12cb2016-01-01 07:47:58 +01001794
Yann Colletb8a6f682016-02-15 17:06:29 +01001795static 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 +01001796{
1797 const BYTE* const base = zc->base;
1798 const U32 target = (U32)(ip - base);
1799 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001800
1801 while(idx < target)
1802 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001803}
1804
Yann Collet52447382016-03-20 16:00:00 +01001805/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001806static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001807 ZSTD_CCtx* zc,
1808 const BYTE* const ip, const BYTE* const iLimit,
1809 size_t* offsetPtr,
1810 const U32 maxNbAttempts, const U32 mls)
1811{
1812 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001813 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001814 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1815}
1816
1817
Yann Collet768c6bc2016-02-10 14:01:49 +01001818static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001819 ZSTD_CCtx* zc, /* Index table will be updated */
1820 const BYTE* ip, const BYTE* const iLimit,
1821 size_t* offsetPtr,
1822 const U32 maxNbAttempts, const U32 matchLengthSearch)
1823{
1824 switch(matchLengthSearch)
1825 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001826 default : /* includes case 3 */
Yann Collet2cc12cb2016-01-01 07:47:58 +01001827 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1828 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07001829 case 7 :
Yann Collet2cc12cb2016-01-01 07:47:58 +01001830 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1831 }
1832}
1833
1834
Yann Colletb8a6f682016-02-15 17:06:29 +01001835static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1836{
1837 const BYTE* const base = zc->base;
1838 const U32 target = (U32)(ip - base);
1839 U32 idx = zc->nextToUpdate;
1840
1841 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1842}
1843
inikep64d7bcb2016-04-07 19:14:09 +02001844
Yann Collet03526e12015-11-23 15:29:15 +01001845/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001846static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001847 ZSTD_CCtx* zc,
1848 const BYTE* const ip, const BYTE* const iLimit,
1849 size_t* offsetPtr,
1850 const U32 maxNbAttempts, const U32 mls)
1851{
Yann Colletee3f4512015-12-29 22:26:09 +01001852 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001853 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001854 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001855}
1856
1857
Yann Collet82260dd2016-02-11 07:14:25 +01001858static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001859 ZSTD_CCtx* zc, /* Index table will be updated */
1860 const BYTE* ip, const BYTE* const iLimit,
1861 size_t* offsetPtr,
1862 const U32 maxNbAttempts, const U32 matchLengthSearch)
1863{
1864 switch(matchLengthSearch)
1865 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001866 default : /* includes case 3 */
Yann Collet03526e12015-11-23 15:29:15 +01001867 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1868 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07001869 case 7 :
Yann Collet03526e12015-11-23 15:29:15 +01001870 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1871 }
1872}
1873
1874
Yann Collet5106a762015-11-05 15:00:24 +01001875
Yann Collet731ef162016-07-27 21:05:12 +02001876/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02001877* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02001878***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02001879#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1880
1881/* Update chains up to ip (excluded)
Anders Oleson517577b2017-02-20 12:08:59 -08001882 Assumption : always within prefix (i.e. not within extDict) */
inikep64d7bcb2016-04-07 19:14:09 +02001883FORCE_INLINE
1884U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1885{
1886 U32* const hashTable = zc->hashTable;
1887 const U32 hashLog = zc->params.cParams.hashLog;
1888 U32* const chainTable = zc->chainTable;
1889 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1890 const BYTE* const base = zc->base;
1891 const U32 target = (U32)(ip - base);
1892 U32 idx = zc->nextToUpdate;
1893
Yann Collet22d76322016-06-21 08:01:51 +02001894 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001895 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1896 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1897 hashTable[h] = idx;
1898 idx++;
1899 }
1900
1901 zc->nextToUpdate = target;
1902 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1903}
1904
1905
1906
1907FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1908size_t ZSTD_HcFindBestMatch_generic (
1909 ZSTD_CCtx* zc, /* Index table will be updated */
1910 const BYTE* const ip, const BYTE* const iLimit,
1911 size_t* offsetPtr,
1912 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1913{
1914 U32* const chainTable = zc->chainTable;
1915 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1916 const U32 chainMask = chainSize-1;
1917 const BYTE* const base = zc->base;
1918 const BYTE* const dictBase = zc->dictBase;
1919 const U32 dictLimit = zc->dictLimit;
1920 const BYTE* const prefixStart = base + dictLimit;
1921 const BYTE* const dictEnd = dictBase + dictLimit;
1922 const U32 lowLimit = zc->lowLimit;
1923 const U32 current = (U32)(ip-base);
1924 const U32 minChain = current > chainSize ? current - chainSize : 0;
1925 int nbAttempts=maxNbAttempts;
Yann Collete42afbc2017-04-26 11:39:35 -07001926 size_t ml=4-1;
inikep64d7bcb2016-04-07 19:14:09 +02001927
1928 /* HC4 match finder */
1929 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1930
Yann Collet22d76322016-06-21 08:01:51 +02001931 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02001932 const BYTE* match;
1933 size_t currentMl=0;
1934 if ((!extDict) || matchIndex >= dictLimit) {
1935 match = base + matchIndex;
1936 if (match[ml] == ip[ml]) /* potentially better */
1937 currentMl = ZSTD_count(ip, match, iLimit);
1938 } else {
1939 match = dictBase + matchIndex;
1940 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
Yann Collete42afbc2017-04-26 11:39:35 -07001941 currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02001942 }
1943
1944 /* save best solution */
Yann Colletc17e0202017-04-20 12:50:02 -07001945 if (currentMl > ml) {
1946 ml = currentMl;
1947 *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
1948 if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
1949 }
inikep64d7bcb2016-04-07 19:14:09 +02001950
1951 if (matchIndex <= minChain) break;
1952 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1953 }
1954
1955 return ml;
1956}
1957
1958
1959FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1960 ZSTD_CCtx* zc,
1961 const BYTE* ip, const BYTE* const iLimit,
1962 size_t* offsetPtr,
1963 const U32 maxNbAttempts, const U32 matchLengthSearch)
1964{
1965 switch(matchLengthSearch)
1966 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001967 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02001968 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1969 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
Yann Collet933ce4a2017-03-29 14:32:15 -07001970 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02001971 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1972 }
1973}
1974
1975
1976FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1977 ZSTD_CCtx* zc,
1978 const BYTE* ip, const BYTE* const iLimit,
1979 size_t* offsetPtr,
1980 const U32 maxNbAttempts, const U32 matchLengthSearch)
1981{
1982 switch(matchLengthSearch)
1983 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001984 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02001985 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1986 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
Yann Collet933ce4a2017-03-29 14:32:15 -07001987 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02001988 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1989 }
1990}
1991
inikep64d7bcb2016-04-07 19:14:09 +02001992
Yann Collet287b7d92015-11-22 13:24:05 +01001993/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001994* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001995*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001996FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001997void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1998 const void* src, size_t srcSize,
1999 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01002000{
inikepfaa8d8a2016-04-05 19:01:10 +02002001 seqStore_t* seqStorePtr = &(ctx->seqStore);
2002 const BYTE* const istart = (const BYTE*)src;
2003 const BYTE* ip = istart;
2004 const BYTE* anchor = istart;
2005 const BYTE* const iend = istart + srcSize;
2006 const BYTE* const ilimit = iend - 8;
2007 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002008
Yann Collet793c6492016-04-09 20:32:00 +02002009 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
2010 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002011
inikep64d7bcb2016-04-07 19:14:09 +02002012 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2013 size_t* offsetPtr,
2014 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02002015 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02002016 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02002017
inikepfaa8d8a2016-04-05 19:01:10 +02002018 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02002019 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02002020 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02002021 { U32 const maxRep = (U32)(ip-base);
2022 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
2023 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
2024 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002025
inikepfaa8d8a2016-04-05 19:01:10 +02002026 /* Match Loop */
2027 while (ip < ilimit) {
2028 size_t matchLength=0;
2029 size_t offset=0;
2030 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01002031
inikepfaa8d8a2016-04-05 19:01:10 +02002032 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02002033 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02002034 /* repcode : we take it */
Yann Collete42afbc2017-04-26 11:39:35 -07002035 matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002036 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01002037 }
Yann Collet5be2dd22015-11-11 13:43:58 +01002038
inikepfaa8d8a2016-04-05 19:01:10 +02002039 /* first search (depth 0) */
2040 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002041 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002042 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002043 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002044 }
Yann Collet5106a762015-11-05 15:00:24 +01002045
Yann Collete42afbc2017-04-26 11:39:35 -07002046 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002047 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2048 continue;
2049 }
2050
inikep64d7bcb2016-04-07 19:14:09 +02002051 /* let's try to find a better solution */
2052 if (depth>=1)
2053 while (ip<ilimit) {
2054 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002055 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002056 size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002057 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002058 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002059 if ((mlRep >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002060 matchLength = mlRep, offset = 0, start = ip;
2061 }
2062 { size_t offset2=99999999;
2063 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002064 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2065 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002066 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002067 matchLength = ml2, offset = offset2, start = ip;
2068 continue; /* search a better one */
2069 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002070
inikep64d7bcb2016-04-07 19:14:09 +02002071 /* let's find an even better one */
2072 if ((depth==2) && (ip<ilimit)) {
2073 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002074 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002075 size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002076 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002077 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002078 if ((ml2 >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002079 matchLength = ml2, offset = 0, start = ip;
2080 }
2081 { size_t offset2=99999999;
2082 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002083 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2084 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002085 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002086 matchLength = ml2, offset = offset2, start = ip;
2087 continue;
2088 } } }
2089 break; /* nothing found : store previous solution */
2090 }
2091
2092 /* catch up */
2093 if (offset) {
Yann Colletc17e0202017-04-20 12:50:02 -07002094 while ( (start > anchor)
2095 && (start > base+offset-ZSTD_REP_MOVE)
2096 && (start[-1] == start[-1-offset+ZSTD_REP_MOVE]) ) /* only search for offset within prefix */
inikep64d7bcb2016-04-07 19:14:09 +02002097 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02002098 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02002099 }
2100
inikepfaa8d8a2016-04-05 19:01:10 +02002101 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002102_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002103 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002104 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002105 anchor = ip = start + matchLength;
2106 }
Yann Collet48537162016-04-07 15:24:29 +02002107
inikepfaa8d8a2016-04-05 19:01:10 +02002108 /* check immediate repcode */
2109 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02002110 && ((offset_2>0)
2111 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02002112 /* store sequence */
Yann Collete42afbc2017-04-26 11:39:35 -07002113 matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet9634f672016-07-03 01:23:58 +02002114 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02002115 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2116 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002117 anchor = ip;
2118 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02002119 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002120
Yann Collet4266c0a2016-06-14 01:49:25 +02002121 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002122 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
2123 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02002124
inikepfaa8d8a2016-04-05 19:01:10 +02002125 /* Last Literals */
2126 { size_t const lastLLSize = iend - anchor;
2127 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2128 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002129 }
Yann Collet5106a762015-11-05 15:00:24 +01002130}
2131
Yann Collet5be2dd22015-11-11 13:43:58 +01002132
inikep64d7bcb2016-04-07 19:14:09 +02002133static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2134{
2135 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2136}
2137
2138static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2139{
2140 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2141}
2142
2143static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2144{
2145 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2146}
2147
2148static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2149{
2150 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2151}
2152
2153
inikepfaa8d8a2016-04-05 19:01:10 +02002154FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002155void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2156 const void* src, size_t srcSize,
2157 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002158{
inikepfaa8d8a2016-04-05 19:01:10 +02002159 seqStore_t* seqStorePtr = &(ctx->seqStore);
2160 const BYTE* const istart = (const BYTE*)src;
2161 const BYTE* ip = istart;
2162 const BYTE* anchor = istart;
2163 const BYTE* const iend = istart + srcSize;
2164 const BYTE* const ilimit = iend - 8;
2165 const BYTE* const base = ctx->base;
2166 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002167 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002168 const BYTE* const prefixStart = base + dictLimit;
2169 const BYTE* const dictBase = ctx->dictBase;
2170 const BYTE* const dictEnd = dictBase + dictLimit;
2171 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2172
2173 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2174 const U32 mls = ctx->params.cParams.searchLength;
2175
inikep64d7bcb2016-04-07 19:14:09 +02002176 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2177 size_t* offsetPtr,
2178 U32 maxNbAttempts, U32 matchLengthSearch);
2179 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2180
Yann Collet302ff032016-07-03 01:28:16 +02002181 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002182
Yann Collet302ff032016-07-03 01:28:16 +02002183 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002184 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002185 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002186
2187 /* Match Loop */
2188 while (ip < ilimit) {
2189 size_t matchLength=0;
2190 size_t offset=0;
2191 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002192 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002193
2194 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002195 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002196 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2197 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002198 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002199 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002200 /* repcode detected we should take it */
2201 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002202 matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002203 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002204 } }
2205
2206 /* first search (depth 0) */
2207 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002208 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002209 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002210 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002211 }
2212
Yann Collete42afbc2017-04-26 11:39:35 -07002213 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002214 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2215 continue;
2216 }
2217
inikep64d7bcb2016-04-07 19:14:09 +02002218 /* let's try to find a better solution */
2219 if (depth>=1)
2220 while (ip<ilimit) {
2221 ip ++;
2222 current++;
2223 /* check repCode */
2224 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002225 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002226 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2227 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002228 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002229 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2230 /* repcode detected */
2231 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002232 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002233 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002234 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002235 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002236 matchLength = repLength, offset = 0, start = ip;
2237 } }
2238
2239 /* search match, depth 1 */
2240 { size_t offset2=99999999;
2241 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002242 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2243 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002244 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002245 matchLength = ml2, offset = offset2, start = ip;
2246 continue; /* search a better one */
2247 } }
2248
2249 /* let's find an even better one */
2250 if ((depth==2) && (ip<ilimit)) {
2251 ip ++;
2252 current++;
2253 /* check repCode */
2254 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002255 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002256 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2257 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002258 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002259 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2260 /* repcode detected */
2261 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002262 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Colletc17e0202017-04-20 12:50:02 -07002263 int const gain2 = (int)(repLength * 4);
2264 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002265 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002266 matchLength = repLength, offset = 0, start = ip;
2267 } }
2268
2269 /* search match, depth 2 */
2270 { size_t offset2=99999999;
2271 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002272 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2273 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002274 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002275 matchLength = ml2, offset = offset2, start = ip;
2276 continue;
2277 } } }
2278 break; /* nothing found : store previous solution */
2279 }
2280
inikepfaa8d8a2016-04-05 19:01:10 +02002281 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002282 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002283 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002284 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2285 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002286 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002287 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002288 }
inikepfaa8d8a2016-04-05 19:01:10 +02002289
inikepfaa8d8a2016-04-05 19:01:10 +02002290 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002291_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002292 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002293 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002294 anchor = ip = start + matchLength;
2295 }
2296
2297 /* check immediate repcode */
2298 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002299 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002300 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2301 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002302 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002303 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2304 /* repcode detected we should take it */
2305 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002306 matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Collet302ff032016-07-03 01:28:16 +02002307 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002308 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2309 ip += matchLength;
2310 anchor = ip;
2311 continue; /* faster when present ... (?) */
2312 }
2313 break;
2314 } }
2315
Yann Collet4266c0a2016-06-14 01:49:25 +02002316 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002317 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002318
inikepfaa8d8a2016-04-05 19:01:10 +02002319 /* Last Literals */
2320 { size_t const lastLLSize = iend - anchor;
2321 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2322 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002323 }
2324}
2325
2326
Yann Collet59d1f792016-01-23 19:28:41 +01002327void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002328{
inikep64d7bcb2016-04-07 19:14:09 +02002329 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002330}
2331
Yann Collet59d1f792016-01-23 19:28:41 +01002332static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002333{
Yann Colleta1249dc2016-01-25 04:22:03 +01002334 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002335}
Yann Collet9a24e592015-11-22 02:53:43 +01002336
Yann Collet59d1f792016-01-23 19:28:41 +01002337static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002338{
Yann Colleta1249dc2016-01-25 04:22:03 +01002339 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002340}
2341
Yann Collet59d1f792016-01-23 19:28:41 +01002342static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002343{
Yann Colleta1249dc2016-01-25 04:22:03 +01002344 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002345}
2346
inikepef519412016-04-21 11:08:43 +02002347
inikepef519412016-04-21 11:08:43 +02002348/* The optimal parser */
2349#include "zstd_opt.h"
2350
2351static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2352{
Yann Colletd4f4e582016-06-27 01:31:35 +02002353#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002354 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2355#else
2356 (void)ctx; (void)src; (void)srcSize;
2357 return;
2358#endif
2359}
2360
2361static void ZSTD_compressBlock_btopt2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2362{
2363#ifdef ZSTD_OPT_H_91842398743
2364 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002365#else
2366 (void)ctx; (void)src; (void)srcSize;
2367 return;
2368#endif
inikepef519412016-04-21 11:08:43 +02002369}
2370
inikepd3b8d7a2016-02-22 10:06:17 +01002371static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002372{
Yann Colletd4f4e582016-06-27 01:31:35 +02002373#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002374 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2375#else
2376 (void)ctx; (void)src; (void)srcSize;
2377 return;
2378#endif
2379}
2380
2381static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2382{
2383#ifdef ZSTD_OPT_H_91842398743
2384 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002385#else
2386 (void)ctx; (void)src; (void)srcSize;
2387 return;
2388#endif
inikepe2bfe242016-01-31 11:25:48 +01002389}
2390
Yann Collet7a231792015-11-21 15:27:35 +01002391
Yann Collet59d1f792016-01-23 19:28:41 +01002392typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002393
Yann Colletb923f652016-01-26 03:14:20 +01002394static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002395{
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002396 static const ZSTD_blockCompressor blockCompressor[2][8] = {
Yann Colletc17e0202017-04-20 12:50:02 -07002397 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy,
2398 ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2,
2399 ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2 },
2400 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict,
2401 ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict,
2402 ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btopt2_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01002403 };
2404
2405 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002406}
2407
2408
Yann Colletd1b26842016-03-15 01:24:33 +01002409static 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 +01002410{
Yann Collet19cab462016-06-17 12:54:52 +02002411 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002412 const BYTE* const base = zc->base;
2413 const BYTE* const istart = (const BYTE*)src;
2414 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002415 if (srcSize < MIN_CBLOCK_SIZE+ZSTD_blockHeaderSize+1) return 0; /* don't even attempt compression below a certain srcSize */
Yann Collet19cab462016-06-17 12:54:52 +02002416 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002417 if (current > zc->nextToUpdate + 384)
Yann Colletc17e0202017-04-20 12:50:02 -07002418 zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384)); /* limited update after finding a very long match */
Yann Collet59d1f792016-01-23 19:28:41 +01002419 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002420 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002421}
2422
2423
Yann Colletc991cc12016-07-28 00:55:43 +02002424/*! ZSTD_compress_generic() :
2425* Compress a chunk of data into one or multiple blocks.
2426* All blocks will be terminated, all input will be consumed.
2427* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2428* Frame is supposed already started (header already produced)
2429* @return : compressed size, or an error code
2430*/
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002431static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2432 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002433 const void* src, size_t srcSize,
2434 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002435{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002436 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002437 size_t remaining = srcSize;
2438 const BYTE* ip = (const BYTE*)src;
2439 BYTE* const ostart = (BYTE*)dst;
2440 BYTE* op = ostart;
Yann Colletd4180ca2016-07-27 21:21:36 +02002441 U32 const maxDist = 1 << cctx->params.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002442
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002443 if (cctx->params.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002444 XXH64_update(&cctx->xxhState, src, srcSize);
2445
Yann Collet2ce49232016-02-02 14:36:49 +01002446 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002447 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002448 size_t cSize;
2449
Yann Colletc17e0202017-04-20 12:50:02 -07002450 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
2451 return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01002452 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002453
Yann Collet346efcc2016-08-02 14:26:00 +02002454 /* preemptive overflow correction */
Sean Purcell881abe42017-03-07 16:52:23 -08002455 if (cctx->lowLimit > (3U<<29)) {
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002456 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002457 U32 const current = (U32)(ip - cctx->base);
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002458 U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002459 U32 const correction = current - newCurrent;
2460 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002461 ZSTD_reduceIndex(cctx, correction);
2462 cctx->base += correction;
2463 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002464 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002465 cctx->dictLimit -= correction;
2466 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2467 else cctx->nextToUpdate -= correction;
2468 }
2469
Yann Collet06e76972017-01-25 16:39:03 -08002470 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002471 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002472 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2473 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2474 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002475 }
Yann Collet89db5e02015-11-13 11:27:46 +01002476
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002477 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002478 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002479
Yann Collet2ce49232016-02-02 14:36:49 +01002480 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002481 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2482 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2483 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2484 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2485 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002486 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002487 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002488 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002489 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002490 }
2491
2492 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002493 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002494 ip += blockSize;
2495 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002496 }
2497
Yann Collet62470b42016-07-28 15:29:08 +02002498 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002499 return op-ostart;
2500}
2501
2502
Yann Collet6236eba2016-04-12 15:52:33 +02002503static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002504 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002505{ BYTE* const op = (BYTE*)dst;
Yann Collet731ef162016-07-27 21:05:12 +02002506 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2507 U32 const checksumFlag = params.fParams.checksumFlag>0;
2508 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002509 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002510 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2511 U32 const fcsCode = params.fParams.contentSizeFlag ?
Yann Collet673f0d72016-06-06 00:26:38 +02002512 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
2513 0;
Yann Collet731ef162016-07-27 21:05:12 +02002514 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002515 size_t pos;
2516
2517 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet6236eba2016-04-12 15:52:33 +02002518
2519 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002520 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002521 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002522 switch(dictIDSizeCode)
2523 {
2524 default: /* impossible */
2525 case 0 : break;
2526 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002527 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002528 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2529 }
Yann Collet673f0d72016-06-06 00:26:38 +02002530 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002531 {
2532 default: /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002533 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002534 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2535 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002536 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002537 }
Yann Colletc46fb922016-05-29 05:01:04 +02002538 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002539}
2540
2541
Yann Collet346efcc2016-08-02 14:26:00 +02002542static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002543 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002544 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002545 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002546{
Yann Collet2acb5d32015-10-29 16:49:43 +01002547 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002548 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002549
Yann Collet346efcc2016-08-02 14:26:00 +02002550 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002551
Yann Collet346efcc2016-08-02 14:26:00 +02002552 if (frame && (cctx->stage==ZSTDcs_init)) {
2553 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002554 if (ZSTD_isError(fhSize)) return fhSize;
2555 dstCapacity -= fhSize;
2556 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002557 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002558 }
Yann Colletf3eca252015-10-22 15:31:46 +01002559
Yann Collet417890c2015-12-04 17:16:37 +01002560 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002561 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002562 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002563 ptrdiff_t const delta = cctx->nextSrc - ip;
2564 cctx->lowLimit = cctx->dictLimit;
2565 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2566 cctx->dictBase = cctx->base;
2567 cctx->base -= delta;
2568 cctx->nextToUpdate = cctx->dictLimit;
2569 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002570 }
2571
Yann Collet346efcc2016-08-02 14:26:00 +02002572 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2573 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2574 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2575 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2576 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002577 }
2578
Yann Collet346efcc2016-08-02 14:26:00 +02002579 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002580
Yann Collet5eb749e2017-01-11 18:21:25 +01002581 if (srcSize) {
2582 size_t const cSize = frame ?
Yann Collet346efcc2016-08-02 14:26:00 +02002583 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2584 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002585 if (ZSTD_isError(cSize)) return cSize;
Yann Collet20d5e032017-04-11 18:34:02 -07002586 cctx->consumedSrcSize += srcSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002587 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01002588 } else
2589 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002590}
2591
Yann Colletbf42c8e2016-01-09 01:08:23 +01002592
Yann Collet5b567392016-07-28 01:17:22 +02002593size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002594 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002595 const void* src, size_t srcSize)
2596{
Yann Collet20d5e032017-04-11 18:34:02 -07002597 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
Yann Collet5b567392016-07-28 01:17:22 +02002598}
2599
2600
Yann Colletcf05b9d2016-07-18 16:52:10 +02002601size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002602{
Yann Colletcf05b9d2016-07-18 16:52:10 +02002603 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
2604}
2605
2606size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2607{
2608 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002609 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07002610 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002611}
2612
Yann Collet16a0b102017-03-24 12:46:46 -07002613/*! ZSTD_loadDictionaryContent() :
2614 * @return : 0, or an error code
2615 */
Yann Colletb923f652016-01-26 03:14:20 +01002616static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002617{
2618 const BYTE* const ip = (const BYTE*) src;
2619 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002620
Yann Collet417890c2015-12-04 17:16:37 +01002621 /* input becomes current prefix */
2622 zc->lowLimit = zc->dictLimit;
2623 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2624 zc->dictBase = zc->base;
2625 zc->base += ip - zc->nextSrc;
2626 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08002627 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002628
2629 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002630 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002631
Yann Collet3b719252016-03-30 19:48:05 +02002632 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002633 {
2634 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002635 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002636 break;
2637
Yann Collet45dc3562016-07-12 09:47:31 +02002638 case ZSTD_dfast:
2639 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2640 break;
2641
Yann Collet417890c2015-12-04 17:16:37 +01002642 case ZSTD_greedy:
2643 case ZSTD_lazy:
2644 case ZSTD_lazy2:
Yann Collet16a0b102017-03-24 12:46:46 -07002645 if (srcSize >= HASH_READ_SIZE)
2646 ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002647 break;
2648
2649 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002650 case ZSTD_btopt:
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002651 case ZSTD_btopt2:
Yann Collet16a0b102017-03-24 12:46:46 -07002652 if (srcSize >= HASH_READ_SIZE)
2653 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002654 break;
2655
2656 default:
2657 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2658 }
2659
Nick Terrellecf90ca2017-02-13 18:27:34 -08002660 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002661 return 0;
2662}
2663
2664
Nick Terrellf9c9af32016-10-19 17:22:08 -07002665/* Dictionaries that assign zero probability to symbols that show up causes problems
2666 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2667 that we may encounter during compression.
2668 NOTE: This behavior is not standard and could be improved in the future. */
2669static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2670 U32 s;
2671 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
2672 for (s = 0; s <= maxSymbolValue; ++s) {
2673 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
2674 }
2675 return 0;
2676}
2677
2678
Yann Colletb923f652016-01-26 03:14:20 +01002679/* Dictionary format :
Yann Colletbea78e82017-03-22 18:09:11 -07002680 * See :
2681 * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
2682 */
Yann Collet16a0b102017-03-24 12:46:46 -07002683/*! ZSTD_loadZstdDictionary() :
2684 * @return : 0, or an error code
2685 * assumptions : magic number supposed already checked
2686 * dictSize supposed > 8
Yann Colletbea78e82017-03-22 18:09:11 -07002687 */
Yann Collet16a0b102017-03-24 12:46:46 -07002688static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002689{
Yann Collet52a06222016-06-15 13:53:34 +02002690 const BYTE* dictPtr = (const BYTE*)dict;
2691 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07002692 short offcodeNCount[MaxOff+1];
2693 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08002694 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01002695
Yann Colletbea78e82017-03-22 18:09:11 -07002696 dictPtr += 4; /* skip magic number */
2697 cctx->dictID = cctx->params.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
2698 dictPtr += 4;
2699
Yann Collet71ddeb62017-04-20 22:54:54 -07002700 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufCTable, 255, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002701 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002702 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002703 }
Yann Colletfb810d62016-01-28 00:18:06 +01002704
Nick Terrellf9c9af32016-10-19 17:22:08 -07002705 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02002706 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002707 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002708 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002709 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Colletc17e0202017-04-20 12:50:02 -07002710 CHECK_E( FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)),
2711 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002712 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002713 }
Yann Colletfb810d62016-01-28 00:18:06 +01002714
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002715 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002716 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002717 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002718 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002719 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002720 /* Every match length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07002721 CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
2722 CHECK_E( FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)),
2723 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002724 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002725 }
Yann Colletfb810d62016-01-28 00:18:06 +01002726
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002727 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002728 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002729 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002730 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002731 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002732 /* Every literal length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07002733 CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
2734 CHECK_E( FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)),
2735 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002736 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002737 }
Yann Colletfb810d62016-01-28 00:18:06 +01002738
Yann Collet52a06222016-06-15 13:53:34 +02002739 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07002740 cctx->rep[0] = MEM_readLE32(dictPtr+0);
2741 cctx->rep[1] = MEM_readLE32(dictPtr+4);
2742 cctx->rep[2] = MEM_readLE32(dictPtr+8);
Yann Collet52a06222016-06-15 13:53:34 +02002743 dictPtr += 12;
2744
Yann Colletbea78e82017-03-22 18:09:11 -07002745 { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
2746 U32 offcodeMax = MaxOff;
2747 if (dictContentSize <= ((U32)-1) - 128 KB) {
2748 U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
2749 offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
Nick Terrellb2c39a22016-10-24 14:11:27 -07002750 }
Yann Colletbea78e82017-03-22 18:09:11 -07002751 /* All offset values <= dictContentSize + 128 KB must be representable */
Nick Terrellf9c9af32016-10-19 17:22:08 -07002752 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
Yann Colletbea78e82017-03-22 18:09:11 -07002753 /* All repCodes must be <= dictContentSize and != 0*/
2754 { U32 u;
2755 for (u=0; u<3; u++) {
2756 if (cctx->rep[u] == 0) return ERROR(dictionary_corrupted);
2757 if (cctx->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07002758 } }
Nick Terrellf9c9af32016-10-19 17:22:08 -07002759
Yann Collet71ddeb62017-04-20 22:54:54 -07002760 cctx->fseCTables_ready = 1;
2761 cctx->hufCTable_repeatMode = HUF_repeat_valid;
Yann Collet16a0b102017-03-24 12:46:46 -07002762 return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
2763 }
Yann Colletb923f652016-01-26 03:14:20 +01002764}
2765
Yann Colletd1b26842016-03-15 01:24:33 +01002766/** ZSTD_compress_insertDictionary() :
2767* @return : 0, or an error code */
Yann Collet16a0b102017-03-24 12:46:46 -07002768static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002769{
Yann Colletc46fb922016-05-29 05:01:04 +02002770 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002771
Yann Collet14312d82017-02-23 23:42:12 -08002772 /* dict as pure content */
Yann Collet16a0b102017-03-24 12:46:46 -07002773 if ((MEM_readLE32(dict) != ZSTD_DICT_MAGIC) || (cctx->forceRawDict))
2774 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002775
Yann Colletbea78e82017-03-22 18:09:11 -07002776 /* dict as zstd dictionary */
Yann Collet16a0b102017-03-24 12:46:46 -07002777 return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002778}
2779
Yann Collet27caf2a2016-04-01 15:48:48 +02002780/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002781* @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02002782static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01002783 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002784 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002785{
Yann Colleta7737f62016-09-06 09:44:59 +02002786 ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
Yann Colletab9162e2017-04-11 10:46:20 -07002787 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet30fb4992017-04-18 14:08:50 -07002788 CHECK_F(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, crp));
Yann Colleta7737f62016-09-06 09:44:59 +02002789 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002790}
2791
2792
Yann Collet27caf2a2016-04-01 15:48:48 +02002793/*! ZSTD_compressBegin_advanced() :
2794* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002795size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002796 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02002797 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02002798{
2799 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02002800 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet81e13ef2016-06-07 00:51:51 +02002801 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002802}
2803
2804
Yann Collet81e13ef2016-06-07 00:51:51 +02002805size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002806{
Yann Collet6c6e1752016-06-27 15:28:45 +02002807 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002808 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002809}
Yann Collet083fcc82015-10-25 14:06:35 +01002810
inikep19bd48f2016-04-04 12:10:00 +02002811
Yann Colletb05c4822017-01-12 02:01:28 +01002812size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002813{
Yann Colletb05c4822017-01-12 02:01:28 +01002814 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002815}
2816
2817
Yann Collet62470b42016-07-28 15:29:08 +02002818/*! ZSTD_writeEpilogue() :
2819* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01002820* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02002821static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002822{
Yann Colletc991cc12016-07-28 00:55:43 +02002823 BYTE* const ostart = (BYTE*)dst;
2824 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02002825 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002826
Yann Collet87c18b22016-08-26 01:43:47 +02002827 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02002828
2829 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02002830 if (cctx->stage == ZSTDcs_init) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002831 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002832 if (ZSTD_isError(fhSize)) return fhSize;
2833 dstCapacity -= fhSize;
2834 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02002835 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002836 }
2837
Yann Colletc991cc12016-07-28 00:55:43 +02002838 if (cctx->stage != ZSTDcs_ending) {
2839 /* write one last empty block, make it the "last" block */
2840 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2841 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2842 MEM_writeLE32(op, cBlockHeader24);
2843 op += ZSTD_blockHeaderSize;
2844 dstCapacity -= ZSTD_blockHeaderSize;
2845 }
2846
2847 if (cctx->params.fParams.checksumFlag) {
2848 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2849 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2850 MEM_writeLE32(op, checksum);
2851 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002852 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002853
Yann Collet731ef162016-07-27 21:05:12 +02002854 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02002855 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01002856}
2857
Yann Colletfd416f12016-01-30 03:14:15 +01002858
Yann Collet62470b42016-07-28 15:29:08 +02002859size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2860 void* dst, size_t dstCapacity,
2861 const void* src, size_t srcSize)
2862{
2863 size_t endResult;
Yann Collet20d5e032017-04-11 18:34:02 -07002864 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 1 /* last chunk */);
Yann Collet62470b42016-07-28 15:29:08 +02002865 if (ZSTD_isError(cSize)) return cSize;
2866 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2867 if (ZSTD_isError(endResult)) return endResult;
Yann Collet20d5e032017-04-11 18:34:02 -07002868 if (cctx->params.fParams.contentSizeFlag) { /* control src size */
2869 if (cctx->frameContentSize != cctx->consumedSrcSize) return ERROR(srcSize_wrong);
2870 }
Yann Collet62470b42016-07-28 15:29:08 +02002871 return cSize + endResult;
2872}
2873
2874
Yann Collet19c10022016-07-28 01:25:46 +02002875static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002876 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002877 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002878 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002879 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002880{
Yann Collet3e21ec52016-09-06 15:36:19 +02002881 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize));
Yann Collet62470b42016-07-28 15:29:08 +02002882 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002883}
2884
Yann Collet21588e32016-03-30 16:50:44 +02002885size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2886 void* dst, size_t dstCapacity,
2887 const void* src, size_t srcSize,
2888 const void* dict,size_t dictSize,
2889 ZSTD_parameters params)
2890{
Yann Colletcf409a72016-09-26 16:41:05 +02002891 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02002892 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2893}
2894
Yann Colletc17e0202017-04-20 12:50:02 -07002895size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
2896 const void* dict, size_t dictSize, int compressionLevel)
Yann Collet31683c02015-12-18 01:26:48 +01002897{
Yann Collet407a11f2016-11-03 15:52:01 -07002898 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02002899 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002900 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002901}
2902
Yann Colletd1b26842016-03-15 01:24:33 +01002903size_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 +01002904{
Yann Collet21588e32016-03-30 16:50:44 +02002905 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002906}
2907
Yann Colletd1b26842016-03-15 01:24:33 +01002908size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002909{
Yann Collet44fe9912015-10-29 22:02:40 +01002910 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002911 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002912 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002913 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002914 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Collet23b6e052016-08-28 21:05:43 -07002915 ZSTD_free(ctxBody.workSpace, defaultCustomMem); /* can't free ctxBody itself, as it's on stack; free only heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002916 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002917}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002918
Yann Colletfd416f12016-01-30 03:14:15 +01002919
Yann Collet81e13ef2016-06-07 00:51:51 +02002920/* ===== Dictionary API ===== */
2921
2922struct ZSTD_CDict_s {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002923 void* dictBuffer;
2924 const void* dictContent;
Yann Collet81e13ef2016-06-07 00:51:51 +02002925 size_t dictContentSize;
2926 ZSTD_CCtx* refContext;
David Lamda9d3b72016-08-29 09:03:12 -07002927}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
Yann Collet81e13ef2016-06-07 00:51:51 +02002928
Yann Colletd7c65892016-09-15 02:50:27 +02002929size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2930{
2931 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Colletaca113f2016-12-23 22:25:03 +01002932 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02002933}
2934
Yann Collet1f57c2e2016-12-21 16:20:11 +01002935ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
2936 ZSTD_parameters params, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02002937{
Yann Collet23b6e052016-08-28 21:05:43 -07002938 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2939 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02002940
Yann Collet23b6e052016-08-28 21:05:43 -07002941 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002942 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2943
Yann Collet1f57c2e2016-12-21 16:20:11 +01002944 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07002945 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01002946 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02002947 return NULL;
2948 }
2949
Yann Collet1f57c2e2016-12-21 16:20:11 +01002950 if ((byReference) || (!dictBuffer) || (!dictSize)) {
2951 cdict->dictBuffer = NULL;
2952 cdict->dictContent = dictBuffer;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002953 } else {
2954 void* const internalBuffer = ZSTD_malloc(dictSize, customMem);
Yann Collet4e5eea62016-12-21 16:44:35 +01002955 if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002956 memcpy(internalBuffer, dictBuffer, dictSize);
2957 cdict->dictBuffer = internalBuffer;
2958 cdict->dictContent = internalBuffer;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002959 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002960
2961 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
Yann Collet81e13ef2016-06-07 00:51:51 +02002962 if (ZSTD_isError(errorCode)) {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002963 ZSTD_free(cdict->dictBuffer, customMem);
Yann Collet1f57c2e2016-12-21 16:20:11 +01002964 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01002965 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02002966 return NULL;
2967 } }
2968
Yann Collet81e13ef2016-06-07 00:51:51 +02002969 cdict->refContext = cctx;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002970 cdict->dictContentSize = dictSize;
Yann Collet81e13ef2016-06-07 00:51:51 +02002971 return cdict;
2972 }
2973}
2974
2975ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2976{
2977 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet07639052016-08-03 01:57:57 +02002978 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002979 params.fParams.contentSizeFlag = 1;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002980 return ZSTD_createCDict_advanced(dict, dictSize, 0, params, allocator);
2981}
2982
2983ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
2984{
2985 ZSTD_customMem const allocator = { NULL, NULL, NULL };
2986 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
2987 params.fParams.contentSizeFlag = 1;
2988 return ZSTD_createCDict_advanced(dict, dictSize, 1, params, allocator);
Yann Collet81e13ef2016-06-07 00:51:51 +02002989}
2990
2991size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2992{
Yann Collet23b6e052016-08-28 21:05:43 -07002993 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02002994 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07002995 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01002996 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002997 ZSTD_free(cdict, cMem);
2998 return 0;
2999 }
Yann Collet81e13ef2016-06-07 00:51:51 +02003000}
3001
Yann Collet95162342016-10-25 16:19:52 -07003002static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
3003 return ZSTD_getParamsFromCCtx(cdict->refContext);
3004}
3005
Yann Collet715b9aa2017-04-18 13:55:53 -07003006/* ZSTD_compressBegin_usingCDict_advanced() :
Yann Collet4f818182017-04-17 17:57:35 -07003007 * cdict must be != NULL */
Yann Collet715b9aa2017-04-18 13:55:53 -07003008size_t ZSTD_compressBegin_usingCDict_advanced(
Yann Collet4f818182017-04-17 17:57:35 -07003009 ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
3010 ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003011{
Yann Collet7cf78f12017-04-04 12:38:14 -07003012 if (cdict==NULL) return ERROR(GENERIC); /* does not support NULL cdict */
Yann Collet4f818182017-04-17 17:57:35 -07003013 if (cdict->dictContentSize)
Yann Colleta4cab802017-04-18 14:54:54 -07003014 CHECK_F( ZSTD_copyCCtx_internal(cctx, cdict->refContext, fParams, pledgedSrcSize) )
Sean Purcell2db72492017-02-09 10:50:43 -08003015 else {
3016 ZSTD_parameters params = cdict->refContext->params;
Yann Collet4f818182017-04-17 17:57:35 -07003017 params.fParams = fParams;
Yann Colletab9162e2017-04-11 10:46:20 -07003018 CHECK_F(ZSTD_compressBegin_internal(cctx, NULL, 0, params, pledgedSrcSize));
Sean Purcell2db72492017-02-09 10:50:43 -08003019 }
Yann Collet4cb21292016-09-15 14:54:07 +02003020 return 0;
3021}
3022
Yann Collet4f818182017-04-17 17:57:35 -07003023/* ZSTD_compressBegin_usingCDict() :
3024 * pledgedSrcSize=0 means "unknown"
3025 * if pledgedSrcSize>0, it will enable contentSizeFlag */
3026size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize)
3027{
3028 ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
3029 fParams.contentSizeFlag = (pledgedSrcSize > 0);
Yann Collet715b9aa2017-04-18 13:55:53 -07003030 return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, pledgedSrcSize);
Yann Collet4f818182017-04-17 17:57:35 -07003031}
3032
Yann Collet07639052016-08-03 01:57:57 +02003033/*! ZSTD_compress_usingCDict() :
Yann Collet4f818182017-04-17 17:57:35 -07003034 * Compression using a digested Dictionary.
3035 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
3036 * Note that compression parameters are decided at CDict creation time
3037 * while frame parameters are hardcoded */
Yann Collet4cb21292016-09-15 14:54:07 +02003038size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
3039 void* dst, size_t dstCapacity,
3040 const void* src, size_t srcSize,
3041 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02003042{
Yann Collet4f818182017-04-17 17:57:35 -07003043 ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Collet715b9aa2017-04-18 13:55:53 -07003044 CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */
Yann Collet07639052016-08-03 01:57:57 +02003045 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02003046}
3047
3048
3049
Yann Collet104e5b02016-08-12 13:04:27 +02003050/* ******************************************************************
3051* Streaming
3052********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003053
3054typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
3055
3056struct ZSTD_CStream_s {
Yann Colletfa0c0972016-09-15 14:11:01 +02003057 ZSTD_CCtx* cctx;
Yann Collet95162342016-10-25 16:19:52 -07003058 ZSTD_CDict* cdictLocal;
3059 const ZSTD_CDict* cdict;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003060 char* inBuff;
3061 size_t inBuffSize;
3062 size_t inToCompress;
3063 size_t inBuffPos;
3064 size_t inBuffTarget;
3065 size_t blockSize;
3066 char* outBuff;
3067 size_t outBuffSize;
3068 size_t outBuffContentSize;
3069 size_t outBuffFlushedSize;
3070 ZSTD_cStreamStage stage;
3071 U32 checksum;
3072 U32 frameEnded;
Yann Collete795c8a2016-12-13 16:39:36 +01003073 U64 pledgedSrcSize;
Yann Colletee5b7252016-10-27 14:20:55 -07003074 ZSTD_parameters params;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003075 ZSTD_customMem customMem;
3076}; /* typedef'd to ZSTD_CStream within "zstd.h" */
3077
3078ZSTD_CStream* ZSTD_createCStream(void)
3079{
3080 return ZSTD_createCStream_advanced(defaultCustomMem);
3081}
3082
3083ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
3084{
3085 ZSTD_CStream* zcs;
3086
Yann Collet23b6e052016-08-28 21:05:43 -07003087 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
3088 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003089
Yann Collet23b6e052016-08-28 21:05:43 -07003090 zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003091 if (zcs==NULL) return NULL;
3092 memset(zcs, 0, sizeof(ZSTD_CStream));
3093 memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
Yann Colletfa0c0972016-09-15 14:11:01 +02003094 zcs->cctx = ZSTD_createCCtx_advanced(customMem);
3095 if (zcs->cctx == NULL) { ZSTD_freeCStream(zcs); return NULL; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003096 return zcs;
3097}
3098
3099size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
3100{
3101 if (zcs==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -07003102 { ZSTD_customMem const cMem = zcs->customMem;
Yann Colletfa0c0972016-09-15 14:11:01 +02003103 ZSTD_freeCCtx(zcs->cctx);
Nick Terrelleaf69b02017-03-21 13:20:59 -07003104 zcs->cctx = NULL;
Yann Collet95162342016-10-25 16:19:52 -07003105 ZSTD_freeCDict(zcs->cdictLocal);
Nick Terrelleaf69b02017-03-21 13:20:59 -07003106 zcs->cdictLocal = NULL;
Yann Collet23b6e052016-08-28 21:05:43 -07003107 ZSTD_free(zcs->inBuff, cMem);
Nick Terrelleaf69b02017-03-21 13:20:59 -07003108 zcs->inBuff = NULL;
Yann Collet23b6e052016-08-28 21:05:43 -07003109 ZSTD_free(zcs->outBuff, cMem);
Nick Terrelleaf69b02017-03-21 13:20:59 -07003110 zcs->outBuff = NULL;
Yann Collet23b6e052016-08-28 21:05:43 -07003111 ZSTD_free(zcs, cMem);
3112 return 0;
3113 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003114}
3115
3116
Yann Collet104e5b02016-08-12 13:04:27 +02003117/*====== Initialization ======*/
3118
3119size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
Yann Colletc17e0202017-04-20 12:50:02 -07003120
3121size_t ZSTD_CStreamOutSize(void)
3122{
3123 return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
3124}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003125
Sean Purcell2db72492017-02-09 10:50:43 -08003126static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003127{
Yann Colletd564faa2016-12-18 21:39:15 +01003128 if (zcs->inBuffSize==0) return ERROR(stage_wrong); /* zcs has not been init at least once => can't reset */
Yann Colletee5b7252016-10-27 14:20:55 -07003129
Yann Collet715b9aa2017-04-18 13:55:53 -07003130 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict_advanced(zcs->cctx, zcs->cdict, zcs->params.fParams, pledgedSrcSize))
Yann Colletab9162e2017-04-11 10:46:20 -07003131 else CHECK_F(ZSTD_compressBegin_internal(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize));
Yann Collet4cb21292016-09-15 14:54:07 +02003132
3133 zcs->inToCompress = 0;
3134 zcs->inBuffPos = 0;
3135 zcs->inBuffTarget = zcs->blockSize;
3136 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
3137 zcs->stage = zcss_load;
3138 zcs->frameEnded = 0;
Yann Collete795c8a2016-12-13 16:39:36 +01003139 zcs->pledgedSrcSize = pledgedSrcSize;
Yann Collet4cb21292016-09-15 14:54:07 +02003140 return 0; /* ready to go */
3141}
3142
Sean Purcell2db72492017-02-09 10:50:43 -08003143size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
3144{
3145
3146 zcs->params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
Sean Purcell2db72492017-02-09 10:50:43 -08003147 return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
3148}
3149
Yann Collet4b987ad2017-04-10 17:50:44 -07003150/* ZSTD_initCStream_internal() :
Yann Collete88034f2017-04-10 22:24:02 -07003151 * params are supposed validated at this stage
3152 * and zcs->cdict is supposed to be correct */
3153static size_t ZSTD_initCStream_stage2(ZSTD_CStream* zcs,
3154 const ZSTD_parameters params,
3155 unsigned long long pledgedSrcSize)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003156{
Yann Collet4b987ad2017-04-10 17:50:44 -07003157 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collete88034f2017-04-10 22:24:02 -07003158
Yann Collet5a0c8e22016-08-12 01:20:36 +02003159 /* allocate buffers */
3160 { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
3161 if (zcs->inBuffSize < neededInBuffSize) {
Yann Collet02d37aa2017-04-05 14:53:51 -07003162 zcs->inBuffSize = 0;
Yann Colletcf409a72016-09-26 16:41:05 +02003163 ZSTD_free(zcs->inBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003164 zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003165 if (zcs->inBuff == NULL) return ERROR(memory_allocation);
Yann Collet02d37aa2017-04-05 14:53:51 -07003166 zcs->inBuffSize = neededInBuffSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003167 }
3168 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
3169 }
3170 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
Yann Collet02d37aa2017-04-05 14:53:51 -07003171 size_t const outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
3172 zcs->outBuffSize = 0;
Yann Colletcf409a72016-09-26 16:41:05 +02003173 ZSTD_free(zcs->outBuff, zcs->customMem);
Yann Collet02d37aa2017-04-05 14:53:51 -07003174 zcs->outBuff = (char*) ZSTD_malloc(outBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003175 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
Yann Collet02d37aa2017-04-05 14:53:51 -07003176 zcs->outBuffSize = outBuffSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003177 }
3178
Yann Collet5a0c8e22016-08-12 01:20:36 +02003179 zcs->checksum = params.fParams.checksumFlag > 0;
Yann Colletee5b7252016-10-27 14:20:55 -07003180 zcs->params = params;
Yann Collet4cb21292016-09-15 14:54:07 +02003181
Sean Purcell2db72492017-02-09 10:50:43 -08003182 return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003183}
3184
Yann Collete88034f2017-04-10 22:24:02 -07003185/* note : cdict must outlive compression session */
3186size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3187{
3188 if (!cdict) return ERROR(GENERIC); /* cannot handle NULL cdict (does not know what to do) */
Yann Collet4ee6b152017-04-11 11:59:44 -07003189 { ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict);
3190 params.fParams.contentSizeFlag = 0;
Yann Collete88034f2017-04-10 22:24:02 -07003191 zcs->cdict = cdict;
3192 return ZSTD_initCStream_stage2(zcs, params, 0);
3193 }
3194}
3195
3196static size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
3197 const void* dict, size_t dictSize,
3198 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3199{
3200 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
3201 zcs->cdict = NULL;
3202
3203 if (dict && dictSize >= 8) {
3204 ZSTD_freeCDict(zcs->cdictLocal);
3205 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0 /* copy */, params, zcs->customMem);
3206 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
3207 zcs->cdict = zcs->cdictLocal;
3208 }
3209
3210 return ZSTD_initCStream_stage2(zcs, params, pledgedSrcSize);
3211}
3212
Yann Collet4b987ad2017-04-10 17:50:44 -07003213size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
3214 const void* dict, size_t dictSize,
3215 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3216{
3217 CHECK_F( ZSTD_checkCParams(params.cParams) );
3218 return ZSTD_initCStream_internal(zcs, dict, dictSize, params, pledgedSrcSize);
3219}
3220
Yann Collet5a0c8e22016-08-12 01:20:36 +02003221size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3222{
3223 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet4b987ad2017-04-10 17:50:44 -07003224 return ZSTD_initCStream_internal(zcs, dict, dictSize, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003225}
3226
Yann Collete795c8a2016-12-13 16:39:36 +01003227size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3228{
Yann Colletd564faa2016-12-18 21:39:15 +01003229 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
Yann Collete88034f2017-04-10 22:24:02 -07003230 params.fParams.contentSizeFlag = (pledgedSrcSize>0);
Yann Collet4b987ad2017-04-10 17:50:44 -07003231 return ZSTD_initCStream_internal(zcs, NULL, 0, params, pledgedSrcSize);
Yann Collete795c8a2016-12-13 16:39:36 +01003232}
3233
Yann Collet5a0c8e22016-08-12 01:20:36 +02003234size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3235{
Yann Collete88034f2017-04-10 22:24:02 -07003236 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0);
3237 return ZSTD_initCStream_internal(zcs, NULL, 0, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003238}
3239
Yann Collet70e3b312016-08-23 01:18:06 +02003240size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
Yann Colletcb327632016-08-23 00:30:31 +02003241{
Yann Colletd7c65892016-09-15 02:50:27 +02003242 if (zcs==NULL) return 0; /* support sizeof on NULL */
Nick Terrelle06c3032017-03-08 13:45:10 -08003243 return sizeof(*zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + ZSTD_sizeof_CDict(zcs->cdictLocal) + zcs->outBuffSize + zcs->inBuffSize;
Yann Colletcb327632016-08-23 00:30:31 +02003244}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003245
Yann Collet104e5b02016-08-12 13:04:27 +02003246/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003247
3248typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
3249
3250MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
3251{
3252 size_t const length = MIN(dstCapacity, srcSize);
3253 memcpy(dst, src, length);
3254 return length;
3255}
3256
3257static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3258 void* dst, size_t* dstCapacityPtr,
3259 const void* src, size_t* srcSizePtr,
3260 ZSTD_flush_e const flush)
3261{
3262 U32 someMoreWork = 1;
3263 const char* const istart = (const char*)src;
3264 const char* const iend = istart + *srcSizePtr;
3265 const char* ip = istart;
3266 char* const ostart = (char*)dst;
3267 char* const oend = ostart + *dstCapacityPtr;
3268 char* op = ostart;
3269
3270 while (someMoreWork) {
3271 switch(zcs->stage)
3272 {
3273 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
3274
3275 case zcss_load:
3276 /* complete inBuffer */
3277 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3278 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
3279 zcs->inBuffPos += loaded;
3280 ip += loaded;
3281 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
3282 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
3283 } }
3284 /* compress current block (note : this stage cannot be stopped in the middle) */
3285 { void* cDst;
3286 size_t cSize;
3287 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3288 size_t oSize = oend-op;
3289 if (oSize >= ZSTD_compressBound(iSize))
3290 cDst = op; /* compress directly into output buffer (avoid flush stage) */
3291 else
3292 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
3293 cSize = (flush == zsf_end) ?
Yann Colletfa0c0972016-09-15 14:11:01 +02003294 ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
3295 ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003296 if (ZSTD_isError(cSize)) return cSize;
3297 if (flush == zsf_end) zcs->frameEnded = 1;
3298 /* prepare next block */
3299 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3300 if (zcs->inBuffTarget > zcs->inBuffSize)
3301 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
3302 zcs->inToCompress = zcs->inBuffPos;
3303 if (cDst == op) { op += cSize; break; } /* no need to flush */
3304 zcs->outBuffContentSize = cSize;
3305 zcs->outBuffFlushedSize = 0;
3306 zcs->stage = zcss_flush; /* pass-through to flush stage */
3307 }
3308
3309 case zcss_flush:
3310 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3311 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3312 op += flushed;
3313 zcs->outBuffFlushedSize += flushed;
3314 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
3315 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
3316 zcs->stage = zcss_load;
3317 break;
3318 }
3319
3320 case zcss_final:
3321 someMoreWork = 0; /* do nothing */
3322 break;
3323
3324 default:
3325 return ERROR(GENERIC); /* impossible */
3326 }
3327 }
3328
3329 *srcSizePtr = ip - istart;
3330 *dstCapacityPtr = op - ostart;
3331 if (zcs->frameEnded) return 0;
3332 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3333 if (hintInSize==0) hintInSize = zcs->blockSize;
3334 return hintInSize;
3335 }
3336}
3337
Yann Collet53e17fb2016-08-17 01:39:22 +02003338size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003339{
Yann Collet53e17fb2016-08-17 01:39:22 +02003340 size_t sizeRead = input->size - input->pos;
3341 size_t sizeWritten = output->size - output->pos;
3342 size_t const result = ZSTD_compressStream_generic(zcs,
3343 (char*)(output->dst) + output->pos, &sizeWritten,
3344 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
3345 input->pos += sizeRead;
3346 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003347 return result;
3348}
3349
3350
Yann Collet104e5b02016-08-12 13:04:27 +02003351/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003352
3353/*! ZSTD_flushStream() :
3354* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003355size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003356{
3357 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003358 size_t sizeWritten = output->size - output->pos;
Yann Colletc4119022016-08-17 01:50:54 +02003359 size_t const result = ZSTD_compressStream_generic(zcs,
Yann Collet95d07d72016-09-06 16:38:51 +02003360 (char*)(output->dst) + output->pos, &sizeWritten,
3361 &srcSize, &srcSize, /* use a valid src address instead of NULL */
Yann Colletc4119022016-08-17 01:50:54 +02003362 zsf_flush);
Yann Collet53e17fb2016-08-17 01:39:22 +02003363 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003364 if (ZSTD_isError(result)) return result;
3365 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3366}
3367
3368
Yann Collet53e17fb2016-08-17 01:39:22 +02003369size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003370{
Yann Collet53e17fb2016-08-17 01:39:22 +02003371 BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
3372 BYTE* const oend = (BYTE*)(output->dst) + output->size;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003373 BYTE* op = ostart;
3374
3375 if (zcs->stage != zcss_final) {
3376 /* flush whatever remains */
3377 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003378 size_t sizeWritten = output->size - output->pos;
Yann Colletc17e0202017-04-20 12:50:02 -07003379 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten,
3380 &srcSize /* use a valid src address instead of NULL */, &srcSize, zsf_end);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003381 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3382 op += sizeWritten;
3383 if (remainingToFlush) {
Yann Collet53e17fb2016-08-17 01:39:22 +02003384 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003385 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4);
3386 }
3387 /* create epilogue */
3388 zcs->stage = zcss_final;
3389 zcs->outBuffContentSize = !notEnded ? 0 :
Yann Colletc17e0202017-04-20 12:50:02 -07003390 /* write epilogue, including final empty block, into outBuff */
3391 ZSTD_compressEnd(zcs->cctx, zcs->outBuff, zcs->outBuffSize, NULL, 0);
Yann Collet88009a82017-04-12 00:51:24 -07003392 if (ZSTD_isError(zcs->outBuffContentSize)) return zcs->outBuffContentSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003393 }
3394
3395 /* flush epilogue */
3396 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3397 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3398 op += flushed;
3399 zcs->outBuffFlushedSize += flushed;
Yann Collet53e17fb2016-08-17 01:39:22 +02003400 output->pos += op-ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003401 if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */
3402 return toFlush - flushed;
3403 }
3404}
3405
3406
3407
Yann Collet70e8c382016-02-10 13:37:52 +01003408/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003409
Yann Collet236d94f2016-05-18 12:06:33 +02003410#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02003411#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003412int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003413
Yann Collet3b719252016-03-30 19:48:05 +02003414static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003415{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003416 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003417 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003418 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3419 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003420 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3421 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003422 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3423 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3424 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003425 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003426 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3427 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3428 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3429 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3430 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3431 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3432 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3433 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003434 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
3435 { 23, 23, 22, 6, 5, 32, ZSTD_btopt }, /* level 18 */
3436 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003437 { 25, 25, 23, 7, 3, 64, ZSTD_btopt2 }, /* level 20 */
3438 { 26, 26, 23, 7, 3,256, ZSTD_btopt2 }, /* level 21 */
3439 { 27, 27, 25, 9, 3,512, ZSTD_btopt2 }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003440},
3441{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003442 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003443 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003444 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003445 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3446 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3447 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3448 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3449 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3450 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3451 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3452 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3453 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3454 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3455 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3456 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003457 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003458 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3459 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3460 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003461 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3462 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003463 { 18, 19, 18, 11, 3,512, ZSTD_btopt2 }, /* level 20.*/
3464 { 18, 19, 18, 12, 3,512, ZSTD_btopt2 }, /* level 21.*/
3465 { 18, 19, 18, 13, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003466},
3467{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003468 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003469 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3470 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3471 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3472 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3473 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3474 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3475 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3476 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3477 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3478 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3479 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3480 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3481 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3482 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003483 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3484 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3485 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3486 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3487 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3488 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003489 { 17, 18, 17, 9, 3,256, ZSTD_btopt2 }, /* level 20.*/
3490 { 17, 18, 17, 10, 3,256, ZSTD_btopt2 }, /* level 21.*/
3491 { 17, 18, 17, 11, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003492},
3493{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003494 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003495 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003496 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003497 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3498 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3499 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3500 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3501 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3502 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3503 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3504 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003505 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3506 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3507 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3508 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3509 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3510 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3511 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3512 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3513 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3514 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003515 { 14, 15, 15, 8, 3,256, ZSTD_btopt2 }, /* level 20.*/
3516 { 14, 15, 15, 9, 3,256, ZSTD_btopt2 }, /* level 21.*/
3517 { 14, 15, 15, 10, 3,256, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003518},
3519};
3520
Yann Collet236d94f2016-05-18 12:06:33 +02003521/*! ZSTD_getCParams() :
3522* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3523* Size values are optional, provide 0 if not known or unused */
Yann Collet52c04fe2016-07-07 11:53:18 +02003524ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003525{
Yann Collet15354142016-04-04 04:22:53 +02003526 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02003527 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02003528 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003529 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02003530 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003531 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003532 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003533 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3534 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003535 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003536 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3537 }
Yann Collet70d13012016-06-01 18:45:34 +02003538 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003539 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003540}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003541
3542/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003543* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003544* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet52c04fe2016-07-07 11:53:18 +02003545ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003546 ZSTD_parameters params;
3547 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3548 memset(&params, 0, sizeof(params));
3549 params.cParams = cParams;
3550 return params;
3551}