blob: dfaa1854ff8e9756874e73bfa402ce77c2b49d51 [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 Colletb0edb7f2017-05-12 15:31:53 -070012* Tuning parameters
13***************************************/
Yann Collet6d4fef32017-05-17 18:36:15 -070014#ifndef ZSTD_CLEVEL_DEFAULT
15# define ZSTD_CLEVEL_DEFAULT 3
Yann Colletb0edb7f2017-05-12 15:31:53 -070016#endif
17
18/*-*************************************
Yann Colletae7aa062016-02-03 02:46:46 +010019* Dependencies
Yann Colletf3eca252015-10-22 15:31:46 +010020***************************************/
Yann Colletd3b7f8d2016-06-04 19:47:02 +020021#include <string.h> /* memset */
Yann Collet14983e72015-11-11 21:38:21 +010022#include "mem.h"
Yann Collet5a0c8e22016-08-12 01:20:36 +020023#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
Yann Colletd0e2cd12016-06-05 00:58:01 +020024#include "fse.h"
Yann Collet130fe112016-06-05 00:42:28 +020025#define HUF_STATIC_LINKING_ONLY
26#include "huf.h"
Yann Colletd3b7f8d2016-06-04 19:47:02 +020027#include "zstd_internal.h" /* includes zstd.h */
Yann Colletc4a5a212017-06-01 17:56:14 -070028#include "zstdmt_compress.h"
Yann Colletf3eca252015-10-22 15:31:46 +010029
30
Yann Collet7d360282016-02-12 00:07:30 +010031/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010032* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010033***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010034static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Collet731ef162016-07-27 21:05:12 +020035#define HASH_READ_SIZE 8
36typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
Yann Colletf3eca252015-10-22 15:31:46 +010037
Yann Collet71ddeb62017-04-20 22:54:54 -070038/* entropy tables always have same size */
39static size_t const hufCTable_size = HUF_CTABLE_SIZE(255);
Yann Collete42afbc2017-04-26 11:39:35 -070040static size_t const litlengthCTable_size = FSE_CTABLE_SIZE(LLFSELog, MaxLL);
41static size_t const offcodeCTable_size = FSE_CTABLE_SIZE(OffFSELog, MaxOff);
42static size_t const matchlengthCTable_size = FSE_CTABLE_SIZE(MLFSELog, MaxML);
Yann Collet72712032017-04-20 23:21:19 -070043static size_t const entropyScratchSpace_size = HUF_WORKSPACE_SIZE;
Yann Colleta34a39c2017-04-20 18:17:58 -070044
Yann Colletf3eca252015-10-22 15:31:46 +010045
Yann Collet7d360282016-02-12 00:07:30 +010046/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010047* Helper functions
48***************************************/
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 Collet6d4fef32017-05-17 18:36:15 -070070typedef enum { zcss_init=0, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
Yann Collet0be6fd32017-05-08 16:08:01 -070071
Yann Collet18803372017-05-22 18:21:51 -070072struct ZSTD_CDict_s {
73 void* dictBuffer;
74 const void* dictContent;
75 size_t dictContentSize;
76 ZSTD_CCtx* refContext;
Yann Collet8c910d22017-06-03 01:15:02 -070077}; /* typedef'd to ZSTD_CDict within "zstd.h" */
Yann Collet18803372017-05-22 18:21:51 -070078
Yann Colletaca113f2016-12-23 22:25:03 +010079struct ZSTD_CCtx_s {
Yann Collet89db5e02015-11-13 11:27:46 +010080 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010081 const BYTE* base; /* All regular indexes relative to this position */
82 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010083 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010084 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010085 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010086 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +010087 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Colletbb002742017-01-25 16:25:38 -080088 U32 loadedDictEnd; /* index of end of dictionary */
89 U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
Yann Collet14312d82017-02-23 23:42:12 -080090 U32 forceRawDict; /* Force loading dictionary in "content-only" mode (no header analysis) */
Yann Collet731ef162016-07-27 21:05:12 +020091 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +020092 U32 rep[ZSTD_REP_NUM];
Yann Colletb459aad2017-01-19 17:33:37 -080093 U32 repToConfirm[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +020094 U32 dictID;
Yann Colletb0edb7f2017-05-12 15:31:53 -070095 int compressionLevel;
Yann Collet1ad7c822017-05-22 17:06:04 -070096 ZSTD_parameters requestedParams;
97 ZSTD_parameters appliedParams;
Yann Collet712def92015-10-29 18:41:45 +010098 void* workSpace;
99 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100100 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +0200101 U64 frameContentSize;
Yann Collet20d5e032017-04-11 18:34:02 -0700102 U64 consumedSrcSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200103 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +0200104 ZSTD_customMem customMem;
Yann Colletc7fe2622017-05-23 13:16:00 -0700105 size_t staticSize;
Yann Colletecd651b2016-01-07 15:35:18 +0100106
Yann Collet712def92015-10-29 18:41:45 +0100107 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100108 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +0100109 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +0200110 U32* chainTable;
Yann Collet71ddeb62017-04-20 22:54:54 -0700111 HUF_repeat hufCTable_repeatMode;
112 HUF_CElt* hufCTable;
113 U32 fseCTables_ready;
Yann Collet71aaa322017-04-20 23:03:38 -0700114 FSE_CTable* offcodeCTable;
115 FSE_CTable* matchlengthCTable;
116 FSE_CTable* litlengthCTable;
Yann Collete42afbc2017-04-26 11:39:35 -0700117 unsigned* entropyScratchSpace;
Yann Collet0be6fd32017-05-08 16:08:01 -0700118
119 /* streaming */
120 ZSTD_CDict* cdictLocal;
121 const ZSTD_CDict* cdict;
122 char* inBuff;
123 size_t inBuffSize;
124 size_t inToCompress;
125 size_t inBuffPos;
126 size_t inBuffTarget;
127 char* outBuff;
128 size_t outBuffSize;
129 size_t outBuffContentSize;
130 size_t outBuffFlushedSize;
131 ZSTD_cStreamStage streamStage;
132 U32 frameEnded;
Yann Colletc4a5a212017-06-01 17:56:14 -0700133
134 /* Multi-threading */
Yann Colletc35e5352017-06-01 18:44:06 -0700135 U32 nbThreads;
Yann Colletc4a5a212017-06-01 17:56:14 -0700136 ZSTDMT_CCtx* mtctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100137};
138
Yann Colletc4a5a212017-06-01 17:56:14 -0700139
Yann Collet5be2dd22015-11-11 13:43:58 +0100140ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100141{
Yann Colletae728a42017-05-30 17:11:39 -0700142 return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
inikep50e82c02016-05-23 15:49:09 +0200143}
144
145ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
146{
Yann Collet69c2cdb2016-07-14 16:52:45 +0200147 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +0200148
Yann Colletae728a42017-05-30 17:11:39 -0700149 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200150
Yann Colletc4f46b92017-05-30 17:45:37 -0700151 cctx = (ZSTD_CCtx*) ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200152 if (!cctx) return NULL;
Yann Colletbb002742017-01-25 16:25:38 -0800153 cctx->customMem = customMem;
Yann Collet6d4fef32017-05-17 18:36:15 -0700154 cctx->compressionLevel = ZSTD_CLEVEL_DEFAULT;
Yann Collet69c2cdb2016-07-14 16:52:45 +0200155 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100156}
157
Yann Colletc7fe2622017-05-23 13:16:00 -0700158ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
159{
160 ZSTD_CCtx* cctx = (ZSTD_CCtx*) workspace;
161 if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
162 if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
163 memset(workspace, 0, workspaceSize);
164 cctx->staticSize = workspaceSize;
165 cctx->workSpace = (void*)(cctx+1);
166 cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
167
168 /* entropy space (never moves) */
169 /* note : this code should be shared with resetCCtx, instead of copied */
170 { void* ptr = cctx->workSpace;
171 cctx->hufCTable = (HUF_CElt*)ptr;
Yann Collet0fdc71c2017-05-24 17:41:41 -0700172 ptr = (char*)cctx->hufCTable + hufCTable_size;
Yann Colletc7fe2622017-05-23 13:16:00 -0700173 cctx->offcodeCTable = (FSE_CTable*) ptr;
174 ptr = (char*)ptr + offcodeCTable_size;
175 cctx->matchlengthCTable = (FSE_CTable*) ptr;
176 ptr = (char*)ptr + matchlengthCTable_size;
177 cctx->litlengthCTable = (FSE_CTable*) ptr;
178 ptr = (char*)ptr + litlengthCTable_size;
179 assert(((size_t)ptr & 3) == 0); /* ensure correct alignment */
180 cctx->entropyScratchSpace = (unsigned*) ptr;
181 }
182
183 return cctx;
184}
185
Yann Collet5be2dd22015-11-11 13:43:58 +0100186size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100187{
inikep36403962016-06-03 16:36:50 +0200188 if (cctx==NULL) return 0; /* support free on NULL */
Yann Colletc4a5a212017-06-01 17:56:14 -0700189 if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */
Yann Collet23b6e052016-08-28 21:05:43 -0700190 ZSTD_free(cctx->workSpace, cctx->customMem);
Yann Collet78553662017-05-08 17:15:00 -0700191 cctx->workSpace = NULL;
192 ZSTD_freeCDict(cctx->cdictLocal);
193 cctx->cdictLocal = NULL;
Yann Colletc4a5a212017-06-01 17:56:14 -0700194 ZSTDMT_freeCCtx(cctx->mtctx);
195 cctx->mtctx = NULL;
Yann Collet23b6e052016-08-28 21:05:43 -0700196 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100197 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100198}
199
Yann Collet70e3b312016-08-23 01:18:06 +0200200size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200201{
Yann Colletd7c65892016-09-15 02:50:27 +0200202 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet791d7442017-05-08 16:17:30 -0700203 return sizeof(*cctx) + cctx->workSpaceSize
204 + ZSTD_sizeof_CDict(cctx->cdictLocal)
Yann Colletc4a5a212017-06-01 17:56:14 -0700205 + cctx->outBuffSize + cctx->inBuffSize
206 + ZSTDMT_sizeof_CCtx(cctx->mtctx);
Yann Collet3ae543c2016-07-11 03:12:17 +0200207}
208
Yann Collet009d6042017-05-19 10:17:59 -0700209size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
210{
211 return ZSTD_sizeof_CCtx(zcs); /* same object */
212}
213
Yann Colletb0edb7f2017-05-12 15:31:53 -0700214/* private API call, for dictBuilder only */
215const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
216
Yann Collet1ad7c822017-05-22 17:06:04 -0700217static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return cctx->appliedParams; }
Yann Colletb0edb7f2017-05-12 15:31:53 -0700218
Yann Colletef738c12017-05-12 13:53:46 -0700219/* older variant; will be deprecated */
Yann Colletbb002742017-01-25 16:25:38 -0800220size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
221{
222 switch(param)
223 {
Yann Collet06e76972017-01-25 16:39:03 -0800224 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
Yann Collet14312d82017-02-23 23:42:12 -0800225 case ZSTD_p_forceRawDict : cctx->forceRawDict = value>0; return 0;
Yann Colletbb002742017-01-25 16:25:38 -0800226 default: return ERROR(parameter_unknown);
227 }
228}
229
Yann Colletadd66f82017-05-12 15:59:48 -0700230
Yann Collet6d4fef32017-05-17 18:36:15 -0700231#define ZSTD_CLEVEL_CUSTOM 999
Yann Colletadd66f82017-05-12 15:59:48 -0700232static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx)
233{
Yann Collet1ad7c822017-05-22 17:06:04 -0700234 if (cctx->compressionLevel==ZSTD_CLEVEL_CUSTOM) return;
235 cctx->requestedParams.cParams = ZSTD_getCParams(cctx->compressionLevel,
236 cctx->frameContentSize, 0);
Yann Collet6d4fef32017-05-17 18:36:15 -0700237 cctx->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Colletadd66f82017-05-12 15:59:48 -0700238}
239
Yann Colletb0edb7f2017-05-12 15:31:53 -0700240size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value)
Yann Collet7d360282016-02-12 00:07:30 +0100241{
Yann Collet334a2882017-05-19 11:04:41 -0700242# define CLAMPCHECK(val,min,max) { \
243 if ((val<min) | (val>max)) { \
Yann Collet559ee822017-06-16 11:58:21 -0700244 return ERROR(compressionParameter_outOfBound); \
Yann Collet334a2882017-05-19 11:04:41 -0700245 } }
246
Yann Collet24de7b02017-05-22 13:05:45 -0700247 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700248
249 switch(param)
250 {
251 case ZSTD_p_compressionLevel :
Yann Colletcd2892f2017-06-01 09:44:54 -0700252 if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel(); /* cap max compression level */
253 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
254 cctx->compressionLevel = value;
255 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700256
257 case ZSTD_p_windowLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700258 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
259 CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
260 ZSTD_cLevelToCParams(cctx);
261 cctx->requestedParams.cParams.windowLog = value;
262 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700263
264 case ZSTD_p_hashLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700265 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
266 CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
267 ZSTD_cLevelToCParams(cctx);
268 cctx->requestedParams.cParams.hashLog = value;
269 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700270
271 case ZSTD_p_chainLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700272 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
273 CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
274 ZSTD_cLevelToCParams(cctx);
275 cctx->requestedParams.cParams.chainLog = value;
276 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700277
278 case ZSTD_p_searchLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700279 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
280 CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
281 ZSTD_cLevelToCParams(cctx);
282 cctx->requestedParams.cParams.searchLog = value;
283 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700284
Yann Collet6d4fef32017-05-17 18:36:15 -0700285 case ZSTD_p_minMatch :
Yann Colletcd2892f2017-06-01 09:44:54 -0700286 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
287 CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
288 ZSTD_cLevelToCParams(cctx);
289 cctx->requestedParams.cParams.searchLength = value;
290 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700291
292 case ZSTD_p_targetLength :
Yann Colletcd2892f2017-06-01 09:44:54 -0700293 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
294 CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
295 ZSTD_cLevelToCParams(cctx);
296 cctx->requestedParams.cParams.targetLength = value;
297 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700298
299 case ZSTD_p_compressionStrategy :
Yann Colletcd2892f2017-06-01 09:44:54 -0700300 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
301 CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
302 ZSTD_cLevelToCParams(cctx);
303 cctx->requestedParams.cParams.strategy = (ZSTD_strategy)value;
304 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700305
306#if 0
307 case ZSTD_p_windowSize : /* to be done later */
Yann Colletcd2892f2017-06-01 09:44:54 -0700308 return ERROR(compressionParameter_unsupported);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700309#endif
310
Yann Colletcd2892f2017-06-01 09:44:54 -0700311 case ZSTD_p_contentSizeFlag :
312 /* Content size written in frame header _when known_ (default:1) */
313 cctx->requestedParams.fParams.contentSizeFlag = value>0;
314 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700315
Yann Colletcd2892f2017-06-01 09:44:54 -0700316 case ZSTD_p_checksumFlag :
317 /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
318 cctx->requestedParams.fParams.checksumFlag = value>0;
319 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700320
Yann Collet1ad7c822017-05-22 17:06:04 -0700321 case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
Yann Colletcd2892f2017-06-01 09:44:54 -0700322 DEBUGLOG(5, "set dictIDFlag = %u", (value>0));
323 cctx->requestedParams.fParams.noDictIDFlag = (value==0);
324 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700325
326 case ZSTD_p_refDictContent : /* to be done later */
Yann Colletcd2892f2017-06-01 09:44:54 -0700327 return ERROR(compressionParameter_unsupported);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700328
329 case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize,
330 * even when referencing into Dictionary content
331 * default : 0 when using a CDict, 1 when using a Prefix */
Yann Colletc35e5352017-06-01 18:44:06 -0700332 cctx->forceWindow = value>0;
333 cctx->loadedDictEnd = 0;
334 return 0;
335
336 case ZSTD_p_nbThreads:
337 if (value==0) return 0;
338#ifndef ZSTD_MULTITHREAD
339 if (value > 1) return ERROR(compressionParameter_unsupported);
340#endif
341 if ((value>1) && (cctx->nbThreads != value)) {
Yann Collet05ae4b22017-06-15 18:03:34 -0700342 if (cctx->staticSize) /* MT not compatible with static alloc */
343 return ERROR(compressionParameter_unsupported);
Yann Colletc35e5352017-06-01 18:44:06 -0700344 ZSTDMT_freeCCtx(cctx->mtctx);
Yann Collet559ee822017-06-16 11:58:21 -0700345 cctx->nbThreads = 1;
Yann Colletc35e5352017-06-01 18:44:06 -0700346 cctx->mtctx = ZSTDMT_createCCtx(value);
347 if (cctx->mtctx == NULL) return ERROR(memory_allocation);
Yann Collet559ee822017-06-16 11:58:21 -0700348 cctx->nbThreads = value;
349 } else
350 cctx->nbThreads = 1;
Yann Colletc35e5352017-06-01 18:44:06 -0700351 return 0;
352
Yann Collet559ee822017-06-16 11:58:21 -0700353 case ZSTD_p_jobSize:
Yann Colletc35e5352017-06-01 18:44:06 -0700354 if (cctx->nbThreads <= 1) return ERROR(compressionParameter_unsupported);
355 assert(cctx->mtctx != NULL);
356 return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_sectionSize, value);
357
Yann Collet559ee822017-06-16 11:58:21 -0700358 case ZSTD_p_overlapSizeLog:
Yann Colletc35e5352017-06-01 18:44:06 -0700359 if (cctx->nbThreads <= 1) return ERROR(compressionParameter_unsupported);
360 assert(cctx->mtctx != NULL);
361 return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_overlapSectionLog, value);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700362
363 case ZSTD_p_rawContentDict : /* load dictionary in "content-only" mode (no header analysis) (default:0) */
Yann Colletcd2892f2017-06-01 09:44:54 -0700364 cctx->forceRawDict = value>0;
365 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700366
367 default: return ERROR(parameter_unknown);
368 }
Yann Collet7d360282016-02-12 00:07:30 +0100369}
370
Yann Colletb0edb7f2017-05-12 15:31:53 -0700371ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
Yann Collet95162342016-10-25 16:19:52 -0700372{
Yann Collet24de7b02017-05-22 13:05:45 -0700373 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700374 cctx->frameContentSize = pledgedSrcSize;
375 return 0;
376}
377
Yann Collet6d4fef32017-05-17 18:36:15 -0700378ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
379{
Yann Collet24de7b02017-05-22 13:05:45 -0700380 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletc7fe2622017-05-23 13:16:00 -0700381 if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
Yann Collet6d4fef32017-05-17 18:36:15 -0700382 ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */
383 if (dict==NULL || dictSize==0) { /* no dictionary mode */
384 cctx->cdictLocal = NULL;
385 cctx->cdict = NULL;
386 } else {
Yann Collet8b21ec42017-05-19 19:46:15 -0700387 ZSTD_compressionParameters const cParams =
388 cctx->compressionLevel == ZSTD_CLEVEL_CUSTOM ?
Yann Collet1ad7c822017-05-22 17:06:04 -0700389 cctx->requestedParams.cParams :
Yann Collet8b21ec42017-05-19 19:46:15 -0700390 ZSTD_getCParams(cctx->compressionLevel, 0, dictSize);
Yann Collet6d4fef32017-05-17 18:36:15 -0700391 cctx->cdictLocal = ZSTD_createCDict_advanced(
392 dict, dictSize,
393 0 /* byReference */,
Yann Collet8b21ec42017-05-19 19:46:15 -0700394 cParams, cctx->customMem);
Yann Collet6d4fef32017-05-17 18:36:15 -0700395 cctx->cdict = cctx->cdictLocal;
396 if (cctx->cdictLocal == NULL)
397 return ERROR(memory_allocation);
398 }
399 return 0;
400}
401
Yann Colletb0edb7f2017-05-12 15:31:53 -0700402/* Not ready yet ! */
Yann Colletbd18c882017-06-16 10:17:50 -0700403size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
Yann Colletb0edb7f2017-05-12 15:31:53 -0700404{
405 (void)cctx; (void)prefix; (void)prefixSize; /* to be done later */
Yann Collet24de7b02017-05-22 13:05:45 -0700406 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700407 return ERROR(compressionParameter_unsupported);
408}
409
Yann Colletbd18c882017-06-16 10:17:50 -0700410size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
Yann Colletb0edb7f2017-05-12 15:31:53 -0700411{
Yann Collet24de7b02017-05-22 13:05:45 -0700412 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
413 cctx->cdict = cdict;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700414 return ERROR(compressionParameter_unsupported);
Yann Collet95162342016-10-25 16:19:52 -0700415}
416
Yann Collet59d70632015-11-04 12:05:27 +0100417
Yann Colletbd18c882017-06-16 10:17:50 -0700418void ZSTD_CCtx_reset(ZSTD_CCtx* cctx)
419{
420 cctx->streamStage = zcss_init;
421 cctx->frameContentSize = ZSTD_CONTENTSIZE_UNKNOWN;
422 cctx->cdict = NULL;
423}
424
Yann Collet21588e32016-03-30 16:50:44 +0200425/** ZSTD_checkParams() :
426 ensure param values remain within authorized range.
427 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200428size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200429{
Yann Collet15354142016-04-04 04:22:53 +0200430 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200431 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200432 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
433 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Collet2e2e78d2017-03-29 16:02:47 -0700434 CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200435 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800436 if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200437 return 0;
438}
439
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100440/** ZSTD_cycleLog() :
441 * condition for correct operation : hashLog > 1 */
442static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
443{
444 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
445 return hashLog - btScale;
446}
447
Yann Collet70d13012016-06-01 18:45:34 +0200448/** ZSTD_adjustCParams() :
Yann Colletcf409a72016-09-26 16:41:05 +0200449 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200450 mostly downsizing to reduce memory consumption and initialization.
451 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
452 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200453 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200454ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100455{
Yann Collet70d13012016-06-01 18:45:34 +0200456 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100457
Yann Collet70e45772016-03-19 18:08:32 +0100458 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200459 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
460 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200461 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200462 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200463 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200464 } }
Yann Collet70d13012016-06-01 18:45:34 +0200465 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100466 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
467 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
468 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100469
Yann Collet70d13012016-06-01 18:45:34 +0200470 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200471
472 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100473}
474
475
Yann Collet88472382016-07-14 17:05:38 +0200476size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100477{
Yann Colletfa3671e2017-05-19 10:51:30 -0700478 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
Yann Collet731ef162016-07-27 21:05:12 +0200479 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
480 size_t const maxNbSeq = blockSize / divider;
481 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200482
Yann Collet731ef162016-07-27 21:05:12 +0200483 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
484 size_t const hSize = ((size_t)1) << cParams.hashLog;
485 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
486 size_t const h3Size = ((size_t)1) << hashLog3;
Yann Collet71ddeb62017-04-20 22:54:54 -0700487 size_t const entropySpace = hufCTable_size + litlengthCTable_size
Yann Colleta4086452017-04-20 23:09:39 -0700488 + offcodeCTable_size + matchlengthCTable_size
Yann Collet72712032017-04-20 23:21:19 -0700489 + entropyScratchSpace_size;
Yann Collet731ef162016-07-27 21:05:12 +0200490 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200491
Yann Colletfc514592017-05-08 17:07:59 -0700492 size_t const optBudget = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
Yann Collet3ae543c2016-07-11 03:12:17 +0200493 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
Nick Terrell5f2c7212017-05-10 16:49:58 -0700494 size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
Yann Colletfc514592017-05-08 17:07:59 -0700495 size_t const neededSpace = entropySpace + tableSpace + tokenSpace + optSpace;
Yann Collet3ae543c2016-07-11 03:12:17 +0200496
497 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100498}
499
Yann Colletc7fe2622017-05-23 13:16:00 -0700500size_t ZSTD_estimateCStreamSize(ZSTD_compressionParameters cParams)
501{
502 size_t const CCtxSize = ZSTD_estimateCCtxSize(cParams);
503 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
504 size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
505 size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
506 size_t const streamingSize = inBuffSize + outBuffSize;
507
508 return CCtxSize + streamingSize;
509}
510
Yann Colleta7737f62016-09-06 09:44:59 +0200511
Yann Collet009d6042017-05-19 10:17:59 -0700512static U32 ZSTD_equivalentParams(ZSTD_compressionParameters cParams1,
513 ZSTD_compressionParameters cParams2)
Yann Colleta7737f62016-09-06 09:44:59 +0200514{
Yann Colletfa3671e2017-05-19 10:51:30 -0700515 U32 bslog1 = MIN(cParams1.windowLog, ZSTD_BLOCKSIZELOG_MAX);
516 U32 bslog2 = MIN(cParams2.windowLog, ZSTD_BLOCKSIZELOG_MAX);
Yann Collet009d6042017-05-19 10:17:59 -0700517 return (bslog1 == bslog2) /* same block size */
518 & (cParams1.hashLog == cParams2.hashLog)
519 & (cParams1.chainLog == cParams2.chainLog)
520 & (cParams1.strategy == cParams2.strategy) /* opt parser space */
521 & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */
Yann Colleta7737f62016-09-06 09:44:59 +0200522}
523
524/*! ZSTD_continueCCtx() :
525 reuse CCtx without reset (note : requires no dictionary) */
526static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
527{
528 U32 const end = (U32)(cctx->nextSrc - cctx->base);
Yann Collet1ad7c822017-05-22 17:06:04 -0700529 cctx->appliedParams = params;
Yann Colleta7737f62016-09-06 09:44:59 +0200530 cctx->frameContentSize = frameContentSize;
Yann Collet20d5e032017-04-11 18:34:02 -0700531 cctx->consumedSrcSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200532 cctx->lowLimit = end;
533 cctx->dictLimit = end;
534 cctx->nextToUpdate = end+1;
535 cctx->stage = ZSTDcs_init;
536 cctx->dictID = 0;
537 cctx->loadedDictEnd = 0;
538 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200539 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
540 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200541 return 0;
542}
543
Yann Colletb0739bc2017-05-22 17:45:15 -0700544typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
Yann Colleta7737f62016-09-06 09:44:59 +0200545
Yann Collet30fb4992017-04-18 14:08:50 -0700546/*! ZSTD_resetCCtx_internal() :
Yann Collet5ac72b42017-05-23 11:18:24 -0700547 note : `params` are assumed fully validated at this stage */
548static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
549 ZSTD_parameters params, U64 frameContentSize,
550 ZSTD_compResetPolicy_e const crp,
551 ZSTD_buffered_policy_e const zbuff)
Yann Colleta7737f62016-09-06 09:44:59 +0200552{
Yann Collet5ac72b42017-05-23 11:18:24 -0700553 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet0be6fd32017-05-08 16:08:01 -0700554
Yann Colletb0739bc2017-05-22 17:45:15 -0700555 if (crp == ZSTDcrp_continue) {
Yann Collet1ad7c822017-05-22 17:06:04 -0700556 if (ZSTD_equivalentParams(params.cParams, zc->appliedParams.cParams)) {
Yann Collet009d6042017-05-19 10:17:59 -0700557 DEBUGLOG(5, "ZSTD_equivalentParams()==1");
Yann Collet71ddeb62017-04-20 22:54:54 -0700558 zc->fseCTables_ready = 0;
559 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200560 return ZSTD_continueCCtx(zc, params, frameContentSize);
Yann Colletb0739bc2017-05-22 17:45:15 -0700561 } }
inikep87d4f3d2016-03-02 15:56:24 +0100562
Yann Colletfa3671e2017-05-19 10:51:30 -0700563 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200564 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
565 size_t const maxNbSeq = blockSize / divider;
566 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet5ac72b42017-05-23 11:18:24 -0700567 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ?
568 0 : (1 << params.cParams.chainLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200569 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
Yann Collet5ac72b42017-05-23 11:18:24 -0700570 U32 const hashLog3 = (params.cParams.searchLength>3) ?
571 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200572 size_t const h3Size = ((size_t)1) << hashLog3;
573 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet5ac72b42017-05-23 11:18:24 -0700574 size_t const buffOutSize = ZSTD_compressBound(blockSize)+1;
575 size_t const buffInSize = ((size_t)1 << params.cParams.windowLog) + blockSize;
Yann Colleta7737f62016-09-06 09:44:59 +0200576 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100577
Yann Colleta7737f62016-09-06 09:44:59 +0200578 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Collet71ddeb62017-04-20 22:54:54 -0700579 { size_t const entropySpace = hufCTable_size + litlengthCTable_size
Yann Colleta4086452017-04-20 23:09:39 -0700580 + offcodeCTable_size + matchlengthCTable_size
Yann Collet72712032017-04-20 23:21:19 -0700581 + entropyScratchSpace_size;
Yann Collet71ddeb62017-04-20 22:54:54 -0700582 size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
Yann Collete6fa70a2017-04-20 17:28:31 -0700583 + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
Yann Collet5ac72b42017-05-23 11:18:24 -0700584 size_t const optSpace = ( (params.cParams.strategy == ZSTD_btopt)
585 || (params.cParams.strategy == ZSTD_btultra)) ?
586 optPotentialSpace : 0;
587 size_t const bufferSpace = (zbuff==ZSTDb_buffered) ?
588 buffInSize + buffOutSize : 0;
589 size_t const neededSpace = entropySpace + optSpace + tableSpace
590 + tokenSpace + bufferSpace;
Yann Colletc7fe2622017-05-23 13:16:00 -0700591
592 if (zc->workSpaceSize < neededSpace) { /* too small : resize /*/
Yann Collet0be6fd32017-05-08 16:08:01 -0700593 DEBUGLOG(5, "Need to update workSpaceSize from %uK to %uK \n",
Yann Colletc7fe2622017-05-23 13:16:00 -0700594 (unsigned)zc->workSpaceSize>>10,
595 (unsigned)neededSpace>>10);
596 /* static cctx : no resize, error out */
597 if (zc->staticSize) return ERROR(memory_allocation);
598
Yann Collet0181fef2017-04-06 01:25:26 -0700599 zc->workSpaceSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200600 ZSTD_free(zc->workSpace, zc->customMem);
601 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
602 if (zc->workSpace == NULL) return ERROR(memory_allocation);
603 zc->workSpaceSize = neededSpace;
Yann Collet7bb60b12017-04-20 17:38:56 -0700604 ptr = zc->workSpace;
605
606 /* entropy space */
Yann Collet71ddeb62017-04-20 22:54:54 -0700607 zc->hufCTable = (HUF_CElt*)ptr;
608 ptr = (char*)zc->hufCTable + hufCTable_size; /* note : HUF_CElt* is incomplete type, size is estimated via macro */
Yann Collet71aaa322017-04-20 23:03:38 -0700609 zc->offcodeCTable = (FSE_CTable*) ptr;
610 ptr = (char*)ptr + offcodeCTable_size;
Yann Collet72712032017-04-20 23:21:19 -0700611 zc->matchlengthCTable = (FSE_CTable*) ptr;
Yann Collet71aaa322017-04-20 23:03:38 -0700612 ptr = (char*)ptr + matchlengthCTable_size;
Yann Collet72712032017-04-20 23:21:19 -0700613 zc->litlengthCTable = (FSE_CTable*) ptr;
614 ptr = (char*)ptr + litlengthCTable_size;
615 assert(((size_t)ptr & 3) == 0); /* ensure correct alignment */
Yann Collete42afbc2017-04-26 11:39:35 -0700616 zc->entropyScratchSpace = (unsigned*) ptr;
Yann Colleta7737f62016-09-06 09:44:59 +0200617 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100618
Yann Collete6fa70a2017-04-20 17:28:31 -0700619 /* init params */
Yann Collet1ad7c822017-05-22 17:06:04 -0700620 zc->appliedParams = params;
Yann Collete6fa70a2017-04-20 17:28:31 -0700621 zc->frameContentSize = frameContentSize;
622 zc->consumedSrcSize = 0;
Yann Colletcc9f9b72017-06-15 18:17:10 -0700623 if (frameContentSize == ZSTD_CONTENTSIZE_UNKNOWN)
624 zc->appliedParams.fParams.contentSizeFlag = 0;
625 zc->blockSize = blockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100626
Yann Collet083fcc82015-10-25 14:06:35 +0100627 XXH64_reset(&zc->xxhState, 0);
Yann Collete6fa70a2017-04-20 17:28:31 -0700628 zc->stage = ZSTDcs_init;
629 zc->dictID = 0;
630 zc->loadedDictEnd = 0;
Yann Collet71ddeb62017-04-20 22:54:54 -0700631 zc->fseCTables_ready = 0;
632 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200633 zc->nextToUpdate = 1;
634 zc->nextSrc = NULL;
635 zc->base = NULL;
636 zc->dictBase = NULL;
637 zc->dictLimit = 0;
638 zc->lowLimit = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200639 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
Yann Collete6fa70a2017-04-20 17:28:31 -0700640 zc->hashLog3 = hashLog3;
641 zc->seqStore.litLengthSum = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200642
Yann Collet71aaa322017-04-20 23:03:38 -0700643 /* ensure entropy tables are close together at the beginning */
644 assert((void*)zc->hufCTable == zc->workSpace);
645 assert((char*)zc->offcodeCTable == (char*)zc->hufCTable + hufCTable_size);
646 assert((char*)zc->matchlengthCTable == (char*)zc->offcodeCTable + offcodeCTable_size);
647 assert((char*)zc->litlengthCTable == (char*)zc->matchlengthCTable + matchlengthCTable_size);
Yann Collete42afbc2017-04-26 11:39:35 -0700648 assert((char*)zc->entropyScratchSpace == (char*)zc->litlengthCTable + litlengthCTable_size);
649 ptr = (char*)zc->entropyScratchSpace + entropyScratchSpace_size;
Yann Collete6fa70a2017-04-20 17:28:31 -0700650
651 /* opt parser space */
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800652 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) {
Yann Collet009d6042017-05-19 10:17:59 -0700653 DEBUGLOG(5, "reserving optimal parser space");
Yann Collete6fa70a2017-04-20 17:28:31 -0700654 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
Yann Colleta7737f62016-09-06 09:44:59 +0200655 zc->seqStore.litFreq = (U32*)ptr;
656 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
657 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
658 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
659 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
660 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
661 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
662 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
663 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
Yann Colleta7737f62016-09-06 09:44:59 +0200664 }
Yann Collete6fa70a2017-04-20 17:28:31 -0700665
666 /* table Space */
667 if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
668 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
669 zc->hashTable = (U32*)(ptr);
670 zc->chainTable = zc->hashTable + hSize;
671 zc->hashTable3 = zc->chainTable + chainSize;
672 ptr = zc->hashTable3 + h3Size;
673
674 /* sequences storage */
Yann Colleta7737f62016-09-06 09:44:59 +0200675 zc->seqStore.sequencesStart = (seqDef*)ptr;
676 ptr = zc->seqStore.sequencesStart + maxNbSeq;
677 zc->seqStore.llCode = (BYTE*) ptr;
678 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
679 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
680 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
Yann Collet5ac72b42017-05-23 11:18:24 -0700681 ptr = zc->seqStore.litStart + blockSize;
682
683 /* buffers */
684 zc->inBuffSize = buffInSize;
685 zc->inBuff = (char*)ptr;
686 zc->outBuffSize = buffOutSize;
687 zc->outBuff = zc->inBuff + buffInSize;
Yann Colleta7737f62016-09-06 09:44:59 +0200688
Yann Colleta7737f62016-09-06 09:44:59 +0200689 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100690 }
Yann Colletf3eca252015-10-22 15:31:46 +0100691}
692
Yann Collet32dfae62017-01-19 10:32:55 -0800693/* ZSTD_invalidateRepCodes() :
694 * ensures next compression will not use repcodes from previous block.
695 * Note : only works with regular variant;
696 * do not use with extDict variant ! */
697void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
698 int i;
699 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0;
700}
Yann Collet083fcc82015-10-25 14:06:35 +0100701
Yann Collet7b51a292016-01-26 15:58:49 +0100702
Yann Colleta4cab802017-04-18 14:54:54 -0700703/*! ZSTD_copyCCtx_internal() :
704 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
705 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
706 * pledgedSrcSize=0 means "empty" if fParams.contentSizeFlag=1
707 * @return : 0, or an error code */
Yann Collet1ad7c822017-05-22 17:06:04 -0700708static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
709 const ZSTD_CCtx* srcCCtx,
710 ZSTD_frameParameters fParams,
711 unsigned long long pledgedSrcSize)
Yann Collet7b51a292016-01-26 15:58:49 +0100712{
Yann Collet009d6042017-05-19 10:17:59 -0700713 DEBUGLOG(5, "ZSTD_copyCCtx_internal");
Yann Collet7b51a292016-01-26 15:58:49 +0100714 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Sean Purcell2db72492017-02-09 10:50:43 -0800715
inikep28669512016-06-02 13:04:18 +0200716 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Yann Collet5ac72b42017-05-23 11:18:24 -0700717 { ZSTD_buffered_policy_e const zbuff = srcCCtx->inBuffSize ?
718 ZSTDb_buffered : ZSTDb_not_buffered;
719 ZSTD_parameters params = srcCCtx->appliedParams;
Yann Colleta4cab802017-04-18 14:54:54 -0700720 params.fParams = fParams;
Yann Collet5ac72b42017-05-23 11:18:24 -0700721 ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
722 ZSTDcrp_noMemset, zbuff);
Sean Purcell2db72492017-02-09 10:50:43 -0800723 }
Yann Collet7b51a292016-01-26 15:58:49 +0100724
725 /* copy tables */
Yann Collet1ad7c822017-05-22 17:06:04 -0700726 { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->appliedParams.cParams.chainLog);
727 size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +0200728 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
729 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collete6fa70a2017-04-20 17:28:31 -0700730 assert((U32*)dstCCtx->chainTable == (U32*)dstCCtx->hashTable + hSize); /* chainTable must follow hashTable */
731 assert((U32*)dstCCtx->hashTable3 == (U32*)dstCCtx->chainTable + chainSize);
732 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); /* presumes all tables follow each other */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100733 }
Yann Collet7b51a292016-01-26 15:58:49 +0100734
Yann Colletc46fb922016-05-29 05:01:04 +0200735 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100736 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
737 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
738 dstCCtx->nextSrc = srcCCtx->nextSrc;
739 dstCCtx->base = srcCCtx->base;
740 dstCCtx->dictBase = srcCCtx->dictBase;
741 dstCCtx->dictLimit = srcCCtx->dictLimit;
742 dstCCtx->lowLimit = srcCCtx->lowLimit;
743 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200744 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100745
Yann Colletfb810d62016-01-28 00:18:06 +0100746 /* copy entropy tables */
Yann Collet71ddeb62017-04-20 22:54:54 -0700747 dstCCtx->fseCTables_ready = srcCCtx->fseCTables_ready;
748 if (srcCCtx->fseCTables_ready) {
Yann Colleta34a39c2017-04-20 18:17:58 -0700749 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, litlengthCTable_size);
750 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, matchlengthCTable_size);
751 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, offcodeCTable_size);
Yann Colletfb810d62016-01-28 00:18:06 +0100752 }
Yann Collet71ddeb62017-04-20 22:54:54 -0700753 dstCCtx->hufCTable_repeatMode = srcCCtx->hufCTable_repeatMode;
754 if (srcCCtx->hufCTable_repeatMode) {
755 memcpy(dstCCtx->hufCTable, srcCCtx->hufCTable, hufCTable_size);
Nick Terrella4197772017-03-01 17:51:56 -0800756 }
Yann Collet7b51a292016-01-26 15:58:49 +0100757
758 return 0;
759}
760
Yann Colleta4cab802017-04-18 14:54:54 -0700761/*! ZSTD_copyCCtx() :
762 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
763 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
764 * pledgedSrcSize==0 means "unknown".
765* @return : 0, or an error code */
766size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
767{
768 ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
769 fParams.contentSizeFlag = pledgedSrcSize>0;
770
771 return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, fParams, pledgedSrcSize);
772}
773
Yann Collet7b51a292016-01-26 15:58:49 +0100774
Yann Colletecabfe32016-03-20 16:20:06 +0100775/*! ZSTD_reduceTable() :
Yann Colleta4cab802017-04-18 14:54:54 -0700776 * reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100777static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100778{
Yann Colletecabfe32016-03-20 16:20:06 +0100779 U32 u;
780 for (u=0 ; u < size ; u++) {
781 if (table[u] < reducerValue) table[u] = 0;
782 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100783 }
784}
785
Yann Colletecabfe32016-03-20 16:20:06 +0100786/*! ZSTD_reduceIndex() :
787* rescale all indexes to avoid future overflow (indexes are U32) */
788static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
789{
Yann Collet1ad7c822017-05-22 17:06:04 -0700790 { U32 const hSize = 1 << zc->appliedParams.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100791 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
792
Yann Collet1ad7c822017-05-22 17:06:04 -0700793 { U32 const chainSize = (zc->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->appliedParams.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200794 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100795
Yann Collet731ef162016-07-27 21:05:12 +0200796 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100797 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
798}
799
Yann Collet89db5e02015-11-13 11:27:46 +0100800
Yann Collet863ec402016-01-28 17:56:33 +0100801/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100802* Block entropic compression
803*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100804
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200805/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100806
Yann Colletd1b26842016-03-15 01:24:33 +0100807size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100808{
Yann Colletd1b26842016-03-15 01:24:33 +0100809 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200810 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
811 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100812 return ZSTD_blockHeaderSize+srcSize;
813}
814
815
Yann Colletd1b26842016-03-15 01:24:33 +0100816static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100817{
818 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200819 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100820
Yann Colletd1b26842016-03-15 01:24:33 +0100821 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100822
Yann Collet59d1f792016-01-23 19:28:41 +0100823 switch(flSize)
824 {
825 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200826 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100827 break;
828 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200829 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100830 break;
Yann Collet59d1f792016-01-23 19:28:41 +0100831 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200832 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100833 break;
Yann Colletcd2892f2017-06-01 09:44:54 -0700834 default: /* not necessary : flSize is {1,2,3} */
835 assert(0);
Yann Collet59d1f792016-01-23 19:28:41 +0100836 }
837
838 memcpy(ostart + flSize, src, srcSize);
839 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100840}
841
Yann Colletd1b26842016-03-15 01:24:33 +0100842static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100843{
844 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200845 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100846
Yann Collet198e6aa2016-07-20 20:12:24 +0200847 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100848
849 switch(flSize)
850 {
851 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200852 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100853 break;
854 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200855 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100856 break;
Yann Collet59d1f792016-01-23 19:28:41 +0100857 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200858 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100859 break;
Yann Colletcd2892f2017-06-01 09:44:54 -0700860 default: /* not necessary : flSize is {1,2,3} */
861 assert(0);
Yann Collet59d1f792016-01-23 19:28:41 +0100862 }
863
864 ostart[flSize] = *(const BYTE*)src;
865 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100866}
867
Yann Collet59d1f792016-01-23 19:28:41 +0100868
Yann Colleta5c2c082016-03-20 01:09:18 +0100869static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100870
Yann Colletb923f652016-01-26 03:14:20 +0100871static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100872 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100873 const void* src, size_t srcSize)
874{
Yann Colleta910dc82016-03-18 12:37:45 +0100875 size_t const minGain = ZSTD_minGain(srcSize);
876 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200877 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100878 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200879 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100880 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100881
Yann Collet14983e72015-11-11 21:38:21 +0100882
Yann Colleta5c2c082016-03-20 01:09:18 +0100883 /* small ? don't even attempt compression (speed opt) */
884# define LITERAL_NOENTROPY 63
Yann Collet71ddeb62017-04-20 22:54:54 -0700885 { size_t const minLitSize = zc->hufCTable_repeatMode == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
Yann Colleta5c2c082016-03-20 01:09:18 +0100886 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
887 }
888
889 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Collet71ddeb62017-04-20 22:54:54 -0700890 { HUF_repeat repeat = zc->hufCTable_repeatMode;
Yann Collet1ad7c822017-05-22 17:06:04 -0700891 int const preferRepeat = zc->appliedParams.cParams.strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
Nick Terrella4197772017-03-01 17:51:56 -0800892 if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
Yann Collete348dad2017-04-20 11:14:13 -0700893 cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Yann Collete42afbc2017-04-26 11:39:35 -0700894 zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat)
Yann Collete348dad2017-04-20 11:14:13 -0700895 : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Yann Collete42afbc2017-04-26 11:39:35 -0700896 zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat);
Nick Terrella4197772017-03-01 17:51:56 -0800897 if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
Yann Collet71ddeb62017-04-20 22:54:54 -0700898 else { zc->hufCTable_repeatMode = HUF_repeat_check; } /* now have a table to reuse */
Yann Colletb923f652016-01-26 03:14:20 +0100899 }
Yann Collet14983e72015-11-11 21:38:21 +0100900
Nick Terrella4197772017-03-01 17:51:56 -0800901 if ((cLitSize==0) | (cLitSize >= srcSize - minGain)) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700902 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100903 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800904 }
905 if (cLitSize==1) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700906 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100907 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800908 }
Yann Collet14983e72015-11-11 21:38:21 +0100909
910 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100911 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100912 {
Yann Collet59d1f792016-01-23 19:28:41 +0100913 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200914 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200915 MEM_writeLE24(ostart, lhc);
916 break;
917 }
Yann Collet59d1f792016-01-23 19:28:41 +0100918 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200919 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200920 MEM_writeLE32(ostart, lhc);
921 break;
922 }
Yann Collet59d1f792016-01-23 19:28:41 +0100923 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200924 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200925 MEM_writeLE32(ostart, lhc);
926 ostart[4] = (BYTE)(cLitSize >> 10);
927 break;
928 }
Yann Colletcd2892f2017-06-01 09:44:54 -0700929 default: /* not possible : lhSize is {3,4,5} */
930 assert(0);
Yann Collet14983e72015-11-11 21:38:21 +0100931 }
Yann Colleta910dc82016-03-18 12:37:45 +0100932 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100933}
934
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200935static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
936 8, 9, 10, 11, 12, 13, 14, 15,
937 16, 16, 17, 17, 18, 18, 19, 19,
938 20, 20, 20, 20, 21, 21, 21, 21,
939 22, 22, 22, 22, 22, 22, 22, 22,
940 23, 23, 23, 23, 23, 23, 23, 23,
941 24, 24, 24, 24, 24, 24, 24, 24,
942 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100943
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200944static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
945 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
946 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
947 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
948 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
949 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
950 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
951 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200952
953
954void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100955{
Yann Colleted57d852016-07-29 21:22:17 +0200956 BYTE const LL_deltaCode = 19;
957 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200958 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200959 BYTE* const llCodeTable = seqStorePtr->llCode;
960 BYTE* const ofCodeTable = seqStorePtr->ofCode;
961 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200962 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200963 U32 u;
964 for (u=0; u<nbSeq; u++) {
965 U32 const llv = sequences[u].litLength;
966 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200967 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200968 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200969 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200970 }
Yann Colleted57d852016-07-29 21:22:17 +0200971 if (seqStorePtr->longLengthID==1)
972 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
973 if (seqStorePtr->longLengthID==2)
974 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100975}
976
Sean Purcell553f67e2017-03-02 15:15:31 -0800977MEM_STATIC size_t ZSTD_compressSequences (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100978 void* dst, size_t dstCapacity,
Sean Purcell553f67e2017-03-02 15:15:31 -0800979 size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100980{
Yann Collet1ad7c822017-05-22 17:06:04 -0700981 const int longOffsets = zc->appliedParams.cParams.windowLog > STREAM_ACCUMULATOR_MIN;
Yann Colletb923f652016-01-26 03:14:20 +0100982 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100983 U32 count[MaxSeq+1];
984 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100985 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
986 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
987 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100988 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200989 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200990 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
991 const BYTE* const llCodeTable = seqStorePtr->llCode;
992 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +0100993 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100994 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100995 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200996 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +0100997 BYTE* seqHead;
Yann Colletd79a9a02016-11-30 15:52:20 -0800998 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Collet14983e72015-11-11 21:38:21 +0100999
Yann Collet14983e72015-11-11 21:38:21 +01001000 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +01001001 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +01001002 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +01001003 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +01001004 if (ZSTD_isError(cSize)) return cSize;
1005 op += cSize;
1006 }
1007
1008 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +01001009 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +01001010 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
1011 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
1012 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +01001013 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +01001014
Yann Colletbe391432016-03-22 23:19:28 +01001015 /* seqHead : flags for FSE encoding type */
1016 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +01001017
Yann Colletfb810d62016-01-28 00:18:06 +01001018#define MIN_SEQ_FOR_DYNAMIC_FSE 64
1019#define MAX_SEQ_FOR_STATIC_FSE 1000
1020
Yann Colletb44be742016-03-26 20:52:14 +01001021 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +02001022 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +01001023
Yann Collet14983e72015-11-11 21:38:21 +01001024 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +01001025 { U32 max = MaxLL;
Yann Collete42afbc2017-04-26 11:39:35 -07001026 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +01001027 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
1028 *op++ = llCodeTable[0];
1029 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +02001030 LLtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -07001031 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +02001032 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +01001033 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -08001034 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001035 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +01001036 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +01001037 size_t nbSeq_1 = nbSeq;
1038 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
1039 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
1040 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +01001041 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -07001042 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +01001043 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -08001044 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001045 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +01001046 } }
Yann Collet14983e72015-11-11 21:38:21 +01001047
Yann Colletb44be742016-03-26 20:52:14 +01001048 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +01001049 { U32 max = MaxOff;
Yann Collete42afbc2017-04-26 11:39:35 -07001050 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +01001051 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +01001052 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +01001053 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +02001054 Offtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -07001055 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +02001056 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +02001057 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -08001058 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001059 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +01001060 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +01001061 size_t nbSeq_1 = nbSeq;
1062 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +01001063 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +01001064 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +01001065 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -07001066 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +01001067 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -08001068 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001069 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +01001070 } }
1071
Yann Collet14983e72015-11-11 21:38:21 +01001072 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +01001073 { U32 max = MaxML;
Yann Collete42afbc2017-04-26 11:39:35 -07001074 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +01001075 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +01001076 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +01001077 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +02001078 MLtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -07001079 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +02001080 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +01001081 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -08001082 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001083 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +01001084 } else {
1085 size_t nbSeq_1 = nbSeq;
1086 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
1087 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
1088 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
1089 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -07001090 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletfadda6c2016-03-22 12:14:26 +01001091 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -08001092 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001093 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +01001094 } }
Yann Collet14983e72015-11-11 21:38:21 +01001095
Yann Colletbe391432016-03-22 23:19:28 +01001096 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Collet71ddeb62017-04-20 22:54:54 -07001097 zc->fseCTables_ready = 0;
Yann Collet14983e72015-11-11 21:38:21 +01001098
1099 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +01001100 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +01001101 FSE_CState_t stateMatchLength;
1102 FSE_CState_t stateOffsetBits;
1103 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +01001104
Yann Collet95d07d72016-09-06 16:38:51 +02001105 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +01001106
Yann Collet597847a2016-03-20 19:14:22 +01001107 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +01001108 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +01001109 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +01001110 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +02001111 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +01001112 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +02001113 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +01001114 if (MEM_32bits()) BIT_flushBits(&blockStream);
Sean Purcelld44703d2017-03-01 14:36:25 -08001115 if (longOffsets) {
1116 U32 const ofBits = ofCodeTable[nbSeq-1];
1117 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1118 if (extraBits) {
1119 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
1120 BIT_flushBits(&blockStream);
1121 }
1122 BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
1123 ofBits - extraBits);
1124 } else {
1125 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
1126 }
Yann Collet597847a2016-03-20 19:14:22 +01001127 BIT_flushBits(&blockStream);
1128
Yann Colletfadda6c2016-03-22 12:14:26 +01001129 { size_t n;
1130 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +02001131 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +02001132 BYTE const ofCode = ofCodeTable[n];
1133 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +02001134 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +02001135 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +02001136 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +01001137 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +01001138 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
1139 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
1140 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
1141 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +02001142 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +01001143 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +02001144 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +01001145 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +02001146 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +01001147 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Sean Purcelld44703d2017-03-01 14:36:25 -08001148 if (longOffsets) {
1149 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1150 if (extraBits) {
1151 BIT_addBits(&blockStream, sequences[n].offset, extraBits);
1152 BIT_flushBits(&blockStream); /* (7)*/
1153 }
1154 BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
1155 ofBits - extraBits); /* 31 */
1156 } else {
1157 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
1158 }
Yann Colletb9151402016-03-26 17:18:11 +01001159 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +01001160 } }
Yann Collet14983e72015-11-11 21:38:21 +01001161
1162 FSE_flushCState(&blockStream, &stateMatchLength);
1163 FSE_flushCState(&blockStream, &stateOffsetBits);
1164 FSE_flushCState(&blockStream, &stateLitLength);
1165
Yann Colletb9151402016-03-26 17:18:11 +01001166 { size_t const streamSize = BIT_closeCStream(&blockStream);
1167 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
1168 op += streamSize;
1169 } }
Yann Collet14983e72015-11-11 21:38:21 +01001170
1171 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +01001172_check_compressibility:
Nick Terrella4197772017-03-01 17:51:56 -08001173 { size_t const minGain = ZSTD_minGain(srcSize);
1174 size_t const maxCSize = srcSize - minGain;
1175 if ((size_t)(op-ostart) >= maxCSize) {
Yann Collet71ddeb62017-04-20 22:54:54 -07001176 zc->hufCTable_repeatMode = HUF_repeat_none;
Nick Terrella4197772017-03-01 17:51:56 -08001177 return 0;
1178 } }
Yann Collet14983e72015-11-11 21:38:21 +01001179
Yann Collet4266c0a2016-06-14 01:49:25 +02001180 /* confirm repcodes */
Yann Colletb459aad2017-01-19 17:33:37 -08001181 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; }
Yann Collet4266c0a2016-06-14 01:49:25 +02001182
Yann Collet5054ee02015-11-23 13:34:21 +01001183 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +01001184}
1185
Yann Colletbb002742017-01-25 16:25:38 -08001186
Yann Collet95cd0c22016-03-08 18:24:21 +01001187/*! ZSTD_storeSeq() :
1188 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
1189 `offsetCode` : distance to match, or 0 == repCode.
1190 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +01001191*/
Yann Colletd57dffb2016-07-03 01:48:26 +02001192MEM_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 +01001193{
Yann Collet009d6042017-05-19 10:17:59 -07001194#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
1195 static const BYTE* g_start = NULL;
1196 U32 const pos = (U32)((const BYTE*)literals - g_start);
1197 if (g_start==NULL) g_start = (const BYTE*)literals;
1198 if ((pos > 0) && (pos < 1000000000))
1199 DEBUGLOG(6, "Cpos %6u :%5u literals & match %3u bytes at distance %6u",
1200 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +01001201#endif
Yann Collet14983e72015-11-11 21:38:21 +01001202 /* copy Literals */
Yann Collet009d6042017-05-19 10:17:59 -07001203 assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB);
Yann Collet14983e72015-11-11 21:38:21 +01001204 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
1205 seqStorePtr->lit += litLength;
1206
1207 /* literal Length */
Yann Collete6fa70a2017-04-20 17:28:31 -07001208 if (litLength>0xFFFF) {
1209 seqStorePtr->longLengthID = 1;
1210 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
1211 }
Yann Colletc0ce4f12016-07-30 00:55:13 +02001212 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +01001213
1214 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +02001215 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +01001216
1217 /* match Length */
Yann Collete6fa70a2017-04-20 17:28:31 -07001218 if (matchCode>0xFFFF) {
1219 seqStorePtr->longLengthID = 2;
1220 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
1221 }
Yann Colletc0ce4f12016-07-30 00:55:13 +02001222 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +02001223
Yann Colletc0ce4f12016-07-30 00:55:13 +02001224 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +01001225}
1226
1227
Yann Collet7d360282016-02-12 00:07:30 +01001228/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001229* Match length counter
1230***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +01001231static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +01001232{
Yann Collet863ec402016-01-28 17:56:33 +01001233 if (MEM_isLittleEndian()) {
1234 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +01001235# if defined(_MSC_VER) && defined(_WIN64)
1236 unsigned long r = 0;
1237 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +01001238 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +01001239# elif defined(__GNUC__) && (__GNUC__ >= 3)
1240 return (__builtin_ctzll((U64)val) >> 3);
1241# else
Yann Collete348dad2017-04-20 11:14:13 -07001242 static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
1243 0, 3, 1, 3, 1, 4, 2, 7,
1244 0, 2, 3, 6, 1, 5, 3, 5,
1245 1, 3, 4, 4, 2, 5, 6, 7,
1246 7, 0, 1, 2, 3, 3, 4, 6,
1247 2, 6, 5, 5, 3, 4, 5, 6,
1248 7, 1, 2, 4, 6, 4, 4, 5,
1249 7, 2, 6, 5, 7, 6, 7, 7 };
Yann Collet14983e72015-11-11 21:38:21 +01001250 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
1251# endif
Yann Collet863ec402016-01-28 17:56:33 +01001252 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +01001253# if defined(_MSC_VER)
1254 unsigned long r=0;
1255 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +01001256 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +01001257# elif defined(__GNUC__) && (__GNUC__ >= 3)
1258 return (__builtin_ctz((U32)val) >> 3);
1259# else
Yann Collete348dad2017-04-20 11:14:13 -07001260 static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
1261 3, 2, 2, 1, 3, 2, 0, 1,
1262 3, 3, 1, 2, 2, 2, 2, 0,
1263 3, 1, 2, 0, 1, 0, 1, 1 };
Yann Collet14983e72015-11-11 21:38:21 +01001264 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
1265# endif
1266 }
Yann Collet863ec402016-01-28 17:56:33 +01001267 } else { /* Big Endian CPU */
1268 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +01001269# if defined(_MSC_VER) && defined(_WIN64)
1270 unsigned long r = 0;
1271 _BitScanReverse64( &r, val );
1272 return (unsigned)(r>>3);
1273# elif defined(__GNUC__) && (__GNUC__ >= 3)
1274 return (__builtin_clzll(val) >> 3);
1275# else
1276 unsigned r;
1277 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
1278 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
1279 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
1280 r += (!val);
1281 return r;
1282# endif
Yann Collet863ec402016-01-28 17:56:33 +01001283 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +01001284# if defined(_MSC_VER)
1285 unsigned long r = 0;
1286 _BitScanReverse( &r, (unsigned long)val );
1287 return (unsigned)(r>>3);
1288# elif defined(__GNUC__) && (__GNUC__ >= 3)
1289 return (__builtin_clz((U32)val) >> 3);
1290# else
1291 unsigned r;
1292 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
1293 r += (!val);
1294 return r;
1295# endif
Yann Collet863ec402016-01-28 17:56:33 +01001296 } }
Yann Collet14983e72015-11-11 21:38:21 +01001297}
1298
1299
Yann Colleta436a522016-06-20 23:34:04 +02001300static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +01001301{
1302 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +02001303 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +01001304
Yann Colleta436a522016-06-20 23:34:04 +02001305 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +02001306 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +01001307 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
1308 pIn += ZSTD_NbCommonBytes(diff);
1309 return (size_t)(pIn - pStart);
1310 }
Yann Collet14983e72015-11-11 21:38:21 +01001311 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
1312 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
1313 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
1314 return (size_t)(pIn - pStart);
1315}
1316
Yann Collet04b12d82016-02-11 06:23:24 +01001317/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +01001318* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +01001319* convention : on reaching mEnd, match count continue starting from iStart
1320*/
1321static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
1322{
Yann Collet7591a7f2016-05-20 11:44:43 +02001323 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +02001324 size_t const matchLength = ZSTD_count(ip, match, vEnd);
1325 if (match + matchLength != mEnd) return matchLength;
1326 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +01001327}
1328
Yann Collet14983e72015-11-11 21:38:21 +01001329
Yann Collet863ec402016-01-28 17:56:33 +01001330/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001331* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +01001332***************************************/
inikepcc52a972016-02-19 10:09:35 +01001333static const U32 prime3bytes = 506832829U;
1334static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Collete6fa70a2017-04-20 17:28:31 -07001335MEM_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 +01001336
Yann Collet4b100f42015-10-30 15:49:48 +01001337static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +01001338static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +01001339static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +01001340
Yann Collet4b100f42015-10-30 15:49:48 +01001341static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001342static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001343static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001344
1345static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001346static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001347static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001348
Yann Collet14983e72015-11-11 21:38:21 +01001349static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001350static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001351static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001352
Yann Collet45dc3562016-07-12 09:47:31 +02001353static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
1354static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
1355static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
1356
Yann Collet5be2dd22015-11-11 13:43:58 +01001357static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001358{
1359 switch(mls)
1360 {
1361 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001362 case 4: return ZSTD_hash4Ptr(p, hBits);
1363 case 5: return ZSTD_hash5Ptr(p, hBits);
1364 case 6: return ZSTD_hash6Ptr(p, hBits);
1365 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +02001366 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001367 }
1368}
Yann Collet2acb5d32015-10-29 16:49:43 +01001369
Yann Collet863ec402016-01-28 17:56:33 +01001370
Yann Collet2ce49232016-02-02 14:36:49 +01001371/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001372* Fast Scan
1373***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001374static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1375{
1376 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001377 U32 const hBits = zc->appliedParams.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001378 const BYTE* const base = zc->base;
1379 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001380 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001381 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001382
Yann Colletfb810d62016-01-28 00:18:06 +01001383 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001384 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001385 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001386 }
1387}
1388
1389
Yann Collet1f44b3f2015-11-05 17:32:18 +01001390FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +02001391void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +02001392 const void* src, size_t srcSize,
1393 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001394{
Yann Collet4266c0a2016-06-14 01:49:25 +02001395 U32* const hashTable = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001396 U32 const hBits = cctx->appliedParams.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +02001397 seqStore_t* seqStorePtr = &(cctx->seqStore);
1398 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001399 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001400 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001401 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +02001402 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +02001403 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001404 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001405 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +02001406 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1407 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001408
Yann Collet1f44b3f2015-11-05 17:32:18 +01001409 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001410 ip += (ip==lowest);
1411 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +02001412 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1413 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +02001414 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001415
1416 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +02001417 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +02001418 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +02001419 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
1420 U32 const current = (U32)(ip-base);
1421 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +01001422 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001423 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001424
Yann Collet280f9a82016-08-08 00:44:00 +02001425 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +02001426 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +01001427 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001428 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1429 } else {
Yann Collet92d75662016-07-03 01:10:53 +02001430 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001431 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001432 ip += ((ip-anchor) >> g_searchStrength) + 1;
1433 continue;
1434 }
Yann Collet45dc3562016-07-12 09:47:31 +02001435 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001436 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001437 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001438 offset_2 = offset_1;
1439 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001440
Yann Colleta436a522016-06-20 23:34:04 +02001441 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001442 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001443
Yann Collet402fdcf2015-11-20 12:46:08 +01001444 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001445 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001446 anchor = ip;
1447
Yann Colletfb810d62016-01-28 00:18:06 +01001448 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001449 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001450 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 +01001451 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1452 /* check immediate repcode */
1453 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001454 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001455 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001456 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001457 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001458 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001459 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001460 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1461 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001462 anchor = ip;
1463 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001464 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001465
Yann Collet4266c0a2016-06-14 01:49:25 +02001466 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001467 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1468 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001469
Yann Collet70e45772016-03-19 18:08:32 +01001470 /* Last Literals */
1471 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001472 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1473 seqStorePtr->lit += lastLLSize;
1474 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001475}
1476
1477
Yann Collet82260dd2016-02-11 07:14:25 +01001478static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001479 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001480{
Yann Collet1ad7c822017-05-22 17:06:04 -07001481 const U32 mls = ctx->appliedParams.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001482 switch(mls)
1483 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001484 default: /* includes case 3 */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001485 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001486 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001487 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001488 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001489 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001490 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001491 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001492 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001493 }
1494}
Yann Colletf3eca252015-10-22 15:31:46 +01001495
Yann Colletf3eca252015-10-22 15:31:46 +01001496
Yann Collet82260dd2016-02-11 07:14:25 +01001497static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001498 const void* src, size_t srcSize,
1499 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001500{
1501 U32* hashTable = ctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001502 const U32 hBits = ctx->appliedParams.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001503 seqStore_t* seqStorePtr = &(ctx->seqStore);
1504 const BYTE* const base = ctx->base;
1505 const BYTE* const dictBase = ctx->dictBase;
1506 const BYTE* const istart = (const BYTE*)src;
1507 const BYTE* ip = istart;
1508 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001509 const U32 lowestIndex = ctx->lowLimit;
1510 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001511 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001512 const BYTE* const lowPrefixPtr = base + dictLimit;
1513 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001514 const BYTE* const iend = istart + srcSize;
1515 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001516 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001517
Yann Colleta436a522016-06-20 23:34:04 +02001518 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001519 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001520 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001521 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001522 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001523 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001524 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001525 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001526 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001527 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001528 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001529 hashTable[h] = current; /* update hash table */
1530
Yann Colleta436a522016-06-20 23:34:04 +02001531 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001532 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001533 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001534 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
Yann Collet743402c2015-11-20 12:03:53 +01001535 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001536 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001537 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001538 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001539 (MEM_read32(match) != MEM_read32(ip)) ) {
1540 ip += ((ip-anchor) >> g_searchStrength) + 1;
1541 continue;
1542 }
1543 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001544 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001545 U32 offset;
Yann Collete6fa70a2017-04-20 17:28:31 -07001546 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
Yann Colleta436a522016-06-20 23:34:04 +02001547 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001548 offset = current - matchIndex;
1549 offset_2 = offset_1;
1550 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001551 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001552 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001553
Yann Collet5054ee02015-11-23 13:34:21 +01001554 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001555 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001556 anchor = ip;
1557
Yann Colletfb810d62016-01-28 00:18:06 +01001558 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001559 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001560 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001561 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1562 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001563 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001564 U32 const current2 = (U32)(ip-base);
1565 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001566 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001567 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1568 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001569 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001570 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet5054ee02015-11-23 13:34:21 +01001571 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001572 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001573 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001574 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001575 anchor = ip;
1576 continue;
1577 }
Yann Collet743402c2015-11-20 12:03:53 +01001578 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001579 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001580
Yann Collet4266c0a2016-06-14 01:49:25 +02001581 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001582 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001583
Yann Collet89db5e02015-11-13 11:27:46 +01001584 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001585 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001586 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1587 seqStorePtr->lit += lastLLSize;
1588 }
Yann Collet89db5e02015-11-13 11:27:46 +01001589}
1590
1591
Yann Collet82260dd2016-02-11 07:14:25 +01001592static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001593 const void* src, size_t srcSize)
1594{
Yann Collet1ad7c822017-05-22 17:06:04 -07001595 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001596 switch(mls)
1597 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001598 default: /* includes case 3 */
Yann Collet89db5e02015-11-13 11:27:46 +01001599 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001600 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001601 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001602 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001603 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001604 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001605 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001606 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001607 }
1608}
1609
1610
Yann Collet04b12d82016-02-11 06:23:24 +01001611/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001612* Double Fast
1613***************************************/
1614static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1615{
1616 U32* const hashLarge = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001617 U32 const hBitsL = cctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001618 U32* const hashSmall = cctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001619 U32 const hBitsS = cctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001620 const BYTE* const base = cctx->base;
1621 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001622 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001623 const size_t fastHashFillStep = 3;
1624
1625 while(ip <= iend) {
1626 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1627 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1628 ip += fastHashFillStep;
1629 }
1630}
1631
1632
1633FORCE_INLINE
1634void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1635 const void* src, size_t srcSize,
1636 const U32 mls)
1637{
1638 U32* const hashLong = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001639 const U32 hBitsL = cctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001640 U32* const hashSmall = cctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001641 const U32 hBitsS = cctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001642 seqStore_t* seqStorePtr = &(cctx->seqStore);
1643 const BYTE* const base = cctx->base;
1644 const BYTE* const istart = (const BYTE*)src;
1645 const BYTE* ip = istart;
1646 const BYTE* anchor = istart;
1647 const U32 lowestIndex = cctx->dictLimit;
1648 const BYTE* const lowest = base + lowestIndex;
1649 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001650 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001651 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1652 U32 offsetSaved = 0;
1653
1654 /* init */
1655 ip += (ip==lowest);
1656 { U32 const maxRep = (U32)(ip-lowest);
1657 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1658 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1659 }
1660
1661 /* Main Search Loop */
1662 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1663 size_t mLength;
1664 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1665 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1666 U32 const current = (U32)(ip-base);
1667 U32 const matchIndexL = hashLong[h2];
1668 U32 const matchIndexS = hashSmall[h];
1669 const BYTE* matchLong = base + matchIndexL;
1670 const BYTE* match = base + matchIndexS;
1671 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1672
Yann Colletc17e0202017-04-20 12:50:02 -07001673 assert(offset_1 <= current); /* supposed guaranteed by construction */
1674 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001675 /* favor repcode */
Yann Collet45dc3562016-07-12 09:47:31 +02001676 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1677 ip++;
1678 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1679 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001680 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001681 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1682 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001683 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001684 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1685 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001686 size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1687 U32 const matchIndexL3 = hashLong[hl3];
1688 const BYTE* matchL3 = base + matchIndexL3;
1689 hashLong[hl3] = current + 1;
1690 if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
1691 mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
Yann Colletc54692f2016-08-24 01:10:42 +02001692 ip++;
Yann Collete6fa70a2017-04-20 17:28:31 -07001693 offset = (U32)(ip-matchL3);
1694 while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
Yann Colletc54692f2016-08-24 01:10:42 +02001695 } else {
1696 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1697 offset = (U32)(ip-match);
1698 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1699 }
Yann Collet45dc3562016-07-12 09:47:31 +02001700 } else {
1701 ip += ((ip-anchor) >> g_searchStrength) + 1;
1702 continue;
1703 }
1704
1705 offset_2 = offset_1;
1706 offset_1 = offset;
1707
1708 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1709 }
1710
1711 /* match found */
1712 ip += mLength;
1713 anchor = ip;
1714
1715 if (ip <= ilimit) {
1716 /* Fill Table */
1717 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1718 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1719 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1720 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1721
1722 /* check immediate repcode */
1723 while ( (ip <= ilimit)
1724 && ( (offset_2>0)
1725 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1726 /* store sequence */
1727 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001728 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001729 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1730 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1731 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1732 ip += rLength;
1733 anchor = ip;
1734 continue; /* faster when present ... (?) */
1735 } } }
1736
1737 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001738 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1739 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet45dc3562016-07-12 09:47:31 +02001740
1741 /* Last Literals */
1742 { size_t const lastLLSize = iend - anchor;
1743 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1744 seqStorePtr->lit += lastLLSize;
1745 }
1746}
1747
1748
1749static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1750{
Yann Collet1ad7c822017-05-22 17:06:04 -07001751 const U32 mls = ctx->appliedParams.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001752 switch(mls)
1753 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001754 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001755 case 4 :
1756 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1757 case 5 :
1758 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1759 case 6 :
1760 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1761 case 7 :
1762 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1763 }
1764}
1765
1766
1767static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1768 const void* src, size_t srcSize,
1769 const U32 mls)
1770{
1771 U32* const hashLong = ctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001772 U32 const hBitsL = ctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001773 U32* const hashSmall = ctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001774 U32 const hBitsS = ctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001775 seqStore_t* seqStorePtr = &(ctx->seqStore);
1776 const BYTE* const base = ctx->base;
1777 const BYTE* const dictBase = ctx->dictBase;
1778 const BYTE* const istart = (const BYTE*)src;
1779 const BYTE* ip = istart;
1780 const BYTE* anchor = istart;
1781 const U32 lowestIndex = ctx->lowLimit;
1782 const BYTE* const dictStart = dictBase + lowestIndex;
1783 const U32 dictLimit = ctx->dictLimit;
1784 const BYTE* const lowPrefixPtr = base + dictLimit;
1785 const BYTE* const dictEnd = dictBase + dictLimit;
1786 const BYTE* const iend = istart + srcSize;
1787 const BYTE* const ilimit = iend - 8;
1788 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1789
1790 /* Search Loop */
1791 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1792 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1793 const U32 matchIndex = hashSmall[hSmall];
1794 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1795 const BYTE* match = matchBase + matchIndex;
1796
1797 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1798 const U32 matchLongIndex = hashLong[hLong];
1799 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1800 const BYTE* matchLong = matchLongBase + matchLongIndex;
1801
1802 const U32 current = (U32)(ip-base);
1803 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1804 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1805 const BYTE* repMatch = repBase + repIndex;
1806 size_t mLength;
1807 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1808
1809 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1810 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1811 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1812 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1813 ip++;
1814 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1815 } else {
1816 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1817 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1818 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1819 U32 offset;
1820 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1821 offset = current - matchLongIndex;
1822 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1823 offset_2 = offset_1;
1824 offset_1 = offset;
1825 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001826
Yann Collet73d74a02016-07-12 13:03:48 +02001827 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001828 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1829 U32 const matchIndex3 = hashLong[h3];
1830 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1831 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001832 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001833 hashLong[h3] = current + 1;
1834 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1835 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1836 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1837 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1838 ip++;
1839 offset = current+1 - matchIndex3;
1840 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1841 } else {
1842 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1843 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1844 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1845 offset = current - matchIndex;
1846 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1847 }
Yann Collet45dc3562016-07-12 09:47:31 +02001848 offset_2 = offset_1;
1849 offset_1 = offset;
1850 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001851
Yann Collet45dc3562016-07-12 09:47:31 +02001852 } else {
1853 ip += ((ip-anchor) >> g_searchStrength) + 1;
1854 continue;
1855 } }
1856
1857 /* found a match : store it */
1858 ip += mLength;
1859 anchor = ip;
1860
1861 if (ip <= ilimit) {
1862 /* Fill Table */
Nick Terrellf35ef5c2017-03-09 12:51:33 -08001863 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1864 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
Yann Collet45dc3562016-07-12 09:47:31 +02001865 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1866 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1867 /* check immediate repcode */
1868 while (ip <= ilimit) {
1869 U32 const current2 = (U32)(ip-base);
1870 U32 const repIndex2 = current2 - offset_2;
1871 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1872 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1873 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1874 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07001875 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet45dc3562016-07-12 09:47:31 +02001876 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1877 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1878 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1879 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1880 ip += repLength2;
1881 anchor = ip;
1882 continue;
1883 }
1884 break;
1885 } } }
1886
1887 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001888 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet45dc3562016-07-12 09:47:31 +02001889
1890 /* Last Literals */
1891 { size_t const lastLLSize = iend - anchor;
1892 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1893 seqStorePtr->lit += lastLLSize;
1894 }
1895}
1896
1897
1898static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1899 const void* src, size_t srcSize)
1900{
Yann Collet1ad7c822017-05-22 17:06:04 -07001901 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001902 switch(mls)
1903 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001904 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001905 case 4 :
1906 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1907 case 5 :
1908 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1909 case 6 :
1910 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1911 case 7 :
1912 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1913 }
1914}
1915
1916
1917/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001918* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001919***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001920/** ZSTD_insertBt1() : add one or multiple positions to tree.
1921* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001922* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001923static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1924 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001925{
Yann Collet731ef162016-07-27 21:05:12 +02001926 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001927 U32 const hashLog = zc->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +02001928 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1929 U32* const bt = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001930 U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
Yann Collet731ef162016-07-27 21:05:12 +02001931 U32 const btMask = (1 << btLog) - 1;
1932 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001933 size_t commonLengthSmaller=0, commonLengthLarger=0;
1934 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001935 const BYTE* const dictBase = zc->dictBase;
1936 const U32 dictLimit = zc->dictLimit;
1937 const BYTE* const dictEnd = dictBase + dictLimit;
1938 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07001939 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001940 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001941 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001942 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001943 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001944 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001945 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001946 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001947 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001948#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001949 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1950 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1951 predictedSmall += (predictedSmall>0);
1952 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001953#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001954
Yann Collet6c3e2e72015-12-11 10:44:07 +01001955 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001956
Yann Colletfb810d62016-01-28 00:18:06 +01001957 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001958 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001959 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08001960
Yann Colletc0932082016-06-30 14:07:30 +02001961#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001962 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001963 if (matchIndex == predictedSmall) {
1964 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001965 *smallerPtr = matchIndex;
1966 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1967 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1968 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001969 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001970 continue;
1971 }
Yann Colletfb810d62016-01-28 00:18:06 +01001972 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001973 *largerPtr = matchIndex;
1974 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1975 largerPtr = nextPtr;
1976 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001977 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001978 continue;
1979 }
Yann Collet04b12d82016-02-11 06:23:24 +01001980#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001981 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001982 match = base + matchIndex;
1983 if (match[matchLength] == ip[matchLength])
1984 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001985 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001986 match = dictBase + matchIndex;
1987 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1988 if (matchIndex+matchLength >= dictLimit)
Nick Terrellf35ef5c2017-03-09 12:51:33 -08001989 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet1358f912016-01-01 07:29:39 +01001990 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001991
Yann Colletb8a6f682016-02-15 17:06:29 +01001992 if (matchLength > bestLength) {
1993 bestLength = matchLength;
1994 if (matchLength > matchEndIdx - matchIndex)
1995 matchEndIdx = matchIndex + (U32)matchLength;
1996 }
Yann Colletee3f4512015-12-29 22:26:09 +01001997
Yann Collet59d70632015-11-04 12:05:27 +01001998 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001999 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002000
Yann Colletfb810d62016-01-28 00:18:06 +01002001 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002002 /* match is smaller than current */
2003 *smallerPtr = matchIndex; /* update smaller idx */
2004 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01002005 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002006 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01002007 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01002008 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01002009 /* match is larger than current */
2010 *largerPtr = matchIndex;
2011 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01002012 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002013 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01002014 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01002015 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002016
Yann Collet59d70632015-11-04 12:05:27 +01002017 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02002018 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01002019 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
2020 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002021}
2022
2023
Yann Collet82260dd2016-02-11 07:14:25 +01002024static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01002025 ZSTD_CCtx* zc,
2026 const BYTE* const ip, const BYTE* const iend,
2027 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01002028 U32 nbCompares, const U32 mls,
2029 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01002030{
Yann Collet731ef162016-07-27 21:05:12 +02002031 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002032 U32 const hashLog = zc->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +02002033 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
2034 U32* const bt = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002035 U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
Yann Collet731ef162016-07-27 21:05:12 +02002036 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01002037 U32 matchIndex = hashTable[h];
2038 size_t commonLengthSmaller=0, commonLengthLarger=0;
2039 const BYTE* const base = zc->base;
2040 const BYTE* const dictBase = zc->dictBase;
2041 const U32 dictLimit = zc->dictLimit;
2042 const BYTE* const dictEnd = dictBase + dictLimit;
2043 const BYTE* const prefixStart = base + dictLimit;
2044 const U32 current = (U32)(ip-base);
2045 const U32 btLow = btMask >= current ? 0 : current - btMask;
2046 const U32 windowLow = zc->lowLimit;
2047 U32* smallerPtr = bt + 2*(current&btMask);
2048 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01002049 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01002050 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02002051 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01002052
Yann Collet6c3e2e72015-12-11 10:44:07 +01002053 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01002054
Yann Colletfb810d62016-01-28 00:18:06 +01002055 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08002056 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01002057 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
2058 const BYTE* match;
2059
Yann Colletfb810d62016-01-28 00:18:06 +01002060 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01002061 match = base + matchIndex;
2062 if (match[matchLength] == ip[matchLength])
2063 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01002064 } else {
Yann Collet03526e12015-11-23 15:29:15 +01002065 match = dictBase + matchIndex;
2066 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01002067 if (matchIndex+matchLength >= dictLimit)
Nick Terrellf35ef5c2017-03-09 12:51:33 -08002068 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01002069 }
2070
Yann Colletfb810d62016-01-28 00:18:06 +01002071 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01002072 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01002073 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02002074 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02002075 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01002076 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
2077 break; /* drop, to guarantee consistency (miss a little bit of compression) */
2078 }
2079
Yann Colletfb810d62016-01-28 00:18:06 +01002080 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01002081 /* match is smaller than current */
2082 *smallerPtr = matchIndex; /* update smaller idx */
2083 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
2084 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2085 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
2086 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01002087 } else {
Yann Collet03526e12015-11-23 15:29:15 +01002088 /* match is larger than current */
2089 *largerPtr = matchIndex;
2090 commonLengthLarger = matchLength;
2091 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2092 largerPtr = nextPtr;
2093 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01002094 } }
Yann Collet03526e12015-11-23 15:29:15 +01002095
2096 *smallerPtr = *largerPtr = 0;
2097
Yann Collet72e84cf2015-12-31 19:08:44 +01002098 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02002099 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01002100}
2101
Yann Collet2cc12cb2016-01-01 07:47:58 +01002102
Yann Colletb8a6f682016-02-15 17:06:29 +01002103static 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 +01002104{
2105 const BYTE* const base = zc->base;
2106 const U32 target = (U32)(ip - base);
2107 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01002108
2109 while(idx < target)
2110 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01002111}
2112
Yann Collet52447382016-03-20 16:00:00 +01002113/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01002114static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01002115 ZSTD_CCtx* zc,
2116 const BYTE* const ip, const BYTE* const iLimit,
2117 size_t* offsetPtr,
2118 const U32 maxNbAttempts, const U32 mls)
2119{
2120 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01002121 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01002122 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
2123}
2124
2125
Yann Collet768c6bc2016-02-10 14:01:49 +01002126static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01002127 ZSTD_CCtx* zc, /* Index table will be updated */
2128 const BYTE* ip, const BYTE* const iLimit,
2129 size_t* offsetPtr,
2130 const U32 maxNbAttempts, const U32 matchLengthSearch)
2131{
2132 switch(matchLengthSearch)
2133 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002134 default : /* includes case 3 */
Yann Collet2cc12cb2016-01-01 07:47:58 +01002135 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
2136 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07002137 case 7 :
Yann Collet2cc12cb2016-01-01 07:47:58 +01002138 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
2139 }
2140}
2141
2142
Yann Colletb8a6f682016-02-15 17:06:29 +01002143static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
2144{
2145 const BYTE* const base = zc->base;
2146 const U32 target = (U32)(ip - base);
2147 U32 idx = zc->nextToUpdate;
2148
2149 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
2150}
2151
inikep64d7bcb2016-04-07 19:14:09 +02002152
Yann Collet03526e12015-11-23 15:29:15 +01002153/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01002154static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01002155 ZSTD_CCtx* zc,
2156 const BYTE* const ip, const BYTE* const iLimit,
2157 size_t* offsetPtr,
2158 const U32 maxNbAttempts, const U32 mls)
2159{
Yann Colletee3f4512015-12-29 22:26:09 +01002160 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01002161 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01002162 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01002163}
2164
2165
Yann Collet82260dd2016-02-11 07:14:25 +01002166static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01002167 ZSTD_CCtx* zc, /* Index table will be updated */
2168 const BYTE* ip, const BYTE* const iLimit,
2169 size_t* offsetPtr,
2170 const U32 maxNbAttempts, const U32 matchLengthSearch)
2171{
2172 switch(matchLengthSearch)
2173 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002174 default : /* includes case 3 */
Yann Collet03526e12015-11-23 15:29:15 +01002175 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
2176 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07002177 case 7 :
Yann Collet03526e12015-11-23 15:29:15 +01002178 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
2179 }
2180}
2181
2182
Yann Collet5106a762015-11-05 15:00:24 +01002183
Yann Collet731ef162016-07-27 21:05:12 +02002184/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02002185* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02002186***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02002187#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
2188
2189/* Update chains up to ip (excluded)
Anders Oleson517577b2017-02-20 12:08:59 -08002190 Assumption : always within prefix (i.e. not within extDict) */
inikep64d7bcb2016-04-07 19:14:09 +02002191FORCE_INLINE
2192U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
2193{
2194 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002195 const U32 hashLog = zc->appliedParams.cParams.hashLog;
inikep64d7bcb2016-04-07 19:14:09 +02002196 U32* const chainTable = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002197 const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1;
inikep64d7bcb2016-04-07 19:14:09 +02002198 const BYTE* const base = zc->base;
2199 const U32 target = (U32)(ip - base);
2200 U32 idx = zc->nextToUpdate;
2201
Yann Collet22d76322016-06-21 08:01:51 +02002202 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002203 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
2204 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
2205 hashTable[h] = idx;
2206 idx++;
2207 }
2208
2209 zc->nextToUpdate = target;
2210 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
2211}
2212
2213
Nick Terrell55fc1f92017-05-24 13:50:10 -07002214/* inlining is important to hardwire a hot branch (template emulation) */
2215FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002216size_t ZSTD_HcFindBestMatch_generic (
2217 ZSTD_CCtx* zc, /* Index table will be updated */
2218 const BYTE* const ip, const BYTE* const iLimit,
2219 size_t* offsetPtr,
2220 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
2221{
2222 U32* const chainTable = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002223 const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog);
inikep64d7bcb2016-04-07 19:14:09 +02002224 const U32 chainMask = chainSize-1;
2225 const BYTE* const base = zc->base;
2226 const BYTE* const dictBase = zc->dictBase;
2227 const U32 dictLimit = zc->dictLimit;
2228 const BYTE* const prefixStart = base + dictLimit;
2229 const BYTE* const dictEnd = dictBase + dictLimit;
2230 const U32 lowLimit = zc->lowLimit;
2231 const U32 current = (U32)(ip-base);
2232 const U32 minChain = current > chainSize ? current - chainSize : 0;
2233 int nbAttempts=maxNbAttempts;
Yann Collete42afbc2017-04-26 11:39:35 -07002234 size_t ml=4-1;
inikep64d7bcb2016-04-07 19:14:09 +02002235
2236 /* HC4 match finder */
2237 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
2238
Yann Collet22d76322016-06-21 08:01:51 +02002239 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02002240 const BYTE* match;
2241 size_t currentMl=0;
2242 if ((!extDict) || matchIndex >= dictLimit) {
2243 match = base + matchIndex;
2244 if (match[ml] == ip[ml]) /* potentially better */
2245 currentMl = ZSTD_count(ip, match, iLimit);
2246 } else {
2247 match = dictBase + matchIndex;
2248 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
Yann Collete42afbc2017-04-26 11:39:35 -07002249 currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002250 }
2251
2252 /* save best solution */
Yann Colletc17e0202017-04-20 12:50:02 -07002253 if (currentMl > ml) {
2254 ml = currentMl;
2255 *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
2256 if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
2257 }
inikep64d7bcb2016-04-07 19:14:09 +02002258
2259 if (matchIndex <= minChain) break;
2260 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
2261 }
2262
2263 return ml;
2264}
2265
2266
2267FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
2268 ZSTD_CCtx* zc,
2269 const BYTE* ip, const BYTE* const iLimit,
2270 size_t* offsetPtr,
2271 const U32 maxNbAttempts, const U32 matchLengthSearch)
2272{
2273 switch(matchLengthSearch)
2274 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002275 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02002276 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
2277 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
Yann Collet933ce4a2017-03-29 14:32:15 -07002278 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02002279 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
2280 }
2281}
2282
2283
2284FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
2285 ZSTD_CCtx* zc,
2286 const BYTE* ip, const BYTE* const iLimit,
2287 size_t* offsetPtr,
2288 const U32 maxNbAttempts, const U32 matchLengthSearch)
2289{
2290 switch(matchLengthSearch)
2291 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002292 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02002293 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
2294 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
Yann Collet933ce4a2017-03-29 14:32:15 -07002295 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02002296 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
2297 }
2298}
2299
inikep64d7bcb2016-04-07 19:14:09 +02002300
Yann Collet287b7d92015-11-22 13:24:05 +01002301/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02002302* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02002303*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01002304FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002305void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
2306 const void* src, size_t srcSize,
2307 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01002308{
inikepfaa8d8a2016-04-05 19:01:10 +02002309 seqStore_t* seqStorePtr = &(ctx->seqStore);
2310 const BYTE* const istart = (const BYTE*)src;
2311 const BYTE* ip = istart;
2312 const BYTE* anchor = istart;
2313 const BYTE* const iend = istart + srcSize;
2314 const BYTE* const ilimit = iend - 8;
2315 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002316
Yann Collet1ad7c822017-05-22 17:06:04 -07002317 U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
2318 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002319
inikep64d7bcb2016-04-07 19:14:09 +02002320 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2321 size_t* offsetPtr,
2322 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02002323 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02002324 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02002325
inikepfaa8d8a2016-04-05 19:01:10 +02002326 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02002327 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02002328 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02002329 { U32 const maxRep = (U32)(ip-base);
2330 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
2331 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
2332 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002333
inikepfaa8d8a2016-04-05 19:01:10 +02002334 /* Match Loop */
2335 while (ip < ilimit) {
2336 size_t matchLength=0;
2337 size_t offset=0;
2338 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01002339
inikepfaa8d8a2016-04-05 19:01:10 +02002340 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02002341 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02002342 /* repcode : we take it */
Yann Collete42afbc2017-04-26 11:39:35 -07002343 matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002344 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01002345 }
Yann Collet5be2dd22015-11-11 13:43:58 +01002346
inikepfaa8d8a2016-04-05 19:01:10 +02002347 /* first search (depth 0) */
2348 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002349 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002350 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002351 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002352 }
Yann Collet5106a762015-11-05 15:00:24 +01002353
Yann Collete42afbc2017-04-26 11:39:35 -07002354 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002355 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2356 continue;
2357 }
2358
inikep64d7bcb2016-04-07 19:14:09 +02002359 /* let's try to find a better solution */
2360 if (depth>=1)
2361 while (ip<ilimit) {
2362 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002363 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002364 size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002365 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002366 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002367 if ((mlRep >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002368 matchLength = mlRep, offset = 0, start = ip;
2369 }
2370 { size_t offset2=99999999;
2371 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002372 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2373 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002374 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002375 matchLength = ml2, offset = offset2, start = ip;
2376 continue; /* search a better one */
2377 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002378
inikep64d7bcb2016-04-07 19:14:09 +02002379 /* let's find an even better one */
2380 if ((depth==2) && (ip<ilimit)) {
2381 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002382 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002383 size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002384 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002385 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002386 if ((ml2 >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002387 matchLength = ml2, offset = 0, start = ip;
2388 }
2389 { size_t offset2=99999999;
2390 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002391 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2392 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002393 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002394 matchLength = ml2, offset = offset2, start = ip;
2395 continue;
2396 } } }
2397 break; /* nothing found : store previous solution */
2398 }
2399
2400 /* catch up */
2401 if (offset) {
Yann Colletc17e0202017-04-20 12:50:02 -07002402 while ( (start > anchor)
2403 && (start > base+offset-ZSTD_REP_MOVE)
2404 && (start[-1] == start[-1-offset+ZSTD_REP_MOVE]) ) /* only search for offset within prefix */
inikep64d7bcb2016-04-07 19:14:09 +02002405 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02002406 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02002407 }
2408
inikepfaa8d8a2016-04-05 19:01:10 +02002409 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002410_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002411 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002412 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002413 anchor = ip = start + matchLength;
2414 }
Yann Collet48537162016-04-07 15:24:29 +02002415
inikepfaa8d8a2016-04-05 19:01:10 +02002416 /* check immediate repcode */
2417 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02002418 && ((offset_2>0)
2419 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02002420 /* store sequence */
Yann Collete42afbc2017-04-26 11:39:35 -07002421 matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet9634f672016-07-03 01:23:58 +02002422 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02002423 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2424 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002425 anchor = ip;
2426 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02002427 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002428
Yann Collet4266c0a2016-06-14 01:49:25 +02002429 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002430 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
2431 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02002432
inikepfaa8d8a2016-04-05 19:01:10 +02002433 /* Last Literals */
2434 { size_t const lastLLSize = iend - anchor;
2435 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2436 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002437 }
Yann Collet5106a762015-11-05 15:00:24 +01002438}
2439
Yann Collet5be2dd22015-11-11 13:43:58 +01002440
inikep64d7bcb2016-04-07 19:14:09 +02002441static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2442{
2443 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2444}
2445
2446static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2447{
2448 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2449}
2450
2451static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2452{
2453 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2454}
2455
2456static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2457{
2458 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2459}
2460
2461
inikepfaa8d8a2016-04-05 19:01:10 +02002462FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002463void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2464 const void* src, size_t srcSize,
2465 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002466{
inikepfaa8d8a2016-04-05 19:01:10 +02002467 seqStore_t* seqStorePtr = &(ctx->seqStore);
2468 const BYTE* const istart = (const BYTE*)src;
2469 const BYTE* ip = istart;
2470 const BYTE* anchor = istart;
2471 const BYTE* const iend = istart + srcSize;
2472 const BYTE* const ilimit = iend - 8;
2473 const BYTE* const base = ctx->base;
2474 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002475 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002476 const BYTE* const prefixStart = base + dictLimit;
2477 const BYTE* const dictBase = ctx->dictBase;
2478 const BYTE* const dictEnd = dictBase + dictLimit;
2479 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2480
Yann Collet1ad7c822017-05-22 17:06:04 -07002481 const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
2482 const U32 mls = ctx->appliedParams.cParams.searchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002483
inikep64d7bcb2016-04-07 19:14:09 +02002484 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2485 size_t* offsetPtr,
2486 U32 maxNbAttempts, U32 matchLengthSearch);
2487 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2488
Yann Collet302ff032016-07-03 01:28:16 +02002489 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002490
Yann Collet302ff032016-07-03 01:28:16 +02002491 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002492 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002493 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002494
2495 /* Match Loop */
2496 while (ip < ilimit) {
2497 size_t matchLength=0;
2498 size_t offset=0;
2499 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002500 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002501
2502 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002503 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002504 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2505 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002506 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002507 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002508 /* repcode detected we should take it */
2509 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002510 matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002511 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002512 } }
2513
2514 /* first search (depth 0) */
2515 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002516 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002517 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002518 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002519 }
2520
Yann Collete42afbc2017-04-26 11:39:35 -07002521 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002522 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2523 continue;
2524 }
2525
inikep64d7bcb2016-04-07 19:14:09 +02002526 /* let's try to find a better solution */
2527 if (depth>=1)
2528 while (ip<ilimit) {
2529 ip ++;
2530 current++;
2531 /* check repCode */
2532 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002533 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002534 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2535 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002536 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002537 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2538 /* repcode detected */
2539 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002540 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002541 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002542 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002543 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002544 matchLength = repLength, offset = 0, start = ip;
2545 } }
2546
2547 /* search match, depth 1 */
2548 { size_t offset2=99999999;
2549 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002550 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2551 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002552 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002553 matchLength = ml2, offset = offset2, start = ip;
2554 continue; /* search a better one */
2555 } }
2556
2557 /* let's find an even better one */
2558 if ((depth==2) && (ip<ilimit)) {
2559 ip ++;
2560 current++;
2561 /* check repCode */
2562 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002563 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002564 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2565 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002566 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002567 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2568 /* repcode detected */
2569 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002570 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Colletc17e0202017-04-20 12:50:02 -07002571 int const gain2 = (int)(repLength * 4);
2572 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002573 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002574 matchLength = repLength, offset = 0, start = ip;
2575 } }
2576
2577 /* search match, depth 2 */
2578 { size_t offset2=99999999;
2579 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002580 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2581 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002582 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002583 matchLength = ml2, offset = offset2, start = ip;
2584 continue;
2585 } } }
2586 break; /* nothing found : store previous solution */
2587 }
2588
inikepfaa8d8a2016-04-05 19:01:10 +02002589 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002590 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002591 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002592 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2593 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002594 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002595 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002596 }
inikepfaa8d8a2016-04-05 19:01:10 +02002597
inikepfaa8d8a2016-04-05 19:01:10 +02002598 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002599_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002600 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002601 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002602 anchor = ip = start + matchLength;
2603 }
2604
2605 /* check immediate repcode */
2606 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002607 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002608 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2609 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002610 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002611 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2612 /* repcode detected we should take it */
2613 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002614 matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Collet302ff032016-07-03 01:28:16 +02002615 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002616 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2617 ip += matchLength;
2618 anchor = ip;
2619 continue; /* faster when present ... (?) */
2620 }
2621 break;
2622 } }
2623
Yann Collet4266c0a2016-06-14 01:49:25 +02002624 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002625 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002626
inikepfaa8d8a2016-04-05 19:01:10 +02002627 /* Last Literals */
2628 { size_t const lastLLSize = iend - anchor;
2629 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2630 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002631 }
2632}
2633
2634
Yann Collet59d1f792016-01-23 19:28:41 +01002635void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002636{
inikep64d7bcb2016-04-07 19:14:09 +02002637 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002638}
2639
Yann Collet59d1f792016-01-23 19:28:41 +01002640static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002641{
Yann Colleta1249dc2016-01-25 04:22:03 +01002642 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002643}
Yann Collet9a24e592015-11-22 02:53:43 +01002644
Yann Collet59d1f792016-01-23 19:28:41 +01002645static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002646{
Yann Colleta1249dc2016-01-25 04:22:03 +01002647 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002648}
2649
Yann Collet59d1f792016-01-23 19:28:41 +01002650static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002651{
Yann Colleta1249dc2016-01-25 04:22:03 +01002652 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002653}
2654
inikepef519412016-04-21 11:08:43 +02002655
inikepef519412016-04-21 11:08:43 +02002656/* The optimal parser */
2657#include "zstd_opt.h"
2658
2659static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2660{
Yann Colletd4f4e582016-06-27 01:31:35 +02002661#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002662 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2663#else
2664 (void)ctx; (void)src; (void)srcSize;
2665 return;
2666#endif
2667}
2668
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002669static void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002670{
2671#ifdef ZSTD_OPT_H_91842398743
2672 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002673#else
2674 (void)ctx; (void)src; (void)srcSize;
2675 return;
2676#endif
inikepef519412016-04-21 11:08:43 +02002677}
2678
inikepd3b8d7a2016-02-22 10:06:17 +01002679static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002680{
Yann Colletd4f4e582016-06-27 01:31:35 +02002681#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002682 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2683#else
2684 (void)ctx; (void)src; (void)srcSize;
2685 return;
2686#endif
2687}
2688
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002689static void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002690{
2691#ifdef ZSTD_OPT_H_91842398743
2692 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002693#else
2694 (void)ctx; (void)src; (void)srcSize;
2695 return;
2696#endif
inikepe2bfe242016-01-31 11:25:48 +01002697}
2698
Yann Collet7a231792015-11-21 15:27:35 +01002699
Yann Collet59d1f792016-01-23 19:28:41 +01002700typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002701
Yann Colletb923f652016-01-26 03:14:20 +01002702static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002703{
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002704 static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
2705 { NULL,
2706 ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy,
Yann Colletc17e0202017-04-20 12:50:02 -07002707 ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002708 ZSTD_compressBlock_btopt, ZSTD_compressBlock_btultra },
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002709 { NULL,
2710 ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict,
Yann Colletc17e0202017-04-20 12:50:02 -07002711 ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002712 ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01002713 };
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002714 ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
Yann Collet7fe531e2015-11-29 02:38:09 +01002715
2716 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002717}
2718
2719
Yann Colletd1b26842016-03-15 01:24:33 +01002720static 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 +01002721{
Yann Collet1ad7c822017-05-22 17:06:04 -07002722 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002723 const BYTE* const base = zc->base;
2724 const BYTE* const istart = (const BYTE*)src;
2725 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002726 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 +02002727 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002728 if (current > zc->nextToUpdate + 384)
Yann Colletc17e0202017-04-20 12:50:02 -07002729 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 +01002730 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002731 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002732}
2733
2734
Yann Colletdb8e21d2017-05-12 13:46:49 -07002735/*! ZSTD_compress_frameChunk() :
Yann Colletc991cc12016-07-28 00:55:43 +02002736* Compress a chunk of data into one or multiple blocks.
2737* All blocks will be terminated, all input will be consumed.
2738* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2739* Frame is supposed already started (header already produced)
2740* @return : compressed size, or an error code
2741*/
Yann Colletdb8e21d2017-05-12 13:46:49 -07002742static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002743 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002744 const void* src, size_t srcSize,
2745 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002746{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002747 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002748 size_t remaining = srcSize;
2749 const BYTE* ip = (const BYTE*)src;
2750 BYTE* const ostart = (BYTE*)dst;
2751 BYTE* op = ostart;
Yann Collet1ad7c822017-05-22 17:06:04 -07002752 U32 const maxDist = 1 << cctx->appliedParams.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002753
Yann Collet1ad7c822017-05-22 17:06:04 -07002754 if (cctx->appliedParams.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002755 XXH64_update(&cctx->xxhState, src, srcSize);
2756
Yann Collet2ce49232016-02-02 14:36:49 +01002757 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002758 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002759 size_t cSize;
2760
Yann Colletc17e0202017-04-20 12:50:02 -07002761 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
2762 return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01002763 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002764
Yann Collet346efcc2016-08-02 14:26:00 +02002765 /* preemptive overflow correction */
Sean Purcell881abe42017-03-07 16:52:23 -08002766 if (cctx->lowLimit > (3U<<29)) {
Yann Collet1ad7c822017-05-22 17:06:04 -07002767 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->appliedParams.cParams.hashLog, cctx->appliedParams.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002768 U32 const current = (U32)(ip - cctx->base);
Yann Collet1ad7c822017-05-22 17:06:04 -07002769 U32 const newCurrent = (current & cycleMask) + (1 << cctx->appliedParams.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002770 U32 const correction = current - newCurrent;
2771 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002772 ZSTD_reduceIndex(cctx, correction);
2773 cctx->base += correction;
2774 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002775 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002776 cctx->dictLimit -= correction;
2777 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2778 else cctx->nextToUpdate -= correction;
2779 }
2780
Yann Collet06e76972017-01-25 16:39:03 -08002781 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002782 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002783 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2784 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2785 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002786 }
Yann Collet89db5e02015-11-13 11:27:46 +01002787
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002788 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002789 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002790
Yann Collet2ce49232016-02-02 14:36:49 +01002791 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002792 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2793 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2794 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2795 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2796 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002797 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002798 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002799 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002800 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002801 }
2802
2803 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002804 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002805 ip += blockSize;
2806 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002807 }
2808
Yann Collet62470b42016-07-28 15:29:08 +02002809 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002810 return op-ostart;
2811}
2812
2813
Yann Collet6236eba2016-04-12 15:52:33 +02002814static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002815 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002816{ BYTE* const op = (BYTE*)dst;
Yann Collet31533ba2017-04-27 00:29:04 -07002817 U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2818 U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002819 U32 const checksumFlag = params.fParams.checksumFlag>0;
2820 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002821 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002822 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2823 U32 const fcsCode = params.fParams.contentSizeFlag ?
Nick Terrell55fc1f92017-05-24 13:50:10 -07002824 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002825 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002826 size_t pos;
2827
2828 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet009d6042017-05-19 10:17:59 -07002829 DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
Yann Collet0be6fd32017-05-08 16:08:01 -07002830 !params.fParams.noDictIDFlag, dictID, dictIDSizeCode);
Yann Collet6236eba2016-04-12 15:52:33 +02002831
2832 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002833 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002834 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002835 switch(dictIDSizeCode)
2836 {
Yann Colletcd2892f2017-06-01 09:44:54 -07002837 default: assert(0); /* impossible */
Yann Colletc46fb922016-05-29 05:01:04 +02002838 case 0 : break;
2839 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002840 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002841 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2842 }
Yann Collet673f0d72016-06-06 00:26:38 +02002843 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002844 {
Yann Colletcd2892f2017-06-01 09:44:54 -07002845 default: assert(0); /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002846 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002847 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2848 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002849 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002850 }
Yann Colletc46fb922016-05-29 05:01:04 +02002851 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002852}
2853
2854
Yann Collet346efcc2016-08-02 14:26:00 +02002855static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002856 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002857 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002858 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002859{
Yann Collet2acb5d32015-10-29 16:49:43 +01002860 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002861 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002862
Yann Collet346efcc2016-08-02 14:26:00 +02002863 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002864
Yann Collet346efcc2016-08-02 14:26:00 +02002865 if (frame && (cctx->stage==ZSTDcs_init)) {
Yann Collet1ad7c822017-05-22 17:06:04 -07002866 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002867 if (ZSTD_isError(fhSize)) return fhSize;
2868 dstCapacity -= fhSize;
2869 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002870 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002871 }
Yann Colletf3eca252015-10-22 15:31:46 +01002872
Yann Collet417890c2015-12-04 17:16:37 +01002873 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002874 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002875 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002876 ptrdiff_t const delta = cctx->nextSrc - ip;
2877 cctx->lowLimit = cctx->dictLimit;
2878 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2879 cctx->dictBase = cctx->base;
2880 cctx->base -= delta;
2881 cctx->nextToUpdate = cctx->dictLimit;
2882 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002883 }
2884
Yann Collet346efcc2016-08-02 14:26:00 +02002885 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2886 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2887 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2888 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2889 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002890 }
2891
Yann Collet346efcc2016-08-02 14:26:00 +02002892 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002893
Yann Collet5eb749e2017-01-11 18:21:25 +01002894 if (srcSize) {
2895 size_t const cSize = frame ?
Yann Colletdb8e21d2017-05-12 13:46:49 -07002896 ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
Yann Collet346efcc2016-08-02 14:26:00 +02002897 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002898 if (ZSTD_isError(cSize)) return cSize;
Yann Collet20d5e032017-04-11 18:34:02 -07002899 cctx->consumedSrcSize += srcSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002900 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01002901 } else
2902 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002903}
2904
Yann Colletbf42c8e2016-01-09 01:08:23 +01002905
Yann Collet5b567392016-07-28 01:17:22 +02002906size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002907 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002908 const void* src, size_t srcSize)
2909{
Yann Collet20d5e032017-04-11 18:34:02 -07002910 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
Yann Collet5b567392016-07-28 01:17:22 +02002911}
2912
2913
Yann Colletfa3671e2017-05-19 10:51:30 -07002914size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002915{
Yann Colletfa3671e2017-05-19 10:51:30 -07002916 U32 const cLevel = cctx->compressionLevel;
2917 ZSTD_compressionParameters cParams = (cLevel == ZSTD_CLEVEL_CUSTOM) ?
Yann Collet1ad7c822017-05-22 17:06:04 -07002918 cctx->appliedParams.cParams :
Yann Colletfa3671e2017-05-19 10:51:30 -07002919 ZSTD_getCParams(cLevel, 0, 0);
2920 return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog);
Yann Colletcf05b9d2016-07-18 16:52:10 +02002921}
2922
2923size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2924{
Yann Colletfa3671e2017-05-19 10:51:30 -07002925 size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002926 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07002927 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002928}
2929
Yann Collet16a0b102017-03-24 12:46:46 -07002930/*! ZSTD_loadDictionaryContent() :
2931 * @return : 0, or an error code
2932 */
Yann Colletb923f652016-01-26 03:14:20 +01002933static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002934{
2935 const BYTE* const ip = (const BYTE*) src;
2936 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002937
Yann Collet417890c2015-12-04 17:16:37 +01002938 /* input becomes current prefix */
2939 zc->lowLimit = zc->dictLimit;
2940 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2941 zc->dictBase = zc->base;
2942 zc->base += ip - zc->nextSrc;
2943 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08002944 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002945
2946 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002947 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002948
Yann Collet1ad7c822017-05-22 17:06:04 -07002949 switch(zc->appliedParams.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002950 {
2951 case ZSTD_fast:
Yann Collet1ad7c822017-05-22 17:06:04 -07002952 ZSTD_fillHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002953 break;
2954
Yann Collet45dc3562016-07-12 09:47:31 +02002955 case ZSTD_dfast:
Yann Collet1ad7c822017-05-22 17:06:04 -07002956 ZSTD_fillDoubleHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
Yann Collet45dc3562016-07-12 09:47:31 +02002957 break;
2958
Yann Collet417890c2015-12-04 17:16:37 +01002959 case ZSTD_greedy:
2960 case ZSTD_lazy:
2961 case ZSTD_lazy2:
Yann Collet16a0b102017-03-24 12:46:46 -07002962 if (srcSize >= HASH_READ_SIZE)
Yann Collet1ad7c822017-05-22 17:06:04 -07002963 ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002964 break;
2965
2966 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002967 case ZSTD_btopt:
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002968 case ZSTD_btultra:
Yann Collet16a0b102017-03-24 12:46:46 -07002969 if (srcSize >= HASH_READ_SIZE)
Yann Collet1ad7c822017-05-22 17:06:04 -07002970 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002971 break;
2972
2973 default:
Yann Colletcd2892f2017-06-01 09:44:54 -07002974 assert(0); /* not possible : not a valid strategy id */
Yann Collet417890c2015-12-04 17:16:37 +01002975 }
2976
Nick Terrellecf90ca2017-02-13 18:27:34 -08002977 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002978 return 0;
2979}
2980
2981
Nick Terrellf9c9af32016-10-19 17:22:08 -07002982/* Dictionaries that assign zero probability to symbols that show up causes problems
2983 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2984 that we may encounter during compression.
2985 NOTE: This behavior is not standard and could be improved in the future. */
2986static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2987 U32 s;
2988 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
2989 for (s = 0; s <= maxSymbolValue; ++s) {
2990 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
2991 }
2992 return 0;
2993}
2994
2995
Yann Colletb923f652016-01-26 03:14:20 +01002996/* Dictionary format :
Yann Colletbea78e82017-03-22 18:09:11 -07002997 * See :
2998 * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
2999 */
Yann Collet16a0b102017-03-24 12:46:46 -07003000/*! ZSTD_loadZstdDictionary() :
3001 * @return : 0, or an error code
3002 * assumptions : magic number supposed already checked
3003 * dictSize supposed > 8
Yann Colletbea78e82017-03-22 18:09:11 -07003004 */
Yann Collet16a0b102017-03-24 12:46:46 -07003005static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01003006{
Yann Collet52a06222016-06-15 13:53:34 +02003007 const BYTE* dictPtr = (const BYTE*)dict;
3008 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07003009 short offcodeNCount[MaxOff+1];
3010 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08003011 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01003012
Yann Colletbea78e82017-03-22 18:09:11 -07003013 dictPtr += 4; /* skip magic number */
Yann Collet1ad7c822017-05-22 17:06:04 -07003014 cctx->dictID = cctx->appliedParams.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
Yann Colletbea78e82017-03-22 18:09:11 -07003015 dictPtr += 4;
3016
Yann Collet71ddeb62017-04-20 22:54:54 -07003017 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufCTable, 255, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003018 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003019 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003020 }
Yann Colletfb810d62016-01-28 00:18:06 +01003021
Nick Terrellf9c9af32016-10-19 17:22:08 -07003022 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02003023 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003024 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003025 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003026 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Colletc17e0202017-04-20 12:50:02 -07003027 CHECK_E( FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)),
3028 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003029 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003030 }
Yann Colletfb810d62016-01-28 00:18:06 +01003031
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003032 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07003033 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02003034 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003035 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003036 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003037 /* Every match length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07003038 CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
3039 CHECK_E( FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)),
3040 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003041 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003042 }
Yann Colletfb810d62016-01-28 00:18:06 +01003043
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003044 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07003045 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02003046 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003047 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003048 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003049 /* Every literal length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07003050 CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
3051 CHECK_E( FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)),
3052 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003053 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003054 }
Yann Colletfb810d62016-01-28 00:18:06 +01003055
Yann Collet52a06222016-06-15 13:53:34 +02003056 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07003057 cctx->rep[0] = MEM_readLE32(dictPtr+0);
3058 cctx->rep[1] = MEM_readLE32(dictPtr+4);
3059 cctx->rep[2] = MEM_readLE32(dictPtr+8);
Yann Collet52a06222016-06-15 13:53:34 +02003060 dictPtr += 12;
3061
Yann Colletbea78e82017-03-22 18:09:11 -07003062 { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
3063 U32 offcodeMax = MaxOff;
3064 if (dictContentSize <= ((U32)-1) - 128 KB) {
3065 U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
3066 offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
Nick Terrellb2c39a22016-10-24 14:11:27 -07003067 }
Yann Colletbea78e82017-03-22 18:09:11 -07003068 /* All offset values <= dictContentSize + 128 KB must be representable */
Nick Terrellf9c9af32016-10-19 17:22:08 -07003069 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
Yann Colletbea78e82017-03-22 18:09:11 -07003070 /* All repCodes must be <= dictContentSize and != 0*/
3071 { U32 u;
3072 for (u=0; u<3; u++) {
3073 if (cctx->rep[u] == 0) return ERROR(dictionary_corrupted);
3074 if (cctx->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07003075 } }
Nick Terrellf9c9af32016-10-19 17:22:08 -07003076
Yann Collet71ddeb62017-04-20 22:54:54 -07003077 cctx->fseCTables_ready = 1;
3078 cctx->hufCTable_repeatMode = HUF_repeat_valid;
Yann Collet16a0b102017-03-24 12:46:46 -07003079 return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
3080 }
Yann Colletb923f652016-01-26 03:14:20 +01003081}
3082
Yann Colletd1b26842016-03-15 01:24:33 +01003083/** ZSTD_compress_insertDictionary() :
3084* @return : 0, or an error code */
Yann Collet16a0b102017-03-24 12:46:46 -07003085static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01003086{
Yann Colletc46fb922016-05-29 05:01:04 +02003087 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01003088
Yann Collet14312d82017-02-23 23:42:12 -08003089 /* dict as pure content */
Yann Collet16a0b102017-03-24 12:46:46 -07003090 if ((MEM_readLE32(dict) != ZSTD_DICT_MAGIC) || (cctx->forceRawDict))
3091 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
Yann Colletd1b26842016-03-15 01:24:33 +01003092
Yann Colletbea78e82017-03-22 18:09:11 -07003093 /* dict as zstd dictionary */
Yann Collet16a0b102017-03-24 12:46:46 -07003094 return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
Yann Colletecd651b2016-01-07 15:35:18 +01003095}
3096
Yann Collet27caf2a2016-04-01 15:48:48 +02003097/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01003098* @return : 0, or an error code */
Yann Collet8c910d22017-06-03 01:15:02 -07003099size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01003100 const void* dict, size_t dictSize,
Yann Collet18803372017-05-22 18:21:51 -07003101 const ZSTD_CDict* cdict,
Yann Collet5ac72b42017-05-23 11:18:24 -07003102 ZSTD_parameters params, U64 pledgedSrcSize,
3103 ZSTD_buffered_policy_e zbuff)
Yann Colletf3eca252015-10-22 15:31:46 +01003104{
Yann Collet5ac72b42017-05-23 11:18:24 -07003105 /* params are supposed to be fully validated at this point */
Yann Colletab9162e2017-04-11 10:46:20 -07003106 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet18803372017-05-22 18:21:51 -07003107 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
3108
3109 if (cdict && cdict->dictContentSize>0)
Yann Collet5ac72b42017-05-23 11:18:24 -07003110 return ZSTD_copyCCtx_internal(cctx, cdict->refContext,
3111 params.fParams, pledgedSrcSize);
Yann Collet18803372017-05-22 18:21:51 -07003112
Yann Collet5ac72b42017-05-23 11:18:24 -07003113 CHECK_F(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
3114 ZSTDcrp_continue, zbuff));
Yann Colleta7737f62016-09-06 09:44:59 +02003115 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01003116}
3117
3118
Yann Collet27caf2a2016-04-01 15:48:48 +02003119/*! ZSTD_compressBegin_advanced() :
3120* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02003121size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02003122 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02003123 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02003124{
3125 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02003126 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet5ac72b42017-05-23 11:18:24 -07003127 return ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL,
3128 params, pledgedSrcSize, ZSTDb_not_buffered);
Yann Collet27caf2a2016-04-01 15:48:48 +02003129}
3130
3131
Yann Collet81e13ef2016-06-07 00:51:51 +02003132size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01003133{
Yann Collet6c6e1752016-06-27 15:28:45 +02003134 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet5ac72b42017-05-23 11:18:24 -07003135 return ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL,
3136 params, 0, ZSTDb_not_buffered);
Yann Collet1c8e1942016-01-26 16:31:22 +01003137}
Yann Collet083fcc82015-10-25 14:06:35 +01003138
inikep19bd48f2016-04-04 12:10:00 +02003139
Yann Colletb05c4822017-01-12 02:01:28 +01003140size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01003141{
Yann Colletb05c4822017-01-12 02:01:28 +01003142 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01003143}
3144
3145
Yann Collet62470b42016-07-28 15:29:08 +02003146/*! ZSTD_writeEpilogue() :
3147* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01003148* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02003149static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01003150{
Yann Colletc991cc12016-07-28 00:55:43 +02003151 BYTE* const ostart = (BYTE*)dst;
3152 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02003153 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01003154
Yann Collet009d6042017-05-19 10:17:59 -07003155 DEBUGLOG(5, "ZSTD_writeEpilogue");
Yann Collet87c18b22016-08-26 01:43:47 +02003156 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02003157
3158 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02003159 if (cctx->stage == ZSTDcs_init) {
Yann Collet1ad7c822017-05-22 17:06:04 -07003160 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02003161 if (ZSTD_isError(fhSize)) return fhSize;
3162 dstCapacity -= fhSize;
3163 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02003164 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01003165 }
3166
Yann Colletc991cc12016-07-28 00:55:43 +02003167 if (cctx->stage != ZSTDcs_ending) {
3168 /* write one last empty block, make it the "last" block */
3169 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
3170 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
3171 MEM_writeLE32(op, cBlockHeader24);
3172 op += ZSTD_blockHeaderSize;
3173 dstCapacity -= ZSTD_blockHeaderSize;
3174 }
3175
Yann Collet1ad7c822017-05-22 17:06:04 -07003176 if (cctx->appliedParams.fParams.checksumFlag) {
Yann Colletc991cc12016-07-28 00:55:43 +02003177 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
3178 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
3179 MEM_writeLE32(op, checksum);
3180 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003181 }
Yann Collet2acb5d32015-10-29 16:49:43 +01003182
Yann Collet731ef162016-07-27 21:05:12 +02003183 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02003184 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01003185}
3186
Yann Colletfd416f12016-01-30 03:14:15 +01003187
Yann Collet62470b42016-07-28 15:29:08 +02003188size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
3189 void* dst, size_t dstCapacity,
3190 const void* src, size_t srcSize)
3191{
3192 size_t endResult;
Yann Collet009d6042017-05-19 10:17:59 -07003193 size_t const cSize = ZSTD_compressContinue_internal(cctx,
3194 dst, dstCapacity, src, srcSize,
3195 1 /* frame mode */, 1 /* last chunk */);
Yann Collet62470b42016-07-28 15:29:08 +02003196 if (ZSTD_isError(cSize)) return cSize;
3197 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
3198 if (ZSTD_isError(endResult)) return endResult;
Yann Collet1ad7c822017-05-22 17:06:04 -07003199 if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */
Yann Collet0be6fd32017-05-08 16:08:01 -07003200 if (cctx->frameContentSize != cctx->consumedSrcSize)
3201 return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07003202 }
Yann Collet62470b42016-07-28 15:29:08 +02003203 return cSize + endResult;
3204}
3205
3206
Yann Collet19c10022016-07-28 01:25:46 +02003207static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01003208 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01003209 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01003210 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01003211 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01003212{
Yann Collet5ac72b42017-05-23 11:18:24 -07003213 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL,
3214 params, srcSize, ZSTDb_not_buffered));
Yann Collet62470b42016-07-28 15:29:08 +02003215 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01003216}
3217
Yann Collet21588e32016-03-30 16:50:44 +02003218size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
3219 void* dst, size_t dstCapacity,
3220 const void* src, size_t srcSize,
3221 const void* dict,size_t dictSize,
3222 ZSTD_parameters params)
3223{
Yann Colletcf409a72016-09-26 16:41:05 +02003224 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02003225 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
3226}
3227
Yann Colletc17e0202017-04-20 12:50:02 -07003228size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
3229 const void* dict, size_t dictSize, int compressionLevel)
Yann Collet31683c02015-12-18 01:26:48 +01003230{
Yann Collet407a11f2016-11-03 15:52:01 -07003231 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02003232 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02003233 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01003234}
3235
Yann Colletd1b26842016-03-15 01:24:33 +01003236size_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 +01003237{
Yann Collet21588e32016-03-30 16:50:44 +02003238 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01003239}
3240
Yann Colletd1b26842016-03-15 01:24:33 +01003241size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01003242{
Yann Collet44fe9912015-10-29 22:02:40 +01003243 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01003244 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01003245 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Colletae728a42017-05-30 17:11:39 -07003246 ctxBody.customMem = ZSTD_defaultCMem;
Yann Colletd1b26842016-03-15 01:24:33 +01003247 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Colletae728a42017-05-30 17:11:39 -07003248 ZSTD_free(ctxBody.workSpace, ZSTD_defaultCMem); /* can't free ctxBody itself, as it's on stack; free only heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01003249 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01003250}
Yann Colletfdcad6d2015-12-17 23:50:15 +01003251
Yann Colletfd416f12016-01-30 03:14:15 +01003252
Yann Collet81e13ef2016-06-07 00:51:51 +02003253/* ===== Dictionary API ===== */
3254
Yann Colleta1d67042017-05-08 17:51:49 -07003255/*! ZSTD_estimateCDictSize() :
3256 * Estimate amount of memory that will be needed to create a dictionary with following arguments */
Yann Collet25989e32017-05-25 15:07:37 -07003257size_t ZSTD_estimateCDictSize(ZSTD_compressionParameters cParams, size_t dictSize, unsigned byReference)
Yann Colleta1d67042017-05-08 17:51:49 -07003258{
Yann Collet25989e32017-05-25 15:07:37 -07003259 return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize(cParams)
3260 + (byReference ? 0 : dictSize);
Yann Colleta1d67042017-05-08 17:51:49 -07003261}
3262
Yann Colletd7c65892016-09-15 02:50:27 +02003263size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
3264{
3265 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Colletaca113f2016-12-23 22:25:03 +01003266 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02003267}
3268
Yann Collet1c3ab0c2017-04-27 12:57:11 -07003269static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_frameParameters fParams)
3270{
3271 ZSTD_parameters params;
3272 params.cParams = cParams;
3273 params.fParams = fParams;
3274 return params;
3275}
3276
Yann Colletcdf7e822017-05-25 18:05:49 -07003277static size_t ZSTD_initCDict_internal(
3278 ZSTD_CDict* cdict,
3279 const void* dictBuffer, size_t dictSize, unsigned byReference,
3280 ZSTD_compressionParameters cParams)
3281{
3282 if ((byReference) || (!dictBuffer) || (!dictSize)) {
3283 cdict->dictBuffer = NULL;
3284 cdict->dictContent = dictBuffer;
3285 } else {
3286 void* const internalBuffer = ZSTD_malloc(dictSize, cdict->refContext->customMem);
3287 if (!internalBuffer) return ERROR(memory_allocation);
3288 memcpy(internalBuffer, dictBuffer, dictSize);
3289 cdict->dictBuffer = internalBuffer;
3290 cdict->dictContent = internalBuffer;
3291 }
3292 cdict->dictContentSize = dictSize;
3293
3294 { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */,
3295 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */
3296 ZSTD_parameters const params = ZSTD_makeParams(cParams, fParams);
3297 CHECK_F( ZSTD_compressBegin_advanced(cdict->refContext,
3298 cdict->dictContent, dictSize,
3299 params, 0 /* srcSize */) );
3300 }
3301
3302 return 0;
3303}
3304
Yann Collet1f57c2e2016-12-21 16:20:11 +01003305ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
Yann Collet31533ba2017-04-27 00:29:04 -07003306 ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02003307{
Yann Collet8b21ec42017-05-19 19:46:15 -07003308 DEBUGLOG(5, "ZSTD_createCDict_advanced");
Yann Colletae728a42017-05-30 17:11:39 -07003309 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02003310
Yann Collet23b6e052016-08-28 21:05:43 -07003311 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02003312 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
3313
Yann Collet1f57c2e2016-12-21 16:20:11 +01003314 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07003315 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01003316 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02003317 return NULL;
3318 }
Yann Colletcdf7e822017-05-25 18:05:49 -07003319 cdict->refContext = cctx;
Yann Collet81e13ef2016-06-07 00:51:51 +02003320
Yann Colletcdf7e822017-05-25 18:05:49 -07003321 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3322 dictBuffer, dictSize, byReference,
3323 cParams) )) {
3324 ZSTD_freeCDict(cdict);
3325 return NULL;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07003326 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01003327
Yann Collet81e13ef2016-06-07 00:51:51 +02003328 return cdict;
3329 }
3330}
3331
3332ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
3333{
3334 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet31533ba2017-04-27 00:29:04 -07003335 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
3336 return ZSTD_createCDict_advanced(dict, dictSize, 0, cParams, allocator);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003337}
3338
3339ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
3340{
3341 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet31533ba2017-04-27 00:29:04 -07003342 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
3343 return ZSTD_createCDict_advanced(dict, dictSize, 1, cParams, allocator);
Yann Collet81e13ef2016-06-07 00:51:51 +02003344}
3345
3346size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
3347{
Yann Collet23b6e052016-08-28 21:05:43 -07003348 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02003349 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07003350 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01003351 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003352 ZSTD_free(cdict, cMem);
3353 return 0;
3354 }
Yann Collet81e13ef2016-06-07 00:51:51 +02003355}
3356
Yann Colletcdf7e822017-05-25 18:05:49 -07003357/*! ZSTD_initStaticCDict_advanced() :
3358 * Generate a digested dictionary in provided memory area.
3359 * workspace: The memory area to emplace the dictionary into.
3360 * Provided pointer must 8-bytes aligned.
3361 * It must outlive dictionary usage.
3362 * workspaceSize: Use ZSTD_estimateCDictSize()
3363 * to determine how large workspace must be.
3364 * cParams : use ZSTD_getCParams() to transform a compression level
3365 * into its relevants cParams.
3366 * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
3367 * Note : there is no corresponding "free" function.
3368 * Since workspace was allocated externally, it must be freed externally.
3369 */
3370ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
3371 const void* dict, size_t dictSize, unsigned byReference,
3372 ZSTD_compressionParameters cParams)
3373{
3374 size_t const cctxSize = ZSTD_estimateCCtxSize(cParams);
3375 size_t const neededSize = sizeof(ZSTD_CDict) + (byReference ? 0 : dictSize)
3376 + cctxSize;
3377 ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
3378 void* ptr;
3379 DEBUGLOG(2, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7);
3380 if ((size_t)workspace & 7) return NULL; /* 8-aligned */
3381 DEBUGLOG(2, "(workspaceSize < neededSize) : (%u < %u) => %u",
3382 (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize));
3383 if (workspaceSize < neededSize) return NULL;
3384
3385 if (!byReference) {
3386 memcpy(cdict+1, dict, dictSize);
3387 dict = cdict+1;
3388 ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize;
3389 } else {
3390 ptr = cdict+1;
3391 }
3392 cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize);
3393
3394 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3395 dict, dictSize, 1 /* by Reference */,
3396 cParams) ))
3397 return NULL;
3398
3399 return cdict;
3400}
3401
Yann Collet8c910d22017-06-03 01:15:02 -07003402ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
Yann Collet95162342016-10-25 16:19:52 -07003403 return ZSTD_getParamsFromCCtx(cdict->refContext);
3404}
3405
Yann Collet715b9aa2017-04-18 13:55:53 -07003406/* ZSTD_compressBegin_usingCDict_advanced() :
Yann Collet4f818182017-04-17 17:57:35 -07003407 * cdict must be != NULL */
Yann Collet715b9aa2017-04-18 13:55:53 -07003408size_t ZSTD_compressBegin_usingCDict_advanced(
Yann Collet4f818182017-04-17 17:57:35 -07003409 ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
3410 ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003411{
Yann Collet5ac72b42017-05-23 11:18:24 -07003412 if (cdict==NULL) return ERROR(dictionary_wrong);
Yann Collet18803372017-05-22 18:21:51 -07003413 { ZSTD_parameters params = cdict->refContext->appliedParams;
Yann Collet4f818182017-04-17 17:57:35 -07003414 params.fParams = fParams;
Yann Collet18803372017-05-22 18:21:51 -07003415 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced");
Yann Collet5ac72b42017-05-23 11:18:24 -07003416 return ZSTD_compressBegin_internal(cctx, NULL, 0, cdict,
3417 params, pledgedSrcSize, ZSTDb_not_buffered);
Sean Purcell2db72492017-02-09 10:50:43 -08003418 }
Yann Collet4cb21292016-09-15 14:54:07 +02003419}
3420
Yann Collet4f818182017-04-17 17:57:35 -07003421/* ZSTD_compressBegin_usingCDict() :
3422 * pledgedSrcSize=0 means "unknown"
3423 * if pledgedSrcSize>0, it will enable contentSizeFlag */
Yann Collet768df122017-04-26 15:42:10 -07003424size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
Yann Collet4f818182017-04-17 17:57:35 -07003425{
Yann Collet768df122017-04-26 15:42:10 -07003426 ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Collet009d6042017-05-19 10:17:59 -07003427 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
Yann Collet768df122017-04-26 15:42:10 -07003428 return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0);
Yann Collet4f818182017-04-17 17:57:35 -07003429}
3430
Yann Colletf4bd8572017-04-27 11:31:55 -07003431size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
3432 void* dst, size_t dstCapacity,
3433 const void* src, size_t srcSize,
3434 const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
3435{
3436 CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */
3437 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02003438}
3439
Yann Collet07639052016-08-03 01:57:57 +02003440/*! ZSTD_compress_usingCDict() :
Yann Collet4f818182017-04-17 17:57:35 -07003441 * Compression using a digested Dictionary.
3442 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
3443 * Note that compression parameters are decided at CDict creation time
3444 * while frame parameters are hardcoded */
Yann Collet4cb21292016-09-15 14:54:07 +02003445size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
3446 void* dst, size_t dstCapacity,
3447 const void* src, size_t srcSize,
3448 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02003449{
Yann Collet4f818182017-04-17 17:57:35 -07003450 ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Colletf4bd8572017-04-27 11:31:55 -07003451 return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
Yann Collet81e13ef2016-06-07 00:51:51 +02003452}
3453
3454
3455
Yann Collet104e5b02016-08-12 13:04:27 +02003456/* ******************************************************************
3457* Streaming
3458********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003459
Yann Collet5a0c8e22016-08-12 01:20:36 +02003460ZSTD_CStream* ZSTD_createCStream(void)
3461{
Yann Colletae728a42017-05-30 17:11:39 -07003462 return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003463}
3464
3465ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
Yann Colletae728a42017-05-30 17:11:39 -07003466{ /* CStream and CCtx are now same object */
Yann Collet6fb2f242017-05-10 11:06:06 -07003467 return ZSTD_createCCtx_advanced(customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003468}
3469
3470size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
3471{
Yann Collet78553662017-05-08 17:15:00 -07003472 return ZSTD_freeCCtx(zcs); /* same object */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003473}
3474
Yann Collet5a0c8e22016-08-12 01:20:36 +02003475
3476
Yann Collet104e5b02016-08-12 13:04:27 +02003477/*====== Initialization ======*/
3478
Yann Colletfa3671e2017-05-19 10:51:30 -07003479size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003480
Yann Colletc17e0202017-04-20 12:50:02 -07003481size_t ZSTD_CStreamOutSize(void)
3482{
Yann Colletfa3671e2017-05-19 10:51:30 -07003483 return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
Yann Colletc17e0202017-04-20 12:50:02 -07003484}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003485
Yann Collet1ad7c822017-05-22 17:06:04 -07003486static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs,
3487 ZSTD_parameters params,
3488 unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003489{
Yann Collet1ad7c822017-05-22 17:06:04 -07003490 DEBUGLOG(5, "ZSTD_resetCStream_internal");
Yann Collet31533ba2017-04-27 00:29:04 -07003491
Yann Collet5ac72b42017-05-23 11:18:24 -07003492 CHECK_F(ZSTD_compressBegin_internal(zcs, NULL, 0, zcs->cdict,
3493 params, pledgedSrcSize, ZSTDb_buffered));
Yann Collet4cb21292016-09-15 14:54:07 +02003494
3495 zcs->inToCompress = 0;
3496 zcs->inBuffPos = 0;
3497 zcs->inBuffTarget = zcs->blockSize;
3498 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -07003499 zcs->streamStage = zcss_load;
Yann Collet4cb21292016-09-15 14:54:07 +02003500 zcs->frameEnded = 0;
3501 return 0; /* ready to go */
3502}
3503
Yann Collet009d6042017-05-19 10:17:59 -07003504size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
3505{
Yann Collet1ad7c822017-05-22 17:06:04 -07003506 ZSTD_parameters params = zcs->requestedParams;
Yann Collet009d6042017-05-19 10:17:59 -07003507 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
Yann Colletb0739bc2017-05-22 17:45:15 -07003508 DEBUGLOG(5, "ZSTD_resetCStream");
Yann Collet009d6042017-05-19 10:17:59 -07003509 if (zcs->compressionLevel != ZSTD_CLEVEL_CUSTOM) {
3510 params.cParams = ZSTD_getCParams(zcs->compressionLevel, pledgedSrcSize, 0 /* dictSize */);
3511 }
Yann Collet5ac72b42017-05-23 11:18:24 -07003512 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Yann Collet009d6042017-05-19 10:17:59 -07003513}
3514
Yann Collet8c910d22017-06-03 01:15:02 -07003515size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
3516 const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
3517 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collete88034f2017-04-10 22:24:02 -07003518{
3519 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet8c910d22017-06-03 01:15:02 -07003520 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
Yann Collete88034f2017-04-10 22:24:02 -07003521
3522 if (dict && dictSize >= 8) {
Yann Colletc7fe2622017-05-23 13:16:00 -07003523 if (zcs->staticSize) { /* static CCtx : never uses malloc */
3524 /* incompatible with internal cdict creation */
3525 return ERROR(memory_allocation);
3526 }
Yann Collete88034f2017-04-10 22:24:02 -07003527 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet8c910d22017-06-03 01:15:02 -07003528 zcs->cdict = NULL;
Yann Collet31533ba2017-04-27 00:29:04 -07003529 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0 /* copy */, params.cParams, zcs->customMem);
Yann Collete88034f2017-04-10 22:24:02 -07003530 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
3531 zcs->cdict = zcs->cdictLocal;
Yann Collet8c910d22017-06-03 01:15:02 -07003532 } else {
3533 if (cdict) {
3534 ZSTD_parameters const cdictParams = ZSTD_getParamsFromCDict(cdict);
3535 params.cParams = cdictParams.cParams; /* cParams are enforced from cdict */
3536 }
3537 zcs->cdict = cdict;
Yann Collete88034f2017-04-10 22:24:02 -07003538 }
3539
Yann Collet8c910d22017-06-03 01:15:02 -07003540 zcs->requestedParams = params;
3541 zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Collet5ac72b42017-05-23 11:18:24 -07003542 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Sean Purcell2db72492017-02-09 10:50:43 -08003543}
3544
Yann Collet8c910d22017-06-03 01:15:02 -07003545/* ZSTD_initCStream_usingCDict_advanced() :
3546 * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
3547size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
3548 const ZSTD_CDict* cdict,
3549 ZSTD_frameParameters fParams,
3550 unsigned long long pledgedSrcSize)
3551{ /* cannot handle NULL cdict (does not know what to do) */
3552 if (!cdict) return ERROR(dictionary_wrong);
3553 { ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict);
3554 params.fParams = fParams;
3555 return ZSTD_initCStream_internal(zcs,
3556 NULL, 0, cdict,
3557 params, pledgedSrcSize);
3558 }
3559}
3560
3561/* note : cdict must outlive compression session */
3562size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3563{
3564 ZSTD_frameParameters const fParams = { 0 /* contentSize */, 0 /* checksum */, 0 /* hideDictID */ };
3565 return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, 0); /* note : will check that cdict != NULL */
3566}
3567
Yann Collet5a0c8e22016-08-12 01:20:36 +02003568size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
3569 const void* dict, size_t dictSize,
3570 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3571{
Yann Collet4b987ad2017-04-10 17:50:44 -07003572 CHECK_F( ZSTD_checkCParams(params.cParams) );
Yann Collet1ad7c822017-05-22 17:06:04 -07003573 zcs->requestedParams = params;
3574 zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Collet8c910d22017-06-03 01:15:02 -07003575 return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, pledgedSrcSize);
Yann Collet95162342016-10-25 16:19:52 -07003576}
3577
Yann Collet5a0c8e22016-08-12 01:20:36 +02003578size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3579{
3580 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet1ad7c822017-05-22 17:06:04 -07003581 zcs->compressionLevel = compressionLevel;
Yann Collet8c910d22017-06-03 01:15:02 -07003582 return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003583}
3584
Yann Collete795c8a2016-12-13 16:39:36 +01003585size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3586{
Yann Colletd564faa2016-12-18 21:39:15 +01003587 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
Yann Collete88034f2017-04-10 22:24:02 -07003588 params.fParams.contentSizeFlag = (pledgedSrcSize>0);
Yann Collet8c910d22017-06-03 01:15:02 -07003589 return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, params, pledgedSrcSize);
Yann Collete795c8a2016-12-13 16:39:36 +01003590}
3591
Yann Collet5a0c8e22016-08-12 01:20:36 +02003592size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3593{
Yann Collete88034f2017-04-10 22:24:02 -07003594 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0);
Yann Collet8c910d22017-06-03 01:15:02 -07003595 return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003596}
3597
Yann Collet104e5b02016-08-12 13:04:27 +02003598/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003599
Yann Collet01b15492017-05-30 18:10:26 -07003600MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity,
3601 const void* src, size_t srcSize)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003602{
3603 size_t const length = MIN(dstCapacity, srcSize);
Yann Collet18ab5af2017-05-31 09:59:22 -07003604 if (length) memcpy(dst, src, length);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003605 return length;
3606}
3607
3608static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
Yann Collet01b15492017-05-30 18:10:26 -07003609 ZSTD_outBuffer* output,
3610 ZSTD_inBuffer* input,
3611 ZSTD_EndDirective const flushMode)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003612{
Yann Collet01b15492017-05-30 18:10:26 -07003613 const char* const istart = (const char*)input->src;
3614 const char* const iend = istart + input->size;
3615 const char* ip = istart + input->pos;
3616 char* const ostart = (char*)output->dst;
3617 char* const oend = ostart + output->size;
3618 char* op = ostart + output->pos;
Yann Collet58e8d792017-06-02 18:20:48 -07003619 U32 someMoreWork = 1;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003620
Yann Collet58e8d792017-06-02 18:20:48 -07003621 /* check expectations */
Yann Collet8c910d22017-06-03 01:15:02 -07003622 DEBUGLOG(5, "ZSTD_compressStream_generic");
Yann Collet6d4fef32017-05-17 18:36:15 -07003623 assert(zcs->inBuff != NULL);
3624 assert(zcs->outBuff!= NULL);
Yann Collet58e8d792017-06-02 18:20:48 -07003625 assert(output->pos <= output->size);
3626 assert(input->pos <= input->size);
Yann Collet009d6042017-05-19 10:17:59 -07003627
Yann Collet5a0c8e22016-08-12 01:20:36 +02003628 while (someMoreWork) {
Yann Collet0be6fd32017-05-08 16:08:01 -07003629 switch(zcs->streamStage)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003630 {
Yann Collet1ad7c822017-05-22 17:06:04 -07003631 case zcss_init:
3632 /* call ZSTD_initCStream() first ! */
3633 return ERROR(init_missing);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003634
3635 case zcss_load:
3636 /* complete inBuffer */
3637 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
Yann Collet06589fe2017-05-31 10:03:20 -07003638 size_t const loaded = ZSTD_limitCopy(
3639 zcs->inBuff + zcs->inBuffPos, toLoad,
3640 ip, iend-ip);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003641 zcs->inBuffPos += loaded;
3642 ip += loaded;
Yann Collet009d6042017-05-19 10:17:59 -07003643 if ( (flushMode == ZSTD_e_continue)
3644 && (zcs->inBuffPos < zcs->inBuffTarget) ) {
3645 /* not enough input to fill full block : stop here */
3646 someMoreWork = 0; break;
3647 }
3648 if ( (flushMode == ZSTD_e_flush)
3649 && (zcs->inBuffPos == zcs->inToCompress) ) {
3650 /* empty */
3651 someMoreWork = 0; break;
Yann Collet559ee822017-06-16 11:58:21 -07003652 }
3653 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003654 /* compress current block (note : this stage cannot be stopped in the middle) */
Yann Collet009d6042017-05-19 10:17:59 -07003655 DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003656 { void* cDst;
3657 size_t cSize;
3658 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3659 size_t oSize = oend-op;
Yann Collet009d6042017-05-19 10:17:59 -07003660 unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003661 if (oSize >= ZSTD_compressBound(iSize))
Yann Collet559ee822017-06-16 11:58:21 -07003662 cDst = op; /* compress into output buffer, to skip flush stage */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003663 else
3664 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
Yann Collet009d6042017-05-19 10:17:59 -07003665 cSize = lastBlock ?
3666 ZSTD_compressEnd(zcs, cDst, oSize,
3667 zcs->inBuff + zcs->inToCompress, iSize) :
3668 ZSTD_compressContinue(zcs, cDst, oSize,
3669 zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003670 if (ZSTD_isError(cSize)) return cSize;
Yann Collet009d6042017-05-19 10:17:59 -07003671 zcs->frameEnded = lastBlock;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003672 /* prepare next block */
3673 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3674 if (zcs->inBuffTarget > zcs->inBuffSize)
Yann Collet009d6042017-05-19 10:17:59 -07003675 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
Yann Collet8b21ec42017-05-19 19:46:15 -07003676 DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
3677 (U32)zcs->inBuffTarget, (U32)zcs->inBuffSize);
3678 if (!lastBlock)
3679 assert(zcs->inBuffTarget <= zcs->inBuffSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003680 zcs->inToCompress = zcs->inBuffPos;
Yann Collet009d6042017-05-19 10:17:59 -07003681 if (cDst == op) { /* no need to flush */
3682 op += cSize;
3683 if (zcs->frameEnded) {
Yann Collet559ee822017-06-16 11:58:21 -07003684 DEBUGLOG(5, "Frame completed directly in outBuffer");
Yann Collet009d6042017-05-19 10:17:59 -07003685 someMoreWork = 0;
3686 zcs->streamStage = zcss_init;
3687 }
3688 break;
3689 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003690 zcs->outBuffContentSize = cSize;
3691 zcs->outBuffFlushedSize = 0;
Yann Collet009d6042017-05-19 10:17:59 -07003692 zcs->streamStage = zcss_flush; /* pass-through to flush stage */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003693 }
Jos Collin7cd7a752017-05-11 13:17:20 +05303694 /* fall-through */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003695 case zcss_flush:
Yann Collet009d6042017-05-19 10:17:59 -07003696 DEBUGLOG(5, "flush stage");
Yann Collet5a0c8e22016-08-12 01:20:36 +02003697 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
Yann Collet01b15492017-05-30 18:10:26 -07003698 size_t const flushed = ZSTD_limitCopy(op, oend-op,
3699 zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
Yann Collet009d6042017-05-19 10:17:59 -07003700 DEBUGLOG(5, "toFlush: %u ; flushed: %u", (U32)toFlush, (U32)flushed);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003701 op += flushed;
3702 zcs->outBuffFlushedSize += flushed;
Yann Collet01b15492017-05-30 18:10:26 -07003703 if (toFlush!=flushed) {
3704 /* dst too small to store flushed data : stop there */
3705 someMoreWork = 0;
3706 break;
3707 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003708 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet009d6042017-05-19 10:17:59 -07003709 if (zcs->frameEnded) {
Yann Collet559ee822017-06-16 11:58:21 -07003710 DEBUGLOG(5, "Frame completed on flush");
Yann Collet009d6042017-05-19 10:17:59 -07003711 someMoreWork = 0;
3712 zcs->streamStage = zcss_init;
3713 break;
3714 }
Yann Collet0be6fd32017-05-08 16:08:01 -07003715 zcs->streamStage = zcss_load;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003716 break;
3717 }
3718
3719 case zcss_final:
Yann Collet009d6042017-05-19 10:17:59 -07003720 someMoreWork = 0; break; /* useless */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003721
Yann Colletcd2892f2017-06-01 09:44:54 -07003722 default: /* impossible */
3723 assert(0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003724 }
3725 }
3726
Yann Collet01b15492017-05-30 18:10:26 -07003727 input->pos = ip - istart;
3728 output->pos = op - ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003729 if (zcs->frameEnded) return 0;
3730 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3731 if (hintInSize==0) hintInSize = zcs->blockSize;
3732 return hintInSize;
3733 }
3734}
3735
Yann Collet53e17fb2016-08-17 01:39:22 +02003736size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003737{
Yann Collet01b15492017-05-30 18:10:26 -07003738 /* check conditions */
3739 if (output->pos > output->size) return ERROR(GENERIC);
3740 if (input->pos > input->size) return ERROR(GENERIC);
3741
3742 return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003743}
3744
Yann Colletf35e2de2017-06-05 18:32:48 -07003745/*! ZSTDMT_initCStream_internal() :
3746 * Private use only. Init streaming operation.
3747 * expects params to be valid.
3748 * must receive dict, or cdict, or none, but not both.
3749 * @return : 0, or an error code */
3750size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
3751 const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
3752 ZSTD_parameters params, unsigned long long pledgedSrcSize);
3753
3754
Yann Colletdeee6e52017-05-30 17:42:00 -07003755size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
3756 ZSTD_outBuffer* output,
3757 ZSTD_inBuffer* input,
3758 ZSTD_EndDirective endOp)
Yann Collet6d4fef32017-05-17 18:36:15 -07003759{
3760 /* check conditions */
Yann Colletdeee6e52017-05-30 17:42:00 -07003761 if (output->pos > output->size) return ERROR(GENERIC);
3762 if (input->pos > input->size) return ERROR(GENERIC);
Yann Collet6d4fef32017-05-17 18:36:15 -07003763 assert(cctx!=NULL);
Yann Collet01b15492017-05-30 18:10:26 -07003764
Yann Collet6d4fef32017-05-17 18:36:15 -07003765 if (cctx->streamStage == zcss_init) {
3766 /* transparent reset */
Yann Collet1ad7c822017-05-22 17:06:04 -07003767 ZSTD_parameters params = cctx->requestedParams;
Yann Collet6d4fef32017-05-17 18:36:15 -07003768 if (cctx->compressionLevel != ZSTD_CLEVEL_CUSTOM)
3769 params.cParams = ZSTD_getCParams(cctx->compressionLevel,
3770 cctx->frameContentSize, 0 /* dictSize */);
Yann Colletf129fd32017-06-11 18:46:09 -07003771
3772#ifdef ZSTD_MULTITHREAD
Yann Colletf35e2de2017-06-05 18:32:48 -07003773 if (cctx->nbThreads > 1) {
3774 CHECK_F( ZSTDMT_initCStream_internal(cctx->mtctx, NULL, 0, cctx->cdict, params, cctx->frameContentSize) );
Yann Collet23aace92017-06-11 18:32:36 -07003775 cctx->streamStage = zcss_load;
Yann Colletf129fd32017-06-11 18:46:09 -07003776 } else
3777#endif
3778 {
Yann Colletf35e2de2017-06-05 18:32:48 -07003779 CHECK_F( ZSTD_resetCStream_internal(cctx, params, cctx->frameContentSize) );
3780 } }
3781
Yann Colletf129fd32017-06-11 18:46:09 -07003782#ifdef ZSTD_MULTITHREAD
Yann Colletf35e2de2017-06-05 18:32:48 -07003783 if (cctx->nbThreads > 1) {
Yann Collet559ee822017-06-16 11:58:21 -07003784 DEBUGLOG(5, "calling ZSTDMT_compressStream_generic(%i,...)", endOp);
Yann Collet23aace92017-06-11 18:32:36 -07003785 size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
Yann Collet559ee822017-06-16 11:58:21 -07003786 DEBUGLOG(5, "ZSTDMT result : %u", (U32)flushMin);
Yann Collet23aace92017-06-11 18:32:36 -07003787 if (ZSTD_isError(flushMin)) cctx->streamStage = zcss_init;
Yann Collet559ee822017-06-16 11:58:21 -07003788 if (endOp == ZSTD_e_end && flushMin==0)
3789 cctx->streamStage = zcss_init; /* compression completed */
Yann Collet23aace92017-06-11 18:32:36 -07003790 return flushMin;
Yann Collet6d4fef32017-05-17 18:36:15 -07003791 }
Yann Colletf129fd32017-06-11 18:46:09 -07003792#endif
Yann Collet6d4fef32017-05-17 18:36:15 -07003793
Yann Collet559ee822017-06-16 11:58:21 -07003794 DEBUGLOG(5, "calling ZSTD_compressStream_generic(%i,...)", endOp);
Yann Collet01b15492017-05-30 18:10:26 -07003795 CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
Yann Collet559ee822017-06-16 11:58:21 -07003796 DEBUGLOG(5, "completed ZSTD_compress_generic");
Yann Colletdeee6e52017-05-30 17:42:00 -07003797 return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
Yann Collet6d4fef32017-05-17 18:36:15 -07003798}
3799
Yann Colletdeee6e52017-05-30 17:42:00 -07003800size_t ZSTD_compress_generic_simpleArgs (
3801 ZSTD_CCtx* cctx,
3802 void* dst, size_t dstCapacity, size_t* dstPos,
3803 const void* src, size_t srcSize, size_t* srcPos,
3804 ZSTD_EndDirective endOp)
Yann Collet6d4fef32017-05-17 18:36:15 -07003805{
Yann Colletdeee6e52017-05-30 17:42:00 -07003806 ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
3807 ZSTD_inBuffer input = { src, srcSize, *srcPos };
Yann Collet01b15492017-05-30 18:10:26 -07003808 /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
Yann Collet58e8d792017-06-02 18:20:48 -07003809 size_t const cErr = ZSTD_compress_generic(cctx, &output, &input, endOp);
Yann Colletdeee6e52017-05-30 17:42:00 -07003810 *dstPos = output.pos;
3811 *srcPos = input.pos;
Yann Collet58e8d792017-06-02 18:20:48 -07003812 return cErr;
Yann Collet6d4fef32017-05-17 18:36:15 -07003813}
3814
Yann Collet5a0c8e22016-08-12 01:20:36 +02003815
Yann Collet104e5b02016-08-12 13:04:27 +02003816/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003817
3818/*! ZSTD_flushStream() :
3819* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003820size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003821{
Yann Collet18ab5af2017-05-31 09:59:22 -07003822 ZSTD_inBuffer input = { NULL, 0, 0 };
Yann Collet01b15492017-05-30 18:10:26 -07003823 if (output->pos > output->size) return ERROR(GENERIC);
3824 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_flush) );
3825 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003826}
3827
3828
Yann Collet53e17fb2016-08-17 01:39:22 +02003829size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003830{
Yann Collet18ab5af2017-05-31 09:59:22 -07003831 ZSTD_inBuffer input = { NULL, 0, 0 };
Yann Collet01b15492017-05-30 18:10:26 -07003832 if (output->pos > output->size) return ERROR(GENERIC);
3833 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_end) );
Yann Collet009d6042017-05-19 10:17:59 -07003834
Yann Collet48855fa2017-05-19 10:56:11 -07003835 DEBUGLOG(5, "ZSTD_endStream : remaining to flush : %u",
Yann Collet009d6042017-05-19 10:17:59 -07003836 (unsigned)(zcs->outBuffContentSize - zcs->outBuffFlushedSize));
Yann Collet009d6042017-05-19 10:17:59 -07003837 return zcs->outBuffContentSize - zcs->outBuffFlushedSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003838}
3839
3840
Yann Collet70e8c382016-02-10 13:37:52 +01003841/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003842
inikep2c5eeea2016-04-15 13:44:46 +02003843#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003844int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003845
Yann Collet3b719252016-03-30 19:48:05 +02003846static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003847{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003848 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003849 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003850 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3851 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003852 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3853 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003854 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3855 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3856 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003857 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003858 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3859 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3860 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3861 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3862 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3863 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3864 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3865 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003866 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
Yann Collet29297c62017-04-27 17:44:01 -07003867 { 23, 22, 22, 5, 4, 32, ZSTD_btopt }, /* level 18 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003868 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Nick Terrell374f8682017-05-10 17:48:42 -07003869 { 25, 25, 23, 7, 3, 64, ZSTD_btultra }, /* level 20 */
3870 { 26, 26, 23, 7, 3,256, ZSTD_btultra }, /* level 21 */
3871 { 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003872},
3873{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003874 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003875 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003876 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003877 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3878 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3879 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3880 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3881 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3882 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3883 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3884 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3885 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3886 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3887 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3888 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003889 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003890 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3891 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3892 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003893 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3894 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003895 { 18, 19, 18, 11, 3,512, ZSTD_btultra }, /* level 20.*/
3896 { 18, 19, 18, 12, 3,512, ZSTD_btultra }, /* level 21.*/
3897 { 18, 19, 18, 13, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003898},
3899{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003900 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003901 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3902 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3903 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3904 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3905 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3906 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3907 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3908 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3909 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3910 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3911 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3912 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3913 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3914 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003915 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3916 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3917 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3918 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3919 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3920 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003921 { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/
3922 { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/
3923 { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003924},
3925{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003926 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003927 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003928 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003929 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3930 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3931 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3932 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3933 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3934 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3935 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3936 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003937 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3938 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3939 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3940 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3941 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3942 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3943 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3944 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3945 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3946 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003947 { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/
3948 { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/
3949 { 14, 15, 15, 10, 3,256, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003950},
3951};
3952
Yann Collet236d94f2016-05-18 12:06:33 +02003953/*! ZSTD_getCParams() :
3954* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3955* Size values are optional, provide 0 if not known or unused */
Yann Collet009d6042017-05-19 10:17:59 -07003956ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003957{
Yann Collet15354142016-04-04 04:22:53 +02003958 ZSTD_compressionParameters cp;
Yann Collet009d6042017-05-19 10:17:59 -07003959 size_t const addedSize = srcSizeHint ? 0 : 500;
3960 U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003961 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet6d4fef32017-05-17 18:36:15 -07003962 if (compressionLevel <= 0) compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003963 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003964 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003965 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3966 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003967 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003968 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3969 }
Yann Collet009d6042017-05-19 10:17:59 -07003970 cp = ZSTD_adjustCParams(cp, srcSizeHint, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003971 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003972}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003973
3974/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003975* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003976* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet009d6042017-05-19 10:17:59 -07003977ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003978 ZSTD_parameters params;
Yann Collet009d6042017-05-19 10:17:59 -07003979 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize);
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003980 memset(&params, 0, sizeof(params));
3981 params.cParams = cParams;
3982 return params;
3983}