blob: 8f7c200b234718955b6e4eff08caf9c72dd700e1 [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 Collet31533ba2017-04-27 00:29:04 -070032* Debug
33***************************************/
34#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
35# include <assert.h>
36#else
37# define assert(condition) ((void)0)
38#endif
39
40#define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; }
41
42#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2)
43# include <stdio.h>
44 static unsigned g_debugLevel = ZSTD_DEBUG;
Yann Collet009d6042017-05-19 10:17:59 -070045# define DEBUGLOG(l, ...) { \
46 if (l<=g_debugLevel) { \
47 fprintf(stderr, __FILE__ ": "); \
48 fprintf(stderr, __VA_ARGS__); \
49 fprintf(stderr, " \n"); \
50 } }
Yann Collet31533ba2017-04-27 00:29:04 -070051#else
52# define DEBUGLOG(l, ...) {} /* disabled */
53#endif
54
55
56/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010057* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010058***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010059static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Collet731ef162016-07-27 21:05:12 +020060#define HASH_READ_SIZE 8
61typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
Yann Colletf3eca252015-10-22 15:31:46 +010062
Yann Collet71ddeb62017-04-20 22:54:54 -070063/* entropy tables always have same size */
64static size_t const hufCTable_size = HUF_CTABLE_SIZE(255);
Yann Collete42afbc2017-04-26 11:39:35 -070065static size_t const litlengthCTable_size = FSE_CTABLE_SIZE(LLFSELog, MaxLL);
66static size_t const offcodeCTable_size = FSE_CTABLE_SIZE(OffFSELog, MaxOff);
67static size_t const matchlengthCTable_size = FSE_CTABLE_SIZE(MLFSELog, MaxML);
Yann Collet72712032017-04-20 23:21:19 -070068static size_t const entropyScratchSpace_size = HUF_WORKSPACE_SIZE;
Yann Colleta34a39c2017-04-20 18:17:58 -070069
Yann Colletf3eca252015-10-22 15:31:46 +010070
Yann Collet7d360282016-02-12 00:07:30 +010071/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010072* Helper functions
73***************************************/
Yann Collet3f75d522017-03-31 17:11:38 -070074size_t ZSTD_compressBound(size_t srcSize) {
Yann Collet30c76982017-03-31 18:27:03 -070075 size_t const lowLimit = 256 KB;
76 size_t const margin = (srcSize < lowLimit) ? (lowLimit-srcSize) >> 12 : 0; /* from 64 to 0 */
Yann Collet3f75d522017-03-31 17:11:38 -070077 return srcSize + (srcSize >> 8) + margin;
78}
Yann Collet59d1f792016-01-23 19:28:41 +010079
80
Yann Collet7d360282016-02-12 00:07:30 +010081/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010082* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010083***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010084static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
85{
Yann Collet14983e72015-11-11 21:38:21 +010086 ssPtr->lit = ssPtr->litStart;
Yann Colletc0ce4f12016-07-30 00:55:13 +020087 ssPtr->sequences = ssPtr->sequencesStart;
Yann Collet5d393572016-04-07 17:19:00 +020088 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010089}
90
91
Yann Collet7d360282016-02-12 00:07:30 +010092/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010093* Context memory management
94***************************************/
Yann Collet6d4fef32017-05-17 18:36:15 -070095typedef enum { zcss_init=0, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
Yann Collet0be6fd32017-05-08 16:08:01 -070096
Yann Collet18803372017-05-22 18:21:51 -070097struct ZSTD_CDict_s {
98 void* dictBuffer;
99 const void* dictContent;
100 size_t dictContentSize;
101 ZSTD_CCtx* refContext;
102}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
103
Yann Colletaca113f2016-12-23 22:25:03 +0100104struct ZSTD_CCtx_s {
Yann Collet89db5e02015-11-13 11:27:46 +0100105 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100106 const BYTE* base; /* All regular indexes relative to this position */
107 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +0100108 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100109 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +0100110 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +0100111 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +0100112 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Colletbb002742017-01-25 16:25:38 -0800113 U32 loadedDictEnd; /* index of end of dictionary */
114 U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
Yann Collet14312d82017-02-23 23:42:12 -0800115 U32 forceRawDict; /* Force loading dictionary in "content-only" mode (no header analysis) */
Yann Collet731ef162016-07-27 21:05:12 +0200116 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +0200117 U32 rep[ZSTD_REP_NUM];
Yann Colletb459aad2017-01-19 17:33:37 -0800118 U32 repToConfirm[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +0200119 U32 dictID;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700120 int compressionLevel;
Yann Collet1ad7c822017-05-22 17:06:04 -0700121 ZSTD_parameters requestedParams;
122 ZSTD_parameters appliedParams;
Yann Collet712def92015-10-29 18:41:45 +0100123 void* workSpace;
124 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100125 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +0200126 U64 frameContentSize;
Yann Collet20d5e032017-04-11 18:34:02 -0700127 U64 consumedSrcSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200128 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +0200129 ZSTD_customMem customMem;
Yann Colletc7fe2622017-05-23 13:16:00 -0700130 size_t staticSize;
Yann Colletecd651b2016-01-07 15:35:18 +0100131
Yann Collet712def92015-10-29 18:41:45 +0100132 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100133 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +0100134 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +0200135 U32* chainTable;
Yann Collet71ddeb62017-04-20 22:54:54 -0700136 HUF_repeat hufCTable_repeatMode;
137 HUF_CElt* hufCTable;
138 U32 fseCTables_ready;
Yann Collet71aaa322017-04-20 23:03:38 -0700139 FSE_CTable* offcodeCTable;
140 FSE_CTable* matchlengthCTable;
141 FSE_CTable* litlengthCTable;
Yann Collete42afbc2017-04-26 11:39:35 -0700142 unsigned* entropyScratchSpace;
Yann Collet0be6fd32017-05-08 16:08:01 -0700143
144 /* streaming */
145 ZSTD_CDict* cdictLocal;
146 const ZSTD_CDict* cdict;
147 char* inBuff;
148 size_t inBuffSize;
149 size_t inToCompress;
150 size_t inBuffPos;
151 size_t inBuffTarget;
152 char* outBuff;
153 size_t outBuffSize;
154 size_t outBuffContentSize;
155 size_t outBuffFlushedSize;
156 ZSTD_cStreamStage streamStage;
157 U32 frameEnded;
Yann Colletc4a5a212017-06-01 17:56:14 -0700158
159 /* Multi-threading */
Yann Colletc35e5352017-06-01 18:44:06 -0700160 U32 nbThreads;
Yann Colletc4a5a212017-06-01 17:56:14 -0700161 ZSTDMT_CCtx* mtctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100162};
163
Yann Colletc4a5a212017-06-01 17:56:14 -0700164
Yann Collet5be2dd22015-11-11 13:43:58 +0100165ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100166{
Yann Colletae728a42017-05-30 17:11:39 -0700167 return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
inikep50e82c02016-05-23 15:49:09 +0200168}
169
170ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
171{
Yann Collet69c2cdb2016-07-14 16:52:45 +0200172 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +0200173
Yann Colletae728a42017-05-30 17:11:39 -0700174 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200175
Yann Colletc4f46b92017-05-30 17:45:37 -0700176 cctx = (ZSTD_CCtx*) ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200177 if (!cctx) return NULL;
Yann Colletbb002742017-01-25 16:25:38 -0800178 cctx->customMem = customMem;
Yann Collet6d4fef32017-05-17 18:36:15 -0700179 cctx->compressionLevel = ZSTD_CLEVEL_DEFAULT;
Yann Collet69c2cdb2016-07-14 16:52:45 +0200180 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100181}
182
Yann Colletc7fe2622017-05-23 13:16:00 -0700183ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
184{
185 ZSTD_CCtx* cctx = (ZSTD_CCtx*) workspace;
186 if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
187 if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
188 memset(workspace, 0, workspaceSize);
189 cctx->staticSize = workspaceSize;
190 cctx->workSpace = (void*)(cctx+1);
191 cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
192
193 /* entropy space (never moves) */
194 /* note : this code should be shared with resetCCtx, instead of copied */
195 { void* ptr = cctx->workSpace;
196 cctx->hufCTable = (HUF_CElt*)ptr;
Yann Collet0fdc71c2017-05-24 17:41:41 -0700197 ptr = (char*)cctx->hufCTable + hufCTable_size;
Yann Colletc7fe2622017-05-23 13:16:00 -0700198 cctx->offcodeCTable = (FSE_CTable*) ptr;
199 ptr = (char*)ptr + offcodeCTable_size;
200 cctx->matchlengthCTable = (FSE_CTable*) ptr;
201 ptr = (char*)ptr + matchlengthCTable_size;
202 cctx->litlengthCTable = (FSE_CTable*) ptr;
203 ptr = (char*)ptr + litlengthCTable_size;
204 assert(((size_t)ptr & 3) == 0); /* ensure correct alignment */
205 cctx->entropyScratchSpace = (unsigned*) ptr;
206 }
207
208 return cctx;
209}
210
Yann Collet5be2dd22015-11-11 13:43:58 +0100211size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100212{
inikep36403962016-06-03 16:36:50 +0200213 if (cctx==NULL) return 0; /* support free on NULL */
Yann Colletc4a5a212017-06-01 17:56:14 -0700214 if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */
Yann Collet23b6e052016-08-28 21:05:43 -0700215 ZSTD_free(cctx->workSpace, cctx->customMem);
Yann Collet78553662017-05-08 17:15:00 -0700216 cctx->workSpace = NULL;
217 ZSTD_freeCDict(cctx->cdictLocal);
218 cctx->cdictLocal = NULL;
Yann Colletc4a5a212017-06-01 17:56:14 -0700219 ZSTDMT_freeCCtx(cctx->mtctx);
220 cctx->mtctx = NULL;
Yann Collet23b6e052016-08-28 21:05:43 -0700221 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100222 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100223}
224
Yann Collet70e3b312016-08-23 01:18:06 +0200225size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200226{
Yann Colletd7c65892016-09-15 02:50:27 +0200227 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet791d7442017-05-08 16:17:30 -0700228 return sizeof(*cctx) + cctx->workSpaceSize
229 + ZSTD_sizeof_CDict(cctx->cdictLocal)
Yann Colletc4a5a212017-06-01 17:56:14 -0700230 + cctx->outBuffSize + cctx->inBuffSize
231 + ZSTDMT_sizeof_CCtx(cctx->mtctx);
Yann Collet3ae543c2016-07-11 03:12:17 +0200232}
233
Yann Collet009d6042017-05-19 10:17:59 -0700234size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
235{
236 return ZSTD_sizeof_CCtx(zcs); /* same object */
237}
238
Yann Colletb0edb7f2017-05-12 15:31:53 -0700239/* private API call, for dictBuilder only */
240const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
241
Yann Collet1ad7c822017-05-22 17:06:04 -0700242static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return cctx->appliedParams; }
Yann Colletb0edb7f2017-05-12 15:31:53 -0700243
Yann Colletef738c12017-05-12 13:53:46 -0700244/* older variant; will be deprecated */
Yann Colletbb002742017-01-25 16:25:38 -0800245size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
246{
247 switch(param)
248 {
Yann Collet06e76972017-01-25 16:39:03 -0800249 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
Yann Collet14312d82017-02-23 23:42:12 -0800250 case ZSTD_p_forceRawDict : cctx->forceRawDict = value>0; return 0;
Yann Colletbb002742017-01-25 16:25:38 -0800251 default: return ERROR(parameter_unknown);
252 }
253}
254
Yann Colletadd66f82017-05-12 15:59:48 -0700255
Yann Collet6d4fef32017-05-17 18:36:15 -0700256#define ZSTD_CLEVEL_CUSTOM 999
Yann Colletadd66f82017-05-12 15:59:48 -0700257static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx)
258{
Yann Collet1ad7c822017-05-22 17:06:04 -0700259 if (cctx->compressionLevel==ZSTD_CLEVEL_CUSTOM) return;
260 cctx->requestedParams.cParams = ZSTD_getCParams(cctx->compressionLevel,
261 cctx->frameContentSize, 0);
Yann Collet6d4fef32017-05-17 18:36:15 -0700262 cctx->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Colletadd66f82017-05-12 15:59:48 -0700263}
264
Yann Colletb0edb7f2017-05-12 15:31:53 -0700265size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value)
Yann Collet7d360282016-02-12 00:07:30 +0100266{
Yann Collet334a2882017-05-19 11:04:41 -0700267# define CLAMPCHECK(val,min,max) { \
268 if ((val<min) | (val>max)) { \
269 return ERROR(compressionParameter_unsupported); \
270 } }
271
Yann Collet24de7b02017-05-22 13:05:45 -0700272 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700273
274 switch(param)
275 {
276 case ZSTD_p_compressionLevel :
Yann Colletcd2892f2017-06-01 09:44:54 -0700277 if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel(); /* cap max compression level */
278 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
279 cctx->compressionLevel = value;
280 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700281
282 case ZSTD_p_windowLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700283 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
284 CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
285 ZSTD_cLevelToCParams(cctx);
286 cctx->requestedParams.cParams.windowLog = value;
287 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700288
289 case ZSTD_p_hashLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700290 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
291 CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
292 ZSTD_cLevelToCParams(cctx);
293 cctx->requestedParams.cParams.hashLog = value;
294 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700295
296 case ZSTD_p_chainLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700297 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
298 CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
299 ZSTD_cLevelToCParams(cctx);
300 cctx->requestedParams.cParams.chainLog = value;
301 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700302
303 case ZSTD_p_searchLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700304 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
305 CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
306 ZSTD_cLevelToCParams(cctx);
307 cctx->requestedParams.cParams.searchLog = value;
308 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700309
Yann Collet6d4fef32017-05-17 18:36:15 -0700310 case ZSTD_p_minMatch :
Yann Colletcd2892f2017-06-01 09:44:54 -0700311 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
312 CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
313 ZSTD_cLevelToCParams(cctx);
314 cctx->requestedParams.cParams.searchLength = value;
315 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700316
317 case ZSTD_p_targetLength :
Yann Colletcd2892f2017-06-01 09:44:54 -0700318 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
319 CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
320 ZSTD_cLevelToCParams(cctx);
321 cctx->requestedParams.cParams.targetLength = value;
322 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700323
324 case ZSTD_p_compressionStrategy :
Yann Colletcd2892f2017-06-01 09:44:54 -0700325 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
326 CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
327 ZSTD_cLevelToCParams(cctx);
328 cctx->requestedParams.cParams.strategy = (ZSTD_strategy)value;
329 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700330
331#if 0
332 case ZSTD_p_windowSize : /* to be done later */
Yann Colletcd2892f2017-06-01 09:44:54 -0700333 return ERROR(compressionParameter_unsupported);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700334#endif
335
Yann Colletcd2892f2017-06-01 09:44:54 -0700336 case ZSTD_p_contentSizeFlag :
337 /* Content size written in frame header _when known_ (default:1) */
338 cctx->requestedParams.fParams.contentSizeFlag = value>0;
339 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700340
Yann Colletcd2892f2017-06-01 09:44:54 -0700341 case ZSTD_p_checksumFlag :
342 /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
343 cctx->requestedParams.fParams.checksumFlag = value>0;
344 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700345
Yann Collet1ad7c822017-05-22 17:06:04 -0700346 case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
Yann Colletcd2892f2017-06-01 09:44:54 -0700347 DEBUGLOG(5, "set dictIDFlag = %u", (value>0));
348 cctx->requestedParams.fParams.noDictIDFlag = (value==0);
349 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700350
351 case ZSTD_p_refDictContent : /* to be done later */
Yann Colletcd2892f2017-06-01 09:44:54 -0700352 return ERROR(compressionParameter_unsupported);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700353
354 case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize,
355 * even when referencing into Dictionary content
356 * default : 0 when using a CDict, 1 when using a Prefix */
Yann Colletc35e5352017-06-01 18:44:06 -0700357 cctx->forceWindow = value>0;
358 cctx->loadedDictEnd = 0;
359 return 0;
360
361 case ZSTD_p_nbThreads:
362 if (value==0) return 0;
363#ifndef ZSTD_MULTITHREAD
364 if (value > 1) return ERROR(compressionParameter_unsupported);
365#endif
366 if ((value>1) && (cctx->nbThreads != value)) {
367 ZSTDMT_freeCCtx(cctx->mtctx);
368 cctx->nbThreads = value;
369 cctx->mtctx = ZSTDMT_createCCtx(value);
370 if (cctx->mtctx == NULL) return ERROR(memory_allocation);
371 }
372 cctx->nbThreads = 1;
373 return 0;
374
375 case ZSTDMT_p_jobSize:
376 if (cctx->nbThreads <= 1) return ERROR(compressionParameter_unsupported);
377 assert(cctx->mtctx != NULL);
378 return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_sectionSize, value);
379
380 case ZSTDMT_p_overlapSizeLog:
381 if (cctx->nbThreads <= 1) return ERROR(compressionParameter_unsupported);
382 assert(cctx->mtctx != NULL);
383 return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_overlapSectionLog, value);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700384
385 case ZSTD_p_rawContentDict : /* load dictionary in "content-only" mode (no header analysis) (default:0) */
Yann Colletcd2892f2017-06-01 09:44:54 -0700386 cctx->forceRawDict = value>0;
387 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700388
389 default: return ERROR(parameter_unknown);
390 }
Yann Collet7d360282016-02-12 00:07:30 +0100391}
392
Yann Colletb0edb7f2017-05-12 15:31:53 -0700393ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
Yann Collet95162342016-10-25 16:19:52 -0700394{
Yann Collet24de7b02017-05-22 13:05:45 -0700395 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700396 cctx->frameContentSize = pledgedSrcSize;
397 return 0;
398}
399
Yann Collet6d4fef32017-05-17 18:36:15 -0700400ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
401{
Yann Collet24de7b02017-05-22 13:05:45 -0700402 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletc7fe2622017-05-23 13:16:00 -0700403 if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
Yann Collet6d4fef32017-05-17 18:36:15 -0700404 ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */
405 if (dict==NULL || dictSize==0) { /* no dictionary mode */
406 cctx->cdictLocal = NULL;
407 cctx->cdict = NULL;
408 } else {
Yann Collet8b21ec42017-05-19 19:46:15 -0700409 ZSTD_compressionParameters const cParams =
410 cctx->compressionLevel == ZSTD_CLEVEL_CUSTOM ?
Yann Collet1ad7c822017-05-22 17:06:04 -0700411 cctx->requestedParams.cParams :
Yann Collet8b21ec42017-05-19 19:46:15 -0700412 ZSTD_getCParams(cctx->compressionLevel, 0, dictSize);
Yann Collet6d4fef32017-05-17 18:36:15 -0700413 cctx->cdictLocal = ZSTD_createCDict_advanced(
414 dict, dictSize,
415 0 /* byReference */,
Yann Collet8b21ec42017-05-19 19:46:15 -0700416 cParams, cctx->customMem);
Yann Collet6d4fef32017-05-17 18:36:15 -0700417 cctx->cdict = cctx->cdictLocal;
418 if (cctx->cdictLocal == NULL)
419 return ERROR(memory_allocation);
420 }
421 return 0;
422}
423
Yann Colletb0edb7f2017-05-12 15:31:53 -0700424/* Not ready yet ! */
425ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
426{
427 (void)cctx; (void)prefix; (void)prefixSize; /* to be done later */
Yann Collet24de7b02017-05-22 13:05:45 -0700428 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700429 return ERROR(compressionParameter_unsupported);
430}
431
Yann Colletb0edb7f2017-05-12 15:31:53 -0700432ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
433{
Yann Collet24de7b02017-05-22 13:05:45 -0700434 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
435 cctx->cdict = cdict;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700436 return ERROR(compressionParameter_unsupported);
Yann Collet95162342016-10-25 16:19:52 -0700437}
438
Yann Collet59d70632015-11-04 12:05:27 +0100439
Yann Collet21588e32016-03-30 16:50:44 +0200440/** ZSTD_checkParams() :
441 ensure param values remain within authorized range.
442 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200443size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200444{
Yann Collet15354142016-04-04 04:22:53 +0200445 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200446 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200447 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
448 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Collet2e2e78d2017-03-29 16:02:47 -0700449 CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200450 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800451 if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200452 return 0;
453}
454
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100455/** ZSTD_cycleLog() :
456 * condition for correct operation : hashLog > 1 */
457static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
458{
459 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
460 return hashLog - btScale;
461}
462
Yann Collet70d13012016-06-01 18:45:34 +0200463/** ZSTD_adjustCParams() :
Yann Colletcf409a72016-09-26 16:41:05 +0200464 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200465 mostly downsizing to reduce memory consumption and initialization.
466 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
467 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200468 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200469ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100470{
Yann Collet70d13012016-06-01 18:45:34 +0200471 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100472
Yann Collet70e45772016-03-19 18:08:32 +0100473 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200474 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
475 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200476 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200477 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200478 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200479 } }
Yann Collet70d13012016-06-01 18:45:34 +0200480 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100481 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
482 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
483 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100484
Yann Collet70d13012016-06-01 18:45:34 +0200485 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200486
487 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100488}
489
490
Yann Collet88472382016-07-14 17:05:38 +0200491size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100492{
Yann Colletfa3671e2017-05-19 10:51:30 -0700493 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
Yann Collet731ef162016-07-27 21:05:12 +0200494 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
495 size_t const maxNbSeq = blockSize / divider;
496 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200497
Yann Collet731ef162016-07-27 21:05:12 +0200498 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
499 size_t const hSize = ((size_t)1) << cParams.hashLog;
500 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
501 size_t const h3Size = ((size_t)1) << hashLog3;
Yann Collet71ddeb62017-04-20 22:54:54 -0700502 size_t const entropySpace = hufCTable_size + litlengthCTable_size
Yann Colleta4086452017-04-20 23:09:39 -0700503 + offcodeCTable_size + matchlengthCTable_size
Yann Collet72712032017-04-20 23:21:19 -0700504 + entropyScratchSpace_size;
Yann Collet731ef162016-07-27 21:05:12 +0200505 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200506
Yann Colletfc514592017-05-08 17:07:59 -0700507 size_t const optBudget = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
Yann Collet3ae543c2016-07-11 03:12:17 +0200508 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
Nick Terrell5f2c7212017-05-10 16:49:58 -0700509 size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
Yann Colletfc514592017-05-08 17:07:59 -0700510 size_t const neededSpace = entropySpace + tableSpace + tokenSpace + optSpace;
Yann Collet3ae543c2016-07-11 03:12:17 +0200511
512 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100513}
514
Yann Colletc7fe2622017-05-23 13:16:00 -0700515size_t ZSTD_estimateCStreamSize(ZSTD_compressionParameters cParams)
516{
517 size_t const CCtxSize = ZSTD_estimateCCtxSize(cParams);
518 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
519 size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
520 size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
521 size_t const streamingSize = inBuffSize + outBuffSize;
522
523 return CCtxSize + streamingSize;
524}
525
Yann Colleta7737f62016-09-06 09:44:59 +0200526
Yann Collet009d6042017-05-19 10:17:59 -0700527static U32 ZSTD_equivalentParams(ZSTD_compressionParameters cParams1,
528 ZSTD_compressionParameters cParams2)
Yann Colleta7737f62016-09-06 09:44:59 +0200529{
Yann Colletfa3671e2017-05-19 10:51:30 -0700530 U32 bslog1 = MIN(cParams1.windowLog, ZSTD_BLOCKSIZELOG_MAX);
531 U32 bslog2 = MIN(cParams2.windowLog, ZSTD_BLOCKSIZELOG_MAX);
Yann Collet009d6042017-05-19 10:17:59 -0700532 return (bslog1 == bslog2) /* same block size */
533 & (cParams1.hashLog == cParams2.hashLog)
534 & (cParams1.chainLog == cParams2.chainLog)
535 & (cParams1.strategy == cParams2.strategy) /* opt parser space */
536 & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */
Yann Colleta7737f62016-09-06 09:44:59 +0200537}
538
539/*! ZSTD_continueCCtx() :
540 reuse CCtx without reset (note : requires no dictionary) */
541static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
542{
543 U32 const end = (U32)(cctx->nextSrc - cctx->base);
Yann Collet1ad7c822017-05-22 17:06:04 -0700544 cctx->appliedParams = params;
Yann Colleta7737f62016-09-06 09:44:59 +0200545 cctx->frameContentSize = frameContentSize;
Yann Collet20d5e032017-04-11 18:34:02 -0700546 cctx->consumedSrcSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200547 cctx->lowLimit = end;
548 cctx->dictLimit = end;
549 cctx->nextToUpdate = end+1;
550 cctx->stage = ZSTDcs_init;
551 cctx->dictID = 0;
552 cctx->loadedDictEnd = 0;
553 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200554 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
555 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200556 return 0;
557}
558
Yann Colletb0739bc2017-05-22 17:45:15 -0700559typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
Yann Colleta7737f62016-09-06 09:44:59 +0200560
Yann Collet5ac72b42017-05-23 11:18:24 -0700561typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
562
Yann Collet30fb4992017-04-18 14:08:50 -0700563/*! ZSTD_resetCCtx_internal() :
Yann Collet5ac72b42017-05-23 11:18:24 -0700564 note : `params` are assumed fully validated at this stage */
565static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
566 ZSTD_parameters params, U64 frameContentSize,
567 ZSTD_compResetPolicy_e const crp,
568 ZSTD_buffered_policy_e const zbuff)
Yann Colleta7737f62016-09-06 09:44:59 +0200569{
Yann Collet009d6042017-05-19 10:17:59 -0700570 DEBUGLOG(5, "ZSTD_resetCCtx_internal : wlog=%u / old=%u",
Yann Collet1ad7c822017-05-22 17:06:04 -0700571 params.cParams.windowLog, zc->appliedParams.cParams.windowLog);
Yann Collet5ac72b42017-05-23 11:18:24 -0700572 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet0be6fd32017-05-08 16:08:01 -0700573
Yann Colletb0739bc2017-05-22 17:45:15 -0700574 if (crp == ZSTDcrp_continue) {
Yann Collet1ad7c822017-05-22 17:06:04 -0700575 if (ZSTD_equivalentParams(params.cParams, zc->appliedParams.cParams)) {
Yann Collet009d6042017-05-19 10:17:59 -0700576 DEBUGLOG(5, "ZSTD_equivalentParams()==1");
Yann Collet71ddeb62017-04-20 22:54:54 -0700577 zc->fseCTables_ready = 0;
578 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200579 return ZSTD_continueCCtx(zc, params, frameContentSize);
Yann Colletb0739bc2017-05-22 17:45:15 -0700580 } }
inikep87d4f3d2016-03-02 15:56:24 +0100581
Yann Colletfa3671e2017-05-19 10:51:30 -0700582 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200583 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
584 size_t const maxNbSeq = blockSize / divider;
585 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet5ac72b42017-05-23 11:18:24 -0700586 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ?
587 0 : (1 << params.cParams.chainLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200588 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
Yann Collet5ac72b42017-05-23 11:18:24 -0700589 U32 const hashLog3 = (params.cParams.searchLength>3) ?
590 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200591 size_t const h3Size = ((size_t)1) << hashLog3;
592 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet5ac72b42017-05-23 11:18:24 -0700593 size_t const buffOutSize = ZSTD_compressBound(blockSize)+1;
594 size_t const buffInSize = ((size_t)1 << params.cParams.windowLog) + blockSize;
Yann Colleta7737f62016-09-06 09:44:59 +0200595 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100596
Yann Colleta7737f62016-09-06 09:44:59 +0200597 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Collet71ddeb62017-04-20 22:54:54 -0700598 { size_t const entropySpace = hufCTable_size + litlengthCTable_size
Yann Colleta4086452017-04-20 23:09:39 -0700599 + offcodeCTable_size + matchlengthCTable_size
Yann Collet72712032017-04-20 23:21:19 -0700600 + entropyScratchSpace_size;
Yann Collet71ddeb62017-04-20 22:54:54 -0700601 size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
Yann Collete6fa70a2017-04-20 17:28:31 -0700602 + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
Yann Collet5ac72b42017-05-23 11:18:24 -0700603 size_t const optSpace = ( (params.cParams.strategy == ZSTD_btopt)
604 || (params.cParams.strategy == ZSTD_btultra)) ?
605 optPotentialSpace : 0;
606 size_t const bufferSpace = (zbuff==ZSTDb_buffered) ?
607 buffInSize + buffOutSize : 0;
608 size_t const neededSpace = entropySpace + optSpace + tableSpace
609 + tokenSpace + bufferSpace;
Yann Colletc7fe2622017-05-23 13:16:00 -0700610
611 if (zc->workSpaceSize < neededSpace) { /* too small : resize /*/
Yann Collet0be6fd32017-05-08 16:08:01 -0700612 DEBUGLOG(5, "Need to update workSpaceSize from %uK to %uK \n",
Yann Colletc7fe2622017-05-23 13:16:00 -0700613 (unsigned)zc->workSpaceSize>>10,
614 (unsigned)neededSpace>>10);
615 /* static cctx : no resize, error out */
616 if (zc->staticSize) return ERROR(memory_allocation);
617
Yann Collet0181fef2017-04-06 01:25:26 -0700618 zc->workSpaceSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200619 ZSTD_free(zc->workSpace, zc->customMem);
620 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
621 if (zc->workSpace == NULL) return ERROR(memory_allocation);
622 zc->workSpaceSize = neededSpace;
Yann Collet7bb60b12017-04-20 17:38:56 -0700623 ptr = zc->workSpace;
624
625 /* entropy space */
Yann Collet71ddeb62017-04-20 22:54:54 -0700626 zc->hufCTable = (HUF_CElt*)ptr;
627 ptr = (char*)zc->hufCTable + hufCTable_size; /* note : HUF_CElt* is incomplete type, size is estimated via macro */
Yann Collet71aaa322017-04-20 23:03:38 -0700628 zc->offcodeCTable = (FSE_CTable*) ptr;
629 ptr = (char*)ptr + offcodeCTable_size;
Yann Collet72712032017-04-20 23:21:19 -0700630 zc->matchlengthCTable = (FSE_CTable*) ptr;
Yann Collet71aaa322017-04-20 23:03:38 -0700631 ptr = (char*)ptr + matchlengthCTable_size;
Yann Collet72712032017-04-20 23:21:19 -0700632 zc->litlengthCTable = (FSE_CTable*) ptr;
633 ptr = (char*)ptr + litlengthCTable_size;
634 assert(((size_t)ptr & 3) == 0); /* ensure correct alignment */
Yann Collete42afbc2017-04-26 11:39:35 -0700635 zc->entropyScratchSpace = (unsigned*) ptr;
Yann Colleta7737f62016-09-06 09:44:59 +0200636 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100637
Yann Collete6fa70a2017-04-20 17:28:31 -0700638 /* init params */
Yann Collet1ad7c822017-05-22 17:06:04 -0700639 zc->appliedParams = params;
Yann Collete6fa70a2017-04-20 17:28:31 -0700640 zc->blockSize = blockSize;
Yann Collet009d6042017-05-19 10:17:59 -0700641 DEBUGLOG(5, "blockSize = %uK", (U32)blockSize>>10);
Yann Collete6fa70a2017-04-20 17:28:31 -0700642 zc->frameContentSize = frameContentSize;
643 zc->consumedSrcSize = 0;
Yann Collet70e8c382016-02-10 13:37:52 +0100644
Yann Collet083fcc82015-10-25 14:06:35 +0100645 XXH64_reset(&zc->xxhState, 0);
Yann Collete6fa70a2017-04-20 17:28:31 -0700646 zc->stage = ZSTDcs_init;
647 zc->dictID = 0;
648 zc->loadedDictEnd = 0;
Yann Collet71ddeb62017-04-20 22:54:54 -0700649 zc->fseCTables_ready = 0;
650 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200651 zc->nextToUpdate = 1;
652 zc->nextSrc = NULL;
653 zc->base = NULL;
654 zc->dictBase = NULL;
655 zc->dictLimit = 0;
656 zc->lowLimit = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200657 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
Yann Collete6fa70a2017-04-20 17:28:31 -0700658 zc->hashLog3 = hashLog3;
659 zc->seqStore.litLengthSum = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200660
Yann Collet71aaa322017-04-20 23:03:38 -0700661 /* ensure entropy tables are close together at the beginning */
662 assert((void*)zc->hufCTable == zc->workSpace);
663 assert((char*)zc->offcodeCTable == (char*)zc->hufCTable + hufCTable_size);
664 assert((char*)zc->matchlengthCTable == (char*)zc->offcodeCTable + offcodeCTable_size);
665 assert((char*)zc->litlengthCTable == (char*)zc->matchlengthCTable + matchlengthCTable_size);
Yann Collete42afbc2017-04-26 11:39:35 -0700666 assert((char*)zc->entropyScratchSpace == (char*)zc->litlengthCTable + litlengthCTable_size);
667 ptr = (char*)zc->entropyScratchSpace + entropyScratchSpace_size;
Yann Collete6fa70a2017-04-20 17:28:31 -0700668
669 /* opt parser space */
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800670 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) {
Yann Collet009d6042017-05-19 10:17:59 -0700671 DEBUGLOG(5, "reserving optimal parser space");
Yann Collete6fa70a2017-04-20 17:28:31 -0700672 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
Yann Colleta7737f62016-09-06 09:44:59 +0200673 zc->seqStore.litFreq = (U32*)ptr;
674 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
675 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
676 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
677 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
678 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
679 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
680 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
681 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
Yann Colleta7737f62016-09-06 09:44:59 +0200682 }
Yann Collete6fa70a2017-04-20 17:28:31 -0700683
684 /* table Space */
685 if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
686 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
687 zc->hashTable = (U32*)(ptr);
688 zc->chainTable = zc->hashTable + hSize;
689 zc->hashTable3 = zc->chainTable + chainSize;
690 ptr = zc->hashTable3 + h3Size;
691
692 /* sequences storage */
Yann Colleta7737f62016-09-06 09:44:59 +0200693 zc->seqStore.sequencesStart = (seqDef*)ptr;
694 ptr = zc->seqStore.sequencesStart + maxNbSeq;
695 zc->seqStore.llCode = (BYTE*) ptr;
696 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
697 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
698 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
Yann Collet5ac72b42017-05-23 11:18:24 -0700699 ptr = zc->seqStore.litStart + blockSize;
700
701 /* buffers */
702 zc->inBuffSize = buffInSize;
703 zc->inBuff = (char*)ptr;
704 zc->outBuffSize = buffOutSize;
705 zc->outBuff = zc->inBuff + buffInSize;
Yann Colleta7737f62016-09-06 09:44:59 +0200706
Yann Colleta7737f62016-09-06 09:44:59 +0200707 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100708 }
Yann Colletf3eca252015-10-22 15:31:46 +0100709}
710
Yann Collet32dfae62017-01-19 10:32:55 -0800711/* ZSTD_invalidateRepCodes() :
712 * ensures next compression will not use repcodes from previous block.
713 * Note : only works with regular variant;
714 * do not use with extDict variant ! */
715void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
716 int i;
717 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0;
718}
Yann Collet083fcc82015-10-25 14:06:35 +0100719
Yann Collet7b51a292016-01-26 15:58:49 +0100720
Yann Colleta4cab802017-04-18 14:54:54 -0700721/*! ZSTD_copyCCtx_internal() :
722 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
723 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
724 * pledgedSrcSize=0 means "empty" if fParams.contentSizeFlag=1
725 * @return : 0, or an error code */
Yann Collet1ad7c822017-05-22 17:06:04 -0700726static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
727 const ZSTD_CCtx* srcCCtx,
728 ZSTD_frameParameters fParams,
729 unsigned long long pledgedSrcSize)
Yann Collet7b51a292016-01-26 15:58:49 +0100730{
Yann Collet009d6042017-05-19 10:17:59 -0700731 DEBUGLOG(5, "ZSTD_copyCCtx_internal");
Yann Collet7b51a292016-01-26 15:58:49 +0100732 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Sean Purcell2db72492017-02-09 10:50:43 -0800733
inikep28669512016-06-02 13:04:18 +0200734 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Yann Collet5ac72b42017-05-23 11:18:24 -0700735 { ZSTD_buffered_policy_e const zbuff = srcCCtx->inBuffSize ?
736 ZSTDb_buffered : ZSTDb_not_buffered;
737 ZSTD_parameters params = srcCCtx->appliedParams;
Yann Colleta4cab802017-04-18 14:54:54 -0700738 params.fParams = fParams;
Yann Collet5ac72b42017-05-23 11:18:24 -0700739 ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
740 ZSTDcrp_noMemset, zbuff);
Sean Purcell2db72492017-02-09 10:50:43 -0800741 }
Yann Collet7b51a292016-01-26 15:58:49 +0100742
743 /* copy tables */
Yann Collet1ad7c822017-05-22 17:06:04 -0700744 { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->appliedParams.cParams.chainLog);
745 size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +0200746 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
747 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collete6fa70a2017-04-20 17:28:31 -0700748 assert((U32*)dstCCtx->chainTable == (U32*)dstCCtx->hashTable + hSize); /* chainTable must follow hashTable */
749 assert((U32*)dstCCtx->hashTable3 == (U32*)dstCCtx->chainTable + chainSize);
750 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); /* presumes all tables follow each other */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100751 }
Yann Collet7b51a292016-01-26 15:58:49 +0100752
Yann Colletc46fb922016-05-29 05:01:04 +0200753 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100754 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
755 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
756 dstCCtx->nextSrc = srcCCtx->nextSrc;
757 dstCCtx->base = srcCCtx->base;
758 dstCCtx->dictBase = srcCCtx->dictBase;
759 dstCCtx->dictLimit = srcCCtx->dictLimit;
760 dstCCtx->lowLimit = srcCCtx->lowLimit;
761 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200762 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100763
Yann Colletfb810d62016-01-28 00:18:06 +0100764 /* copy entropy tables */
Yann Collet71ddeb62017-04-20 22:54:54 -0700765 dstCCtx->fseCTables_ready = srcCCtx->fseCTables_ready;
766 if (srcCCtx->fseCTables_ready) {
Yann Colleta34a39c2017-04-20 18:17:58 -0700767 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, litlengthCTable_size);
768 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, matchlengthCTable_size);
769 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, offcodeCTable_size);
Yann Colletfb810d62016-01-28 00:18:06 +0100770 }
Yann Collet71ddeb62017-04-20 22:54:54 -0700771 dstCCtx->hufCTable_repeatMode = srcCCtx->hufCTable_repeatMode;
772 if (srcCCtx->hufCTable_repeatMode) {
773 memcpy(dstCCtx->hufCTable, srcCCtx->hufCTable, hufCTable_size);
Nick Terrella4197772017-03-01 17:51:56 -0800774 }
Yann Collet7b51a292016-01-26 15:58:49 +0100775
776 return 0;
777}
778
Yann Colleta4cab802017-04-18 14:54:54 -0700779/*! ZSTD_copyCCtx() :
780 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
781 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
782 * pledgedSrcSize==0 means "unknown".
783* @return : 0, or an error code */
784size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
785{
786 ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
787 fParams.contentSizeFlag = pledgedSrcSize>0;
788
789 return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, fParams, pledgedSrcSize);
790}
791
Yann Collet7b51a292016-01-26 15:58:49 +0100792
Yann Colletecabfe32016-03-20 16:20:06 +0100793/*! ZSTD_reduceTable() :
Yann Colleta4cab802017-04-18 14:54:54 -0700794 * reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100795static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100796{
Yann Colletecabfe32016-03-20 16:20:06 +0100797 U32 u;
798 for (u=0 ; u < size ; u++) {
799 if (table[u] < reducerValue) table[u] = 0;
800 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100801 }
802}
803
Yann Colletecabfe32016-03-20 16:20:06 +0100804/*! ZSTD_reduceIndex() :
805* rescale all indexes to avoid future overflow (indexes are U32) */
806static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
807{
Yann Collet1ad7c822017-05-22 17:06:04 -0700808 { U32 const hSize = 1 << zc->appliedParams.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100809 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
810
Yann Collet1ad7c822017-05-22 17:06:04 -0700811 { U32 const chainSize = (zc->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->appliedParams.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200812 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100813
Yann Collet731ef162016-07-27 21:05:12 +0200814 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100815 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
816}
817
Yann Collet89db5e02015-11-13 11:27:46 +0100818
Yann Collet863ec402016-01-28 17:56:33 +0100819/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100820* Block entropic compression
821*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100822
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200823/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100824
Yann Colletd1b26842016-03-15 01:24:33 +0100825size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100826{
Yann Colletd1b26842016-03-15 01:24:33 +0100827 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200828 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
829 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100830 return ZSTD_blockHeaderSize+srcSize;
831}
832
833
Yann Colletd1b26842016-03-15 01:24:33 +0100834static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100835{
836 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200837 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100838
Yann Colletd1b26842016-03-15 01:24:33 +0100839 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100840
Yann Collet59d1f792016-01-23 19:28:41 +0100841 switch(flSize)
842 {
843 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200844 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100845 break;
846 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200847 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100848 break;
Yann Collet59d1f792016-01-23 19:28:41 +0100849 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200850 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100851 break;
Yann Colletcd2892f2017-06-01 09:44:54 -0700852 default: /* not necessary : flSize is {1,2,3} */
853 assert(0);
Yann Collet59d1f792016-01-23 19:28:41 +0100854 }
855
856 memcpy(ostart + flSize, src, srcSize);
857 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100858}
859
Yann Colletd1b26842016-03-15 01:24:33 +0100860static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100861{
862 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200863 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100864
Yann Collet198e6aa2016-07-20 20:12:24 +0200865 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100866
867 switch(flSize)
868 {
869 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200870 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100871 break;
872 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200873 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100874 break;
Yann Collet59d1f792016-01-23 19:28:41 +0100875 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200876 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100877 break;
Yann Colletcd2892f2017-06-01 09:44:54 -0700878 default: /* not necessary : flSize is {1,2,3} */
879 assert(0);
Yann Collet59d1f792016-01-23 19:28:41 +0100880 }
881
882 ostart[flSize] = *(const BYTE*)src;
883 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100884}
885
Yann Collet59d1f792016-01-23 19:28:41 +0100886
Yann Colleta5c2c082016-03-20 01:09:18 +0100887static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100888
Yann Colletb923f652016-01-26 03:14:20 +0100889static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100890 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100891 const void* src, size_t srcSize)
892{
Yann Colleta910dc82016-03-18 12:37:45 +0100893 size_t const minGain = ZSTD_minGain(srcSize);
894 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200895 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100896 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200897 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100898 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100899
Yann Collet14983e72015-11-11 21:38:21 +0100900
Yann Colleta5c2c082016-03-20 01:09:18 +0100901 /* small ? don't even attempt compression (speed opt) */
902# define LITERAL_NOENTROPY 63
Yann Collet71ddeb62017-04-20 22:54:54 -0700903 { size_t const minLitSize = zc->hufCTable_repeatMode == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
Yann Colleta5c2c082016-03-20 01:09:18 +0100904 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
905 }
906
907 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Collet71ddeb62017-04-20 22:54:54 -0700908 { HUF_repeat repeat = zc->hufCTable_repeatMode;
Yann Collet1ad7c822017-05-22 17:06:04 -0700909 int const preferRepeat = zc->appliedParams.cParams.strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
Nick Terrella4197772017-03-01 17:51:56 -0800910 if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
Yann Collete348dad2017-04-20 11:14:13 -0700911 cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Yann Collete42afbc2017-04-26 11:39:35 -0700912 zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat)
Yann Collete348dad2017-04-20 11:14:13 -0700913 : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Yann Collete42afbc2017-04-26 11:39:35 -0700914 zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat);
Nick Terrella4197772017-03-01 17:51:56 -0800915 if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
Yann Collet71ddeb62017-04-20 22:54:54 -0700916 else { zc->hufCTable_repeatMode = HUF_repeat_check; } /* now have a table to reuse */
Yann Colletb923f652016-01-26 03:14:20 +0100917 }
Yann Collet14983e72015-11-11 21:38:21 +0100918
Nick Terrella4197772017-03-01 17:51:56 -0800919 if ((cLitSize==0) | (cLitSize >= srcSize - minGain)) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700920 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100921 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800922 }
923 if (cLitSize==1) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700924 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100925 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800926 }
Yann Collet14983e72015-11-11 21:38:21 +0100927
928 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100929 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100930 {
Yann Collet59d1f792016-01-23 19:28:41 +0100931 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200932 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200933 MEM_writeLE24(ostart, lhc);
934 break;
935 }
Yann Collet59d1f792016-01-23 19:28:41 +0100936 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200937 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200938 MEM_writeLE32(ostart, lhc);
939 break;
940 }
Yann Collet59d1f792016-01-23 19:28:41 +0100941 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200942 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200943 MEM_writeLE32(ostart, lhc);
944 ostart[4] = (BYTE)(cLitSize >> 10);
945 break;
946 }
Yann Colletcd2892f2017-06-01 09:44:54 -0700947 default: /* not possible : lhSize is {3,4,5} */
948 assert(0);
Yann Collet14983e72015-11-11 21:38:21 +0100949 }
Yann Colleta910dc82016-03-18 12:37:45 +0100950 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100951}
952
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200953static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
954 8, 9, 10, 11, 12, 13, 14, 15,
955 16, 16, 17, 17, 18, 18, 19, 19,
956 20, 20, 20, 20, 21, 21, 21, 21,
957 22, 22, 22, 22, 22, 22, 22, 22,
958 23, 23, 23, 23, 23, 23, 23, 23,
959 24, 24, 24, 24, 24, 24, 24, 24,
960 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100961
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200962static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
963 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
964 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
965 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
966 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
967 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
968 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
969 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200970
971
972void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100973{
Yann Colleted57d852016-07-29 21:22:17 +0200974 BYTE const LL_deltaCode = 19;
975 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200976 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200977 BYTE* const llCodeTable = seqStorePtr->llCode;
978 BYTE* const ofCodeTable = seqStorePtr->ofCode;
979 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200980 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200981 U32 u;
982 for (u=0; u<nbSeq; u++) {
983 U32 const llv = sequences[u].litLength;
984 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200985 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200986 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200987 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200988 }
Yann Colleted57d852016-07-29 21:22:17 +0200989 if (seqStorePtr->longLengthID==1)
990 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
991 if (seqStorePtr->longLengthID==2)
992 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100993}
994
Sean Purcell553f67e2017-03-02 15:15:31 -0800995MEM_STATIC size_t ZSTD_compressSequences (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100996 void* dst, size_t dstCapacity,
Sean Purcell553f67e2017-03-02 15:15:31 -0800997 size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100998{
Yann Collet1ad7c822017-05-22 17:06:04 -0700999 const int longOffsets = zc->appliedParams.cParams.windowLog > STREAM_ACCUMULATOR_MIN;
Yann Colletb923f652016-01-26 03:14:20 +01001000 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +01001001 U32 count[MaxSeq+1];
1002 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +01001003 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
1004 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
1005 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +01001006 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +02001007 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +02001008 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
1009 const BYTE* const llCodeTable = seqStorePtr->llCode;
1010 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +01001011 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +01001012 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +01001013 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +02001014 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +01001015 BYTE* seqHead;
Yann Colletd79a9a02016-11-30 15:52:20 -08001016 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Collet14983e72015-11-11 21:38:21 +01001017
Yann Collet14983e72015-11-11 21:38:21 +01001018 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +01001019 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +01001020 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +01001021 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +01001022 if (ZSTD_isError(cSize)) return cSize;
1023 op += cSize;
1024 }
1025
1026 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +01001027 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +01001028 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
1029 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
1030 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +01001031 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +01001032
Yann Colletbe391432016-03-22 23:19:28 +01001033 /* seqHead : flags for FSE encoding type */
1034 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +01001035
Yann Colletfb810d62016-01-28 00:18:06 +01001036#define MIN_SEQ_FOR_DYNAMIC_FSE 64
1037#define MAX_SEQ_FOR_STATIC_FSE 1000
1038
Yann Colletb44be742016-03-26 20:52:14 +01001039 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +02001040 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +01001041
Yann Collet14983e72015-11-11 21:38:21 +01001042 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +01001043 { U32 max = MaxLL;
Yann Collete42afbc2017-04-26 11:39:35 -07001044 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +01001045 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
1046 *op++ = llCodeTable[0];
1047 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +02001048 LLtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -07001049 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +02001050 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +01001051 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -08001052 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001053 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +01001054 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +01001055 size_t nbSeq_1 = nbSeq;
1056 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
1057 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
1058 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +01001059 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -07001060 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +01001061 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -08001062 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001063 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +01001064 } }
Yann Collet14983e72015-11-11 21:38:21 +01001065
Yann Colletb44be742016-03-26 20:52:14 +01001066 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +01001067 { U32 max = MaxOff;
Yann Collete42afbc2017-04-26 11:39:35 -07001068 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +01001069 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +01001070 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +01001071 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +02001072 Offtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -07001073 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +02001074 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +02001075 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -08001076 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001077 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +01001078 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +01001079 size_t nbSeq_1 = nbSeq;
1080 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +01001081 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +01001082 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +01001083 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -07001084 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +01001085 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -08001086 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001087 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +01001088 } }
1089
Yann Collet14983e72015-11-11 21:38:21 +01001090 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +01001091 { U32 max = MaxML;
Yann Collete42afbc2017-04-26 11:39:35 -07001092 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +01001093 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +01001094 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +01001095 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +02001096 MLtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -07001097 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +02001098 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +01001099 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -08001100 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001101 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +01001102 } else {
1103 size_t nbSeq_1 = nbSeq;
1104 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
1105 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
1106 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
1107 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -07001108 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletfadda6c2016-03-22 12:14:26 +01001109 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -08001110 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001111 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +01001112 } }
Yann Collet14983e72015-11-11 21:38:21 +01001113
Yann Colletbe391432016-03-22 23:19:28 +01001114 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Collet71ddeb62017-04-20 22:54:54 -07001115 zc->fseCTables_ready = 0;
Yann Collet14983e72015-11-11 21:38:21 +01001116
1117 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +01001118 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +01001119 FSE_CState_t stateMatchLength;
1120 FSE_CState_t stateOffsetBits;
1121 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +01001122
Yann Collet95d07d72016-09-06 16:38:51 +02001123 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +01001124
Yann Collet597847a2016-03-20 19:14:22 +01001125 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +01001126 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +01001127 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +01001128 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +02001129 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +01001130 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +02001131 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +01001132 if (MEM_32bits()) BIT_flushBits(&blockStream);
Sean Purcelld44703d2017-03-01 14:36:25 -08001133 if (longOffsets) {
1134 U32 const ofBits = ofCodeTable[nbSeq-1];
1135 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1136 if (extraBits) {
1137 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
1138 BIT_flushBits(&blockStream);
1139 }
1140 BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
1141 ofBits - extraBits);
1142 } else {
1143 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
1144 }
Yann Collet597847a2016-03-20 19:14:22 +01001145 BIT_flushBits(&blockStream);
1146
Yann Colletfadda6c2016-03-22 12:14:26 +01001147 { size_t n;
1148 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +02001149 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +02001150 BYTE const ofCode = ofCodeTable[n];
1151 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +02001152 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +02001153 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +02001154 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +01001155 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +01001156 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
1157 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
1158 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
1159 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +02001160 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +01001161 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +02001162 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +01001163 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +02001164 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +01001165 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Sean Purcelld44703d2017-03-01 14:36:25 -08001166 if (longOffsets) {
1167 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1168 if (extraBits) {
1169 BIT_addBits(&blockStream, sequences[n].offset, extraBits);
1170 BIT_flushBits(&blockStream); /* (7)*/
1171 }
1172 BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
1173 ofBits - extraBits); /* 31 */
1174 } else {
1175 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
1176 }
Yann Colletb9151402016-03-26 17:18:11 +01001177 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +01001178 } }
Yann Collet14983e72015-11-11 21:38:21 +01001179
1180 FSE_flushCState(&blockStream, &stateMatchLength);
1181 FSE_flushCState(&blockStream, &stateOffsetBits);
1182 FSE_flushCState(&blockStream, &stateLitLength);
1183
Yann Colletb9151402016-03-26 17:18:11 +01001184 { size_t const streamSize = BIT_closeCStream(&blockStream);
1185 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
1186 op += streamSize;
1187 } }
Yann Collet14983e72015-11-11 21:38:21 +01001188
1189 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +01001190_check_compressibility:
Nick Terrella4197772017-03-01 17:51:56 -08001191 { size_t const minGain = ZSTD_minGain(srcSize);
1192 size_t const maxCSize = srcSize - minGain;
1193 if ((size_t)(op-ostart) >= maxCSize) {
Yann Collet71ddeb62017-04-20 22:54:54 -07001194 zc->hufCTable_repeatMode = HUF_repeat_none;
Nick Terrella4197772017-03-01 17:51:56 -08001195 return 0;
1196 } }
Yann Collet14983e72015-11-11 21:38:21 +01001197
Yann Collet4266c0a2016-06-14 01:49:25 +02001198 /* confirm repcodes */
Yann Colletb459aad2017-01-19 17:33:37 -08001199 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; }
Yann Collet4266c0a2016-06-14 01:49:25 +02001200
Yann Collet5054ee02015-11-23 13:34:21 +01001201 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +01001202}
1203
Yann Colletbb002742017-01-25 16:25:38 -08001204
Yann Collet95cd0c22016-03-08 18:24:21 +01001205/*! ZSTD_storeSeq() :
1206 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
1207 `offsetCode` : distance to match, or 0 == repCode.
1208 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +01001209*/
Yann Colletd57dffb2016-07-03 01:48:26 +02001210MEM_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 +01001211{
Yann Collet009d6042017-05-19 10:17:59 -07001212#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
1213 static const BYTE* g_start = NULL;
1214 U32 const pos = (U32)((const BYTE*)literals - g_start);
1215 if (g_start==NULL) g_start = (const BYTE*)literals;
1216 if ((pos > 0) && (pos < 1000000000))
1217 DEBUGLOG(6, "Cpos %6u :%5u literals & match %3u bytes at distance %6u",
1218 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +01001219#endif
Yann Collet14983e72015-11-11 21:38:21 +01001220 /* copy Literals */
Yann Collet009d6042017-05-19 10:17:59 -07001221 assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB);
Yann Collet14983e72015-11-11 21:38:21 +01001222 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
1223 seqStorePtr->lit += litLength;
1224
1225 /* literal Length */
Yann Collete6fa70a2017-04-20 17:28:31 -07001226 if (litLength>0xFFFF) {
1227 seqStorePtr->longLengthID = 1;
1228 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
1229 }
Yann Colletc0ce4f12016-07-30 00:55:13 +02001230 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +01001231
1232 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +02001233 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +01001234
1235 /* match Length */
Yann Collete6fa70a2017-04-20 17:28:31 -07001236 if (matchCode>0xFFFF) {
1237 seqStorePtr->longLengthID = 2;
1238 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
1239 }
Yann Colletc0ce4f12016-07-30 00:55:13 +02001240 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +02001241
Yann Colletc0ce4f12016-07-30 00:55:13 +02001242 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +01001243}
1244
1245
Yann Collet7d360282016-02-12 00:07:30 +01001246/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001247* Match length counter
1248***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +01001249static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +01001250{
Yann Collet863ec402016-01-28 17:56:33 +01001251 if (MEM_isLittleEndian()) {
1252 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +01001253# if defined(_MSC_VER) && defined(_WIN64)
1254 unsigned long r = 0;
1255 _BitScanForward64( &r, (U64)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_ctzll((U64)val) >> 3);
1259# else
Yann Collete348dad2017-04-20 11:14:13 -07001260 static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
1261 0, 3, 1, 3, 1, 4, 2, 7,
1262 0, 2, 3, 6, 1, 5, 3, 5,
1263 1, 3, 4, 4, 2, 5, 6, 7,
1264 7, 0, 1, 2, 3, 3, 4, 6,
1265 2, 6, 5, 5, 3, 4, 5, 6,
1266 7, 1, 2, 4, 6, 4, 4, 5,
1267 7, 2, 6, 5, 7, 6, 7, 7 };
Yann Collet14983e72015-11-11 21:38:21 +01001268 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
1269# endif
Yann Collet863ec402016-01-28 17:56:33 +01001270 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +01001271# if defined(_MSC_VER)
1272 unsigned long r=0;
1273 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +01001274 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +01001275# elif defined(__GNUC__) && (__GNUC__ >= 3)
1276 return (__builtin_ctz((U32)val) >> 3);
1277# else
Yann Collete348dad2017-04-20 11:14:13 -07001278 static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
1279 3, 2, 2, 1, 3, 2, 0, 1,
1280 3, 3, 1, 2, 2, 2, 2, 0,
1281 3, 1, 2, 0, 1, 0, 1, 1 };
Yann Collet14983e72015-11-11 21:38:21 +01001282 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
1283# endif
1284 }
Yann Collet863ec402016-01-28 17:56:33 +01001285 } else { /* Big Endian CPU */
1286 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +01001287# if defined(_MSC_VER) && defined(_WIN64)
1288 unsigned long r = 0;
1289 _BitScanReverse64( &r, val );
1290 return (unsigned)(r>>3);
1291# elif defined(__GNUC__) && (__GNUC__ >= 3)
1292 return (__builtin_clzll(val) >> 3);
1293# else
1294 unsigned r;
1295 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
1296 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
1297 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
1298 r += (!val);
1299 return r;
1300# endif
Yann Collet863ec402016-01-28 17:56:33 +01001301 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +01001302# if defined(_MSC_VER)
1303 unsigned long r = 0;
1304 _BitScanReverse( &r, (unsigned long)val );
1305 return (unsigned)(r>>3);
1306# elif defined(__GNUC__) && (__GNUC__ >= 3)
1307 return (__builtin_clz((U32)val) >> 3);
1308# else
1309 unsigned r;
1310 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
1311 r += (!val);
1312 return r;
1313# endif
Yann Collet863ec402016-01-28 17:56:33 +01001314 } }
Yann Collet14983e72015-11-11 21:38:21 +01001315}
1316
1317
Yann Colleta436a522016-06-20 23:34:04 +02001318static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +01001319{
1320 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +02001321 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +01001322
Yann Colleta436a522016-06-20 23:34:04 +02001323 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +02001324 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +01001325 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
1326 pIn += ZSTD_NbCommonBytes(diff);
1327 return (size_t)(pIn - pStart);
1328 }
Yann Collet14983e72015-11-11 21:38:21 +01001329 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
1330 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
1331 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
1332 return (size_t)(pIn - pStart);
1333}
1334
Yann Collet04b12d82016-02-11 06:23:24 +01001335/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +01001336* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +01001337* convention : on reaching mEnd, match count continue starting from iStart
1338*/
1339static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
1340{
Yann Collet7591a7f2016-05-20 11:44:43 +02001341 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +02001342 size_t const matchLength = ZSTD_count(ip, match, vEnd);
1343 if (match + matchLength != mEnd) return matchLength;
1344 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +01001345}
1346
Yann Collet14983e72015-11-11 21:38:21 +01001347
Yann Collet863ec402016-01-28 17:56:33 +01001348/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001349* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +01001350***************************************/
inikepcc52a972016-02-19 10:09:35 +01001351static const U32 prime3bytes = 506832829U;
1352static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Collete6fa70a2017-04-20 17:28:31 -07001353MEM_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 +01001354
Yann Collet4b100f42015-10-30 15:49:48 +01001355static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +01001356static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +01001357static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +01001358
Yann Collet4b100f42015-10-30 15:49:48 +01001359static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001360static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001361static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001362
1363static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001364static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001365static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001366
Yann Collet14983e72015-11-11 21:38:21 +01001367static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001368static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001369static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001370
Yann Collet45dc3562016-07-12 09:47:31 +02001371static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
1372static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
1373static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
1374
Yann Collet5be2dd22015-11-11 13:43:58 +01001375static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001376{
1377 switch(mls)
1378 {
1379 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001380 case 4: return ZSTD_hash4Ptr(p, hBits);
1381 case 5: return ZSTD_hash5Ptr(p, hBits);
1382 case 6: return ZSTD_hash6Ptr(p, hBits);
1383 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +02001384 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001385 }
1386}
Yann Collet2acb5d32015-10-29 16:49:43 +01001387
Yann Collet863ec402016-01-28 17:56:33 +01001388
Yann Collet2ce49232016-02-02 14:36:49 +01001389/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001390* Fast Scan
1391***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001392static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1393{
1394 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001395 U32 const hBits = zc->appliedParams.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001396 const BYTE* const base = zc->base;
1397 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001398 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001399 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001400
Yann Colletfb810d62016-01-28 00:18:06 +01001401 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001402 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001403 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001404 }
1405}
1406
1407
Yann Collet1f44b3f2015-11-05 17:32:18 +01001408FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +02001409void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +02001410 const void* src, size_t srcSize,
1411 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001412{
Yann Collet4266c0a2016-06-14 01:49:25 +02001413 U32* const hashTable = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001414 U32 const hBits = cctx->appliedParams.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +02001415 seqStore_t* seqStorePtr = &(cctx->seqStore);
1416 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001417 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001418 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001419 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +02001420 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +02001421 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001422 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001423 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +02001424 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1425 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001426
Yann Collet1f44b3f2015-11-05 17:32:18 +01001427 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001428 ip += (ip==lowest);
1429 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +02001430 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1431 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +02001432 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001433
1434 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +02001435 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +02001436 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +02001437 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
1438 U32 const current = (U32)(ip-base);
1439 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +01001440 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001441 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001442
Yann Collet280f9a82016-08-08 00:44:00 +02001443 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +02001444 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +01001445 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001446 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1447 } else {
Yann Collet92d75662016-07-03 01:10:53 +02001448 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001449 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001450 ip += ((ip-anchor) >> g_searchStrength) + 1;
1451 continue;
1452 }
Yann Collet45dc3562016-07-12 09:47:31 +02001453 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001454 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001455 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001456 offset_2 = offset_1;
1457 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001458
Yann Colleta436a522016-06-20 23:34:04 +02001459 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001460 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001461
Yann Collet402fdcf2015-11-20 12:46:08 +01001462 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001463 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001464 anchor = ip;
1465
Yann Colletfb810d62016-01-28 00:18:06 +01001466 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001467 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001468 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 +01001469 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1470 /* check immediate repcode */
1471 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001472 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001473 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001474 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001475 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001476 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001477 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001478 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1479 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001480 anchor = ip;
1481 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001482 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001483
Yann Collet4266c0a2016-06-14 01:49:25 +02001484 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001485 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1486 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001487
Yann Collet70e45772016-03-19 18:08:32 +01001488 /* Last Literals */
1489 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001490 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1491 seqStorePtr->lit += lastLLSize;
1492 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001493}
1494
1495
Yann Collet82260dd2016-02-11 07:14:25 +01001496static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001497 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001498{
Yann Collet1ad7c822017-05-22 17:06:04 -07001499 const U32 mls = ctx->appliedParams.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001500 switch(mls)
1501 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001502 default: /* includes case 3 */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001503 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001504 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001505 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001506 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001507 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001508 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001509 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001510 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001511 }
1512}
Yann Colletf3eca252015-10-22 15:31:46 +01001513
Yann Colletf3eca252015-10-22 15:31:46 +01001514
Yann Collet82260dd2016-02-11 07:14:25 +01001515static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001516 const void* src, size_t srcSize,
1517 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001518{
1519 U32* hashTable = ctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001520 const U32 hBits = ctx->appliedParams.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001521 seqStore_t* seqStorePtr = &(ctx->seqStore);
1522 const BYTE* const base = ctx->base;
1523 const BYTE* const dictBase = ctx->dictBase;
1524 const BYTE* const istart = (const BYTE*)src;
1525 const BYTE* ip = istart;
1526 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001527 const U32 lowestIndex = ctx->lowLimit;
1528 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001529 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001530 const BYTE* const lowPrefixPtr = base + dictLimit;
1531 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001532 const BYTE* const iend = istart + srcSize;
1533 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001534 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001535
Yann Colleta436a522016-06-20 23:34:04 +02001536 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001537 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001538 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001539 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001540 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001541 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001542 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001543 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001544 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001545 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001546 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001547 hashTable[h] = current; /* update hash table */
1548
Yann Colleta436a522016-06-20 23:34:04 +02001549 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001550 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001551 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001552 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
Yann Collet743402c2015-11-20 12:03:53 +01001553 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001554 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001555 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001556 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001557 (MEM_read32(match) != MEM_read32(ip)) ) {
1558 ip += ((ip-anchor) >> g_searchStrength) + 1;
1559 continue;
1560 }
1561 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001562 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001563 U32 offset;
Yann Collete6fa70a2017-04-20 17:28:31 -07001564 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
Yann Colleta436a522016-06-20 23:34:04 +02001565 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001566 offset = current - matchIndex;
1567 offset_2 = offset_1;
1568 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001569 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001570 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001571
Yann Collet5054ee02015-11-23 13:34:21 +01001572 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001573 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001574 anchor = ip;
1575
Yann Colletfb810d62016-01-28 00:18:06 +01001576 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001577 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001578 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001579 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1580 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001581 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001582 U32 const current2 = (U32)(ip-base);
1583 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001584 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001585 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1586 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001587 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001588 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet5054ee02015-11-23 13:34:21 +01001589 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001590 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001591 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001592 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001593 anchor = ip;
1594 continue;
1595 }
Yann Collet743402c2015-11-20 12:03:53 +01001596 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001597 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001598
Yann Collet4266c0a2016-06-14 01:49:25 +02001599 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001600 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001601
Yann Collet89db5e02015-11-13 11:27:46 +01001602 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001603 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001604 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1605 seqStorePtr->lit += lastLLSize;
1606 }
Yann Collet89db5e02015-11-13 11:27:46 +01001607}
1608
1609
Yann Collet82260dd2016-02-11 07:14:25 +01001610static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001611 const void* src, size_t srcSize)
1612{
Yann Collet1ad7c822017-05-22 17:06:04 -07001613 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001614 switch(mls)
1615 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001616 default: /* includes case 3 */
Yann Collet89db5e02015-11-13 11:27:46 +01001617 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001618 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001619 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001620 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001621 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001622 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001623 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001624 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001625 }
1626}
1627
1628
Yann Collet04b12d82016-02-11 06:23:24 +01001629/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001630* Double Fast
1631***************************************/
1632static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1633{
1634 U32* const hashLarge = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001635 U32 const hBitsL = cctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001636 U32* const hashSmall = cctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001637 U32 const hBitsS = cctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001638 const BYTE* const base = cctx->base;
1639 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001640 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001641 const size_t fastHashFillStep = 3;
1642
1643 while(ip <= iend) {
1644 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1645 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1646 ip += fastHashFillStep;
1647 }
1648}
1649
1650
1651FORCE_INLINE
1652void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1653 const void* src, size_t srcSize,
1654 const U32 mls)
1655{
1656 U32* const hashLong = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001657 const U32 hBitsL = cctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001658 U32* const hashSmall = cctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001659 const U32 hBitsS = cctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001660 seqStore_t* seqStorePtr = &(cctx->seqStore);
1661 const BYTE* const base = cctx->base;
1662 const BYTE* const istart = (const BYTE*)src;
1663 const BYTE* ip = istart;
1664 const BYTE* anchor = istart;
1665 const U32 lowestIndex = cctx->dictLimit;
1666 const BYTE* const lowest = base + lowestIndex;
1667 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001668 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001669 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1670 U32 offsetSaved = 0;
1671
1672 /* init */
1673 ip += (ip==lowest);
1674 { U32 const maxRep = (U32)(ip-lowest);
1675 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1676 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1677 }
1678
1679 /* Main Search Loop */
1680 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1681 size_t mLength;
1682 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1683 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1684 U32 const current = (U32)(ip-base);
1685 U32 const matchIndexL = hashLong[h2];
1686 U32 const matchIndexS = hashSmall[h];
1687 const BYTE* matchLong = base + matchIndexL;
1688 const BYTE* match = base + matchIndexS;
1689 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1690
Yann Colletc17e0202017-04-20 12:50:02 -07001691 assert(offset_1 <= current); /* supposed guaranteed by construction */
1692 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001693 /* favor repcode */
Yann Collet45dc3562016-07-12 09:47:31 +02001694 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1695 ip++;
1696 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1697 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001698 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001699 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1700 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001701 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001702 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1703 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001704 size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1705 U32 const matchIndexL3 = hashLong[hl3];
1706 const BYTE* matchL3 = base + matchIndexL3;
1707 hashLong[hl3] = current + 1;
1708 if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
1709 mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
Yann Colletc54692f2016-08-24 01:10:42 +02001710 ip++;
Yann Collete6fa70a2017-04-20 17:28:31 -07001711 offset = (U32)(ip-matchL3);
1712 while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
Yann Colletc54692f2016-08-24 01:10:42 +02001713 } else {
1714 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1715 offset = (U32)(ip-match);
1716 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1717 }
Yann Collet45dc3562016-07-12 09:47:31 +02001718 } else {
1719 ip += ((ip-anchor) >> g_searchStrength) + 1;
1720 continue;
1721 }
1722
1723 offset_2 = offset_1;
1724 offset_1 = offset;
1725
1726 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1727 }
1728
1729 /* match found */
1730 ip += mLength;
1731 anchor = ip;
1732
1733 if (ip <= ilimit) {
1734 /* Fill Table */
1735 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1736 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1737 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1738 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1739
1740 /* check immediate repcode */
1741 while ( (ip <= ilimit)
1742 && ( (offset_2>0)
1743 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1744 /* store sequence */
1745 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001746 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001747 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1748 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1749 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1750 ip += rLength;
1751 anchor = ip;
1752 continue; /* faster when present ... (?) */
1753 } } }
1754
1755 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001756 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1757 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet45dc3562016-07-12 09:47:31 +02001758
1759 /* Last Literals */
1760 { size_t const lastLLSize = iend - anchor;
1761 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1762 seqStorePtr->lit += lastLLSize;
1763 }
1764}
1765
1766
1767static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1768{
Yann Collet1ad7c822017-05-22 17:06:04 -07001769 const U32 mls = ctx->appliedParams.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001770 switch(mls)
1771 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001772 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001773 case 4 :
1774 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1775 case 5 :
1776 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1777 case 6 :
1778 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1779 case 7 :
1780 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1781 }
1782}
1783
1784
1785static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1786 const void* src, size_t srcSize,
1787 const U32 mls)
1788{
1789 U32* const hashLong = ctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001790 U32 const hBitsL = ctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001791 U32* const hashSmall = ctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001792 U32 const hBitsS = ctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001793 seqStore_t* seqStorePtr = &(ctx->seqStore);
1794 const BYTE* const base = ctx->base;
1795 const BYTE* const dictBase = ctx->dictBase;
1796 const BYTE* const istart = (const BYTE*)src;
1797 const BYTE* ip = istart;
1798 const BYTE* anchor = istart;
1799 const U32 lowestIndex = ctx->lowLimit;
1800 const BYTE* const dictStart = dictBase + lowestIndex;
1801 const U32 dictLimit = ctx->dictLimit;
1802 const BYTE* const lowPrefixPtr = base + dictLimit;
1803 const BYTE* const dictEnd = dictBase + dictLimit;
1804 const BYTE* const iend = istart + srcSize;
1805 const BYTE* const ilimit = iend - 8;
1806 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1807
1808 /* Search Loop */
1809 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1810 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1811 const U32 matchIndex = hashSmall[hSmall];
1812 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1813 const BYTE* match = matchBase + matchIndex;
1814
1815 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1816 const U32 matchLongIndex = hashLong[hLong];
1817 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1818 const BYTE* matchLong = matchLongBase + matchLongIndex;
1819
1820 const U32 current = (U32)(ip-base);
1821 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1822 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1823 const BYTE* repMatch = repBase + repIndex;
1824 size_t mLength;
1825 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1826
1827 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1828 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1829 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1830 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1831 ip++;
1832 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1833 } else {
1834 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1835 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1836 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1837 U32 offset;
1838 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1839 offset = current - matchLongIndex;
1840 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1841 offset_2 = offset_1;
1842 offset_1 = offset;
1843 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001844
Yann Collet73d74a02016-07-12 13:03:48 +02001845 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001846 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1847 U32 const matchIndex3 = hashLong[h3];
1848 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1849 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001850 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001851 hashLong[h3] = current + 1;
1852 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1853 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1854 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1855 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1856 ip++;
1857 offset = current+1 - matchIndex3;
1858 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1859 } else {
1860 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1861 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1862 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1863 offset = current - matchIndex;
1864 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1865 }
Yann Collet45dc3562016-07-12 09:47:31 +02001866 offset_2 = offset_1;
1867 offset_1 = offset;
1868 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001869
Yann Collet45dc3562016-07-12 09:47:31 +02001870 } else {
1871 ip += ((ip-anchor) >> g_searchStrength) + 1;
1872 continue;
1873 } }
1874
1875 /* found a match : store it */
1876 ip += mLength;
1877 anchor = ip;
1878
1879 if (ip <= ilimit) {
1880 /* Fill Table */
Nick Terrellf35ef5c2017-03-09 12:51:33 -08001881 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1882 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
Yann Collet45dc3562016-07-12 09:47:31 +02001883 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1884 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1885 /* check immediate repcode */
1886 while (ip <= ilimit) {
1887 U32 const current2 = (U32)(ip-base);
1888 U32 const repIndex2 = current2 - offset_2;
1889 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1890 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1891 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1892 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07001893 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet45dc3562016-07-12 09:47:31 +02001894 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1895 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1896 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1897 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1898 ip += repLength2;
1899 anchor = ip;
1900 continue;
1901 }
1902 break;
1903 } } }
1904
1905 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001906 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet45dc3562016-07-12 09:47:31 +02001907
1908 /* Last Literals */
1909 { size_t const lastLLSize = iend - anchor;
1910 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1911 seqStorePtr->lit += lastLLSize;
1912 }
1913}
1914
1915
1916static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1917 const void* src, size_t srcSize)
1918{
Yann Collet1ad7c822017-05-22 17:06:04 -07001919 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001920 switch(mls)
1921 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001922 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001923 case 4 :
1924 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1925 case 5 :
1926 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1927 case 6 :
1928 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1929 case 7 :
1930 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1931 }
1932}
1933
1934
1935/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001936* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001937***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001938/** ZSTD_insertBt1() : add one or multiple positions to tree.
1939* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001940* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001941static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1942 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001943{
Yann Collet731ef162016-07-27 21:05:12 +02001944 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001945 U32 const hashLog = zc->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +02001946 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1947 U32* const bt = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001948 U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
Yann Collet731ef162016-07-27 21:05:12 +02001949 U32 const btMask = (1 << btLog) - 1;
1950 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001951 size_t commonLengthSmaller=0, commonLengthLarger=0;
1952 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001953 const BYTE* const dictBase = zc->dictBase;
1954 const U32 dictLimit = zc->dictLimit;
1955 const BYTE* const dictEnd = dictBase + dictLimit;
1956 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07001957 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001958 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001959 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001960 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001961 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001962 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001963 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001964 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001965 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001966#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001967 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1968 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1969 predictedSmall += (predictedSmall>0);
1970 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001971#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001972
Yann Collet6c3e2e72015-12-11 10:44:07 +01001973 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001974
Yann Colletfb810d62016-01-28 00:18:06 +01001975 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001976 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001977 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08001978
Yann Colletc0932082016-06-30 14:07:30 +02001979#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001980 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001981 if (matchIndex == predictedSmall) {
1982 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001983 *smallerPtr = matchIndex;
1984 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1985 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1986 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001987 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001988 continue;
1989 }
Yann Colletfb810d62016-01-28 00:18:06 +01001990 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001991 *largerPtr = matchIndex;
1992 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1993 largerPtr = nextPtr;
1994 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001995 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001996 continue;
1997 }
Yann Collet04b12d82016-02-11 06:23:24 +01001998#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001999 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01002000 match = base + matchIndex;
2001 if (match[matchLength] == ip[matchLength])
2002 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01002003 } else {
Yann Collet1358f912016-01-01 07:29:39 +01002004 match = dictBase + matchIndex;
2005 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
2006 if (matchIndex+matchLength >= dictLimit)
Nick Terrellf35ef5c2017-03-09 12:51:33 -08002007 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet1358f912016-01-01 07:29:39 +01002008 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002009
Yann Colletb8a6f682016-02-15 17:06:29 +01002010 if (matchLength > bestLength) {
2011 bestLength = matchLength;
2012 if (matchLength > matchEndIdx - matchIndex)
2013 matchEndIdx = matchIndex + (U32)matchLength;
2014 }
Yann Colletee3f4512015-12-29 22:26:09 +01002015
Yann Collet59d70632015-11-04 12:05:27 +01002016 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01002017 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002018
Yann Colletfb810d62016-01-28 00:18:06 +01002019 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002020 /* match is smaller than current */
2021 *smallerPtr = matchIndex; /* update smaller idx */
2022 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01002023 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002024 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01002025 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01002026 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01002027 /* match is larger than current */
2028 *largerPtr = matchIndex;
2029 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01002030 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002031 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01002032 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01002033 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002034
Yann Collet59d70632015-11-04 12:05:27 +01002035 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02002036 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01002037 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
2038 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002039}
2040
2041
Yann Collet82260dd2016-02-11 07:14:25 +01002042static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01002043 ZSTD_CCtx* zc,
2044 const BYTE* const ip, const BYTE* const iend,
2045 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01002046 U32 nbCompares, const U32 mls,
2047 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01002048{
Yann Collet731ef162016-07-27 21:05:12 +02002049 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002050 U32 const hashLog = zc->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +02002051 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
2052 U32* const bt = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002053 U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
Yann Collet731ef162016-07-27 21:05:12 +02002054 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01002055 U32 matchIndex = hashTable[h];
2056 size_t commonLengthSmaller=0, commonLengthLarger=0;
2057 const BYTE* const base = zc->base;
2058 const BYTE* const dictBase = zc->dictBase;
2059 const U32 dictLimit = zc->dictLimit;
2060 const BYTE* const dictEnd = dictBase + dictLimit;
2061 const BYTE* const prefixStart = base + dictLimit;
2062 const U32 current = (U32)(ip-base);
2063 const U32 btLow = btMask >= current ? 0 : current - btMask;
2064 const U32 windowLow = zc->lowLimit;
2065 U32* smallerPtr = bt + 2*(current&btMask);
2066 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01002067 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01002068 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02002069 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01002070
Yann Collet6c3e2e72015-12-11 10:44:07 +01002071 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01002072
Yann Colletfb810d62016-01-28 00:18:06 +01002073 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08002074 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01002075 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
2076 const BYTE* match;
2077
Yann Colletfb810d62016-01-28 00:18:06 +01002078 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01002079 match = base + matchIndex;
2080 if (match[matchLength] == ip[matchLength])
2081 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01002082 } else {
Yann Collet03526e12015-11-23 15:29:15 +01002083 match = dictBase + matchIndex;
2084 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01002085 if (matchIndex+matchLength >= dictLimit)
Nick Terrellf35ef5c2017-03-09 12:51:33 -08002086 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01002087 }
2088
Yann Colletfb810d62016-01-28 00:18:06 +01002089 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01002090 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01002091 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02002092 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02002093 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01002094 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
2095 break; /* drop, to guarantee consistency (miss a little bit of compression) */
2096 }
2097
Yann Colletfb810d62016-01-28 00:18:06 +01002098 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01002099 /* match is smaller than current */
2100 *smallerPtr = matchIndex; /* update smaller idx */
2101 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
2102 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2103 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
2104 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01002105 } else {
Yann Collet03526e12015-11-23 15:29:15 +01002106 /* match is larger than current */
2107 *largerPtr = matchIndex;
2108 commonLengthLarger = matchLength;
2109 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2110 largerPtr = nextPtr;
2111 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01002112 } }
Yann Collet03526e12015-11-23 15:29:15 +01002113
2114 *smallerPtr = *largerPtr = 0;
2115
Yann Collet72e84cf2015-12-31 19:08:44 +01002116 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02002117 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01002118}
2119
Yann Collet2cc12cb2016-01-01 07:47:58 +01002120
Yann Colletb8a6f682016-02-15 17:06:29 +01002121static 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 +01002122{
2123 const BYTE* const base = zc->base;
2124 const U32 target = (U32)(ip - base);
2125 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01002126
2127 while(idx < target)
2128 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01002129}
2130
Yann Collet52447382016-03-20 16:00:00 +01002131/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01002132static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01002133 ZSTD_CCtx* zc,
2134 const BYTE* const ip, const BYTE* const iLimit,
2135 size_t* offsetPtr,
2136 const U32 maxNbAttempts, const U32 mls)
2137{
2138 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01002139 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01002140 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
2141}
2142
2143
Yann Collet768c6bc2016-02-10 14:01:49 +01002144static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01002145 ZSTD_CCtx* zc, /* Index table will be updated */
2146 const BYTE* ip, const BYTE* const iLimit,
2147 size_t* offsetPtr,
2148 const U32 maxNbAttempts, const U32 matchLengthSearch)
2149{
2150 switch(matchLengthSearch)
2151 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002152 default : /* includes case 3 */
Yann Collet2cc12cb2016-01-01 07:47:58 +01002153 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
2154 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07002155 case 7 :
Yann Collet2cc12cb2016-01-01 07:47:58 +01002156 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
2157 }
2158}
2159
2160
Yann Colletb8a6f682016-02-15 17:06:29 +01002161static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
2162{
2163 const BYTE* const base = zc->base;
2164 const U32 target = (U32)(ip - base);
2165 U32 idx = zc->nextToUpdate;
2166
2167 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
2168}
2169
inikep64d7bcb2016-04-07 19:14:09 +02002170
Yann Collet03526e12015-11-23 15:29:15 +01002171/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01002172static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01002173 ZSTD_CCtx* zc,
2174 const BYTE* const ip, const BYTE* const iLimit,
2175 size_t* offsetPtr,
2176 const U32 maxNbAttempts, const U32 mls)
2177{
Yann Colletee3f4512015-12-29 22:26:09 +01002178 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01002179 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01002180 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01002181}
2182
2183
Yann Collet82260dd2016-02-11 07:14:25 +01002184static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01002185 ZSTD_CCtx* zc, /* Index table will be updated */
2186 const BYTE* ip, const BYTE* const iLimit,
2187 size_t* offsetPtr,
2188 const U32 maxNbAttempts, const U32 matchLengthSearch)
2189{
2190 switch(matchLengthSearch)
2191 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002192 default : /* includes case 3 */
Yann Collet03526e12015-11-23 15:29:15 +01002193 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
2194 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07002195 case 7 :
Yann Collet03526e12015-11-23 15:29:15 +01002196 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
2197 }
2198}
2199
2200
Yann Collet5106a762015-11-05 15:00:24 +01002201
Yann Collet731ef162016-07-27 21:05:12 +02002202/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02002203* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02002204***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02002205#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
2206
2207/* Update chains up to ip (excluded)
Anders Oleson517577b2017-02-20 12:08:59 -08002208 Assumption : always within prefix (i.e. not within extDict) */
inikep64d7bcb2016-04-07 19:14:09 +02002209FORCE_INLINE
2210U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
2211{
2212 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002213 const U32 hashLog = zc->appliedParams.cParams.hashLog;
inikep64d7bcb2016-04-07 19:14:09 +02002214 U32* const chainTable = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002215 const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1;
inikep64d7bcb2016-04-07 19:14:09 +02002216 const BYTE* const base = zc->base;
2217 const U32 target = (U32)(ip - base);
2218 U32 idx = zc->nextToUpdate;
2219
Yann Collet22d76322016-06-21 08:01:51 +02002220 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002221 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
2222 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
2223 hashTable[h] = idx;
2224 idx++;
2225 }
2226
2227 zc->nextToUpdate = target;
2228 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
2229}
2230
2231
Nick Terrell55fc1f92017-05-24 13:50:10 -07002232/* inlining is important to hardwire a hot branch (template emulation) */
2233FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002234size_t ZSTD_HcFindBestMatch_generic (
2235 ZSTD_CCtx* zc, /* Index table will be updated */
2236 const BYTE* const ip, const BYTE* const iLimit,
2237 size_t* offsetPtr,
2238 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
2239{
2240 U32* const chainTable = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002241 const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog);
inikep64d7bcb2016-04-07 19:14:09 +02002242 const U32 chainMask = chainSize-1;
2243 const BYTE* const base = zc->base;
2244 const BYTE* const dictBase = zc->dictBase;
2245 const U32 dictLimit = zc->dictLimit;
2246 const BYTE* const prefixStart = base + dictLimit;
2247 const BYTE* const dictEnd = dictBase + dictLimit;
2248 const U32 lowLimit = zc->lowLimit;
2249 const U32 current = (U32)(ip-base);
2250 const U32 minChain = current > chainSize ? current - chainSize : 0;
2251 int nbAttempts=maxNbAttempts;
Yann Collete42afbc2017-04-26 11:39:35 -07002252 size_t ml=4-1;
inikep64d7bcb2016-04-07 19:14:09 +02002253
2254 /* HC4 match finder */
2255 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
2256
Yann Collet22d76322016-06-21 08:01:51 +02002257 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02002258 const BYTE* match;
2259 size_t currentMl=0;
2260 if ((!extDict) || matchIndex >= dictLimit) {
2261 match = base + matchIndex;
2262 if (match[ml] == ip[ml]) /* potentially better */
2263 currentMl = ZSTD_count(ip, match, iLimit);
2264 } else {
2265 match = dictBase + matchIndex;
2266 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
Yann Collete42afbc2017-04-26 11:39:35 -07002267 currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002268 }
2269
2270 /* save best solution */
Yann Colletc17e0202017-04-20 12:50:02 -07002271 if (currentMl > ml) {
2272 ml = currentMl;
2273 *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
2274 if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
2275 }
inikep64d7bcb2016-04-07 19:14:09 +02002276
2277 if (matchIndex <= minChain) break;
2278 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
2279 }
2280
2281 return ml;
2282}
2283
2284
2285FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
2286 ZSTD_CCtx* zc,
2287 const BYTE* ip, const BYTE* const iLimit,
2288 size_t* offsetPtr,
2289 const U32 maxNbAttempts, const U32 matchLengthSearch)
2290{
2291 switch(matchLengthSearch)
2292 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002293 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02002294 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
2295 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
Yann Collet933ce4a2017-03-29 14:32:15 -07002296 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02002297 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
2298 }
2299}
2300
2301
2302FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
2303 ZSTD_CCtx* zc,
2304 const BYTE* ip, const BYTE* const iLimit,
2305 size_t* offsetPtr,
2306 const U32 maxNbAttempts, const U32 matchLengthSearch)
2307{
2308 switch(matchLengthSearch)
2309 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002310 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02002311 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
2312 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
Yann Collet933ce4a2017-03-29 14:32:15 -07002313 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02002314 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
2315 }
2316}
2317
inikep64d7bcb2016-04-07 19:14:09 +02002318
Yann Collet287b7d92015-11-22 13:24:05 +01002319/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02002320* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02002321*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01002322FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002323void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
2324 const void* src, size_t srcSize,
2325 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01002326{
inikepfaa8d8a2016-04-05 19:01:10 +02002327 seqStore_t* seqStorePtr = &(ctx->seqStore);
2328 const BYTE* const istart = (const BYTE*)src;
2329 const BYTE* ip = istart;
2330 const BYTE* anchor = istart;
2331 const BYTE* const iend = istart + srcSize;
2332 const BYTE* const ilimit = iend - 8;
2333 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002334
Yann Collet1ad7c822017-05-22 17:06:04 -07002335 U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
2336 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002337
inikep64d7bcb2016-04-07 19:14:09 +02002338 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2339 size_t* offsetPtr,
2340 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02002341 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02002342 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02002343
inikepfaa8d8a2016-04-05 19:01:10 +02002344 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02002345 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02002346 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02002347 { U32 const maxRep = (U32)(ip-base);
2348 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
2349 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
2350 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002351
inikepfaa8d8a2016-04-05 19:01:10 +02002352 /* Match Loop */
2353 while (ip < ilimit) {
2354 size_t matchLength=0;
2355 size_t offset=0;
2356 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01002357
inikepfaa8d8a2016-04-05 19:01:10 +02002358 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02002359 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02002360 /* repcode : we take it */
Yann Collete42afbc2017-04-26 11:39:35 -07002361 matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002362 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01002363 }
Yann Collet5be2dd22015-11-11 13:43:58 +01002364
inikepfaa8d8a2016-04-05 19:01:10 +02002365 /* first search (depth 0) */
2366 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002367 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002368 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002369 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002370 }
Yann Collet5106a762015-11-05 15:00:24 +01002371
Yann Collete42afbc2017-04-26 11:39:35 -07002372 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002373 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2374 continue;
2375 }
2376
inikep64d7bcb2016-04-07 19:14:09 +02002377 /* let's try to find a better solution */
2378 if (depth>=1)
2379 while (ip<ilimit) {
2380 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002381 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002382 size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002383 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002384 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002385 if ((mlRep >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002386 matchLength = mlRep, offset = 0, start = ip;
2387 }
2388 { size_t offset2=99999999;
2389 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002390 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2391 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002392 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002393 matchLength = ml2, offset = offset2, start = ip;
2394 continue; /* search a better one */
2395 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002396
inikep64d7bcb2016-04-07 19:14:09 +02002397 /* let's find an even better one */
2398 if ((depth==2) && (ip<ilimit)) {
2399 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002400 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002401 size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002402 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002403 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002404 if ((ml2 >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002405 matchLength = ml2, offset = 0, start = ip;
2406 }
2407 { size_t offset2=99999999;
2408 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002409 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2410 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002411 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002412 matchLength = ml2, offset = offset2, start = ip;
2413 continue;
2414 } } }
2415 break; /* nothing found : store previous solution */
2416 }
2417
2418 /* catch up */
2419 if (offset) {
Yann Colletc17e0202017-04-20 12:50:02 -07002420 while ( (start > anchor)
2421 && (start > base+offset-ZSTD_REP_MOVE)
2422 && (start[-1] == start[-1-offset+ZSTD_REP_MOVE]) ) /* only search for offset within prefix */
inikep64d7bcb2016-04-07 19:14:09 +02002423 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02002424 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02002425 }
2426
inikepfaa8d8a2016-04-05 19:01:10 +02002427 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002428_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002429 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002430 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002431 anchor = ip = start + matchLength;
2432 }
Yann Collet48537162016-04-07 15:24:29 +02002433
inikepfaa8d8a2016-04-05 19:01:10 +02002434 /* check immediate repcode */
2435 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02002436 && ((offset_2>0)
2437 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02002438 /* store sequence */
Yann Collete42afbc2017-04-26 11:39:35 -07002439 matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet9634f672016-07-03 01:23:58 +02002440 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02002441 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2442 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002443 anchor = ip;
2444 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02002445 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002446
Yann Collet4266c0a2016-06-14 01:49:25 +02002447 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002448 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
2449 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02002450
inikepfaa8d8a2016-04-05 19:01:10 +02002451 /* Last Literals */
2452 { size_t const lastLLSize = iend - anchor;
2453 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2454 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002455 }
Yann Collet5106a762015-11-05 15:00:24 +01002456}
2457
Yann Collet5be2dd22015-11-11 13:43:58 +01002458
inikep64d7bcb2016-04-07 19:14:09 +02002459static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2460{
2461 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2462}
2463
2464static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2465{
2466 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2467}
2468
2469static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2470{
2471 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2472}
2473
2474static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2475{
2476 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2477}
2478
2479
inikepfaa8d8a2016-04-05 19:01:10 +02002480FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002481void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2482 const void* src, size_t srcSize,
2483 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002484{
inikepfaa8d8a2016-04-05 19:01:10 +02002485 seqStore_t* seqStorePtr = &(ctx->seqStore);
2486 const BYTE* const istart = (const BYTE*)src;
2487 const BYTE* ip = istart;
2488 const BYTE* anchor = istart;
2489 const BYTE* const iend = istart + srcSize;
2490 const BYTE* const ilimit = iend - 8;
2491 const BYTE* const base = ctx->base;
2492 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002493 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002494 const BYTE* const prefixStart = base + dictLimit;
2495 const BYTE* const dictBase = ctx->dictBase;
2496 const BYTE* const dictEnd = dictBase + dictLimit;
2497 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2498
Yann Collet1ad7c822017-05-22 17:06:04 -07002499 const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
2500 const U32 mls = ctx->appliedParams.cParams.searchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002501
inikep64d7bcb2016-04-07 19:14:09 +02002502 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2503 size_t* offsetPtr,
2504 U32 maxNbAttempts, U32 matchLengthSearch);
2505 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2506
Yann Collet302ff032016-07-03 01:28:16 +02002507 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002508
Yann Collet302ff032016-07-03 01:28:16 +02002509 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002510 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002511 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002512
2513 /* Match Loop */
2514 while (ip < ilimit) {
2515 size_t matchLength=0;
2516 size_t offset=0;
2517 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002518 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002519
2520 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002521 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002522 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2523 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002524 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002525 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002526 /* repcode detected we should take it */
2527 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002528 matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002529 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002530 } }
2531
2532 /* first search (depth 0) */
2533 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002534 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002535 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002536 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002537 }
2538
Yann Collete42afbc2017-04-26 11:39:35 -07002539 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002540 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2541 continue;
2542 }
2543
inikep64d7bcb2016-04-07 19:14:09 +02002544 /* let's try to find a better solution */
2545 if (depth>=1)
2546 while (ip<ilimit) {
2547 ip ++;
2548 current++;
2549 /* check repCode */
2550 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002551 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002552 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2553 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002554 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002555 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2556 /* repcode detected */
2557 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002558 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002559 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002560 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002561 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002562 matchLength = repLength, offset = 0, start = ip;
2563 } }
2564
2565 /* search match, depth 1 */
2566 { size_t offset2=99999999;
2567 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002568 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2569 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002570 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002571 matchLength = ml2, offset = offset2, start = ip;
2572 continue; /* search a better one */
2573 } }
2574
2575 /* let's find an even better one */
2576 if ((depth==2) && (ip<ilimit)) {
2577 ip ++;
2578 current++;
2579 /* check repCode */
2580 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002581 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002582 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2583 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002584 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002585 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2586 /* repcode detected */
2587 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002588 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Colletc17e0202017-04-20 12:50:02 -07002589 int const gain2 = (int)(repLength * 4);
2590 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002591 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002592 matchLength = repLength, offset = 0, start = ip;
2593 } }
2594
2595 /* search match, depth 2 */
2596 { size_t offset2=99999999;
2597 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002598 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2599 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002600 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002601 matchLength = ml2, offset = offset2, start = ip;
2602 continue;
2603 } } }
2604 break; /* nothing found : store previous solution */
2605 }
2606
inikepfaa8d8a2016-04-05 19:01:10 +02002607 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002608 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002609 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002610 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2611 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002612 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002613 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002614 }
inikepfaa8d8a2016-04-05 19:01:10 +02002615
inikepfaa8d8a2016-04-05 19:01:10 +02002616 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002617_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002618 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002619 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002620 anchor = ip = start + matchLength;
2621 }
2622
2623 /* check immediate repcode */
2624 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002625 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002626 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2627 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002628 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002629 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2630 /* repcode detected we should take it */
2631 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002632 matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Collet302ff032016-07-03 01:28:16 +02002633 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002634 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2635 ip += matchLength;
2636 anchor = ip;
2637 continue; /* faster when present ... (?) */
2638 }
2639 break;
2640 } }
2641
Yann Collet4266c0a2016-06-14 01:49:25 +02002642 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002643 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002644
inikepfaa8d8a2016-04-05 19:01:10 +02002645 /* Last Literals */
2646 { size_t const lastLLSize = iend - anchor;
2647 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2648 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002649 }
2650}
2651
2652
Yann Collet59d1f792016-01-23 19:28:41 +01002653void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002654{
inikep64d7bcb2016-04-07 19:14:09 +02002655 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002656}
2657
Yann Collet59d1f792016-01-23 19:28:41 +01002658static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002659{
Yann Colleta1249dc2016-01-25 04:22:03 +01002660 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002661}
Yann Collet9a24e592015-11-22 02:53:43 +01002662
Yann Collet59d1f792016-01-23 19:28:41 +01002663static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002664{
Yann Colleta1249dc2016-01-25 04:22:03 +01002665 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002666}
2667
Yann Collet59d1f792016-01-23 19:28:41 +01002668static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002669{
Yann Colleta1249dc2016-01-25 04:22:03 +01002670 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002671}
2672
inikepef519412016-04-21 11:08:43 +02002673
inikepef519412016-04-21 11:08:43 +02002674/* The optimal parser */
2675#include "zstd_opt.h"
2676
2677static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2678{
Yann Colletd4f4e582016-06-27 01:31:35 +02002679#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002680 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2681#else
2682 (void)ctx; (void)src; (void)srcSize;
2683 return;
2684#endif
2685}
2686
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002687static void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002688{
2689#ifdef ZSTD_OPT_H_91842398743
2690 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002691#else
2692 (void)ctx; (void)src; (void)srcSize;
2693 return;
2694#endif
inikepef519412016-04-21 11:08:43 +02002695}
2696
inikepd3b8d7a2016-02-22 10:06:17 +01002697static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002698{
Yann Colletd4f4e582016-06-27 01:31:35 +02002699#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002700 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2701#else
2702 (void)ctx; (void)src; (void)srcSize;
2703 return;
2704#endif
2705}
2706
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002707static void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002708{
2709#ifdef ZSTD_OPT_H_91842398743
2710 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002711#else
2712 (void)ctx; (void)src; (void)srcSize;
2713 return;
2714#endif
inikepe2bfe242016-01-31 11:25:48 +01002715}
2716
Yann Collet7a231792015-11-21 15:27:35 +01002717
Yann Collet59d1f792016-01-23 19:28:41 +01002718typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002719
Yann Colletb923f652016-01-26 03:14:20 +01002720static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002721{
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002722 static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
2723 { NULL,
2724 ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy,
Yann Colletc17e0202017-04-20 12:50:02 -07002725 ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002726 ZSTD_compressBlock_btopt, ZSTD_compressBlock_btultra },
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002727 { NULL,
2728 ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict,
Yann Colletc17e0202017-04-20 12:50:02 -07002729 ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002730 ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01002731 };
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002732 ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
Yann Collet7fe531e2015-11-29 02:38:09 +01002733
2734 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002735}
2736
2737
Yann Colletd1b26842016-03-15 01:24:33 +01002738static 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 +01002739{
Yann Collet1ad7c822017-05-22 17:06:04 -07002740 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002741 const BYTE* const base = zc->base;
2742 const BYTE* const istart = (const BYTE*)src;
2743 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002744 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 +02002745 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002746 if (current > zc->nextToUpdate + 384)
Yann Colletc17e0202017-04-20 12:50:02 -07002747 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 +01002748 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002749 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002750}
2751
2752
Yann Colletdb8e21d2017-05-12 13:46:49 -07002753/*! ZSTD_compress_frameChunk() :
Yann Colletc991cc12016-07-28 00:55:43 +02002754* Compress a chunk of data into one or multiple blocks.
2755* All blocks will be terminated, all input will be consumed.
2756* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2757* Frame is supposed already started (header already produced)
2758* @return : compressed size, or an error code
2759*/
Yann Colletdb8e21d2017-05-12 13:46:49 -07002760static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002761 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002762 const void* src, size_t srcSize,
2763 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002764{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002765 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002766 size_t remaining = srcSize;
2767 const BYTE* ip = (const BYTE*)src;
2768 BYTE* const ostart = (BYTE*)dst;
2769 BYTE* op = ostart;
Yann Collet1ad7c822017-05-22 17:06:04 -07002770 U32 const maxDist = 1 << cctx->appliedParams.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002771
Yann Collet1ad7c822017-05-22 17:06:04 -07002772 if (cctx->appliedParams.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002773 XXH64_update(&cctx->xxhState, src, srcSize);
2774
Yann Collet2ce49232016-02-02 14:36:49 +01002775 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002776 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002777 size_t cSize;
2778
Yann Colletc17e0202017-04-20 12:50:02 -07002779 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
2780 return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01002781 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002782
Yann Collet346efcc2016-08-02 14:26:00 +02002783 /* preemptive overflow correction */
Sean Purcell881abe42017-03-07 16:52:23 -08002784 if (cctx->lowLimit > (3U<<29)) {
Yann Collet1ad7c822017-05-22 17:06:04 -07002785 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->appliedParams.cParams.hashLog, cctx->appliedParams.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002786 U32 const current = (U32)(ip - cctx->base);
Yann Collet1ad7c822017-05-22 17:06:04 -07002787 U32 const newCurrent = (current & cycleMask) + (1 << cctx->appliedParams.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002788 U32 const correction = current - newCurrent;
2789 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002790 ZSTD_reduceIndex(cctx, correction);
2791 cctx->base += correction;
2792 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002793 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002794 cctx->dictLimit -= correction;
2795 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2796 else cctx->nextToUpdate -= correction;
2797 }
2798
Yann Collet06e76972017-01-25 16:39:03 -08002799 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002800 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002801 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2802 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2803 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002804 }
Yann Collet89db5e02015-11-13 11:27:46 +01002805
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002806 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002807 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002808
Yann Collet2ce49232016-02-02 14:36:49 +01002809 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002810 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2811 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2812 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2813 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2814 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002815 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002816 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002817 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002818 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002819 }
2820
2821 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002822 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002823 ip += blockSize;
2824 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002825 }
2826
Yann Collet62470b42016-07-28 15:29:08 +02002827 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002828 return op-ostart;
2829}
2830
2831
Yann Collet6236eba2016-04-12 15:52:33 +02002832static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002833 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002834{ BYTE* const op = (BYTE*)dst;
Yann Collet31533ba2017-04-27 00:29:04 -07002835 U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2836 U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002837 U32 const checksumFlag = params.fParams.checksumFlag>0;
2838 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002839 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002840 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2841 U32 const fcsCode = params.fParams.contentSizeFlag ?
Nick Terrell55fc1f92017-05-24 13:50:10 -07002842 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002843 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002844 size_t pos;
2845
2846 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet009d6042017-05-19 10:17:59 -07002847 DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
Yann Collet0be6fd32017-05-08 16:08:01 -07002848 !params.fParams.noDictIDFlag, dictID, dictIDSizeCode);
Yann Collet6236eba2016-04-12 15:52:33 +02002849
2850 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002851 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002852 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002853 switch(dictIDSizeCode)
2854 {
Yann Colletcd2892f2017-06-01 09:44:54 -07002855 default: assert(0); /* impossible */
Yann Colletc46fb922016-05-29 05:01:04 +02002856 case 0 : break;
2857 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002858 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002859 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2860 }
Yann Collet673f0d72016-06-06 00:26:38 +02002861 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002862 {
Yann Colletcd2892f2017-06-01 09:44:54 -07002863 default: assert(0); /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002864 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002865 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2866 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002867 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002868 }
Yann Colletc46fb922016-05-29 05:01:04 +02002869 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002870}
2871
2872
Yann Collet346efcc2016-08-02 14:26:00 +02002873static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002874 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002875 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002876 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002877{
Yann Collet2acb5d32015-10-29 16:49:43 +01002878 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002879 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002880
Yann Collet346efcc2016-08-02 14:26:00 +02002881 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002882
Yann Collet346efcc2016-08-02 14:26:00 +02002883 if (frame && (cctx->stage==ZSTDcs_init)) {
Yann Collet1ad7c822017-05-22 17:06:04 -07002884 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002885 if (ZSTD_isError(fhSize)) return fhSize;
2886 dstCapacity -= fhSize;
2887 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002888 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002889 }
Yann Colletf3eca252015-10-22 15:31:46 +01002890
Yann Collet417890c2015-12-04 17:16:37 +01002891 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002892 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002893 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002894 ptrdiff_t const delta = cctx->nextSrc - ip;
2895 cctx->lowLimit = cctx->dictLimit;
2896 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2897 cctx->dictBase = cctx->base;
2898 cctx->base -= delta;
2899 cctx->nextToUpdate = cctx->dictLimit;
2900 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002901 }
2902
Yann Collet346efcc2016-08-02 14:26:00 +02002903 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2904 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2905 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2906 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2907 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002908 }
2909
Yann Collet346efcc2016-08-02 14:26:00 +02002910 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002911
Yann Collet5eb749e2017-01-11 18:21:25 +01002912 if (srcSize) {
2913 size_t const cSize = frame ?
Yann Colletdb8e21d2017-05-12 13:46:49 -07002914 ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
Yann Collet346efcc2016-08-02 14:26:00 +02002915 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002916 if (ZSTD_isError(cSize)) return cSize;
Yann Collet20d5e032017-04-11 18:34:02 -07002917 cctx->consumedSrcSize += srcSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002918 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01002919 } else
2920 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002921}
2922
Yann Colletbf42c8e2016-01-09 01:08:23 +01002923
Yann Collet5b567392016-07-28 01:17:22 +02002924size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002925 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002926 const void* src, size_t srcSize)
2927{
Yann Collet20d5e032017-04-11 18:34:02 -07002928 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
Yann Collet5b567392016-07-28 01:17:22 +02002929}
2930
2931
Yann Colletfa3671e2017-05-19 10:51:30 -07002932size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002933{
Yann Colletfa3671e2017-05-19 10:51:30 -07002934 U32 const cLevel = cctx->compressionLevel;
2935 ZSTD_compressionParameters cParams = (cLevel == ZSTD_CLEVEL_CUSTOM) ?
Yann Collet1ad7c822017-05-22 17:06:04 -07002936 cctx->appliedParams.cParams :
Yann Colletfa3671e2017-05-19 10:51:30 -07002937 ZSTD_getCParams(cLevel, 0, 0);
2938 return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog);
Yann Colletcf05b9d2016-07-18 16:52:10 +02002939}
2940
2941size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2942{
Yann Colletfa3671e2017-05-19 10:51:30 -07002943 size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002944 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07002945 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002946}
2947
Yann Collet16a0b102017-03-24 12:46:46 -07002948/*! ZSTD_loadDictionaryContent() :
2949 * @return : 0, or an error code
2950 */
Yann Colletb923f652016-01-26 03:14:20 +01002951static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002952{
2953 const BYTE* const ip = (const BYTE*) src;
2954 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002955
Yann Collet417890c2015-12-04 17:16:37 +01002956 /* input becomes current prefix */
2957 zc->lowLimit = zc->dictLimit;
2958 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2959 zc->dictBase = zc->base;
2960 zc->base += ip - zc->nextSrc;
2961 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08002962 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002963
2964 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002965 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002966
Yann Collet1ad7c822017-05-22 17:06:04 -07002967 switch(zc->appliedParams.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002968 {
2969 case ZSTD_fast:
Yann Collet1ad7c822017-05-22 17:06:04 -07002970 ZSTD_fillHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002971 break;
2972
Yann Collet45dc3562016-07-12 09:47:31 +02002973 case ZSTD_dfast:
Yann Collet1ad7c822017-05-22 17:06:04 -07002974 ZSTD_fillDoubleHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
Yann Collet45dc3562016-07-12 09:47:31 +02002975 break;
2976
Yann Collet417890c2015-12-04 17:16:37 +01002977 case ZSTD_greedy:
2978 case ZSTD_lazy:
2979 case ZSTD_lazy2:
Yann Collet16a0b102017-03-24 12:46:46 -07002980 if (srcSize >= HASH_READ_SIZE)
Yann Collet1ad7c822017-05-22 17:06:04 -07002981 ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002982 break;
2983
2984 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002985 case ZSTD_btopt:
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002986 case ZSTD_btultra:
Yann Collet16a0b102017-03-24 12:46:46 -07002987 if (srcSize >= HASH_READ_SIZE)
Yann Collet1ad7c822017-05-22 17:06:04 -07002988 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002989 break;
2990
2991 default:
Yann Colletcd2892f2017-06-01 09:44:54 -07002992 assert(0); /* not possible : not a valid strategy id */
Yann Collet417890c2015-12-04 17:16:37 +01002993 }
2994
Nick Terrellecf90ca2017-02-13 18:27:34 -08002995 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002996 return 0;
2997}
2998
2999
Nick Terrellf9c9af32016-10-19 17:22:08 -07003000/* Dictionaries that assign zero probability to symbols that show up causes problems
3001 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
3002 that we may encounter during compression.
3003 NOTE: This behavior is not standard and could be improved in the future. */
3004static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
3005 U32 s;
3006 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
3007 for (s = 0; s <= maxSymbolValue; ++s) {
3008 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
3009 }
3010 return 0;
3011}
3012
3013
Yann Colletb923f652016-01-26 03:14:20 +01003014/* Dictionary format :
Yann Colletbea78e82017-03-22 18:09:11 -07003015 * See :
3016 * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
3017 */
Yann Collet16a0b102017-03-24 12:46:46 -07003018/*! ZSTD_loadZstdDictionary() :
3019 * @return : 0, or an error code
3020 * assumptions : magic number supposed already checked
3021 * dictSize supposed > 8
Yann Colletbea78e82017-03-22 18:09:11 -07003022 */
Yann Collet16a0b102017-03-24 12:46:46 -07003023static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01003024{
Yann Collet52a06222016-06-15 13:53:34 +02003025 const BYTE* dictPtr = (const BYTE*)dict;
3026 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07003027 short offcodeNCount[MaxOff+1];
3028 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08003029 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01003030
Yann Colletbea78e82017-03-22 18:09:11 -07003031 dictPtr += 4; /* skip magic number */
Yann Collet1ad7c822017-05-22 17:06:04 -07003032 cctx->dictID = cctx->appliedParams.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
Yann Colletbea78e82017-03-22 18:09:11 -07003033 dictPtr += 4;
3034
Yann Collet71ddeb62017-04-20 22:54:54 -07003035 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufCTable, 255, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003036 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003037 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003038 }
Yann Colletfb810d62016-01-28 00:18:06 +01003039
Nick Terrellf9c9af32016-10-19 17:22:08 -07003040 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02003041 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003042 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003043 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003044 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Colletc17e0202017-04-20 12:50:02 -07003045 CHECK_E( FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)),
3046 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003047 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003048 }
Yann Colletfb810d62016-01-28 00:18:06 +01003049
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003050 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07003051 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02003052 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003053 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003054 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003055 /* Every match length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07003056 CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
3057 CHECK_E( FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)),
3058 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003059 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003060 }
Yann Colletfb810d62016-01-28 00:18:06 +01003061
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003062 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07003063 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02003064 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003065 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003066 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003067 /* Every literal length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07003068 CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
3069 CHECK_E( FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)),
3070 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003071 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003072 }
Yann Colletfb810d62016-01-28 00:18:06 +01003073
Yann Collet52a06222016-06-15 13:53:34 +02003074 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07003075 cctx->rep[0] = MEM_readLE32(dictPtr+0);
3076 cctx->rep[1] = MEM_readLE32(dictPtr+4);
3077 cctx->rep[2] = MEM_readLE32(dictPtr+8);
Yann Collet52a06222016-06-15 13:53:34 +02003078 dictPtr += 12;
3079
Yann Colletbea78e82017-03-22 18:09:11 -07003080 { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
3081 U32 offcodeMax = MaxOff;
3082 if (dictContentSize <= ((U32)-1) - 128 KB) {
3083 U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
3084 offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
Nick Terrellb2c39a22016-10-24 14:11:27 -07003085 }
Yann Colletbea78e82017-03-22 18:09:11 -07003086 /* All offset values <= dictContentSize + 128 KB must be representable */
Nick Terrellf9c9af32016-10-19 17:22:08 -07003087 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
Yann Colletbea78e82017-03-22 18:09:11 -07003088 /* All repCodes must be <= dictContentSize and != 0*/
3089 { U32 u;
3090 for (u=0; u<3; u++) {
3091 if (cctx->rep[u] == 0) return ERROR(dictionary_corrupted);
3092 if (cctx->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07003093 } }
Nick Terrellf9c9af32016-10-19 17:22:08 -07003094
Yann Collet71ddeb62017-04-20 22:54:54 -07003095 cctx->fseCTables_ready = 1;
3096 cctx->hufCTable_repeatMode = HUF_repeat_valid;
Yann Collet16a0b102017-03-24 12:46:46 -07003097 return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
3098 }
Yann Colletb923f652016-01-26 03:14:20 +01003099}
3100
Yann Colletd1b26842016-03-15 01:24:33 +01003101/** ZSTD_compress_insertDictionary() :
3102* @return : 0, or an error code */
Yann Collet16a0b102017-03-24 12:46:46 -07003103static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01003104{
Yann Colletc46fb922016-05-29 05:01:04 +02003105 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01003106
Yann Collet14312d82017-02-23 23:42:12 -08003107 /* dict as pure content */
Yann Collet16a0b102017-03-24 12:46:46 -07003108 if ((MEM_readLE32(dict) != ZSTD_DICT_MAGIC) || (cctx->forceRawDict))
3109 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
Yann Colletd1b26842016-03-15 01:24:33 +01003110
Yann Colletbea78e82017-03-22 18:09:11 -07003111 /* dict as zstd dictionary */
Yann Collet16a0b102017-03-24 12:46:46 -07003112 return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
Yann Colletecd651b2016-01-07 15:35:18 +01003113}
3114
Yann Collet27caf2a2016-04-01 15:48:48 +02003115/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01003116* @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02003117static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01003118 const void* dict, size_t dictSize,
Yann Collet18803372017-05-22 18:21:51 -07003119 const ZSTD_CDict* cdict,
Yann Collet5ac72b42017-05-23 11:18:24 -07003120 ZSTD_parameters params, U64 pledgedSrcSize,
3121 ZSTD_buffered_policy_e zbuff)
Yann Colletf3eca252015-10-22 15:31:46 +01003122{
Yann Collet5ac72b42017-05-23 11:18:24 -07003123 /* params are supposed to be fully validated at this point */
Yann Colletab9162e2017-04-11 10:46:20 -07003124 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet18803372017-05-22 18:21:51 -07003125 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
3126
3127 if (cdict && cdict->dictContentSize>0)
Yann Collet5ac72b42017-05-23 11:18:24 -07003128 return ZSTD_copyCCtx_internal(cctx, cdict->refContext,
3129 params.fParams, pledgedSrcSize);
Yann Collet18803372017-05-22 18:21:51 -07003130
Yann Collet5ac72b42017-05-23 11:18:24 -07003131 CHECK_F(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
3132 ZSTDcrp_continue, zbuff));
Yann Colleta7737f62016-09-06 09:44:59 +02003133 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01003134}
3135
3136
Yann Collet27caf2a2016-04-01 15:48:48 +02003137/*! ZSTD_compressBegin_advanced() :
3138* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02003139size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02003140 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02003141 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02003142{
3143 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02003144 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet5ac72b42017-05-23 11:18:24 -07003145 return ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL,
3146 params, pledgedSrcSize, ZSTDb_not_buffered);
Yann Collet27caf2a2016-04-01 15:48:48 +02003147}
3148
3149
Yann Collet81e13ef2016-06-07 00:51:51 +02003150size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01003151{
Yann Collet6c6e1752016-06-27 15:28:45 +02003152 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet5ac72b42017-05-23 11:18:24 -07003153 return ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL,
3154 params, 0, ZSTDb_not_buffered);
Yann Collet1c8e1942016-01-26 16:31:22 +01003155}
Yann Collet083fcc82015-10-25 14:06:35 +01003156
inikep19bd48f2016-04-04 12:10:00 +02003157
Yann Colletb05c4822017-01-12 02:01:28 +01003158size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01003159{
Yann Colletb05c4822017-01-12 02:01:28 +01003160 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01003161}
3162
3163
Yann Collet62470b42016-07-28 15:29:08 +02003164/*! ZSTD_writeEpilogue() :
3165* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01003166* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02003167static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01003168{
Yann Colletc991cc12016-07-28 00:55:43 +02003169 BYTE* const ostart = (BYTE*)dst;
3170 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02003171 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01003172
Yann Collet009d6042017-05-19 10:17:59 -07003173 DEBUGLOG(5, "ZSTD_writeEpilogue");
Yann Collet87c18b22016-08-26 01:43:47 +02003174 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02003175
3176 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02003177 if (cctx->stage == ZSTDcs_init) {
Yann Collet1ad7c822017-05-22 17:06:04 -07003178 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02003179 if (ZSTD_isError(fhSize)) return fhSize;
3180 dstCapacity -= fhSize;
3181 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02003182 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01003183 }
3184
Yann Colletc991cc12016-07-28 00:55:43 +02003185 if (cctx->stage != ZSTDcs_ending) {
3186 /* write one last empty block, make it the "last" block */
3187 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
3188 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
3189 MEM_writeLE32(op, cBlockHeader24);
3190 op += ZSTD_blockHeaderSize;
3191 dstCapacity -= ZSTD_blockHeaderSize;
3192 }
3193
Yann Collet1ad7c822017-05-22 17:06:04 -07003194 if (cctx->appliedParams.fParams.checksumFlag) {
Yann Colletc991cc12016-07-28 00:55:43 +02003195 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
3196 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
3197 MEM_writeLE32(op, checksum);
3198 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003199 }
Yann Collet2acb5d32015-10-29 16:49:43 +01003200
Yann Collet731ef162016-07-27 21:05:12 +02003201 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02003202 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01003203}
3204
Yann Colletfd416f12016-01-30 03:14:15 +01003205
Yann Collet62470b42016-07-28 15:29:08 +02003206size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
3207 void* dst, size_t dstCapacity,
3208 const void* src, size_t srcSize)
3209{
3210 size_t endResult;
Yann Collet009d6042017-05-19 10:17:59 -07003211 size_t const cSize = ZSTD_compressContinue_internal(cctx,
3212 dst, dstCapacity, src, srcSize,
3213 1 /* frame mode */, 1 /* last chunk */);
Yann Collet62470b42016-07-28 15:29:08 +02003214 if (ZSTD_isError(cSize)) return cSize;
3215 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
3216 if (ZSTD_isError(endResult)) return endResult;
Yann Collet1ad7c822017-05-22 17:06:04 -07003217 if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */
Yann Collet0be6fd32017-05-08 16:08:01 -07003218 if (cctx->frameContentSize != cctx->consumedSrcSize)
3219 return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07003220 }
Yann Collet62470b42016-07-28 15:29:08 +02003221 return cSize + endResult;
3222}
3223
3224
Yann Collet19c10022016-07-28 01:25:46 +02003225static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01003226 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01003227 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01003228 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01003229 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01003230{
Yann Collet5ac72b42017-05-23 11:18:24 -07003231 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL,
3232 params, srcSize, ZSTDb_not_buffered));
Yann Collet62470b42016-07-28 15:29:08 +02003233 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01003234}
3235
Yann Collet21588e32016-03-30 16:50:44 +02003236size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
3237 void* dst, size_t dstCapacity,
3238 const void* src, size_t srcSize,
3239 const void* dict,size_t dictSize,
3240 ZSTD_parameters params)
3241{
Yann Colletcf409a72016-09-26 16:41:05 +02003242 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02003243 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
3244}
3245
Yann Colletc17e0202017-04-20 12:50:02 -07003246size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
3247 const void* dict, size_t dictSize, int compressionLevel)
Yann Collet31683c02015-12-18 01:26:48 +01003248{
Yann Collet407a11f2016-11-03 15:52:01 -07003249 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02003250 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02003251 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01003252}
3253
Yann Colletd1b26842016-03-15 01:24:33 +01003254size_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 +01003255{
Yann Collet21588e32016-03-30 16:50:44 +02003256 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01003257}
3258
Yann Colletd1b26842016-03-15 01:24:33 +01003259size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01003260{
Yann Collet44fe9912015-10-29 22:02:40 +01003261 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01003262 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01003263 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Colletae728a42017-05-30 17:11:39 -07003264 ctxBody.customMem = ZSTD_defaultCMem;
Yann Colletd1b26842016-03-15 01:24:33 +01003265 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Colletae728a42017-05-30 17:11:39 -07003266 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 +01003267 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01003268}
Yann Colletfdcad6d2015-12-17 23:50:15 +01003269
Yann Colletfd416f12016-01-30 03:14:15 +01003270
Yann Collet81e13ef2016-06-07 00:51:51 +02003271/* ===== Dictionary API ===== */
3272
Yann Colleta1d67042017-05-08 17:51:49 -07003273/*! ZSTD_estimateCDictSize() :
3274 * Estimate amount of memory that will be needed to create a dictionary with following arguments */
Yann Collet25989e32017-05-25 15:07:37 -07003275size_t ZSTD_estimateCDictSize(ZSTD_compressionParameters cParams, size_t dictSize, unsigned byReference)
Yann Colleta1d67042017-05-08 17:51:49 -07003276{
Yann Collet25989e32017-05-25 15:07:37 -07003277 return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize(cParams)
3278 + (byReference ? 0 : dictSize);
Yann Colleta1d67042017-05-08 17:51:49 -07003279}
3280
Yann Colletd7c65892016-09-15 02:50:27 +02003281size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
3282{
3283 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Colletaca113f2016-12-23 22:25:03 +01003284 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02003285}
3286
Yann Collet1c3ab0c2017-04-27 12:57:11 -07003287static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_frameParameters fParams)
3288{
3289 ZSTD_parameters params;
3290 params.cParams = cParams;
3291 params.fParams = fParams;
3292 return params;
3293}
3294
Yann Colletcdf7e822017-05-25 18:05:49 -07003295static size_t ZSTD_initCDict_internal(
3296 ZSTD_CDict* cdict,
3297 const void* dictBuffer, size_t dictSize, unsigned byReference,
3298 ZSTD_compressionParameters cParams)
3299{
3300 if ((byReference) || (!dictBuffer) || (!dictSize)) {
3301 cdict->dictBuffer = NULL;
3302 cdict->dictContent = dictBuffer;
3303 } else {
3304 void* const internalBuffer = ZSTD_malloc(dictSize, cdict->refContext->customMem);
3305 if (!internalBuffer) return ERROR(memory_allocation);
3306 memcpy(internalBuffer, dictBuffer, dictSize);
3307 cdict->dictBuffer = internalBuffer;
3308 cdict->dictContent = internalBuffer;
3309 }
3310 cdict->dictContentSize = dictSize;
3311
3312 { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */,
3313 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */
3314 ZSTD_parameters const params = ZSTD_makeParams(cParams, fParams);
3315 CHECK_F( ZSTD_compressBegin_advanced(cdict->refContext,
3316 cdict->dictContent, dictSize,
3317 params, 0 /* srcSize */) );
3318 }
3319
3320 return 0;
3321}
3322
Yann Collet1f57c2e2016-12-21 16:20:11 +01003323ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
Yann Collet31533ba2017-04-27 00:29:04 -07003324 ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02003325{
Yann Collet8b21ec42017-05-19 19:46:15 -07003326 DEBUGLOG(5, "ZSTD_createCDict_advanced");
Yann Colletae728a42017-05-30 17:11:39 -07003327 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02003328
Yann Collet23b6e052016-08-28 21:05:43 -07003329 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02003330 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
3331
Yann Collet1f57c2e2016-12-21 16:20:11 +01003332 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07003333 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01003334 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02003335 return NULL;
3336 }
Yann Colletcdf7e822017-05-25 18:05:49 -07003337 cdict->refContext = cctx;
Yann Collet81e13ef2016-06-07 00:51:51 +02003338
Yann Colletcdf7e822017-05-25 18:05:49 -07003339 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3340 dictBuffer, dictSize, byReference,
3341 cParams) )) {
3342 ZSTD_freeCDict(cdict);
3343 return NULL;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07003344 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01003345
Yann Collet81e13ef2016-06-07 00:51:51 +02003346 return cdict;
3347 }
3348}
3349
3350ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
3351{
3352 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet31533ba2017-04-27 00:29:04 -07003353 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
3354 return ZSTD_createCDict_advanced(dict, dictSize, 0, cParams, allocator);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003355}
3356
3357ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
3358{
3359 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet31533ba2017-04-27 00:29:04 -07003360 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
3361 return ZSTD_createCDict_advanced(dict, dictSize, 1, cParams, allocator);
Yann Collet81e13ef2016-06-07 00:51:51 +02003362}
3363
3364size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
3365{
Yann Collet23b6e052016-08-28 21:05:43 -07003366 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02003367 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07003368 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01003369 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003370 ZSTD_free(cdict, cMem);
3371 return 0;
3372 }
Yann Collet81e13ef2016-06-07 00:51:51 +02003373}
3374
Yann Colletcdf7e822017-05-25 18:05:49 -07003375/*! ZSTD_initStaticCDict_advanced() :
3376 * Generate a digested dictionary in provided memory area.
3377 * workspace: The memory area to emplace the dictionary into.
3378 * Provided pointer must 8-bytes aligned.
3379 * It must outlive dictionary usage.
3380 * workspaceSize: Use ZSTD_estimateCDictSize()
3381 * to determine how large workspace must be.
3382 * cParams : use ZSTD_getCParams() to transform a compression level
3383 * into its relevants cParams.
3384 * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
3385 * Note : there is no corresponding "free" function.
3386 * Since workspace was allocated externally, it must be freed externally.
3387 */
3388ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
3389 const void* dict, size_t dictSize, unsigned byReference,
3390 ZSTD_compressionParameters cParams)
3391{
3392 size_t const cctxSize = ZSTD_estimateCCtxSize(cParams);
3393 size_t const neededSize = sizeof(ZSTD_CDict) + (byReference ? 0 : dictSize)
3394 + cctxSize;
3395 ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
3396 void* ptr;
3397 DEBUGLOG(2, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7);
3398 if ((size_t)workspace & 7) return NULL; /* 8-aligned */
3399 DEBUGLOG(2, "(workspaceSize < neededSize) : (%u < %u) => %u",
3400 (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize));
3401 if (workspaceSize < neededSize) return NULL;
3402
3403 if (!byReference) {
3404 memcpy(cdict+1, dict, dictSize);
3405 dict = cdict+1;
3406 ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize;
3407 } else {
3408 ptr = cdict+1;
3409 }
3410 cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize);
3411
3412 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3413 dict, dictSize, 1 /* by Reference */,
3414 cParams) ))
3415 return NULL;
3416
3417 return cdict;
3418}
3419
Yann Collet95162342016-10-25 16:19:52 -07003420static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
3421 return ZSTD_getParamsFromCCtx(cdict->refContext);
3422}
3423
Yann Collet715b9aa2017-04-18 13:55:53 -07003424/* ZSTD_compressBegin_usingCDict_advanced() :
Yann Collet4f818182017-04-17 17:57:35 -07003425 * cdict must be != NULL */
Yann Collet715b9aa2017-04-18 13:55:53 -07003426size_t ZSTD_compressBegin_usingCDict_advanced(
Yann Collet4f818182017-04-17 17:57:35 -07003427 ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
3428 ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003429{
Yann Collet5ac72b42017-05-23 11:18:24 -07003430 if (cdict==NULL) return ERROR(dictionary_wrong);
Yann Collet18803372017-05-22 18:21:51 -07003431 { ZSTD_parameters params = cdict->refContext->appliedParams;
Yann Collet4f818182017-04-17 17:57:35 -07003432 params.fParams = fParams;
Yann Collet18803372017-05-22 18:21:51 -07003433 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced");
Yann Collet5ac72b42017-05-23 11:18:24 -07003434 return ZSTD_compressBegin_internal(cctx, NULL, 0, cdict,
3435 params, pledgedSrcSize, ZSTDb_not_buffered);
Sean Purcell2db72492017-02-09 10:50:43 -08003436 }
Yann Collet4cb21292016-09-15 14:54:07 +02003437}
3438
Yann Collet4f818182017-04-17 17:57:35 -07003439/* ZSTD_compressBegin_usingCDict() :
3440 * pledgedSrcSize=0 means "unknown"
3441 * if pledgedSrcSize>0, it will enable contentSizeFlag */
Yann Collet768df122017-04-26 15:42:10 -07003442size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
Yann Collet4f818182017-04-17 17:57:35 -07003443{
Yann Collet768df122017-04-26 15:42:10 -07003444 ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Collet009d6042017-05-19 10:17:59 -07003445 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
Yann Collet768df122017-04-26 15:42:10 -07003446 return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0);
Yann Collet4f818182017-04-17 17:57:35 -07003447}
3448
Yann Colletf4bd8572017-04-27 11:31:55 -07003449size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
3450 void* dst, size_t dstCapacity,
3451 const void* src, size_t srcSize,
3452 const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
3453{
3454 CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */
3455 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02003456}
3457
Yann Collet07639052016-08-03 01:57:57 +02003458/*! ZSTD_compress_usingCDict() :
Yann Collet4f818182017-04-17 17:57:35 -07003459 * Compression using a digested Dictionary.
3460 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
3461 * Note that compression parameters are decided at CDict creation time
3462 * while frame parameters are hardcoded */
Yann Collet4cb21292016-09-15 14:54:07 +02003463size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
3464 void* dst, size_t dstCapacity,
3465 const void* src, size_t srcSize,
3466 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02003467{
Yann Collet4f818182017-04-17 17:57:35 -07003468 ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Colletf4bd8572017-04-27 11:31:55 -07003469 return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
Yann Collet81e13ef2016-06-07 00:51:51 +02003470}
3471
3472
3473
Yann Collet104e5b02016-08-12 13:04:27 +02003474/* ******************************************************************
3475* Streaming
3476********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003477
Yann Collet5a0c8e22016-08-12 01:20:36 +02003478ZSTD_CStream* ZSTD_createCStream(void)
3479{
Yann Colletae728a42017-05-30 17:11:39 -07003480 return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003481}
3482
3483ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
Yann Colletae728a42017-05-30 17:11:39 -07003484{ /* CStream and CCtx are now same object */
Yann Collet6fb2f242017-05-10 11:06:06 -07003485 return ZSTD_createCCtx_advanced(customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003486}
3487
3488size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
3489{
Yann Collet78553662017-05-08 17:15:00 -07003490 return ZSTD_freeCCtx(zcs); /* same object */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003491}
3492
Yann Collet5a0c8e22016-08-12 01:20:36 +02003493
3494
Yann Collet104e5b02016-08-12 13:04:27 +02003495/*====== Initialization ======*/
3496
Yann Colletfa3671e2017-05-19 10:51:30 -07003497size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003498
Yann Colletc17e0202017-04-20 12:50:02 -07003499size_t ZSTD_CStreamOutSize(void)
3500{
Yann Colletfa3671e2017-05-19 10:51:30 -07003501 return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
Yann Colletc17e0202017-04-20 12:50:02 -07003502}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003503
Yann Collet1ad7c822017-05-22 17:06:04 -07003504static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs,
3505 ZSTD_parameters params,
3506 unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003507{
Yann Collet1ad7c822017-05-22 17:06:04 -07003508 DEBUGLOG(5, "ZSTD_resetCStream_internal");
Yann Collet31533ba2017-04-27 00:29:04 -07003509
Yann Collet5ac72b42017-05-23 11:18:24 -07003510 CHECK_F(ZSTD_compressBegin_internal(zcs, NULL, 0, zcs->cdict,
3511 params, pledgedSrcSize, ZSTDb_buffered));
Yann Collet4cb21292016-09-15 14:54:07 +02003512
3513 zcs->inToCompress = 0;
3514 zcs->inBuffPos = 0;
3515 zcs->inBuffTarget = zcs->blockSize;
3516 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -07003517 zcs->streamStage = zcss_load;
Yann Collet4cb21292016-09-15 14:54:07 +02003518 zcs->frameEnded = 0;
3519 return 0; /* ready to go */
3520}
3521
Yann Collet009d6042017-05-19 10:17:59 -07003522size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
3523{
Yann Collet1ad7c822017-05-22 17:06:04 -07003524 ZSTD_parameters params = zcs->requestedParams;
Yann Collet009d6042017-05-19 10:17:59 -07003525 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
Yann Colletb0739bc2017-05-22 17:45:15 -07003526 DEBUGLOG(5, "ZSTD_resetCStream");
Yann Collet009d6042017-05-19 10:17:59 -07003527 if (zcs->compressionLevel != ZSTD_CLEVEL_CUSTOM) {
3528 params.cParams = ZSTD_getCParams(zcs->compressionLevel, pledgedSrcSize, 0 /* dictSize */);
3529 }
Yann Collet5ac72b42017-05-23 11:18:24 -07003530 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Yann Collet009d6042017-05-19 10:17:59 -07003531}
3532
Yann Collet77bf59e2017-04-27 11:43:04 -07003533/* ZSTD_initCStream_usingCDict_advanced() :
3534 * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
Yann Collet009d6042017-05-19 10:17:59 -07003535size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
3536 const ZSTD_CDict* cdict,
3537 unsigned long long pledgedSrcSize,
3538 ZSTD_frameParameters fParams)
3539{ /* cannot handle NULL cdict (does not know what to do) */
3540 if (!cdict) return ERROR(dictionary_wrong);
Yann Collet4ee6b152017-04-11 11:59:44 -07003541 { ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict);
Yann Collet77bf59e2017-04-27 11:43:04 -07003542 params.fParams = fParams;
Yann Collet1ad7c822017-05-22 17:06:04 -07003543 zcs->requestedParams = params;
3544 zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Collete88034f2017-04-10 22:24:02 -07003545 zcs->cdict = cdict;
Yann Collet5ac72b42017-05-23 11:18:24 -07003546 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Yann Collete88034f2017-04-10 22:24:02 -07003547 }
3548}
3549
Yann Collete88034f2017-04-10 22:24:02 -07003550/* note : cdict must outlive compression session */
3551size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3552{
Yann Colletef738c12017-05-12 13:53:46 -07003553 ZSTD_frameParameters const fParams = { 0 /* contentSize */, 0 /* checksum */, 0 /* hideDictID */ };
Yann Collet1ad7c822017-05-22 17:06:04 -07003554 /* cannot handle NULL cdict (does not know what to do) */
3555 if (!cdict) return ERROR(dictionary_wrong);
Yann Collet77bf59e2017-04-27 11:43:04 -07003556 return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, 0, fParams);
Yann Collete88034f2017-04-10 22:24:02 -07003557}
3558
3559static size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
3560 const void* dict, size_t dictSize,
3561 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3562{
3563 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
3564 zcs->cdict = NULL;
3565
3566 if (dict && dictSize >= 8) {
Yann Colletc7fe2622017-05-23 13:16:00 -07003567 if (zcs->staticSize) { /* static CCtx : never uses malloc */
3568 /* incompatible with internal cdict creation */
3569 return ERROR(memory_allocation);
3570 }
Yann Collete88034f2017-04-10 22:24:02 -07003571 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet31533ba2017-04-27 00:29:04 -07003572 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0 /* copy */, params.cParams, zcs->customMem);
Yann Collete88034f2017-04-10 22:24:02 -07003573 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
3574 zcs->cdict = zcs->cdictLocal;
3575 }
3576
Yann Collet5ac72b42017-05-23 11:18:24 -07003577 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Sean Purcell2db72492017-02-09 10:50:43 -08003578}
3579
Yann Collet5a0c8e22016-08-12 01:20:36 +02003580size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
3581 const void* dict, size_t dictSize,
3582 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3583{
Yann Collet4b987ad2017-04-10 17:50:44 -07003584 CHECK_F( ZSTD_checkCParams(params.cParams) );
Yann Collet1ad7c822017-05-22 17:06:04 -07003585 zcs->requestedParams = params;
3586 zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Collet4b987ad2017-04-10 17:50:44 -07003587 return ZSTD_initCStream_internal(zcs, dict, dictSize, params, pledgedSrcSize);
Yann Collet95162342016-10-25 16:19:52 -07003588}
3589
Yann Collet5a0c8e22016-08-12 01:20:36 +02003590size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3591{
3592 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet1ad7c822017-05-22 17:06:04 -07003593 zcs->compressionLevel = compressionLevel;
Yann Collet4b987ad2017-04-10 17:50:44 -07003594 return ZSTD_initCStream_internal(zcs, dict, dictSize, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003595}
3596
Yann Collete795c8a2016-12-13 16:39:36 +01003597size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3598{
Yann Colletd564faa2016-12-18 21:39:15 +01003599 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
Yann Collete88034f2017-04-10 22:24:02 -07003600 params.fParams.contentSizeFlag = (pledgedSrcSize>0);
Yann Collet4b987ad2017-04-10 17:50:44 -07003601 return ZSTD_initCStream_internal(zcs, NULL, 0, params, pledgedSrcSize);
Yann Collete795c8a2016-12-13 16:39:36 +01003602}
3603
Yann Collet5a0c8e22016-08-12 01:20:36 +02003604size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3605{
Yann Collete88034f2017-04-10 22:24:02 -07003606 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0);
3607 return ZSTD_initCStream_internal(zcs, NULL, 0, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003608}
3609
Yann Collet104e5b02016-08-12 13:04:27 +02003610/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003611
Yann Collet01b15492017-05-30 18:10:26 -07003612MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity,
3613 const void* src, size_t srcSize)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003614{
3615 size_t const length = MIN(dstCapacity, srcSize);
Yann Collet18ab5af2017-05-31 09:59:22 -07003616 if (length) memcpy(dst, src, length);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003617 return length;
3618}
3619
3620static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
Yann Collet01b15492017-05-30 18:10:26 -07003621 ZSTD_outBuffer* output,
3622 ZSTD_inBuffer* input,
3623 ZSTD_EndDirective const flushMode)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003624{
3625 U32 someMoreWork = 1;
Yann Collet01b15492017-05-30 18:10:26 -07003626 const char* const istart = (const char*)input->src;
3627 const char* const iend = istart + input->size;
3628 const char* ip = istart + input->pos;
3629 char* const ostart = (char*)output->dst;
3630 char* const oend = ostart + output->size;
3631 char* op = ostart + output->pos;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003632
Yann Collet01b15492017-05-30 18:10:26 -07003633 /* expected to be already allocated */
Yann Collet6d4fef32017-05-17 18:36:15 -07003634 assert(zcs->inBuff != NULL);
3635 assert(zcs->outBuff!= NULL);
Yann Collet009d6042017-05-19 10:17:59 -07003636
Yann Collet5a0c8e22016-08-12 01:20:36 +02003637 while (someMoreWork) {
Yann Collet0be6fd32017-05-08 16:08:01 -07003638 switch(zcs->streamStage)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003639 {
Yann Collet1ad7c822017-05-22 17:06:04 -07003640 case zcss_init:
3641 /* call ZSTD_initCStream() first ! */
3642 return ERROR(init_missing);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003643
3644 case zcss_load:
3645 /* complete inBuffer */
3646 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
Yann Collet06589fe2017-05-31 10:03:20 -07003647 size_t const loaded = ZSTD_limitCopy(
3648 zcs->inBuff + zcs->inBuffPos, toLoad,
3649 ip, iend-ip);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003650 zcs->inBuffPos += loaded;
3651 ip += loaded;
Yann Collet009d6042017-05-19 10:17:59 -07003652 if ( (flushMode == ZSTD_e_continue)
3653 && (zcs->inBuffPos < zcs->inBuffTarget) ) {
3654 /* not enough input to fill full block : stop here */
3655 someMoreWork = 0; break;
3656 }
3657 if ( (flushMode == ZSTD_e_flush)
3658 && (zcs->inBuffPos == zcs->inToCompress) ) {
3659 /* empty */
3660 someMoreWork = 0; break;
3661 }
3662 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003663 /* compress current block (note : this stage cannot be stopped in the middle) */
Yann Collet009d6042017-05-19 10:17:59 -07003664 DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003665 { void* cDst;
3666 size_t cSize;
3667 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3668 size_t oSize = oend-op;
Yann Collet009d6042017-05-19 10:17:59 -07003669 unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003670 if (oSize >= ZSTD_compressBound(iSize))
Yann Collet009d6042017-05-19 10:17:59 -07003671 cDst = op; /* compress directly into output buffer (skip flush stage) */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003672 else
3673 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
Yann Collet009d6042017-05-19 10:17:59 -07003674 cSize = lastBlock ?
3675 ZSTD_compressEnd(zcs, cDst, oSize,
3676 zcs->inBuff + zcs->inToCompress, iSize) :
3677 ZSTD_compressContinue(zcs, cDst, oSize,
3678 zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003679 if (ZSTD_isError(cSize)) return cSize;
Yann Collet009d6042017-05-19 10:17:59 -07003680 DEBUGLOG(5, "cSize = %u (lastBlock:%u)", (U32)cSize, lastBlock);
3681 zcs->frameEnded = lastBlock;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003682 /* prepare next block */
3683 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3684 if (zcs->inBuffTarget > zcs->inBuffSize)
Yann Collet009d6042017-05-19 10:17:59 -07003685 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
Yann Collet8b21ec42017-05-19 19:46:15 -07003686 DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
3687 (U32)zcs->inBuffTarget, (U32)zcs->inBuffSize);
3688 if (!lastBlock)
3689 assert(zcs->inBuffTarget <= zcs->inBuffSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003690 zcs->inToCompress = zcs->inBuffPos;
Yann Collet009d6042017-05-19 10:17:59 -07003691 if (cDst == op) { /* no need to flush */
3692 op += cSize;
3693 if (zcs->frameEnded) {
3694 DEBUGLOG(5, "Frame directly completed");
3695 someMoreWork = 0;
3696 zcs->streamStage = zcss_init;
3697 }
3698 break;
3699 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003700 zcs->outBuffContentSize = cSize;
3701 zcs->outBuffFlushedSize = 0;
Yann Collet009d6042017-05-19 10:17:59 -07003702 zcs->streamStage = zcss_flush; /* pass-through to flush stage */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003703 }
Jos Collin7cd7a752017-05-11 13:17:20 +05303704 /* fall-through */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003705 case zcss_flush:
Yann Collet009d6042017-05-19 10:17:59 -07003706 DEBUGLOG(5, "flush stage");
Yann Collet5a0c8e22016-08-12 01:20:36 +02003707 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
Yann Collet01b15492017-05-30 18:10:26 -07003708 size_t const flushed = ZSTD_limitCopy(op, oend-op,
3709 zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
Yann Collet009d6042017-05-19 10:17:59 -07003710 DEBUGLOG(5, "toFlush: %u ; flushed: %u", (U32)toFlush, (U32)flushed);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003711 op += flushed;
3712 zcs->outBuffFlushedSize += flushed;
Yann Collet01b15492017-05-30 18:10:26 -07003713 if (toFlush!=flushed) {
3714 /* dst too small to store flushed data : stop there */
3715 someMoreWork = 0;
3716 break;
3717 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003718 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet009d6042017-05-19 10:17:59 -07003719 if (zcs->frameEnded) {
3720 DEBUGLOG(5, "Frame completed");
3721 someMoreWork = 0;
3722 zcs->streamStage = zcss_init;
3723 break;
3724 }
Yann Collet0be6fd32017-05-08 16:08:01 -07003725 zcs->streamStage = zcss_load;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003726 break;
3727 }
3728
3729 case zcss_final:
Yann Collet009d6042017-05-19 10:17:59 -07003730 someMoreWork = 0; break; /* useless */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003731
Yann Colletcd2892f2017-06-01 09:44:54 -07003732 default: /* impossible */
3733 assert(0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003734 }
3735 }
3736
Yann Collet01b15492017-05-30 18:10:26 -07003737 input->pos = ip - istart;
3738 output->pos = op - ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003739 if (zcs->frameEnded) return 0;
3740 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3741 if (hintInSize==0) hintInSize = zcs->blockSize;
3742 return hintInSize;
3743 }
3744}
3745
Yann Collet53e17fb2016-08-17 01:39:22 +02003746size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003747{
Yann Collet01b15492017-05-30 18:10:26 -07003748 /* check conditions */
3749 if (output->pos > output->size) return ERROR(GENERIC);
3750 if (input->pos > input->size) return ERROR(GENERIC);
3751
3752 return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003753}
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 Colletdeee6e52017-05-30 17:42:00 -07003768 DEBUGLOG(5, "ZSTD_compress_generic : transparent reset");
Yann Collet6d4fef32017-05-17 18:36:15 -07003769 if (cctx->compressionLevel != ZSTD_CLEVEL_CUSTOM)
3770 params.cParams = ZSTD_getCParams(cctx->compressionLevel,
3771 cctx->frameContentSize, 0 /* dictSize */);
Yann Collet5ac72b42017-05-23 11:18:24 -07003772 CHECK_F( ZSTD_resetCStream_internal(cctx, params, cctx->frameContentSize) );
Yann Collet6d4fef32017-05-17 18:36:15 -07003773 }
3774
Yann Collet01b15492017-05-30 18:10:26 -07003775 DEBUGLOG(5, "starting ZSTD_compressStream_generic");
3776 CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
3777
Yann Collet6d4fef32017-05-17 18:36:15 -07003778 DEBUGLOG(5, "completing ZSTD_compress_generic_integral");
Yann Colletdeee6e52017-05-30 17:42:00 -07003779 return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
Yann Collet6d4fef32017-05-17 18:36:15 -07003780}
3781
Yann Colletdeee6e52017-05-30 17:42:00 -07003782size_t ZSTD_compress_generic_simpleArgs (
3783 ZSTD_CCtx* cctx,
3784 void* dst, size_t dstCapacity, size_t* dstPos,
3785 const void* src, size_t srcSize, size_t* srcPos,
3786 ZSTD_EndDirective endOp)
Yann Collet6d4fef32017-05-17 18:36:15 -07003787{
Yann Colletdeee6e52017-05-30 17:42:00 -07003788 ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
3789 ZSTD_inBuffer input = { src, srcSize, *srcPos };
Yann Collet01b15492017-05-30 18:10:26 -07003790 /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
Yann Colletdeee6e52017-05-30 17:42:00 -07003791 size_t const hint = ZSTD_compress_generic(cctx, &output, &input, endOp);
3792 if (ZSTD_isError(hint)) return hint;
3793
3794 *dstPos = output.pos;
3795 *srcPos = input.pos;
3796 return hint;
Yann Collet01b15492017-05-30 18:10:26 -07003797
Yann Collet6d4fef32017-05-17 18:36:15 -07003798}
3799
Yann Collet5a0c8e22016-08-12 01:20:36 +02003800
Yann Collet104e5b02016-08-12 13:04:27 +02003801/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003802
3803/*! ZSTD_flushStream() :
3804* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003805size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003806{
Yann Collet18ab5af2017-05-31 09:59:22 -07003807 ZSTD_inBuffer input = { NULL, 0, 0 };
Yann Collet01b15492017-05-30 18:10:26 -07003808 if (output->pos > output->size) return ERROR(GENERIC);
3809 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_flush) );
3810 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003811}
3812
3813
Yann Collet53e17fb2016-08-17 01:39:22 +02003814size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003815{
Yann Collet18ab5af2017-05-31 09:59:22 -07003816 ZSTD_inBuffer input = { NULL, 0, 0 };
Yann Collet01b15492017-05-30 18:10:26 -07003817 if (output->pos > output->size) return ERROR(GENERIC);
3818 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_end) );
Yann Collet009d6042017-05-19 10:17:59 -07003819
Yann Collet48855fa2017-05-19 10:56:11 -07003820 DEBUGLOG(5, "ZSTD_endStream : remaining to flush : %u",
Yann Collet009d6042017-05-19 10:17:59 -07003821 (unsigned)(zcs->outBuffContentSize - zcs->outBuffFlushedSize));
Yann Collet009d6042017-05-19 10:17:59 -07003822 return zcs->outBuffContentSize - zcs->outBuffFlushedSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003823}
3824
3825
Yann Collet70e8c382016-02-10 13:37:52 +01003826/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003827
inikep2c5eeea2016-04-15 13:44:46 +02003828#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003829int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003830
Yann Collet3b719252016-03-30 19:48:05 +02003831static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003832{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003833 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003834 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003835 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3836 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003837 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3838 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003839 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3840 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3841 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003842 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003843 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3844 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3845 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3846 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3847 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3848 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3849 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3850 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003851 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
Yann Collet29297c62017-04-27 17:44:01 -07003852 { 23, 22, 22, 5, 4, 32, ZSTD_btopt }, /* level 18 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003853 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Nick Terrell374f8682017-05-10 17:48:42 -07003854 { 25, 25, 23, 7, 3, 64, ZSTD_btultra }, /* level 20 */
3855 { 26, 26, 23, 7, 3,256, ZSTD_btultra }, /* level 21 */
3856 { 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003857},
3858{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003859 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003860 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003861 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003862 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3863 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3864 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3865 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3866 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3867 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3868 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3869 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3870 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3871 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3872 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3873 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003874 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003875 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3876 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3877 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003878 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3879 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003880 { 18, 19, 18, 11, 3,512, ZSTD_btultra }, /* level 20.*/
3881 { 18, 19, 18, 12, 3,512, ZSTD_btultra }, /* level 21.*/
3882 { 18, 19, 18, 13, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003883},
3884{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003885 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003886 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3887 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3888 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3889 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3890 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3891 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3892 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3893 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3894 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3895 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3896 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3897 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3898 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3899 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003900 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3901 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3902 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3903 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3904 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3905 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003906 { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/
3907 { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/
3908 { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003909},
3910{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003911 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003912 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003913 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003914 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3915 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3916 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3917 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3918 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3919 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3920 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3921 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003922 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3923 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3924 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3925 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3926 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3927 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3928 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3929 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3930 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3931 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003932 { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/
3933 { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/
3934 { 14, 15, 15, 10, 3,256, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003935},
3936};
3937
Yann Collet236d94f2016-05-18 12:06:33 +02003938/*! ZSTD_getCParams() :
3939* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3940* Size values are optional, provide 0 if not known or unused */
Yann Collet009d6042017-05-19 10:17:59 -07003941ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003942{
Yann Collet15354142016-04-04 04:22:53 +02003943 ZSTD_compressionParameters cp;
Yann Collet009d6042017-05-19 10:17:59 -07003944 size_t const addedSize = srcSizeHint ? 0 : 500;
3945 U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003946 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet6d4fef32017-05-17 18:36:15 -07003947 if (compressionLevel <= 0) compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003948 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003949 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003950 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3951 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003952 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003953 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3954 }
Yann Collet009d6042017-05-19 10:17:59 -07003955 cp = ZSTD_adjustCParams(cp, srcSizeHint, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003956 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003957}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003958
3959/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003960* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003961* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet009d6042017-05-19 10:17:59 -07003962ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003963 ZSTD_parameters params;
Yann Collet009d6042017-05-19 10:17:59 -07003964 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize);
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003965 memset(&params, 0, sizeof(params));
3966 params.cParams = cParams;
3967 return params;
3968}