blob: ddbeaf56e65936ee88490a666fba6e9fc14a1e8e [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 Colletf3eca252015-10-22 15:31:46 +010028
29
Yann Collet7d360282016-02-12 00:07:30 +010030/*-*************************************
Yann Collet31533ba2017-04-27 00:29:04 -070031* Debug
32***************************************/
33#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
34# include <assert.h>
35#else
36# define assert(condition) ((void)0)
37#endif
38
39#define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; }
40
41#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2)
42# include <stdio.h>
43 static unsigned g_debugLevel = ZSTD_DEBUG;
Yann Collet009d6042017-05-19 10:17:59 -070044# define DEBUGLOG(l, ...) { \
45 if (l<=g_debugLevel) { \
46 fprintf(stderr, __FILE__ ": "); \
47 fprintf(stderr, __VA_ARGS__); \
48 fprintf(stderr, " \n"); \
49 } }
Yann Collet31533ba2017-04-27 00:29:04 -070050#else
51# define DEBUGLOG(l, ...) {} /* disabled */
52#endif
53
54
55/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010056* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010057***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010058static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Collet731ef162016-07-27 21:05:12 +020059#define HASH_READ_SIZE 8
60typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
Yann Colletf3eca252015-10-22 15:31:46 +010061
Yann Collet71ddeb62017-04-20 22:54:54 -070062/* entropy tables always have same size */
63static size_t const hufCTable_size = HUF_CTABLE_SIZE(255);
Yann Collete42afbc2017-04-26 11:39:35 -070064static size_t const litlengthCTable_size = FSE_CTABLE_SIZE(LLFSELog, MaxLL);
65static size_t const offcodeCTable_size = FSE_CTABLE_SIZE(OffFSELog, MaxOff);
66static size_t const matchlengthCTable_size = FSE_CTABLE_SIZE(MLFSELog, MaxML);
Yann Collet72712032017-04-20 23:21:19 -070067static size_t const entropyScratchSpace_size = HUF_WORKSPACE_SIZE;
Yann Colleta34a39c2017-04-20 18:17:58 -070068
Yann Colletf3eca252015-10-22 15:31:46 +010069
Yann Collet7d360282016-02-12 00:07:30 +010070/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010071* Helper functions
72***************************************/
Yann Collet3f75d522017-03-31 17:11:38 -070073size_t ZSTD_compressBound(size_t srcSize) {
Yann Collet30c76982017-03-31 18:27:03 -070074 size_t const lowLimit = 256 KB;
75 size_t const margin = (srcSize < lowLimit) ? (lowLimit-srcSize) >> 12 : 0; /* from 64 to 0 */
Yann Collet3f75d522017-03-31 17:11:38 -070076 return srcSize + (srcSize >> 8) + margin;
77}
Yann Collet59d1f792016-01-23 19:28:41 +010078
79
Yann Collet7d360282016-02-12 00:07:30 +010080/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010081* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010082***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010083static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
84{
Yann Collet14983e72015-11-11 21:38:21 +010085 ssPtr->lit = ssPtr->litStart;
Yann Colletc0ce4f12016-07-30 00:55:13 +020086 ssPtr->sequences = ssPtr->sequencesStart;
Yann Collet5d393572016-04-07 17:19:00 +020087 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010088}
89
90
Yann Collet7d360282016-02-12 00:07:30 +010091/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010092* Context memory management
93***************************************/
Yann Collet6d4fef32017-05-17 18:36:15 -070094typedef enum { zcss_init=0, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
Yann Collet0be6fd32017-05-08 16:08:01 -070095
Yann Collet18803372017-05-22 18:21:51 -070096struct ZSTD_CDict_s {
97 void* dictBuffer;
98 const void* dictContent;
99 size_t dictContentSize;
100 ZSTD_CCtx* refContext;
101}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
102
Yann Colletaca113f2016-12-23 22:25:03 +0100103struct ZSTD_CCtx_s {
Yann Collet89db5e02015-11-13 11:27:46 +0100104 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100105 const BYTE* base; /* All regular indexes relative to this position */
106 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +0100107 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +0100108 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +0100109 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +0100110 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +0100111 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Colletbb002742017-01-25 16:25:38 -0800112 U32 loadedDictEnd; /* index of end of dictionary */
113 U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
Yann Collet14312d82017-02-23 23:42:12 -0800114 U32 forceRawDict; /* Force loading dictionary in "content-only" mode (no header analysis) */
Yann Collet731ef162016-07-27 21:05:12 +0200115 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +0200116 U32 rep[ZSTD_REP_NUM];
Yann Colletb459aad2017-01-19 17:33:37 -0800117 U32 repToConfirm[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +0200118 U32 dictID;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700119 int compressionLevel;
Yann Collet1ad7c822017-05-22 17:06:04 -0700120 ZSTD_parameters requestedParams;
121 ZSTD_parameters appliedParams;
Yann Collet712def92015-10-29 18:41:45 +0100122 void* workSpace;
123 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100124 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +0200125 U64 frameContentSize;
Yann Collet20d5e032017-04-11 18:34:02 -0700126 U64 consumedSrcSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200127 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +0200128 ZSTD_customMem customMem;
Yann Colletc7fe2622017-05-23 13:16:00 -0700129 size_t staticSize;
Yann Colletecd651b2016-01-07 15:35:18 +0100130
Yann Collet712def92015-10-29 18:41:45 +0100131 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100132 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +0100133 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +0200134 U32* chainTable;
Yann Collet71ddeb62017-04-20 22:54:54 -0700135 HUF_repeat hufCTable_repeatMode;
136 HUF_CElt* hufCTable;
137 U32 fseCTables_ready;
Yann Collet71aaa322017-04-20 23:03:38 -0700138 FSE_CTable* offcodeCTable;
139 FSE_CTable* matchlengthCTable;
140 FSE_CTable* litlengthCTable;
Yann Collete42afbc2017-04-26 11:39:35 -0700141 unsigned* entropyScratchSpace;
Yann Collet0be6fd32017-05-08 16:08:01 -0700142
143 /* streaming */
144 ZSTD_CDict* cdictLocal;
145 const ZSTD_CDict* cdict;
146 char* inBuff;
147 size_t inBuffSize;
148 size_t inToCompress;
149 size_t inBuffPos;
150 size_t inBuffTarget;
151 char* outBuff;
152 size_t outBuffSize;
153 size_t outBuffContentSize;
154 size_t outBuffFlushedSize;
155 ZSTD_cStreamStage streamStage;
156 U32 frameEnded;
Yann Colletf3eca252015-10-22 15:31:46 +0100157};
158
Yann Collet5be2dd22015-11-11 13:43:58 +0100159ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100160{
Yann Colletae728a42017-05-30 17:11:39 -0700161 return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
inikep50e82c02016-05-23 15:49:09 +0200162}
163
164ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
165{
Yann Collet69c2cdb2016-07-14 16:52:45 +0200166 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +0200167
Yann Colletae728a42017-05-30 17:11:39 -0700168 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200169
Yann Colletc4f46b92017-05-30 17:45:37 -0700170 cctx = (ZSTD_CCtx*) ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200171 if (!cctx) return NULL;
Yann Colletbb002742017-01-25 16:25:38 -0800172 cctx->customMem = customMem;
Yann Collet6d4fef32017-05-17 18:36:15 -0700173 cctx->compressionLevel = ZSTD_CLEVEL_DEFAULT;
Yann Collet69c2cdb2016-07-14 16:52:45 +0200174 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100175}
176
Yann Colletc7fe2622017-05-23 13:16:00 -0700177ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
178{
179 ZSTD_CCtx* cctx = (ZSTD_CCtx*) workspace;
180 if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
181 if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
182 memset(workspace, 0, workspaceSize);
183 cctx->staticSize = workspaceSize;
184 cctx->workSpace = (void*)(cctx+1);
185 cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
186
187 /* entropy space (never moves) */
188 /* note : this code should be shared with resetCCtx, instead of copied */
189 { void* ptr = cctx->workSpace;
190 cctx->hufCTable = (HUF_CElt*)ptr;
Yann Collet0fdc71c2017-05-24 17:41:41 -0700191 ptr = (char*)cctx->hufCTable + hufCTable_size;
Yann Colletc7fe2622017-05-23 13:16:00 -0700192 cctx->offcodeCTable = (FSE_CTable*) ptr;
193 ptr = (char*)ptr + offcodeCTable_size;
194 cctx->matchlengthCTable = (FSE_CTable*) ptr;
195 ptr = (char*)ptr + matchlengthCTable_size;
196 cctx->litlengthCTable = (FSE_CTable*) ptr;
197 ptr = (char*)ptr + litlengthCTable_size;
198 assert(((size_t)ptr & 3) == 0); /* ensure correct alignment */
199 cctx->entropyScratchSpace = (unsigned*) ptr;
200 }
201
202 return cctx;
203}
204
Yann Collet5be2dd22015-11-11 13:43:58 +0100205size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100206{
inikep36403962016-06-03 16:36:50 +0200207 if (cctx==NULL) return 0; /* support free on NULL */
Yann Colletc7fe2622017-05-23 13:16:00 -0700208 assert(!cctx->staticSize); /* not compatible with static CCtx */
Yann Collet23b6e052016-08-28 21:05:43 -0700209 ZSTD_free(cctx->workSpace, cctx->customMem);
Yann Collet78553662017-05-08 17:15:00 -0700210 cctx->workSpace = NULL;
211 ZSTD_freeCDict(cctx->cdictLocal);
212 cctx->cdictLocal = NULL;
Yann Collet23b6e052016-08-28 21:05:43 -0700213 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100214 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100215}
216
Yann Collet70e3b312016-08-23 01:18:06 +0200217size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200218{
Yann Colletd7c65892016-09-15 02:50:27 +0200219 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet791d7442017-05-08 16:17:30 -0700220 return sizeof(*cctx) + cctx->workSpaceSize
221 + ZSTD_sizeof_CDict(cctx->cdictLocal)
222 + cctx->outBuffSize + cctx->inBuffSize;
Yann Collet3ae543c2016-07-11 03:12:17 +0200223}
224
Yann Collet009d6042017-05-19 10:17:59 -0700225size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
226{
227 return ZSTD_sizeof_CCtx(zcs); /* same object */
228}
229
Yann Colletb0edb7f2017-05-12 15:31:53 -0700230/* private API call, for dictBuilder only */
231const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
232
Yann Collet1ad7c822017-05-22 17:06:04 -0700233static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return cctx->appliedParams; }
Yann Colletb0edb7f2017-05-12 15:31:53 -0700234
Yann Colletef738c12017-05-12 13:53:46 -0700235/* older variant; will be deprecated */
Yann Colletbb002742017-01-25 16:25:38 -0800236size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
237{
238 switch(param)
239 {
Yann Collet06e76972017-01-25 16:39:03 -0800240 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
Yann Collet14312d82017-02-23 23:42:12 -0800241 case ZSTD_p_forceRawDict : cctx->forceRawDict = value>0; return 0;
Yann Colletbb002742017-01-25 16:25:38 -0800242 default: return ERROR(parameter_unknown);
243 }
244}
245
Yann Colletadd66f82017-05-12 15:59:48 -0700246
Yann Collet6d4fef32017-05-17 18:36:15 -0700247#define ZSTD_CLEVEL_CUSTOM 999
Yann Colletadd66f82017-05-12 15:59:48 -0700248static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx)
249{
Yann Collet1ad7c822017-05-22 17:06:04 -0700250 if (cctx->compressionLevel==ZSTD_CLEVEL_CUSTOM) return;
251 cctx->requestedParams.cParams = ZSTD_getCParams(cctx->compressionLevel,
252 cctx->frameContentSize, 0);
Yann Collet6d4fef32017-05-17 18:36:15 -0700253 cctx->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Colletadd66f82017-05-12 15:59:48 -0700254}
255
Yann Colletb0edb7f2017-05-12 15:31:53 -0700256size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value)
Yann Collet7d360282016-02-12 00:07:30 +0100257{
Yann Collet334a2882017-05-19 11:04:41 -0700258# define CLAMPCHECK(val,min,max) { \
259 if ((val<min) | (val>max)) { \
260 return ERROR(compressionParameter_unsupported); \
261 } }
262
Yann Collet24de7b02017-05-22 13:05:45 -0700263 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700264
265 switch(param)
266 {
267 case ZSTD_p_compressionLevel :
268 if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel(); /* cap max compression level */
269 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
270 cctx->compressionLevel = value;
271 return 0;
272
273 case ZSTD_p_windowLog :
Yann Colletadd66f82017-05-12 15:59:48 -0700274 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletb0edb7f2017-05-12 15:31:53 -0700275 CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Colletadd66f82017-05-12 15:59:48 -0700276 ZSTD_cLevelToCParams(cctx);
Yann Collet1ad7c822017-05-22 17:06:04 -0700277 cctx->requestedParams.cParams.windowLog = value;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700278 return 0;
279
280 case ZSTD_p_hashLog :
Yann Colletadd66f82017-05-12 15:59:48 -0700281 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletb0edb7f2017-05-12 15:31:53 -0700282 CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
Yann Colletadd66f82017-05-12 15:59:48 -0700283 ZSTD_cLevelToCParams(cctx);
Yann Collet1ad7c822017-05-22 17:06:04 -0700284 cctx->requestedParams.cParams.hashLog = value;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700285 return 0;
286
287 case ZSTD_p_chainLog :
Yann Colletadd66f82017-05-12 15:59:48 -0700288 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletb0edb7f2017-05-12 15:31:53 -0700289 CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Colletadd66f82017-05-12 15:59:48 -0700290 ZSTD_cLevelToCParams(cctx);
Yann Collet1ad7c822017-05-22 17:06:04 -0700291 cctx->requestedParams.cParams.chainLog = value;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700292 return 0;
293
294 case ZSTD_p_searchLog :
Yann Colletadd66f82017-05-12 15:59:48 -0700295 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletb0edb7f2017-05-12 15:31:53 -0700296 CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Colletadd66f82017-05-12 15:59:48 -0700297 ZSTD_cLevelToCParams(cctx);
Yann Collet1ad7c822017-05-22 17:06:04 -0700298 cctx->requestedParams.cParams.searchLog = value;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700299 return 0;
300
Yann Collet6d4fef32017-05-17 18:36:15 -0700301 case ZSTD_p_minMatch :
Yann Colletadd66f82017-05-12 15:59:48 -0700302 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletb0edb7f2017-05-12 15:31:53 -0700303 CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
Yann Colletadd66f82017-05-12 15:59:48 -0700304 ZSTD_cLevelToCParams(cctx);
Yann Collet1ad7c822017-05-22 17:06:04 -0700305 cctx->requestedParams.cParams.searchLength = value;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700306 return 0;
307
308 case ZSTD_p_targetLength :
Yann Colletadd66f82017-05-12 15:59:48 -0700309 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletb0edb7f2017-05-12 15:31:53 -0700310 CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Colletadd66f82017-05-12 15:59:48 -0700311 ZSTD_cLevelToCParams(cctx);
Yann Collet1ad7c822017-05-22 17:06:04 -0700312 cctx->requestedParams.cParams.targetLength = value;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700313 return 0;
314
315 case ZSTD_p_compressionStrategy :
Yann Colleta5ffe3d2017-05-12 16:29:19 -0700316 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
317 CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
Yann Colletadd66f82017-05-12 15:59:48 -0700318 ZSTD_cLevelToCParams(cctx);
Yann Collet1ad7c822017-05-22 17:06:04 -0700319 cctx->requestedParams.cParams.strategy = (ZSTD_strategy)value;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700320 return 0;
321
322#if 0
323 case ZSTD_p_windowSize : /* to be done later */
324 return ERROR(compressionParameter_unsupported);
325#endif
326
327 case ZSTD_p_contentSizeFlag : /* Content size will be written in frame header _when known_ (default:1) */
Yann Collet1ad7c822017-05-22 17:06:04 -0700328 cctx->requestedParams.fParams.contentSizeFlag = value>0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700329 return 0;
330
Yann Collet6d4fef32017-05-17 18:36:15 -0700331 case ZSTD_p_checksumFlag : /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
Yann Collet1ad7c822017-05-22 17:06:04 -0700332 cctx->requestedParams.fParams.checksumFlag = value>0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700333 return 0;
334
Yann Collet1ad7c822017-05-22 17:06:04 -0700335 case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
336 DEBUGLOG(5, "set dictIDFlag = %u", (value>0));
337 cctx->requestedParams.fParams.noDictIDFlag = (value==0);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700338 return 0;
339
340 case ZSTD_p_refDictContent : /* to be done later */
341 return ERROR(compressionParameter_unsupported);
342
343 case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize,
344 * even when referencing into Dictionary content
345 * default : 0 when using a CDict, 1 when using a Prefix */
346 cctx->forceWindow = value>0;
347 cctx->loadedDictEnd = 0;
348 return 0;
349
350 case ZSTD_p_rawContentDict : /* load dictionary in "content-only" mode (no header analysis) (default:0) */
351 cctx->forceRawDict = value>0;
352 return 0;
353
354 default: return ERROR(parameter_unknown);
355 }
Yann Collet7d360282016-02-12 00:07:30 +0100356}
357
Yann Colletb0edb7f2017-05-12 15:31:53 -0700358ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
Yann Collet95162342016-10-25 16:19:52 -0700359{
Yann Collet24de7b02017-05-22 13:05:45 -0700360 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700361 cctx->frameContentSize = pledgedSrcSize;
362 return 0;
363}
364
Yann Collet6d4fef32017-05-17 18:36:15 -0700365ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
366{
Yann Collet24de7b02017-05-22 13:05:45 -0700367 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletc7fe2622017-05-23 13:16:00 -0700368 if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
Yann Collet6d4fef32017-05-17 18:36:15 -0700369 ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */
370 if (dict==NULL || dictSize==0) { /* no dictionary mode */
371 cctx->cdictLocal = NULL;
372 cctx->cdict = NULL;
373 } else {
Yann Collet8b21ec42017-05-19 19:46:15 -0700374 ZSTD_compressionParameters const cParams =
375 cctx->compressionLevel == ZSTD_CLEVEL_CUSTOM ?
Yann Collet1ad7c822017-05-22 17:06:04 -0700376 cctx->requestedParams.cParams :
Yann Collet8b21ec42017-05-19 19:46:15 -0700377 ZSTD_getCParams(cctx->compressionLevel, 0, dictSize);
Yann Collet6d4fef32017-05-17 18:36:15 -0700378 cctx->cdictLocal = ZSTD_createCDict_advanced(
379 dict, dictSize,
380 0 /* byReference */,
Yann Collet8b21ec42017-05-19 19:46:15 -0700381 cParams, cctx->customMem);
Yann Collet6d4fef32017-05-17 18:36:15 -0700382 cctx->cdict = cctx->cdictLocal;
383 if (cctx->cdictLocal == NULL)
384 return ERROR(memory_allocation);
385 }
386 return 0;
387}
388
Yann Colletb0edb7f2017-05-12 15:31:53 -0700389/* Not ready yet ! */
390ZSTDLIB_API size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
391{
392 (void)cctx; (void)prefix; (void)prefixSize; /* to be done later */
Yann Collet24de7b02017-05-22 13:05:45 -0700393 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700394 return ERROR(compressionParameter_unsupported);
395}
396
Yann Colletb0edb7f2017-05-12 15:31:53 -0700397ZSTDLIB_API size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
398{
Yann Collet24de7b02017-05-22 13:05:45 -0700399 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
400 cctx->cdict = cdict;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700401 return ERROR(compressionParameter_unsupported);
Yann Collet95162342016-10-25 16:19:52 -0700402}
403
Yann Collet59d70632015-11-04 12:05:27 +0100404
Yann Collet21588e32016-03-30 16:50:44 +0200405/** ZSTD_checkParams() :
406 ensure param values remain within authorized range.
407 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200408size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200409{
Yann Collet15354142016-04-04 04:22:53 +0200410 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200411 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200412 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
413 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Collet2e2e78d2017-03-29 16:02:47 -0700414 CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200415 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800416 if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200417 return 0;
418}
419
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100420/** ZSTD_cycleLog() :
421 * condition for correct operation : hashLog > 1 */
422static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
423{
424 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
425 return hashLog - btScale;
426}
427
Yann Collet70d13012016-06-01 18:45:34 +0200428/** ZSTD_adjustCParams() :
Yann Colletcf409a72016-09-26 16:41:05 +0200429 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200430 mostly downsizing to reduce memory consumption and initialization.
431 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
432 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200433 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200434ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100435{
Yann Collet70d13012016-06-01 18:45:34 +0200436 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100437
Yann Collet70e45772016-03-19 18:08:32 +0100438 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200439 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
440 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200441 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200442 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200443 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200444 } }
Yann Collet70d13012016-06-01 18:45:34 +0200445 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100446 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
447 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
448 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100449
Yann Collet70d13012016-06-01 18:45:34 +0200450 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200451
452 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100453}
454
455
Yann Collet88472382016-07-14 17:05:38 +0200456size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100457{
Yann Colletfa3671e2017-05-19 10:51:30 -0700458 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
Yann Collet731ef162016-07-27 21:05:12 +0200459 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
460 size_t const maxNbSeq = blockSize / divider;
461 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200462
Yann Collet731ef162016-07-27 21:05:12 +0200463 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
464 size_t const hSize = ((size_t)1) << cParams.hashLog;
465 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
466 size_t const h3Size = ((size_t)1) << hashLog3;
Yann Collet71ddeb62017-04-20 22:54:54 -0700467 size_t const entropySpace = hufCTable_size + litlengthCTable_size
Yann Colleta4086452017-04-20 23:09:39 -0700468 + offcodeCTable_size + matchlengthCTable_size
Yann Collet72712032017-04-20 23:21:19 -0700469 + entropyScratchSpace_size;
Yann Collet731ef162016-07-27 21:05:12 +0200470 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200471
Yann Colletfc514592017-05-08 17:07:59 -0700472 size_t const optBudget = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
Yann Collet3ae543c2016-07-11 03:12:17 +0200473 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
Nick Terrell5f2c7212017-05-10 16:49:58 -0700474 size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
Yann Colletfc514592017-05-08 17:07:59 -0700475 size_t const neededSpace = entropySpace + tableSpace + tokenSpace + optSpace;
Yann Collet3ae543c2016-07-11 03:12:17 +0200476
477 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100478}
479
Yann Colletc7fe2622017-05-23 13:16:00 -0700480size_t ZSTD_estimateCStreamSize(ZSTD_compressionParameters cParams)
481{
482 size_t const CCtxSize = ZSTD_estimateCCtxSize(cParams);
483 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
484 size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
485 size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
486 size_t const streamingSize = inBuffSize + outBuffSize;
487
488 return CCtxSize + streamingSize;
489}
490
Yann Colleta7737f62016-09-06 09:44:59 +0200491
Yann Collet009d6042017-05-19 10:17:59 -0700492static U32 ZSTD_equivalentParams(ZSTD_compressionParameters cParams1,
493 ZSTD_compressionParameters cParams2)
Yann Colleta7737f62016-09-06 09:44:59 +0200494{
Yann Colletfa3671e2017-05-19 10:51:30 -0700495 U32 bslog1 = MIN(cParams1.windowLog, ZSTD_BLOCKSIZELOG_MAX);
496 U32 bslog2 = MIN(cParams2.windowLog, ZSTD_BLOCKSIZELOG_MAX);
Yann Collet009d6042017-05-19 10:17:59 -0700497 return (bslog1 == bslog2) /* same block size */
498 & (cParams1.hashLog == cParams2.hashLog)
499 & (cParams1.chainLog == cParams2.chainLog)
500 & (cParams1.strategy == cParams2.strategy) /* opt parser space */
501 & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */
Yann Colleta7737f62016-09-06 09:44:59 +0200502}
503
504/*! ZSTD_continueCCtx() :
505 reuse CCtx without reset (note : requires no dictionary) */
506static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
507{
508 U32 const end = (U32)(cctx->nextSrc - cctx->base);
Yann Collet1ad7c822017-05-22 17:06:04 -0700509 cctx->appliedParams = params;
Yann Colleta7737f62016-09-06 09:44:59 +0200510 cctx->frameContentSize = frameContentSize;
Yann Collet20d5e032017-04-11 18:34:02 -0700511 cctx->consumedSrcSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200512 cctx->lowLimit = end;
513 cctx->dictLimit = end;
514 cctx->nextToUpdate = end+1;
515 cctx->stage = ZSTDcs_init;
516 cctx->dictID = 0;
517 cctx->loadedDictEnd = 0;
518 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200519 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
520 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200521 return 0;
522}
523
Yann Colletb0739bc2017-05-22 17:45:15 -0700524typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
Yann Colleta7737f62016-09-06 09:44:59 +0200525
Yann Collet5ac72b42017-05-23 11:18:24 -0700526typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
527
Yann Collet30fb4992017-04-18 14:08:50 -0700528/*! ZSTD_resetCCtx_internal() :
Yann Collet5ac72b42017-05-23 11:18:24 -0700529 note : `params` are assumed fully validated at this stage */
530static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
531 ZSTD_parameters params, U64 frameContentSize,
532 ZSTD_compResetPolicy_e const crp,
533 ZSTD_buffered_policy_e const zbuff)
Yann Colleta7737f62016-09-06 09:44:59 +0200534{
Yann Collet009d6042017-05-19 10:17:59 -0700535 DEBUGLOG(5, "ZSTD_resetCCtx_internal : wlog=%u / old=%u",
Yann Collet1ad7c822017-05-22 17:06:04 -0700536 params.cParams.windowLog, zc->appliedParams.cParams.windowLog);
Yann Collet5ac72b42017-05-23 11:18:24 -0700537 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet0be6fd32017-05-08 16:08:01 -0700538
Yann Colletb0739bc2017-05-22 17:45:15 -0700539 if (crp == ZSTDcrp_continue) {
Yann Collet1ad7c822017-05-22 17:06:04 -0700540 if (ZSTD_equivalentParams(params.cParams, zc->appliedParams.cParams)) {
Yann Collet009d6042017-05-19 10:17:59 -0700541 DEBUGLOG(5, "ZSTD_equivalentParams()==1");
Yann Collet71ddeb62017-04-20 22:54:54 -0700542 zc->fseCTables_ready = 0;
543 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200544 return ZSTD_continueCCtx(zc, params, frameContentSize);
Yann Colletb0739bc2017-05-22 17:45:15 -0700545 } }
inikep87d4f3d2016-03-02 15:56:24 +0100546
Yann Colletfa3671e2017-05-19 10:51:30 -0700547 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200548 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
549 size_t const maxNbSeq = blockSize / divider;
550 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet5ac72b42017-05-23 11:18:24 -0700551 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ?
552 0 : (1 << params.cParams.chainLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200553 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
Yann Collet5ac72b42017-05-23 11:18:24 -0700554 U32 const hashLog3 = (params.cParams.searchLength>3) ?
555 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200556 size_t const h3Size = ((size_t)1) << hashLog3;
557 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet5ac72b42017-05-23 11:18:24 -0700558 size_t const buffOutSize = ZSTD_compressBound(blockSize)+1;
559 size_t const buffInSize = ((size_t)1 << params.cParams.windowLog) + blockSize;
Yann Colleta7737f62016-09-06 09:44:59 +0200560 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100561
Yann Colleta7737f62016-09-06 09:44:59 +0200562 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Collet71ddeb62017-04-20 22:54:54 -0700563 { size_t const entropySpace = hufCTable_size + litlengthCTable_size
Yann Colleta4086452017-04-20 23:09:39 -0700564 + offcodeCTable_size + matchlengthCTable_size
Yann Collet72712032017-04-20 23:21:19 -0700565 + entropyScratchSpace_size;
Yann Collet71ddeb62017-04-20 22:54:54 -0700566 size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
Yann Collete6fa70a2017-04-20 17:28:31 -0700567 + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
Yann Collet5ac72b42017-05-23 11:18:24 -0700568 size_t const optSpace = ( (params.cParams.strategy == ZSTD_btopt)
569 || (params.cParams.strategy == ZSTD_btultra)) ?
570 optPotentialSpace : 0;
571 size_t const bufferSpace = (zbuff==ZSTDb_buffered) ?
572 buffInSize + buffOutSize : 0;
573 size_t const neededSpace = entropySpace + optSpace + tableSpace
574 + tokenSpace + bufferSpace;
Yann Colletc7fe2622017-05-23 13:16:00 -0700575
576 if (zc->workSpaceSize < neededSpace) { /* too small : resize /*/
Yann Collet0be6fd32017-05-08 16:08:01 -0700577 DEBUGLOG(5, "Need to update workSpaceSize from %uK to %uK \n",
Yann Colletc7fe2622017-05-23 13:16:00 -0700578 (unsigned)zc->workSpaceSize>>10,
579 (unsigned)neededSpace>>10);
580 /* static cctx : no resize, error out */
581 if (zc->staticSize) return ERROR(memory_allocation);
582
Yann Collet0181fef2017-04-06 01:25:26 -0700583 zc->workSpaceSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200584 ZSTD_free(zc->workSpace, zc->customMem);
585 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
586 if (zc->workSpace == NULL) return ERROR(memory_allocation);
587 zc->workSpaceSize = neededSpace;
Yann Collet7bb60b12017-04-20 17:38:56 -0700588 ptr = zc->workSpace;
589
590 /* entropy space */
Yann Collet71ddeb62017-04-20 22:54:54 -0700591 zc->hufCTable = (HUF_CElt*)ptr;
592 ptr = (char*)zc->hufCTable + hufCTable_size; /* note : HUF_CElt* is incomplete type, size is estimated via macro */
Yann Collet71aaa322017-04-20 23:03:38 -0700593 zc->offcodeCTable = (FSE_CTable*) ptr;
594 ptr = (char*)ptr + offcodeCTable_size;
Yann Collet72712032017-04-20 23:21:19 -0700595 zc->matchlengthCTable = (FSE_CTable*) ptr;
Yann Collet71aaa322017-04-20 23:03:38 -0700596 ptr = (char*)ptr + matchlengthCTable_size;
Yann Collet72712032017-04-20 23:21:19 -0700597 zc->litlengthCTable = (FSE_CTable*) ptr;
598 ptr = (char*)ptr + litlengthCTable_size;
599 assert(((size_t)ptr & 3) == 0); /* ensure correct alignment */
Yann Collete42afbc2017-04-26 11:39:35 -0700600 zc->entropyScratchSpace = (unsigned*) ptr;
Yann Colleta7737f62016-09-06 09:44:59 +0200601 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100602
Yann Collete6fa70a2017-04-20 17:28:31 -0700603 /* init params */
Yann Collet1ad7c822017-05-22 17:06:04 -0700604 zc->appliedParams = params;
Yann Collete6fa70a2017-04-20 17:28:31 -0700605 zc->blockSize = blockSize;
Yann Collet009d6042017-05-19 10:17:59 -0700606 DEBUGLOG(5, "blockSize = %uK", (U32)blockSize>>10);
Yann Collete6fa70a2017-04-20 17:28:31 -0700607 zc->frameContentSize = frameContentSize;
608 zc->consumedSrcSize = 0;
Yann Collet70e8c382016-02-10 13:37:52 +0100609
Yann Collet083fcc82015-10-25 14:06:35 +0100610 XXH64_reset(&zc->xxhState, 0);
Yann Collete6fa70a2017-04-20 17:28:31 -0700611 zc->stage = ZSTDcs_init;
612 zc->dictID = 0;
613 zc->loadedDictEnd = 0;
Yann Collet71ddeb62017-04-20 22:54:54 -0700614 zc->fseCTables_ready = 0;
615 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200616 zc->nextToUpdate = 1;
617 zc->nextSrc = NULL;
618 zc->base = NULL;
619 zc->dictBase = NULL;
620 zc->dictLimit = 0;
621 zc->lowLimit = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200622 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
Yann Collete6fa70a2017-04-20 17:28:31 -0700623 zc->hashLog3 = hashLog3;
624 zc->seqStore.litLengthSum = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200625
Yann Collet71aaa322017-04-20 23:03:38 -0700626 /* ensure entropy tables are close together at the beginning */
627 assert((void*)zc->hufCTable == zc->workSpace);
628 assert((char*)zc->offcodeCTable == (char*)zc->hufCTable + hufCTable_size);
629 assert((char*)zc->matchlengthCTable == (char*)zc->offcodeCTable + offcodeCTable_size);
630 assert((char*)zc->litlengthCTable == (char*)zc->matchlengthCTable + matchlengthCTable_size);
Yann Collete42afbc2017-04-26 11:39:35 -0700631 assert((char*)zc->entropyScratchSpace == (char*)zc->litlengthCTable + litlengthCTable_size);
632 ptr = (char*)zc->entropyScratchSpace + entropyScratchSpace_size;
Yann Collete6fa70a2017-04-20 17:28:31 -0700633
634 /* opt parser space */
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800635 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) {
Yann Collet009d6042017-05-19 10:17:59 -0700636 DEBUGLOG(5, "reserving optimal parser space");
Yann Collete6fa70a2017-04-20 17:28:31 -0700637 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
Yann Colleta7737f62016-09-06 09:44:59 +0200638 zc->seqStore.litFreq = (U32*)ptr;
639 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
640 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
641 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
642 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
643 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
644 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
645 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
646 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
Yann Colleta7737f62016-09-06 09:44:59 +0200647 }
Yann Collete6fa70a2017-04-20 17:28:31 -0700648
649 /* table Space */
650 if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
651 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
652 zc->hashTable = (U32*)(ptr);
653 zc->chainTable = zc->hashTable + hSize;
654 zc->hashTable3 = zc->chainTable + chainSize;
655 ptr = zc->hashTable3 + h3Size;
656
657 /* sequences storage */
Yann Colleta7737f62016-09-06 09:44:59 +0200658 zc->seqStore.sequencesStart = (seqDef*)ptr;
659 ptr = zc->seqStore.sequencesStart + maxNbSeq;
660 zc->seqStore.llCode = (BYTE*) ptr;
661 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
662 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
663 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
Yann Collet5ac72b42017-05-23 11:18:24 -0700664 ptr = zc->seqStore.litStart + blockSize;
665
666 /* buffers */
667 zc->inBuffSize = buffInSize;
668 zc->inBuff = (char*)ptr;
669 zc->outBuffSize = buffOutSize;
670 zc->outBuff = zc->inBuff + buffInSize;
Yann Colleta7737f62016-09-06 09:44:59 +0200671
Yann Colleta7737f62016-09-06 09:44:59 +0200672 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100673 }
Yann Colletf3eca252015-10-22 15:31:46 +0100674}
675
Yann Collet32dfae62017-01-19 10:32:55 -0800676/* ZSTD_invalidateRepCodes() :
677 * ensures next compression will not use repcodes from previous block.
678 * Note : only works with regular variant;
679 * do not use with extDict variant ! */
680void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
681 int i;
682 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0;
683}
Yann Collet083fcc82015-10-25 14:06:35 +0100684
Yann Collet7b51a292016-01-26 15:58:49 +0100685
Yann Colleta4cab802017-04-18 14:54:54 -0700686/*! ZSTD_copyCCtx_internal() :
687 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
688 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
689 * pledgedSrcSize=0 means "empty" if fParams.contentSizeFlag=1
690 * @return : 0, or an error code */
Yann Collet1ad7c822017-05-22 17:06:04 -0700691static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
692 const ZSTD_CCtx* srcCCtx,
693 ZSTD_frameParameters fParams,
694 unsigned long long pledgedSrcSize)
Yann Collet7b51a292016-01-26 15:58:49 +0100695{
Yann Collet009d6042017-05-19 10:17:59 -0700696 DEBUGLOG(5, "ZSTD_copyCCtx_internal");
Yann Collet7b51a292016-01-26 15:58:49 +0100697 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Sean Purcell2db72492017-02-09 10:50:43 -0800698
inikep28669512016-06-02 13:04:18 +0200699 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Yann Collet5ac72b42017-05-23 11:18:24 -0700700 { ZSTD_buffered_policy_e const zbuff = srcCCtx->inBuffSize ?
701 ZSTDb_buffered : ZSTDb_not_buffered;
702 ZSTD_parameters params = srcCCtx->appliedParams;
Yann Colleta4cab802017-04-18 14:54:54 -0700703 params.fParams = fParams;
Yann Collet5ac72b42017-05-23 11:18:24 -0700704 ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
705 ZSTDcrp_noMemset, zbuff);
Sean Purcell2db72492017-02-09 10:50:43 -0800706 }
Yann Collet7b51a292016-01-26 15:58:49 +0100707
708 /* copy tables */
Yann Collet1ad7c822017-05-22 17:06:04 -0700709 { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->appliedParams.cParams.chainLog);
710 size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +0200711 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
712 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collete6fa70a2017-04-20 17:28:31 -0700713 assert((U32*)dstCCtx->chainTable == (U32*)dstCCtx->hashTable + hSize); /* chainTable must follow hashTable */
714 assert((U32*)dstCCtx->hashTable3 == (U32*)dstCCtx->chainTable + chainSize);
715 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); /* presumes all tables follow each other */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100716 }
Yann Collet7b51a292016-01-26 15:58:49 +0100717
Yann Colletc46fb922016-05-29 05:01:04 +0200718 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100719 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
720 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
721 dstCCtx->nextSrc = srcCCtx->nextSrc;
722 dstCCtx->base = srcCCtx->base;
723 dstCCtx->dictBase = srcCCtx->dictBase;
724 dstCCtx->dictLimit = srcCCtx->dictLimit;
725 dstCCtx->lowLimit = srcCCtx->lowLimit;
726 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200727 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100728
Yann Colletfb810d62016-01-28 00:18:06 +0100729 /* copy entropy tables */
Yann Collet71ddeb62017-04-20 22:54:54 -0700730 dstCCtx->fseCTables_ready = srcCCtx->fseCTables_ready;
731 if (srcCCtx->fseCTables_ready) {
Yann Colleta34a39c2017-04-20 18:17:58 -0700732 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, litlengthCTable_size);
733 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, matchlengthCTable_size);
734 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, offcodeCTable_size);
Yann Colletfb810d62016-01-28 00:18:06 +0100735 }
Yann Collet71ddeb62017-04-20 22:54:54 -0700736 dstCCtx->hufCTable_repeatMode = srcCCtx->hufCTable_repeatMode;
737 if (srcCCtx->hufCTable_repeatMode) {
738 memcpy(dstCCtx->hufCTable, srcCCtx->hufCTable, hufCTable_size);
Nick Terrella4197772017-03-01 17:51:56 -0800739 }
Yann Collet7b51a292016-01-26 15:58:49 +0100740
741 return 0;
742}
743
Yann Colleta4cab802017-04-18 14:54:54 -0700744/*! ZSTD_copyCCtx() :
745 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
746 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
747 * pledgedSrcSize==0 means "unknown".
748* @return : 0, or an error code */
749size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
750{
751 ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
752 fParams.contentSizeFlag = pledgedSrcSize>0;
753
754 return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, fParams, pledgedSrcSize);
755}
756
Yann Collet7b51a292016-01-26 15:58:49 +0100757
Yann Colletecabfe32016-03-20 16:20:06 +0100758/*! ZSTD_reduceTable() :
Yann Colleta4cab802017-04-18 14:54:54 -0700759 * reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100760static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100761{
Yann Colletecabfe32016-03-20 16:20:06 +0100762 U32 u;
763 for (u=0 ; u < size ; u++) {
764 if (table[u] < reducerValue) table[u] = 0;
765 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100766 }
767}
768
Yann Colletecabfe32016-03-20 16:20:06 +0100769/*! ZSTD_reduceIndex() :
770* rescale all indexes to avoid future overflow (indexes are U32) */
771static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
772{
Yann Collet1ad7c822017-05-22 17:06:04 -0700773 { U32 const hSize = 1 << zc->appliedParams.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100774 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
775
Yann Collet1ad7c822017-05-22 17:06:04 -0700776 { U32 const chainSize = (zc->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->appliedParams.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200777 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100778
Yann Collet731ef162016-07-27 21:05:12 +0200779 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100780 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
781}
782
Yann Collet89db5e02015-11-13 11:27:46 +0100783
Yann Collet863ec402016-01-28 17:56:33 +0100784/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100785* Block entropic compression
786*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100787
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200788/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100789
Yann Colletd1b26842016-03-15 01:24:33 +0100790size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100791{
Yann Colletd1b26842016-03-15 01:24:33 +0100792 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200793 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
794 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100795 return ZSTD_blockHeaderSize+srcSize;
796}
797
798
Yann Colletd1b26842016-03-15 01:24:33 +0100799static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100800{
801 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200802 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100803
Yann Colletd1b26842016-03-15 01:24:33 +0100804 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100805
Yann Collet59d1f792016-01-23 19:28:41 +0100806 switch(flSize)
807 {
808 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200809 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100810 break;
811 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200812 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100813 break;
814 default: /*note : should not be necessary : flSize is within {1,2,3} */
815 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200816 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100817 break;
818 }
819
820 memcpy(ostart + flSize, src, srcSize);
821 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100822}
823
Yann Colletd1b26842016-03-15 01:24:33 +0100824static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100825{
826 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200827 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100828
Yann Collet198e6aa2016-07-20 20:12:24 +0200829 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100830
831 switch(flSize)
832 {
833 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200834 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100835 break;
836 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200837 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100838 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100839 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100840 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200841 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100842 break;
843 }
844
845 ostart[flSize] = *(const BYTE*)src;
846 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100847}
848
Yann Collet59d1f792016-01-23 19:28:41 +0100849
Yann Colleta5c2c082016-03-20 01:09:18 +0100850static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100851
Yann Colletb923f652016-01-26 03:14:20 +0100852static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100853 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100854 const void* src, size_t srcSize)
855{
Yann Colleta910dc82016-03-18 12:37:45 +0100856 size_t const minGain = ZSTD_minGain(srcSize);
857 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200858 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100859 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200860 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100861 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100862
Yann Collet14983e72015-11-11 21:38:21 +0100863
Yann Colleta5c2c082016-03-20 01:09:18 +0100864 /* small ? don't even attempt compression (speed opt) */
865# define LITERAL_NOENTROPY 63
Yann Collet71ddeb62017-04-20 22:54:54 -0700866 { size_t const minLitSize = zc->hufCTable_repeatMode == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
Yann Colleta5c2c082016-03-20 01:09:18 +0100867 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
868 }
869
870 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Collet71ddeb62017-04-20 22:54:54 -0700871 { HUF_repeat repeat = zc->hufCTable_repeatMode;
Yann Collet1ad7c822017-05-22 17:06:04 -0700872 int const preferRepeat = zc->appliedParams.cParams.strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
Nick Terrella4197772017-03-01 17:51:56 -0800873 if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
Yann Collete348dad2017-04-20 11:14:13 -0700874 cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Yann Collete42afbc2017-04-26 11:39:35 -0700875 zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat)
Yann Collete348dad2017-04-20 11:14:13 -0700876 : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Yann Collete42afbc2017-04-26 11:39:35 -0700877 zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat);
Nick Terrella4197772017-03-01 17:51:56 -0800878 if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
Yann Collet71ddeb62017-04-20 22:54:54 -0700879 else { zc->hufCTable_repeatMode = HUF_repeat_check; } /* now have a table to reuse */
Yann Colletb923f652016-01-26 03:14:20 +0100880 }
Yann Collet14983e72015-11-11 21:38:21 +0100881
Nick Terrella4197772017-03-01 17:51:56 -0800882 if ((cLitSize==0) | (cLitSize >= srcSize - minGain)) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700883 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100884 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800885 }
886 if (cLitSize==1) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700887 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100888 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800889 }
Yann Collet14983e72015-11-11 21:38:21 +0100890
891 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100892 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100893 {
Yann Collet59d1f792016-01-23 19:28:41 +0100894 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200895 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200896 MEM_writeLE24(ostart, lhc);
897 break;
898 }
Yann Collet59d1f792016-01-23 19:28:41 +0100899 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200900 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200901 MEM_writeLE32(ostart, lhc);
902 break;
903 }
Yann Colleta910dc82016-03-18 12:37:45 +0100904 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100905 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200906 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200907 MEM_writeLE32(ostart, lhc);
908 ostart[4] = (BYTE)(cLitSize >> 10);
909 break;
910 }
Yann Collet14983e72015-11-11 21:38:21 +0100911 }
Yann Colleta910dc82016-03-18 12:37:45 +0100912 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100913}
914
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200915static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
916 8, 9, 10, 11, 12, 13, 14, 15,
917 16, 16, 17, 17, 18, 18, 19, 19,
918 20, 20, 20, 20, 21, 21, 21, 21,
919 22, 22, 22, 22, 22, 22, 22, 22,
920 23, 23, 23, 23, 23, 23, 23, 23,
921 24, 24, 24, 24, 24, 24, 24, 24,
922 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100923
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200924static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
925 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
926 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
927 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
928 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
929 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
930 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
931 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200932
933
934void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100935{
Yann Colleted57d852016-07-29 21:22:17 +0200936 BYTE const LL_deltaCode = 19;
937 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200938 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200939 BYTE* const llCodeTable = seqStorePtr->llCode;
940 BYTE* const ofCodeTable = seqStorePtr->ofCode;
941 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200942 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200943 U32 u;
944 for (u=0; u<nbSeq; u++) {
945 U32 const llv = sequences[u].litLength;
946 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200947 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200948 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200949 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200950 }
Yann Colleted57d852016-07-29 21:22:17 +0200951 if (seqStorePtr->longLengthID==1)
952 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
953 if (seqStorePtr->longLengthID==2)
954 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100955}
956
Sean Purcell553f67e2017-03-02 15:15:31 -0800957MEM_STATIC size_t ZSTD_compressSequences (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100958 void* dst, size_t dstCapacity,
Sean Purcell553f67e2017-03-02 15:15:31 -0800959 size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100960{
Yann Collet1ad7c822017-05-22 17:06:04 -0700961 const int longOffsets = zc->appliedParams.cParams.windowLog > STREAM_ACCUMULATOR_MIN;
Yann Colletb923f652016-01-26 03:14:20 +0100962 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100963 U32 count[MaxSeq+1];
964 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100965 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
966 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
967 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100968 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200969 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200970 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
971 const BYTE* const llCodeTable = seqStorePtr->llCode;
972 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +0100973 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100974 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100975 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200976 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +0100977 BYTE* seqHead;
Yann Colletd79a9a02016-11-30 15:52:20 -0800978 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Collet14983e72015-11-11 21:38:21 +0100979
Yann Collet14983e72015-11-11 21:38:21 +0100980 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100981 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100982 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100983 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100984 if (ZSTD_isError(cSize)) return cSize;
985 op += cSize;
986 }
987
988 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100989 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100990 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
991 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
992 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100993 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100994
Yann Colletbe391432016-03-22 23:19:28 +0100995 /* seqHead : flags for FSE encoding type */
996 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100997
Yann Colletfb810d62016-01-28 00:18:06 +0100998#define MIN_SEQ_FOR_DYNAMIC_FSE 64
999#define MAX_SEQ_FOR_STATIC_FSE 1000
1000
Yann Colletb44be742016-03-26 20:52:14 +01001001 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +02001002 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +01001003
Yann Collet14983e72015-11-11 21:38:21 +01001004 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +01001005 { U32 max = MaxLL;
Yann Collete42afbc2017-04-26 11:39:35 -07001006 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +01001007 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
1008 *op++ = llCodeTable[0];
1009 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +02001010 LLtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -07001011 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +02001012 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +01001013 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -08001014 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001015 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +01001016 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +01001017 size_t nbSeq_1 = nbSeq;
1018 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
1019 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
1020 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +01001021 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -07001022 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +01001023 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -08001024 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001025 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +01001026 } }
Yann Collet14983e72015-11-11 21:38:21 +01001027
Yann Colletb44be742016-03-26 20:52:14 +01001028 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +01001029 { U32 max = MaxOff;
Yann Collete42afbc2017-04-26 11:39:35 -07001030 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +01001031 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +01001032 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +01001033 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +02001034 Offtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -07001035 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +02001036 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +02001037 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -08001038 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001039 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +01001040 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +01001041 size_t nbSeq_1 = nbSeq;
1042 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +01001043 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +01001044 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +01001045 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -07001046 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +01001047 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -08001048 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001049 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +01001050 } }
1051
Yann Collet14983e72015-11-11 21:38:21 +01001052 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +01001053 { U32 max = MaxML;
Yann Collete42afbc2017-04-26 11:39:35 -07001054 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +01001055 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +01001056 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +01001057 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +02001058 MLtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -07001059 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +02001060 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +01001061 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -08001062 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001063 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +01001064 } else {
1065 size_t nbSeq_1 = nbSeq;
1066 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
1067 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
1068 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
1069 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -07001070 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletfadda6c2016-03-22 12:14:26 +01001071 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -08001072 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001073 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +01001074 } }
Yann Collet14983e72015-11-11 21:38:21 +01001075
Yann Colletbe391432016-03-22 23:19:28 +01001076 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Collet71ddeb62017-04-20 22:54:54 -07001077 zc->fseCTables_ready = 0;
Yann Collet14983e72015-11-11 21:38:21 +01001078
1079 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +01001080 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +01001081 FSE_CState_t stateMatchLength;
1082 FSE_CState_t stateOffsetBits;
1083 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +01001084
Yann Collet95d07d72016-09-06 16:38:51 +02001085 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +01001086
Yann Collet597847a2016-03-20 19:14:22 +01001087 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +01001088 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +01001089 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +01001090 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +02001091 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +01001092 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +02001093 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +01001094 if (MEM_32bits()) BIT_flushBits(&blockStream);
Sean Purcelld44703d2017-03-01 14:36:25 -08001095 if (longOffsets) {
1096 U32 const ofBits = ofCodeTable[nbSeq-1];
1097 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1098 if (extraBits) {
1099 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
1100 BIT_flushBits(&blockStream);
1101 }
1102 BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
1103 ofBits - extraBits);
1104 } else {
1105 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
1106 }
Yann Collet597847a2016-03-20 19:14:22 +01001107 BIT_flushBits(&blockStream);
1108
Yann Colletfadda6c2016-03-22 12:14:26 +01001109 { size_t n;
1110 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +02001111 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +02001112 BYTE const ofCode = ofCodeTable[n];
1113 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +02001114 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +02001115 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +02001116 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +01001117 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +01001118 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
1119 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
1120 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
1121 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +02001122 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +01001123 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +02001124 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +01001125 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +02001126 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +01001127 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Sean Purcelld44703d2017-03-01 14:36:25 -08001128 if (longOffsets) {
1129 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1130 if (extraBits) {
1131 BIT_addBits(&blockStream, sequences[n].offset, extraBits);
1132 BIT_flushBits(&blockStream); /* (7)*/
1133 }
1134 BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
1135 ofBits - extraBits); /* 31 */
1136 } else {
1137 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
1138 }
Yann Colletb9151402016-03-26 17:18:11 +01001139 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +01001140 } }
Yann Collet14983e72015-11-11 21:38:21 +01001141
1142 FSE_flushCState(&blockStream, &stateMatchLength);
1143 FSE_flushCState(&blockStream, &stateOffsetBits);
1144 FSE_flushCState(&blockStream, &stateLitLength);
1145
Yann Colletb9151402016-03-26 17:18:11 +01001146 { size_t const streamSize = BIT_closeCStream(&blockStream);
1147 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
1148 op += streamSize;
1149 } }
Yann Collet14983e72015-11-11 21:38:21 +01001150
1151 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +01001152_check_compressibility:
Nick Terrella4197772017-03-01 17:51:56 -08001153 { size_t const minGain = ZSTD_minGain(srcSize);
1154 size_t const maxCSize = srcSize - minGain;
1155 if ((size_t)(op-ostart) >= maxCSize) {
Yann Collet71ddeb62017-04-20 22:54:54 -07001156 zc->hufCTable_repeatMode = HUF_repeat_none;
Nick Terrella4197772017-03-01 17:51:56 -08001157 return 0;
1158 } }
Yann Collet14983e72015-11-11 21:38:21 +01001159
Yann Collet4266c0a2016-06-14 01:49:25 +02001160 /* confirm repcodes */
Yann Colletb459aad2017-01-19 17:33:37 -08001161 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; }
Yann Collet4266c0a2016-06-14 01:49:25 +02001162
Yann Collet5054ee02015-11-23 13:34:21 +01001163 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +01001164}
1165
Yann Colletbb002742017-01-25 16:25:38 -08001166
Yann Collet95cd0c22016-03-08 18:24:21 +01001167/*! ZSTD_storeSeq() :
1168 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
1169 `offsetCode` : distance to match, or 0 == repCode.
1170 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +01001171*/
Yann Colletd57dffb2016-07-03 01:48:26 +02001172MEM_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 +01001173{
Yann Collet009d6042017-05-19 10:17:59 -07001174#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
1175 static const BYTE* g_start = NULL;
1176 U32 const pos = (U32)((const BYTE*)literals - g_start);
1177 if (g_start==NULL) g_start = (const BYTE*)literals;
1178 if ((pos > 0) && (pos < 1000000000))
1179 DEBUGLOG(6, "Cpos %6u :%5u literals & match %3u bytes at distance %6u",
1180 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +01001181#endif
Yann Collet14983e72015-11-11 21:38:21 +01001182 /* copy Literals */
Yann Collet009d6042017-05-19 10:17:59 -07001183 assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB);
Yann Collet14983e72015-11-11 21:38:21 +01001184 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
1185 seqStorePtr->lit += litLength;
1186
1187 /* literal Length */
Yann Collete6fa70a2017-04-20 17:28:31 -07001188 if (litLength>0xFFFF) {
1189 seqStorePtr->longLengthID = 1;
1190 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
1191 }
Yann Colletc0ce4f12016-07-30 00:55:13 +02001192 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +01001193
1194 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +02001195 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +01001196
1197 /* match Length */
Yann Collete6fa70a2017-04-20 17:28:31 -07001198 if (matchCode>0xFFFF) {
1199 seqStorePtr->longLengthID = 2;
1200 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
1201 }
Yann Colletc0ce4f12016-07-30 00:55:13 +02001202 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +02001203
Yann Colletc0ce4f12016-07-30 00:55:13 +02001204 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +01001205}
1206
1207
Yann Collet7d360282016-02-12 00:07:30 +01001208/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001209* Match length counter
1210***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +01001211static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +01001212{
Yann Collet863ec402016-01-28 17:56:33 +01001213 if (MEM_isLittleEndian()) {
1214 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +01001215# if defined(_MSC_VER) && defined(_WIN64)
1216 unsigned long r = 0;
1217 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +01001218 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +01001219# elif defined(__GNUC__) && (__GNUC__ >= 3)
1220 return (__builtin_ctzll((U64)val) >> 3);
1221# else
Yann Collete348dad2017-04-20 11:14:13 -07001222 static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
1223 0, 3, 1, 3, 1, 4, 2, 7,
1224 0, 2, 3, 6, 1, 5, 3, 5,
1225 1, 3, 4, 4, 2, 5, 6, 7,
1226 7, 0, 1, 2, 3, 3, 4, 6,
1227 2, 6, 5, 5, 3, 4, 5, 6,
1228 7, 1, 2, 4, 6, 4, 4, 5,
1229 7, 2, 6, 5, 7, 6, 7, 7 };
Yann Collet14983e72015-11-11 21:38:21 +01001230 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
1231# endif
Yann Collet863ec402016-01-28 17:56:33 +01001232 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +01001233# if defined(_MSC_VER)
1234 unsigned long r=0;
1235 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +01001236 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +01001237# elif defined(__GNUC__) && (__GNUC__ >= 3)
1238 return (__builtin_ctz((U32)val) >> 3);
1239# else
Yann Collete348dad2017-04-20 11:14:13 -07001240 static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
1241 3, 2, 2, 1, 3, 2, 0, 1,
1242 3, 3, 1, 2, 2, 2, 2, 0,
1243 3, 1, 2, 0, 1, 0, 1, 1 };
Yann Collet14983e72015-11-11 21:38:21 +01001244 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
1245# endif
1246 }
Yann Collet863ec402016-01-28 17:56:33 +01001247 } else { /* Big Endian CPU */
1248 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +01001249# if defined(_MSC_VER) && defined(_WIN64)
1250 unsigned long r = 0;
1251 _BitScanReverse64( &r, val );
1252 return (unsigned)(r>>3);
1253# elif defined(__GNUC__) && (__GNUC__ >= 3)
1254 return (__builtin_clzll(val) >> 3);
1255# else
1256 unsigned r;
1257 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
1258 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
1259 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
1260 r += (!val);
1261 return r;
1262# endif
Yann Collet863ec402016-01-28 17:56:33 +01001263 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +01001264# if defined(_MSC_VER)
1265 unsigned long r = 0;
1266 _BitScanReverse( &r, (unsigned long)val );
1267 return (unsigned)(r>>3);
1268# elif defined(__GNUC__) && (__GNUC__ >= 3)
1269 return (__builtin_clz((U32)val) >> 3);
1270# else
1271 unsigned r;
1272 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
1273 r += (!val);
1274 return r;
1275# endif
Yann Collet863ec402016-01-28 17:56:33 +01001276 } }
Yann Collet14983e72015-11-11 21:38:21 +01001277}
1278
1279
Yann Colleta436a522016-06-20 23:34:04 +02001280static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +01001281{
1282 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +02001283 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +01001284
Yann Colleta436a522016-06-20 23:34:04 +02001285 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +02001286 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +01001287 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
1288 pIn += ZSTD_NbCommonBytes(diff);
1289 return (size_t)(pIn - pStart);
1290 }
Yann Collet14983e72015-11-11 21:38:21 +01001291 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
1292 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
1293 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
1294 return (size_t)(pIn - pStart);
1295}
1296
Yann Collet04b12d82016-02-11 06:23:24 +01001297/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +01001298* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +01001299* convention : on reaching mEnd, match count continue starting from iStart
1300*/
1301static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
1302{
Yann Collet7591a7f2016-05-20 11:44:43 +02001303 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +02001304 size_t const matchLength = ZSTD_count(ip, match, vEnd);
1305 if (match + matchLength != mEnd) return matchLength;
1306 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +01001307}
1308
Yann Collet14983e72015-11-11 21:38:21 +01001309
Yann Collet863ec402016-01-28 17:56:33 +01001310/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001311* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +01001312***************************************/
inikepcc52a972016-02-19 10:09:35 +01001313static const U32 prime3bytes = 506832829U;
1314static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Collete6fa70a2017-04-20 17:28:31 -07001315MEM_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 +01001316
Yann Collet4b100f42015-10-30 15:49:48 +01001317static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +01001318static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +01001319static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +01001320
Yann Collet4b100f42015-10-30 15:49:48 +01001321static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001322static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001323static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001324
1325static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001326static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001327static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001328
Yann Collet14983e72015-11-11 21:38:21 +01001329static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001330static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001331static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001332
Yann Collet45dc3562016-07-12 09:47:31 +02001333static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
1334static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
1335static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
1336
Yann Collet5be2dd22015-11-11 13:43:58 +01001337static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001338{
1339 switch(mls)
1340 {
1341 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001342 case 4: return ZSTD_hash4Ptr(p, hBits);
1343 case 5: return ZSTD_hash5Ptr(p, hBits);
1344 case 6: return ZSTD_hash6Ptr(p, hBits);
1345 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +02001346 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001347 }
1348}
Yann Collet2acb5d32015-10-29 16:49:43 +01001349
Yann Collet863ec402016-01-28 17:56:33 +01001350
Yann Collet2ce49232016-02-02 14:36:49 +01001351/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001352* Fast Scan
1353***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001354static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1355{
1356 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001357 U32 const hBits = zc->appliedParams.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001358 const BYTE* const base = zc->base;
1359 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001360 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001361 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001362
Yann Colletfb810d62016-01-28 00:18:06 +01001363 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001364 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001365 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001366 }
1367}
1368
1369
Yann Collet1f44b3f2015-11-05 17:32:18 +01001370FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +02001371void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +02001372 const void* src, size_t srcSize,
1373 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001374{
Yann Collet4266c0a2016-06-14 01:49:25 +02001375 U32* const hashTable = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001376 U32 const hBits = cctx->appliedParams.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +02001377 seqStore_t* seqStorePtr = &(cctx->seqStore);
1378 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001379 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001380 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001381 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +02001382 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +02001383 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001384 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001385 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +02001386 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1387 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001388
Yann Collet1f44b3f2015-11-05 17:32:18 +01001389 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001390 ip += (ip==lowest);
1391 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +02001392 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1393 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +02001394 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001395
1396 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +02001397 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +02001398 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +02001399 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
1400 U32 const current = (U32)(ip-base);
1401 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +01001402 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001403 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001404
Yann Collet280f9a82016-08-08 00:44:00 +02001405 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +02001406 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +01001407 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001408 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1409 } else {
Yann Collet92d75662016-07-03 01:10:53 +02001410 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001411 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001412 ip += ((ip-anchor) >> g_searchStrength) + 1;
1413 continue;
1414 }
Yann Collet45dc3562016-07-12 09:47:31 +02001415 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001416 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001417 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001418 offset_2 = offset_1;
1419 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001420
Yann Colleta436a522016-06-20 23:34:04 +02001421 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001422 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001423
Yann Collet402fdcf2015-11-20 12:46:08 +01001424 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001425 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001426 anchor = ip;
1427
Yann Colletfb810d62016-01-28 00:18:06 +01001428 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001429 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001430 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 +01001431 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1432 /* check immediate repcode */
1433 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001434 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001435 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001436 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001437 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001438 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001439 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001440 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1441 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001442 anchor = ip;
1443 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001444 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001445
Yann Collet4266c0a2016-06-14 01:49:25 +02001446 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001447 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1448 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001449
Yann Collet70e45772016-03-19 18:08:32 +01001450 /* Last Literals */
1451 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001452 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1453 seqStorePtr->lit += lastLLSize;
1454 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001455}
1456
1457
Yann Collet82260dd2016-02-11 07:14:25 +01001458static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001459 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001460{
Yann Collet1ad7c822017-05-22 17:06:04 -07001461 const U32 mls = ctx->appliedParams.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001462 switch(mls)
1463 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001464 default: /* includes case 3 */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001465 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001466 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001467 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001468 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001469 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001470 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001471 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001472 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001473 }
1474}
Yann Colletf3eca252015-10-22 15:31:46 +01001475
Yann Colletf3eca252015-10-22 15:31:46 +01001476
Yann Collet82260dd2016-02-11 07:14:25 +01001477static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001478 const void* src, size_t srcSize,
1479 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001480{
1481 U32* hashTable = ctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001482 const U32 hBits = ctx->appliedParams.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001483 seqStore_t* seqStorePtr = &(ctx->seqStore);
1484 const BYTE* const base = ctx->base;
1485 const BYTE* const dictBase = ctx->dictBase;
1486 const BYTE* const istart = (const BYTE*)src;
1487 const BYTE* ip = istart;
1488 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001489 const U32 lowestIndex = ctx->lowLimit;
1490 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001491 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001492 const BYTE* const lowPrefixPtr = base + dictLimit;
1493 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001494 const BYTE* const iend = istart + srcSize;
1495 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001496 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001497
Yann Colleta436a522016-06-20 23:34:04 +02001498 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001499 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001500 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001501 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001502 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001503 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001504 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001505 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001506 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001507 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001508 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001509 hashTable[h] = current; /* update hash table */
1510
Yann Colleta436a522016-06-20 23:34:04 +02001511 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001512 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001513 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001514 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
Yann Collet743402c2015-11-20 12:03:53 +01001515 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001516 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001517 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001518 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001519 (MEM_read32(match) != MEM_read32(ip)) ) {
1520 ip += ((ip-anchor) >> g_searchStrength) + 1;
1521 continue;
1522 }
1523 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001524 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001525 U32 offset;
Yann Collete6fa70a2017-04-20 17:28:31 -07001526 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
Yann Colleta436a522016-06-20 23:34:04 +02001527 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001528 offset = current - matchIndex;
1529 offset_2 = offset_1;
1530 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001531 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001532 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001533
Yann Collet5054ee02015-11-23 13:34:21 +01001534 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001535 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001536 anchor = ip;
1537
Yann Colletfb810d62016-01-28 00:18:06 +01001538 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001539 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001540 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001541 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1542 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001543 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001544 U32 const current2 = (U32)(ip-base);
1545 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001546 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001547 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1548 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001549 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001550 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet5054ee02015-11-23 13:34:21 +01001551 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001552 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001553 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001554 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001555 anchor = ip;
1556 continue;
1557 }
Yann Collet743402c2015-11-20 12:03:53 +01001558 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001559 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001560
Yann Collet4266c0a2016-06-14 01:49:25 +02001561 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001562 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001563
Yann Collet89db5e02015-11-13 11:27:46 +01001564 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001565 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001566 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1567 seqStorePtr->lit += lastLLSize;
1568 }
Yann Collet89db5e02015-11-13 11:27:46 +01001569}
1570
1571
Yann Collet82260dd2016-02-11 07:14:25 +01001572static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001573 const void* src, size_t srcSize)
1574{
Yann Collet1ad7c822017-05-22 17:06:04 -07001575 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001576 switch(mls)
1577 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001578 default: /* includes case 3 */
Yann Collet89db5e02015-11-13 11:27:46 +01001579 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001580 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001581 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001582 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001583 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001584 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001585 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001586 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001587 }
1588}
1589
1590
Yann Collet04b12d82016-02-11 06:23:24 +01001591/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001592* Double Fast
1593***************************************/
1594static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1595{
1596 U32* const hashLarge = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001597 U32 const hBitsL = cctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001598 U32* const hashSmall = cctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001599 U32 const hBitsS = cctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001600 const BYTE* const base = cctx->base;
1601 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001602 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001603 const size_t fastHashFillStep = 3;
1604
1605 while(ip <= iend) {
1606 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1607 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1608 ip += fastHashFillStep;
1609 }
1610}
1611
1612
1613FORCE_INLINE
1614void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1615 const void* src, size_t srcSize,
1616 const U32 mls)
1617{
1618 U32* const hashLong = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001619 const U32 hBitsL = cctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001620 U32* const hashSmall = cctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001621 const U32 hBitsS = cctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001622 seqStore_t* seqStorePtr = &(cctx->seqStore);
1623 const BYTE* const base = cctx->base;
1624 const BYTE* const istart = (const BYTE*)src;
1625 const BYTE* ip = istart;
1626 const BYTE* anchor = istart;
1627 const U32 lowestIndex = cctx->dictLimit;
1628 const BYTE* const lowest = base + lowestIndex;
1629 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001630 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001631 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1632 U32 offsetSaved = 0;
1633
1634 /* init */
1635 ip += (ip==lowest);
1636 { U32 const maxRep = (U32)(ip-lowest);
1637 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1638 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1639 }
1640
1641 /* Main Search Loop */
1642 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1643 size_t mLength;
1644 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1645 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1646 U32 const current = (U32)(ip-base);
1647 U32 const matchIndexL = hashLong[h2];
1648 U32 const matchIndexS = hashSmall[h];
1649 const BYTE* matchLong = base + matchIndexL;
1650 const BYTE* match = base + matchIndexS;
1651 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1652
Yann Colletc17e0202017-04-20 12:50:02 -07001653 assert(offset_1 <= current); /* supposed guaranteed by construction */
1654 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001655 /* favor repcode */
Yann Collet45dc3562016-07-12 09:47:31 +02001656 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1657 ip++;
1658 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1659 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001660 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001661 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1662 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001663 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001664 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1665 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001666 size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1667 U32 const matchIndexL3 = hashLong[hl3];
1668 const BYTE* matchL3 = base + matchIndexL3;
1669 hashLong[hl3] = current + 1;
1670 if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
1671 mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
Yann Colletc54692f2016-08-24 01:10:42 +02001672 ip++;
Yann Collete6fa70a2017-04-20 17:28:31 -07001673 offset = (U32)(ip-matchL3);
1674 while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
Yann Colletc54692f2016-08-24 01:10:42 +02001675 } else {
1676 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1677 offset = (U32)(ip-match);
1678 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1679 }
Yann Collet45dc3562016-07-12 09:47:31 +02001680 } else {
1681 ip += ((ip-anchor) >> g_searchStrength) + 1;
1682 continue;
1683 }
1684
1685 offset_2 = offset_1;
1686 offset_1 = offset;
1687
1688 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1689 }
1690
1691 /* match found */
1692 ip += mLength;
1693 anchor = ip;
1694
1695 if (ip <= ilimit) {
1696 /* Fill Table */
1697 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1698 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1699 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1700 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1701
1702 /* check immediate repcode */
1703 while ( (ip <= ilimit)
1704 && ( (offset_2>0)
1705 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1706 /* store sequence */
1707 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001708 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001709 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1710 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1711 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1712 ip += rLength;
1713 anchor = ip;
1714 continue; /* faster when present ... (?) */
1715 } } }
1716
1717 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001718 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1719 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet45dc3562016-07-12 09:47:31 +02001720
1721 /* Last Literals */
1722 { size_t const lastLLSize = iend - anchor;
1723 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1724 seqStorePtr->lit += lastLLSize;
1725 }
1726}
1727
1728
1729static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1730{
Yann Collet1ad7c822017-05-22 17:06:04 -07001731 const U32 mls = ctx->appliedParams.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001732 switch(mls)
1733 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001734 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001735 case 4 :
1736 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1737 case 5 :
1738 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1739 case 6 :
1740 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1741 case 7 :
1742 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1743 }
1744}
1745
1746
1747static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1748 const void* src, size_t srcSize,
1749 const U32 mls)
1750{
1751 U32* const hashLong = ctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001752 U32 const hBitsL = ctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001753 U32* const hashSmall = ctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001754 U32 const hBitsS = ctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001755 seqStore_t* seqStorePtr = &(ctx->seqStore);
1756 const BYTE* const base = ctx->base;
1757 const BYTE* const dictBase = ctx->dictBase;
1758 const BYTE* const istart = (const BYTE*)src;
1759 const BYTE* ip = istart;
1760 const BYTE* anchor = istart;
1761 const U32 lowestIndex = ctx->lowLimit;
1762 const BYTE* const dictStart = dictBase + lowestIndex;
1763 const U32 dictLimit = ctx->dictLimit;
1764 const BYTE* const lowPrefixPtr = base + dictLimit;
1765 const BYTE* const dictEnd = dictBase + dictLimit;
1766 const BYTE* const iend = istart + srcSize;
1767 const BYTE* const ilimit = iend - 8;
1768 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1769
1770 /* Search Loop */
1771 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1772 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1773 const U32 matchIndex = hashSmall[hSmall];
1774 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1775 const BYTE* match = matchBase + matchIndex;
1776
1777 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1778 const U32 matchLongIndex = hashLong[hLong];
1779 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1780 const BYTE* matchLong = matchLongBase + matchLongIndex;
1781
1782 const U32 current = (U32)(ip-base);
1783 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1784 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1785 const BYTE* repMatch = repBase + repIndex;
1786 size_t mLength;
1787 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1788
1789 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1790 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1791 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1792 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1793 ip++;
1794 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1795 } else {
1796 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1797 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1798 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1799 U32 offset;
1800 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1801 offset = current - matchLongIndex;
1802 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1803 offset_2 = offset_1;
1804 offset_1 = offset;
1805 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001806
Yann Collet73d74a02016-07-12 13:03:48 +02001807 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001808 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1809 U32 const matchIndex3 = hashLong[h3];
1810 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1811 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001812 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001813 hashLong[h3] = current + 1;
1814 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1815 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1816 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1817 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1818 ip++;
1819 offset = current+1 - matchIndex3;
1820 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1821 } else {
1822 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1823 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1824 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1825 offset = current - matchIndex;
1826 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1827 }
Yann Collet45dc3562016-07-12 09:47:31 +02001828 offset_2 = offset_1;
1829 offset_1 = offset;
1830 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001831
Yann Collet45dc3562016-07-12 09:47:31 +02001832 } else {
1833 ip += ((ip-anchor) >> g_searchStrength) + 1;
1834 continue;
1835 } }
1836
1837 /* found a match : store it */
1838 ip += mLength;
1839 anchor = ip;
1840
1841 if (ip <= ilimit) {
1842 /* Fill Table */
Nick Terrellf35ef5c2017-03-09 12:51:33 -08001843 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1844 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
Yann Collet45dc3562016-07-12 09:47:31 +02001845 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1846 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1847 /* check immediate repcode */
1848 while (ip <= ilimit) {
1849 U32 const current2 = (U32)(ip-base);
1850 U32 const repIndex2 = current2 - offset_2;
1851 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1852 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1853 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1854 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07001855 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet45dc3562016-07-12 09:47:31 +02001856 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1857 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1858 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1859 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1860 ip += repLength2;
1861 anchor = ip;
1862 continue;
1863 }
1864 break;
1865 } } }
1866
1867 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001868 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet45dc3562016-07-12 09:47:31 +02001869
1870 /* Last Literals */
1871 { size_t const lastLLSize = iend - anchor;
1872 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1873 seqStorePtr->lit += lastLLSize;
1874 }
1875}
1876
1877
1878static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1879 const void* src, size_t srcSize)
1880{
Yann Collet1ad7c822017-05-22 17:06:04 -07001881 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001882 switch(mls)
1883 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001884 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001885 case 4 :
1886 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1887 case 5 :
1888 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1889 case 6 :
1890 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1891 case 7 :
1892 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1893 }
1894}
1895
1896
1897/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001898* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001899***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001900/** ZSTD_insertBt1() : add one or multiple positions to tree.
1901* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001902* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001903static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1904 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001905{
Yann Collet731ef162016-07-27 21:05:12 +02001906 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001907 U32 const hashLog = zc->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +02001908 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1909 U32* const bt = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001910 U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
Yann Collet731ef162016-07-27 21:05:12 +02001911 U32 const btMask = (1 << btLog) - 1;
1912 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001913 size_t commonLengthSmaller=0, commonLengthLarger=0;
1914 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001915 const BYTE* const dictBase = zc->dictBase;
1916 const U32 dictLimit = zc->dictLimit;
1917 const BYTE* const dictEnd = dictBase + dictLimit;
1918 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07001919 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001920 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001921 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001922 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001923 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001924 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001925 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001926 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001927 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001928#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001929 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1930 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1931 predictedSmall += (predictedSmall>0);
1932 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001933#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001934
Yann Collet6c3e2e72015-12-11 10:44:07 +01001935 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001936
Yann Colletfb810d62016-01-28 00:18:06 +01001937 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001938 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001939 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08001940
Yann Colletc0932082016-06-30 14:07:30 +02001941#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001942 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001943 if (matchIndex == predictedSmall) {
1944 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001945 *smallerPtr = matchIndex;
1946 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1947 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1948 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001949 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001950 continue;
1951 }
Yann Colletfb810d62016-01-28 00:18:06 +01001952 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001953 *largerPtr = matchIndex;
1954 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1955 largerPtr = nextPtr;
1956 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001957 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001958 continue;
1959 }
Yann Collet04b12d82016-02-11 06:23:24 +01001960#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001961 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001962 match = base + matchIndex;
1963 if (match[matchLength] == ip[matchLength])
1964 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001965 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001966 match = dictBase + matchIndex;
1967 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1968 if (matchIndex+matchLength >= dictLimit)
Nick Terrellf35ef5c2017-03-09 12:51:33 -08001969 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet1358f912016-01-01 07:29:39 +01001970 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001971
Yann Colletb8a6f682016-02-15 17:06:29 +01001972 if (matchLength > bestLength) {
1973 bestLength = matchLength;
1974 if (matchLength > matchEndIdx - matchIndex)
1975 matchEndIdx = matchIndex + (U32)matchLength;
1976 }
Yann Colletee3f4512015-12-29 22:26:09 +01001977
Yann Collet59d70632015-11-04 12:05:27 +01001978 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001979 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001980
Yann Colletfb810d62016-01-28 00:18:06 +01001981 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001982 /* match is smaller than current */
1983 *smallerPtr = matchIndex; /* update smaller idx */
1984 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001985 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001986 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001987 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001988 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001989 /* match is larger than current */
1990 *largerPtr = matchIndex;
1991 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001992 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001993 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001994 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001995 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001996
Yann Collet59d70632015-11-04 12:05:27 +01001997 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02001998 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01001999 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
2000 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002001}
2002
2003
Yann Collet82260dd2016-02-11 07:14:25 +01002004static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01002005 ZSTD_CCtx* zc,
2006 const BYTE* const ip, const BYTE* const iend,
2007 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01002008 U32 nbCompares, const U32 mls,
2009 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01002010{
Yann Collet731ef162016-07-27 21:05:12 +02002011 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002012 U32 const hashLog = zc->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +02002013 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
2014 U32* const bt = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002015 U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
Yann Collet731ef162016-07-27 21:05:12 +02002016 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01002017 U32 matchIndex = hashTable[h];
2018 size_t commonLengthSmaller=0, commonLengthLarger=0;
2019 const BYTE* const base = zc->base;
2020 const BYTE* const dictBase = zc->dictBase;
2021 const U32 dictLimit = zc->dictLimit;
2022 const BYTE* const dictEnd = dictBase + dictLimit;
2023 const BYTE* const prefixStart = base + dictLimit;
2024 const U32 current = (U32)(ip-base);
2025 const U32 btLow = btMask >= current ? 0 : current - btMask;
2026 const U32 windowLow = zc->lowLimit;
2027 U32* smallerPtr = bt + 2*(current&btMask);
2028 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01002029 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01002030 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02002031 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01002032
Yann Collet6c3e2e72015-12-11 10:44:07 +01002033 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01002034
Yann Colletfb810d62016-01-28 00:18:06 +01002035 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08002036 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01002037 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
2038 const BYTE* match;
2039
Yann Colletfb810d62016-01-28 00:18:06 +01002040 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01002041 match = base + matchIndex;
2042 if (match[matchLength] == ip[matchLength])
2043 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01002044 } else {
Yann Collet03526e12015-11-23 15:29:15 +01002045 match = dictBase + matchIndex;
2046 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01002047 if (matchIndex+matchLength >= dictLimit)
Nick Terrellf35ef5c2017-03-09 12:51:33 -08002048 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01002049 }
2050
Yann Colletfb810d62016-01-28 00:18:06 +01002051 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01002052 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01002053 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02002054 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02002055 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01002056 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
2057 break; /* drop, to guarantee consistency (miss a little bit of compression) */
2058 }
2059
Yann Colletfb810d62016-01-28 00:18:06 +01002060 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01002061 /* match is smaller than current */
2062 *smallerPtr = matchIndex; /* update smaller idx */
2063 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
2064 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2065 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
2066 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01002067 } else {
Yann Collet03526e12015-11-23 15:29:15 +01002068 /* match is larger than current */
2069 *largerPtr = matchIndex;
2070 commonLengthLarger = matchLength;
2071 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2072 largerPtr = nextPtr;
2073 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01002074 } }
Yann Collet03526e12015-11-23 15:29:15 +01002075
2076 *smallerPtr = *largerPtr = 0;
2077
Yann Collet72e84cf2015-12-31 19:08:44 +01002078 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02002079 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01002080}
2081
Yann Collet2cc12cb2016-01-01 07:47:58 +01002082
Yann Colletb8a6f682016-02-15 17:06:29 +01002083static 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 +01002084{
2085 const BYTE* const base = zc->base;
2086 const U32 target = (U32)(ip - base);
2087 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01002088
2089 while(idx < target)
2090 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01002091}
2092
Yann Collet52447382016-03-20 16:00:00 +01002093/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01002094static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01002095 ZSTD_CCtx* zc,
2096 const BYTE* const ip, const BYTE* const iLimit,
2097 size_t* offsetPtr,
2098 const U32 maxNbAttempts, const U32 mls)
2099{
2100 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01002101 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01002102 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
2103}
2104
2105
Yann Collet768c6bc2016-02-10 14:01:49 +01002106static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01002107 ZSTD_CCtx* zc, /* Index table will be updated */
2108 const BYTE* ip, const BYTE* const iLimit,
2109 size_t* offsetPtr,
2110 const U32 maxNbAttempts, const U32 matchLengthSearch)
2111{
2112 switch(matchLengthSearch)
2113 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002114 default : /* includes case 3 */
Yann Collet2cc12cb2016-01-01 07:47:58 +01002115 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
2116 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07002117 case 7 :
Yann Collet2cc12cb2016-01-01 07:47:58 +01002118 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
2119 }
2120}
2121
2122
Yann Colletb8a6f682016-02-15 17:06:29 +01002123static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
2124{
2125 const BYTE* const base = zc->base;
2126 const U32 target = (U32)(ip - base);
2127 U32 idx = zc->nextToUpdate;
2128
2129 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
2130}
2131
inikep64d7bcb2016-04-07 19:14:09 +02002132
Yann Collet03526e12015-11-23 15:29:15 +01002133/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01002134static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01002135 ZSTD_CCtx* zc,
2136 const BYTE* const ip, const BYTE* const iLimit,
2137 size_t* offsetPtr,
2138 const U32 maxNbAttempts, const U32 mls)
2139{
Yann Colletee3f4512015-12-29 22:26:09 +01002140 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01002141 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01002142 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01002143}
2144
2145
Yann Collet82260dd2016-02-11 07:14:25 +01002146static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01002147 ZSTD_CCtx* zc, /* Index table will be updated */
2148 const BYTE* ip, const BYTE* const iLimit,
2149 size_t* offsetPtr,
2150 const U32 maxNbAttempts, const U32 matchLengthSearch)
2151{
2152 switch(matchLengthSearch)
2153 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002154 default : /* includes case 3 */
Yann Collet03526e12015-11-23 15:29:15 +01002155 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
2156 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07002157 case 7 :
Yann Collet03526e12015-11-23 15:29:15 +01002158 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
2159 }
2160}
2161
2162
Yann Collet5106a762015-11-05 15:00:24 +01002163
Yann Collet731ef162016-07-27 21:05:12 +02002164/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02002165* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02002166***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02002167#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
2168
2169/* Update chains up to ip (excluded)
Anders Oleson517577b2017-02-20 12:08:59 -08002170 Assumption : always within prefix (i.e. not within extDict) */
inikep64d7bcb2016-04-07 19:14:09 +02002171FORCE_INLINE
2172U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
2173{
2174 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002175 const U32 hashLog = zc->appliedParams.cParams.hashLog;
inikep64d7bcb2016-04-07 19:14:09 +02002176 U32* const chainTable = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002177 const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1;
inikep64d7bcb2016-04-07 19:14:09 +02002178 const BYTE* const base = zc->base;
2179 const U32 target = (U32)(ip - base);
2180 U32 idx = zc->nextToUpdate;
2181
Yann Collet22d76322016-06-21 08:01:51 +02002182 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002183 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
2184 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
2185 hashTable[h] = idx;
2186 idx++;
2187 }
2188
2189 zc->nextToUpdate = target;
2190 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
2191}
2192
2193
Nick Terrell55fc1f92017-05-24 13:50:10 -07002194/* inlining is important to hardwire a hot branch (template emulation) */
2195FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002196size_t ZSTD_HcFindBestMatch_generic (
2197 ZSTD_CCtx* zc, /* Index table will be updated */
2198 const BYTE* const ip, const BYTE* const iLimit,
2199 size_t* offsetPtr,
2200 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
2201{
2202 U32* const chainTable = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002203 const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog);
inikep64d7bcb2016-04-07 19:14:09 +02002204 const U32 chainMask = chainSize-1;
2205 const BYTE* const base = zc->base;
2206 const BYTE* const dictBase = zc->dictBase;
2207 const U32 dictLimit = zc->dictLimit;
2208 const BYTE* const prefixStart = base + dictLimit;
2209 const BYTE* const dictEnd = dictBase + dictLimit;
2210 const U32 lowLimit = zc->lowLimit;
2211 const U32 current = (U32)(ip-base);
2212 const U32 minChain = current > chainSize ? current - chainSize : 0;
2213 int nbAttempts=maxNbAttempts;
Yann Collete42afbc2017-04-26 11:39:35 -07002214 size_t ml=4-1;
inikep64d7bcb2016-04-07 19:14:09 +02002215
2216 /* HC4 match finder */
2217 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
2218
Yann Collet22d76322016-06-21 08:01:51 +02002219 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02002220 const BYTE* match;
2221 size_t currentMl=0;
2222 if ((!extDict) || matchIndex >= dictLimit) {
2223 match = base + matchIndex;
2224 if (match[ml] == ip[ml]) /* potentially better */
2225 currentMl = ZSTD_count(ip, match, iLimit);
2226 } else {
2227 match = dictBase + matchIndex;
2228 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
Yann Collete42afbc2017-04-26 11:39:35 -07002229 currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002230 }
2231
2232 /* save best solution */
Yann Colletc17e0202017-04-20 12:50:02 -07002233 if (currentMl > ml) {
2234 ml = currentMl;
2235 *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
2236 if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
2237 }
inikep64d7bcb2016-04-07 19:14:09 +02002238
2239 if (matchIndex <= minChain) break;
2240 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
2241 }
2242
2243 return ml;
2244}
2245
2246
2247FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
2248 ZSTD_CCtx* zc,
2249 const BYTE* ip, const BYTE* const iLimit,
2250 size_t* offsetPtr,
2251 const U32 maxNbAttempts, const U32 matchLengthSearch)
2252{
2253 switch(matchLengthSearch)
2254 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002255 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02002256 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
2257 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
Yann Collet933ce4a2017-03-29 14:32:15 -07002258 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02002259 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
2260 }
2261}
2262
2263
2264FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
2265 ZSTD_CCtx* zc,
2266 const BYTE* ip, const BYTE* const iLimit,
2267 size_t* offsetPtr,
2268 const U32 maxNbAttempts, const U32 matchLengthSearch)
2269{
2270 switch(matchLengthSearch)
2271 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002272 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02002273 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
2274 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
Yann Collet933ce4a2017-03-29 14:32:15 -07002275 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02002276 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
2277 }
2278}
2279
inikep64d7bcb2016-04-07 19:14:09 +02002280
Yann Collet287b7d92015-11-22 13:24:05 +01002281/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02002282* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02002283*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01002284FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002285void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
2286 const void* src, size_t srcSize,
2287 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01002288{
inikepfaa8d8a2016-04-05 19:01:10 +02002289 seqStore_t* seqStorePtr = &(ctx->seqStore);
2290 const BYTE* const istart = (const BYTE*)src;
2291 const BYTE* ip = istart;
2292 const BYTE* anchor = istart;
2293 const BYTE* const iend = istart + srcSize;
2294 const BYTE* const ilimit = iend - 8;
2295 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002296
Yann Collet1ad7c822017-05-22 17:06:04 -07002297 U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
2298 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002299
inikep64d7bcb2016-04-07 19:14:09 +02002300 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2301 size_t* offsetPtr,
2302 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02002303 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02002304 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02002305
inikepfaa8d8a2016-04-05 19:01:10 +02002306 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02002307 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02002308 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02002309 { U32 const maxRep = (U32)(ip-base);
2310 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
2311 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
2312 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002313
inikepfaa8d8a2016-04-05 19:01:10 +02002314 /* Match Loop */
2315 while (ip < ilimit) {
2316 size_t matchLength=0;
2317 size_t offset=0;
2318 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01002319
inikepfaa8d8a2016-04-05 19:01:10 +02002320 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02002321 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02002322 /* repcode : we take it */
Yann Collete42afbc2017-04-26 11:39:35 -07002323 matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002324 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01002325 }
Yann Collet5be2dd22015-11-11 13:43:58 +01002326
inikepfaa8d8a2016-04-05 19:01:10 +02002327 /* first search (depth 0) */
2328 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002329 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002330 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002331 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002332 }
Yann Collet5106a762015-11-05 15:00:24 +01002333
Yann Collete42afbc2017-04-26 11:39:35 -07002334 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002335 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2336 continue;
2337 }
2338
inikep64d7bcb2016-04-07 19:14:09 +02002339 /* let's try to find a better solution */
2340 if (depth>=1)
2341 while (ip<ilimit) {
2342 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002343 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002344 size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002345 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002346 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002347 if ((mlRep >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002348 matchLength = mlRep, offset = 0, start = ip;
2349 }
2350 { size_t offset2=99999999;
2351 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002352 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2353 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002354 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002355 matchLength = ml2, offset = offset2, start = ip;
2356 continue; /* search a better one */
2357 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002358
inikep64d7bcb2016-04-07 19:14:09 +02002359 /* let's find an even better one */
2360 if ((depth==2) && (ip<ilimit)) {
2361 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002362 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002363 size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002364 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002365 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002366 if ((ml2 >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002367 matchLength = ml2, offset = 0, start = ip;
2368 }
2369 { size_t offset2=99999999;
2370 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002371 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2372 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002373 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002374 matchLength = ml2, offset = offset2, start = ip;
2375 continue;
2376 } } }
2377 break; /* nothing found : store previous solution */
2378 }
2379
2380 /* catch up */
2381 if (offset) {
Yann Colletc17e0202017-04-20 12:50:02 -07002382 while ( (start > anchor)
2383 && (start > base+offset-ZSTD_REP_MOVE)
2384 && (start[-1] == start[-1-offset+ZSTD_REP_MOVE]) ) /* only search for offset within prefix */
inikep64d7bcb2016-04-07 19:14:09 +02002385 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02002386 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02002387 }
2388
inikepfaa8d8a2016-04-05 19:01:10 +02002389 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002390_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002391 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002392 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002393 anchor = ip = start + matchLength;
2394 }
Yann Collet48537162016-04-07 15:24:29 +02002395
inikepfaa8d8a2016-04-05 19:01:10 +02002396 /* check immediate repcode */
2397 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02002398 && ((offset_2>0)
2399 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02002400 /* store sequence */
Yann Collete42afbc2017-04-26 11:39:35 -07002401 matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet9634f672016-07-03 01:23:58 +02002402 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02002403 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2404 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002405 anchor = ip;
2406 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02002407 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002408
Yann Collet4266c0a2016-06-14 01:49:25 +02002409 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002410 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
2411 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02002412
inikepfaa8d8a2016-04-05 19:01:10 +02002413 /* Last Literals */
2414 { size_t const lastLLSize = iend - anchor;
2415 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2416 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002417 }
Yann Collet5106a762015-11-05 15:00:24 +01002418}
2419
Yann Collet5be2dd22015-11-11 13:43:58 +01002420
inikep64d7bcb2016-04-07 19:14:09 +02002421static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2422{
2423 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2424}
2425
2426static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2427{
2428 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2429}
2430
2431static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2432{
2433 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2434}
2435
2436static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2437{
2438 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2439}
2440
2441
inikepfaa8d8a2016-04-05 19:01:10 +02002442FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002443void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2444 const void* src, size_t srcSize,
2445 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002446{
inikepfaa8d8a2016-04-05 19:01:10 +02002447 seqStore_t* seqStorePtr = &(ctx->seqStore);
2448 const BYTE* const istart = (const BYTE*)src;
2449 const BYTE* ip = istart;
2450 const BYTE* anchor = istart;
2451 const BYTE* const iend = istart + srcSize;
2452 const BYTE* const ilimit = iend - 8;
2453 const BYTE* const base = ctx->base;
2454 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002455 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002456 const BYTE* const prefixStart = base + dictLimit;
2457 const BYTE* const dictBase = ctx->dictBase;
2458 const BYTE* const dictEnd = dictBase + dictLimit;
2459 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2460
Yann Collet1ad7c822017-05-22 17:06:04 -07002461 const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
2462 const U32 mls = ctx->appliedParams.cParams.searchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002463
inikep64d7bcb2016-04-07 19:14:09 +02002464 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2465 size_t* offsetPtr,
2466 U32 maxNbAttempts, U32 matchLengthSearch);
2467 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2468
Yann Collet302ff032016-07-03 01:28:16 +02002469 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002470
Yann Collet302ff032016-07-03 01:28:16 +02002471 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002472 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002473 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002474
2475 /* Match Loop */
2476 while (ip < ilimit) {
2477 size_t matchLength=0;
2478 size_t offset=0;
2479 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002480 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002481
2482 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002483 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002484 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2485 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002486 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002487 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002488 /* repcode detected we should take it */
2489 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002490 matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002491 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002492 } }
2493
2494 /* first search (depth 0) */
2495 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002496 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002497 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002498 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002499 }
2500
Yann Collete42afbc2017-04-26 11:39:35 -07002501 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002502 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2503 continue;
2504 }
2505
inikep64d7bcb2016-04-07 19:14:09 +02002506 /* let's try to find a better solution */
2507 if (depth>=1)
2508 while (ip<ilimit) {
2509 ip ++;
2510 current++;
2511 /* check repCode */
2512 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002513 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002514 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2515 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002516 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002517 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2518 /* repcode detected */
2519 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002520 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002521 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002522 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002523 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002524 matchLength = repLength, offset = 0, start = ip;
2525 } }
2526
2527 /* search match, depth 1 */
2528 { size_t offset2=99999999;
2529 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002530 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2531 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002532 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002533 matchLength = ml2, offset = offset2, start = ip;
2534 continue; /* search a better one */
2535 } }
2536
2537 /* let's find an even better one */
2538 if ((depth==2) && (ip<ilimit)) {
2539 ip ++;
2540 current++;
2541 /* check repCode */
2542 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002543 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002544 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2545 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002546 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002547 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2548 /* repcode detected */
2549 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002550 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Colletc17e0202017-04-20 12:50:02 -07002551 int const gain2 = (int)(repLength * 4);
2552 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002553 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002554 matchLength = repLength, offset = 0, start = ip;
2555 } }
2556
2557 /* search match, depth 2 */
2558 { size_t offset2=99999999;
2559 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002560 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2561 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002562 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002563 matchLength = ml2, offset = offset2, start = ip;
2564 continue;
2565 } } }
2566 break; /* nothing found : store previous solution */
2567 }
2568
inikepfaa8d8a2016-04-05 19:01:10 +02002569 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002570 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002571 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002572 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2573 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002574 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002575 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002576 }
inikepfaa8d8a2016-04-05 19:01:10 +02002577
inikepfaa8d8a2016-04-05 19:01:10 +02002578 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002579_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002580 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002581 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002582 anchor = ip = start + matchLength;
2583 }
2584
2585 /* check immediate repcode */
2586 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002587 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002588 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2589 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002590 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002591 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2592 /* repcode detected we should take it */
2593 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002594 matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Collet302ff032016-07-03 01:28:16 +02002595 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002596 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2597 ip += matchLength;
2598 anchor = ip;
2599 continue; /* faster when present ... (?) */
2600 }
2601 break;
2602 } }
2603
Yann Collet4266c0a2016-06-14 01:49:25 +02002604 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002605 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002606
inikepfaa8d8a2016-04-05 19:01:10 +02002607 /* Last Literals */
2608 { size_t const lastLLSize = iend - anchor;
2609 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2610 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002611 }
2612}
2613
2614
Yann Collet59d1f792016-01-23 19:28:41 +01002615void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002616{
inikep64d7bcb2016-04-07 19:14:09 +02002617 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002618}
2619
Yann Collet59d1f792016-01-23 19:28:41 +01002620static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002621{
Yann Colleta1249dc2016-01-25 04:22:03 +01002622 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002623}
Yann Collet9a24e592015-11-22 02:53:43 +01002624
Yann Collet59d1f792016-01-23 19:28:41 +01002625static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002626{
Yann Colleta1249dc2016-01-25 04:22:03 +01002627 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002628}
2629
Yann Collet59d1f792016-01-23 19:28:41 +01002630static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002631{
Yann Colleta1249dc2016-01-25 04:22:03 +01002632 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002633}
2634
inikepef519412016-04-21 11:08:43 +02002635
inikepef519412016-04-21 11:08:43 +02002636/* The optimal parser */
2637#include "zstd_opt.h"
2638
2639static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2640{
Yann Colletd4f4e582016-06-27 01:31:35 +02002641#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002642 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2643#else
2644 (void)ctx; (void)src; (void)srcSize;
2645 return;
2646#endif
2647}
2648
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002649static void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002650{
2651#ifdef ZSTD_OPT_H_91842398743
2652 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002653#else
2654 (void)ctx; (void)src; (void)srcSize;
2655 return;
2656#endif
inikepef519412016-04-21 11:08:43 +02002657}
2658
inikepd3b8d7a2016-02-22 10:06:17 +01002659static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002660{
Yann Colletd4f4e582016-06-27 01:31:35 +02002661#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002662 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2663#else
2664 (void)ctx; (void)src; (void)srcSize;
2665 return;
2666#endif
2667}
2668
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002669static void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002670{
2671#ifdef ZSTD_OPT_H_91842398743
2672 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002673#else
2674 (void)ctx; (void)src; (void)srcSize;
2675 return;
2676#endif
inikepe2bfe242016-01-31 11:25:48 +01002677}
2678
Yann Collet7a231792015-11-21 15:27:35 +01002679
Yann Collet59d1f792016-01-23 19:28:41 +01002680typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002681
Yann Colletb923f652016-01-26 03:14:20 +01002682static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002683{
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002684 static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
2685 { NULL,
2686 ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy,
Yann Colletc17e0202017-04-20 12:50:02 -07002687 ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002688 ZSTD_compressBlock_btopt, ZSTD_compressBlock_btultra },
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002689 { NULL,
2690 ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict,
Yann Colletc17e0202017-04-20 12:50:02 -07002691 ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002692 ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01002693 };
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002694 ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
Yann Collet7fe531e2015-11-29 02:38:09 +01002695
2696 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002697}
2698
2699
Yann Colletd1b26842016-03-15 01:24:33 +01002700static 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 +01002701{
Yann Collet1ad7c822017-05-22 17:06:04 -07002702 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002703 const BYTE* const base = zc->base;
2704 const BYTE* const istart = (const BYTE*)src;
2705 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002706 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 +02002707 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002708 if (current > zc->nextToUpdate + 384)
Yann Colletc17e0202017-04-20 12:50:02 -07002709 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 +01002710 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002711 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002712}
2713
2714
Yann Colletdb8e21d2017-05-12 13:46:49 -07002715/*! ZSTD_compress_frameChunk() :
Yann Colletc991cc12016-07-28 00:55:43 +02002716* Compress a chunk of data into one or multiple blocks.
2717* All blocks will be terminated, all input will be consumed.
2718* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2719* Frame is supposed already started (header already produced)
2720* @return : compressed size, or an error code
2721*/
Yann Colletdb8e21d2017-05-12 13:46:49 -07002722static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002723 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002724 const void* src, size_t srcSize,
2725 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002726{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002727 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002728 size_t remaining = srcSize;
2729 const BYTE* ip = (const BYTE*)src;
2730 BYTE* const ostart = (BYTE*)dst;
2731 BYTE* op = ostart;
Yann Collet1ad7c822017-05-22 17:06:04 -07002732 U32 const maxDist = 1 << cctx->appliedParams.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002733
Yann Collet1ad7c822017-05-22 17:06:04 -07002734 if (cctx->appliedParams.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002735 XXH64_update(&cctx->xxhState, src, srcSize);
2736
Yann Collet2ce49232016-02-02 14:36:49 +01002737 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002738 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002739 size_t cSize;
2740
Yann Colletc17e0202017-04-20 12:50:02 -07002741 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
2742 return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01002743 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002744
Yann Collet346efcc2016-08-02 14:26:00 +02002745 /* preemptive overflow correction */
Sean Purcell881abe42017-03-07 16:52:23 -08002746 if (cctx->lowLimit > (3U<<29)) {
Yann Collet1ad7c822017-05-22 17:06:04 -07002747 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->appliedParams.cParams.hashLog, cctx->appliedParams.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002748 U32 const current = (U32)(ip - cctx->base);
Yann Collet1ad7c822017-05-22 17:06:04 -07002749 U32 const newCurrent = (current & cycleMask) + (1 << cctx->appliedParams.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002750 U32 const correction = current - newCurrent;
2751 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002752 ZSTD_reduceIndex(cctx, correction);
2753 cctx->base += correction;
2754 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002755 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002756 cctx->dictLimit -= correction;
2757 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2758 else cctx->nextToUpdate -= correction;
2759 }
2760
Yann Collet06e76972017-01-25 16:39:03 -08002761 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002762 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002763 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2764 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2765 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002766 }
Yann Collet89db5e02015-11-13 11:27:46 +01002767
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002768 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002769 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002770
Yann Collet2ce49232016-02-02 14:36:49 +01002771 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002772 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2773 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2774 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2775 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2776 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002777 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002778 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002779 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002780 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002781 }
2782
2783 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002784 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002785 ip += blockSize;
2786 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002787 }
2788
Yann Collet62470b42016-07-28 15:29:08 +02002789 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002790 return op-ostart;
2791}
2792
2793
Yann Collet6236eba2016-04-12 15:52:33 +02002794static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002795 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002796{ BYTE* const op = (BYTE*)dst;
Yann Collet31533ba2017-04-27 00:29:04 -07002797 U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2798 U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002799 U32 const checksumFlag = params.fParams.checksumFlag>0;
2800 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002801 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002802 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2803 U32 const fcsCode = params.fParams.contentSizeFlag ?
Nick Terrell55fc1f92017-05-24 13:50:10 -07002804 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002805 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002806 size_t pos;
2807
2808 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet009d6042017-05-19 10:17:59 -07002809 DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
Yann Collet0be6fd32017-05-08 16:08:01 -07002810 !params.fParams.noDictIDFlag, dictID, dictIDSizeCode);
Yann Collet6236eba2016-04-12 15:52:33 +02002811
2812 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002813 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002814 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002815 switch(dictIDSizeCode)
2816 {
2817 default: /* impossible */
2818 case 0 : break;
2819 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002820 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002821 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2822 }
Yann Collet673f0d72016-06-06 00:26:38 +02002823 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002824 {
2825 default: /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002826 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002827 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2828 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002829 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002830 }
Yann Colletc46fb922016-05-29 05:01:04 +02002831 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002832}
2833
2834
Yann Collet346efcc2016-08-02 14:26:00 +02002835static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002836 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002837 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002838 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002839{
Yann Collet2acb5d32015-10-29 16:49:43 +01002840 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002841 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002842
Yann Collet346efcc2016-08-02 14:26:00 +02002843 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002844
Yann Collet346efcc2016-08-02 14:26:00 +02002845 if (frame && (cctx->stage==ZSTDcs_init)) {
Yann Collet1ad7c822017-05-22 17:06:04 -07002846 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002847 if (ZSTD_isError(fhSize)) return fhSize;
2848 dstCapacity -= fhSize;
2849 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002850 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002851 }
Yann Colletf3eca252015-10-22 15:31:46 +01002852
Yann Collet417890c2015-12-04 17:16:37 +01002853 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002854 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002855 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002856 ptrdiff_t const delta = cctx->nextSrc - ip;
2857 cctx->lowLimit = cctx->dictLimit;
2858 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2859 cctx->dictBase = cctx->base;
2860 cctx->base -= delta;
2861 cctx->nextToUpdate = cctx->dictLimit;
2862 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002863 }
2864
Yann Collet346efcc2016-08-02 14:26:00 +02002865 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2866 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2867 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2868 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2869 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002870 }
2871
Yann Collet346efcc2016-08-02 14:26:00 +02002872 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002873
Yann Collet5eb749e2017-01-11 18:21:25 +01002874 if (srcSize) {
2875 size_t const cSize = frame ?
Yann Colletdb8e21d2017-05-12 13:46:49 -07002876 ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
Yann Collet346efcc2016-08-02 14:26:00 +02002877 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002878 if (ZSTD_isError(cSize)) return cSize;
Yann Collet20d5e032017-04-11 18:34:02 -07002879 cctx->consumedSrcSize += srcSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002880 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01002881 } else
2882 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002883}
2884
Yann Colletbf42c8e2016-01-09 01:08:23 +01002885
Yann Collet5b567392016-07-28 01:17:22 +02002886size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002887 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002888 const void* src, size_t srcSize)
2889{
Yann Collet20d5e032017-04-11 18:34:02 -07002890 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
Yann Collet5b567392016-07-28 01:17:22 +02002891}
2892
2893
Yann Colletfa3671e2017-05-19 10:51:30 -07002894size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002895{
Yann Colletfa3671e2017-05-19 10:51:30 -07002896 U32 const cLevel = cctx->compressionLevel;
2897 ZSTD_compressionParameters cParams = (cLevel == ZSTD_CLEVEL_CUSTOM) ?
Yann Collet1ad7c822017-05-22 17:06:04 -07002898 cctx->appliedParams.cParams :
Yann Colletfa3671e2017-05-19 10:51:30 -07002899 ZSTD_getCParams(cLevel, 0, 0);
2900 return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog);
Yann Colletcf05b9d2016-07-18 16:52:10 +02002901}
2902
2903size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2904{
Yann Colletfa3671e2017-05-19 10:51:30 -07002905 size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002906 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07002907 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002908}
2909
Yann Collet16a0b102017-03-24 12:46:46 -07002910/*! ZSTD_loadDictionaryContent() :
2911 * @return : 0, or an error code
2912 */
Yann Colletb923f652016-01-26 03:14:20 +01002913static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002914{
2915 const BYTE* const ip = (const BYTE*) src;
2916 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002917
Yann Collet417890c2015-12-04 17:16:37 +01002918 /* input becomes current prefix */
2919 zc->lowLimit = zc->dictLimit;
2920 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2921 zc->dictBase = zc->base;
2922 zc->base += ip - zc->nextSrc;
2923 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08002924 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002925
2926 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002927 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002928
Yann Collet1ad7c822017-05-22 17:06:04 -07002929 switch(zc->appliedParams.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002930 {
2931 case ZSTD_fast:
Yann Collet1ad7c822017-05-22 17:06:04 -07002932 ZSTD_fillHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002933 break;
2934
Yann Collet45dc3562016-07-12 09:47:31 +02002935 case ZSTD_dfast:
Yann Collet1ad7c822017-05-22 17:06:04 -07002936 ZSTD_fillDoubleHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
Yann Collet45dc3562016-07-12 09:47:31 +02002937 break;
2938
Yann Collet417890c2015-12-04 17:16:37 +01002939 case ZSTD_greedy:
2940 case ZSTD_lazy:
2941 case ZSTD_lazy2:
Yann Collet16a0b102017-03-24 12:46:46 -07002942 if (srcSize >= HASH_READ_SIZE)
Yann Collet1ad7c822017-05-22 17:06:04 -07002943 ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002944 break;
2945
2946 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002947 case ZSTD_btopt:
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002948 case ZSTD_btultra:
Yann Collet16a0b102017-03-24 12:46:46 -07002949 if (srcSize >= HASH_READ_SIZE)
Yann Collet1ad7c822017-05-22 17:06:04 -07002950 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002951 break;
2952
2953 default:
2954 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2955 }
2956
Nick Terrellecf90ca2017-02-13 18:27:34 -08002957 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002958 return 0;
2959}
2960
2961
Nick Terrellf9c9af32016-10-19 17:22:08 -07002962/* Dictionaries that assign zero probability to symbols that show up causes problems
2963 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2964 that we may encounter during compression.
2965 NOTE: This behavior is not standard and could be improved in the future. */
2966static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2967 U32 s;
2968 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
2969 for (s = 0; s <= maxSymbolValue; ++s) {
2970 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
2971 }
2972 return 0;
2973}
2974
2975
Yann Colletb923f652016-01-26 03:14:20 +01002976/* Dictionary format :
Yann Colletbea78e82017-03-22 18:09:11 -07002977 * See :
2978 * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
2979 */
Yann Collet16a0b102017-03-24 12:46:46 -07002980/*! ZSTD_loadZstdDictionary() :
2981 * @return : 0, or an error code
2982 * assumptions : magic number supposed already checked
2983 * dictSize supposed > 8
Yann Colletbea78e82017-03-22 18:09:11 -07002984 */
Yann Collet16a0b102017-03-24 12:46:46 -07002985static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002986{
Yann Collet52a06222016-06-15 13:53:34 +02002987 const BYTE* dictPtr = (const BYTE*)dict;
2988 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07002989 short offcodeNCount[MaxOff+1];
2990 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08002991 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01002992
Yann Colletbea78e82017-03-22 18:09:11 -07002993 dictPtr += 4; /* skip magic number */
Yann Collet1ad7c822017-05-22 17:06:04 -07002994 cctx->dictID = cctx->appliedParams.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
Yann Colletbea78e82017-03-22 18:09:11 -07002995 dictPtr += 4;
2996
Yann Collet71ddeb62017-04-20 22:54:54 -07002997 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufCTable, 255, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002998 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002999 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003000 }
Yann Colletfb810d62016-01-28 00:18:06 +01003001
Nick Terrellf9c9af32016-10-19 17:22:08 -07003002 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02003003 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003004 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003005 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003006 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Colletc17e0202017-04-20 12:50:02 -07003007 CHECK_E( FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)),
3008 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003009 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003010 }
Yann Colletfb810d62016-01-28 00:18:06 +01003011
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003012 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07003013 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02003014 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003015 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003016 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003017 /* Every match length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07003018 CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
3019 CHECK_E( FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)),
3020 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003021 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003022 }
Yann Colletfb810d62016-01-28 00:18:06 +01003023
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003024 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07003025 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02003026 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003027 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003028 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003029 /* Every literal length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07003030 CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
3031 CHECK_E( FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)),
3032 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003033 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003034 }
Yann Colletfb810d62016-01-28 00:18:06 +01003035
Yann Collet52a06222016-06-15 13:53:34 +02003036 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07003037 cctx->rep[0] = MEM_readLE32(dictPtr+0);
3038 cctx->rep[1] = MEM_readLE32(dictPtr+4);
3039 cctx->rep[2] = MEM_readLE32(dictPtr+8);
Yann Collet52a06222016-06-15 13:53:34 +02003040 dictPtr += 12;
3041
Yann Colletbea78e82017-03-22 18:09:11 -07003042 { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
3043 U32 offcodeMax = MaxOff;
3044 if (dictContentSize <= ((U32)-1) - 128 KB) {
3045 U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
3046 offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
Nick Terrellb2c39a22016-10-24 14:11:27 -07003047 }
Yann Colletbea78e82017-03-22 18:09:11 -07003048 /* All offset values <= dictContentSize + 128 KB must be representable */
Nick Terrellf9c9af32016-10-19 17:22:08 -07003049 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
Yann Colletbea78e82017-03-22 18:09:11 -07003050 /* All repCodes must be <= dictContentSize and != 0*/
3051 { U32 u;
3052 for (u=0; u<3; u++) {
3053 if (cctx->rep[u] == 0) return ERROR(dictionary_corrupted);
3054 if (cctx->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07003055 } }
Nick Terrellf9c9af32016-10-19 17:22:08 -07003056
Yann Collet71ddeb62017-04-20 22:54:54 -07003057 cctx->fseCTables_ready = 1;
3058 cctx->hufCTable_repeatMode = HUF_repeat_valid;
Yann Collet16a0b102017-03-24 12:46:46 -07003059 return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
3060 }
Yann Colletb923f652016-01-26 03:14:20 +01003061}
3062
Yann Colletd1b26842016-03-15 01:24:33 +01003063/** ZSTD_compress_insertDictionary() :
3064* @return : 0, or an error code */
Yann Collet16a0b102017-03-24 12:46:46 -07003065static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01003066{
Yann Colletc46fb922016-05-29 05:01:04 +02003067 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01003068
Yann Collet14312d82017-02-23 23:42:12 -08003069 /* dict as pure content */
Yann Collet16a0b102017-03-24 12:46:46 -07003070 if ((MEM_readLE32(dict) != ZSTD_DICT_MAGIC) || (cctx->forceRawDict))
3071 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
Yann Colletd1b26842016-03-15 01:24:33 +01003072
Yann Colletbea78e82017-03-22 18:09:11 -07003073 /* dict as zstd dictionary */
Yann Collet16a0b102017-03-24 12:46:46 -07003074 return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
Yann Colletecd651b2016-01-07 15:35:18 +01003075}
3076
Yann Collet27caf2a2016-04-01 15:48:48 +02003077/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01003078* @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02003079static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01003080 const void* dict, size_t dictSize,
Yann Collet18803372017-05-22 18:21:51 -07003081 const ZSTD_CDict* cdict,
Yann Collet5ac72b42017-05-23 11:18:24 -07003082 ZSTD_parameters params, U64 pledgedSrcSize,
3083 ZSTD_buffered_policy_e zbuff)
Yann Colletf3eca252015-10-22 15:31:46 +01003084{
Yann Collet5ac72b42017-05-23 11:18:24 -07003085 /* params are supposed to be fully validated at this point */
Yann Colletab9162e2017-04-11 10:46:20 -07003086 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet18803372017-05-22 18:21:51 -07003087 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
3088
3089 if (cdict && cdict->dictContentSize>0)
Yann Collet5ac72b42017-05-23 11:18:24 -07003090 return ZSTD_copyCCtx_internal(cctx, cdict->refContext,
3091 params.fParams, pledgedSrcSize);
Yann Collet18803372017-05-22 18:21:51 -07003092
Yann Collet5ac72b42017-05-23 11:18:24 -07003093 CHECK_F(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
3094 ZSTDcrp_continue, zbuff));
Yann Colleta7737f62016-09-06 09:44:59 +02003095 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01003096}
3097
3098
Yann Collet27caf2a2016-04-01 15:48:48 +02003099/*! ZSTD_compressBegin_advanced() :
3100* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02003101size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02003102 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02003103 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02003104{
3105 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02003106 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet5ac72b42017-05-23 11:18:24 -07003107 return ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL,
3108 params, pledgedSrcSize, ZSTDb_not_buffered);
Yann Collet27caf2a2016-04-01 15:48:48 +02003109}
3110
3111
Yann Collet81e13ef2016-06-07 00:51:51 +02003112size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01003113{
Yann Collet6c6e1752016-06-27 15:28:45 +02003114 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet5ac72b42017-05-23 11:18:24 -07003115 return ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL,
3116 params, 0, ZSTDb_not_buffered);
Yann Collet1c8e1942016-01-26 16:31:22 +01003117}
Yann Collet083fcc82015-10-25 14:06:35 +01003118
inikep19bd48f2016-04-04 12:10:00 +02003119
Yann Colletb05c4822017-01-12 02:01:28 +01003120size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01003121{
Yann Colletb05c4822017-01-12 02:01:28 +01003122 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01003123}
3124
3125
Yann Collet62470b42016-07-28 15:29:08 +02003126/*! ZSTD_writeEpilogue() :
3127* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01003128* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02003129static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01003130{
Yann Colletc991cc12016-07-28 00:55:43 +02003131 BYTE* const ostart = (BYTE*)dst;
3132 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02003133 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01003134
Yann Collet009d6042017-05-19 10:17:59 -07003135 DEBUGLOG(5, "ZSTD_writeEpilogue");
Yann Collet87c18b22016-08-26 01:43:47 +02003136 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02003137
3138 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02003139 if (cctx->stage == ZSTDcs_init) {
Yann Collet1ad7c822017-05-22 17:06:04 -07003140 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02003141 if (ZSTD_isError(fhSize)) return fhSize;
3142 dstCapacity -= fhSize;
3143 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02003144 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01003145 }
3146
Yann Colletc991cc12016-07-28 00:55:43 +02003147 if (cctx->stage != ZSTDcs_ending) {
3148 /* write one last empty block, make it the "last" block */
3149 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
3150 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
3151 MEM_writeLE32(op, cBlockHeader24);
3152 op += ZSTD_blockHeaderSize;
3153 dstCapacity -= ZSTD_blockHeaderSize;
3154 }
3155
Yann Collet1ad7c822017-05-22 17:06:04 -07003156 if (cctx->appliedParams.fParams.checksumFlag) {
Yann Colletc991cc12016-07-28 00:55:43 +02003157 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
3158 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
3159 MEM_writeLE32(op, checksum);
3160 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003161 }
Yann Collet2acb5d32015-10-29 16:49:43 +01003162
Yann Collet731ef162016-07-27 21:05:12 +02003163 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02003164 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01003165}
3166
Yann Colletfd416f12016-01-30 03:14:15 +01003167
Yann Collet62470b42016-07-28 15:29:08 +02003168size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
3169 void* dst, size_t dstCapacity,
3170 const void* src, size_t srcSize)
3171{
3172 size_t endResult;
Yann Collet009d6042017-05-19 10:17:59 -07003173 size_t const cSize = ZSTD_compressContinue_internal(cctx,
3174 dst, dstCapacity, src, srcSize,
3175 1 /* frame mode */, 1 /* last chunk */);
Yann Collet62470b42016-07-28 15:29:08 +02003176 if (ZSTD_isError(cSize)) return cSize;
3177 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
3178 if (ZSTD_isError(endResult)) return endResult;
Yann Collet1ad7c822017-05-22 17:06:04 -07003179 if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */
Yann Collet0be6fd32017-05-08 16:08:01 -07003180 if (cctx->frameContentSize != cctx->consumedSrcSize)
3181 return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07003182 }
Yann Collet62470b42016-07-28 15:29:08 +02003183 return cSize + endResult;
3184}
3185
3186
Yann Collet19c10022016-07-28 01:25:46 +02003187static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01003188 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01003189 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01003190 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01003191 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01003192{
Yann Collet5ac72b42017-05-23 11:18:24 -07003193 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, NULL,
3194 params, srcSize, ZSTDb_not_buffered));
Yann Collet62470b42016-07-28 15:29:08 +02003195 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01003196}
3197
Yann Collet21588e32016-03-30 16:50:44 +02003198size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
3199 void* dst, size_t dstCapacity,
3200 const void* src, size_t srcSize,
3201 const void* dict,size_t dictSize,
3202 ZSTD_parameters params)
3203{
Yann Colletcf409a72016-09-26 16:41:05 +02003204 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02003205 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
3206}
3207
Yann Colletc17e0202017-04-20 12:50:02 -07003208size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
3209 const void* dict, size_t dictSize, int compressionLevel)
Yann Collet31683c02015-12-18 01:26:48 +01003210{
Yann Collet407a11f2016-11-03 15:52:01 -07003211 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02003212 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02003213 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01003214}
3215
Yann Colletd1b26842016-03-15 01:24:33 +01003216size_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 +01003217{
Yann Collet21588e32016-03-30 16:50:44 +02003218 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01003219}
3220
Yann Colletd1b26842016-03-15 01:24:33 +01003221size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01003222{
Yann Collet44fe9912015-10-29 22:02:40 +01003223 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01003224 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01003225 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Colletae728a42017-05-30 17:11:39 -07003226 ctxBody.customMem = ZSTD_defaultCMem;
Yann Colletd1b26842016-03-15 01:24:33 +01003227 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Colletae728a42017-05-30 17:11:39 -07003228 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 +01003229 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01003230}
Yann Colletfdcad6d2015-12-17 23:50:15 +01003231
Yann Colletfd416f12016-01-30 03:14:15 +01003232
Yann Collet81e13ef2016-06-07 00:51:51 +02003233/* ===== Dictionary API ===== */
3234
Yann Colleta1d67042017-05-08 17:51:49 -07003235/*! ZSTD_estimateCDictSize() :
3236 * Estimate amount of memory that will be needed to create a dictionary with following arguments */
Yann Collet25989e32017-05-25 15:07:37 -07003237size_t ZSTD_estimateCDictSize(ZSTD_compressionParameters cParams, size_t dictSize, unsigned byReference)
Yann Colleta1d67042017-05-08 17:51:49 -07003238{
Yann Collet25989e32017-05-25 15:07:37 -07003239 return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize(cParams)
3240 + (byReference ? 0 : dictSize);
Yann Colleta1d67042017-05-08 17:51:49 -07003241}
3242
Yann Colletd7c65892016-09-15 02:50:27 +02003243size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
3244{
3245 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Colletaca113f2016-12-23 22:25:03 +01003246 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02003247}
3248
Yann Collet1c3ab0c2017-04-27 12:57:11 -07003249static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_frameParameters fParams)
3250{
3251 ZSTD_parameters params;
3252 params.cParams = cParams;
3253 params.fParams = fParams;
3254 return params;
3255}
3256
Yann Colletcdf7e822017-05-25 18:05:49 -07003257static size_t ZSTD_initCDict_internal(
3258 ZSTD_CDict* cdict,
3259 const void* dictBuffer, size_t dictSize, unsigned byReference,
3260 ZSTD_compressionParameters cParams)
3261{
3262 if ((byReference) || (!dictBuffer) || (!dictSize)) {
3263 cdict->dictBuffer = NULL;
3264 cdict->dictContent = dictBuffer;
3265 } else {
3266 void* const internalBuffer = ZSTD_malloc(dictSize, cdict->refContext->customMem);
3267 if (!internalBuffer) return ERROR(memory_allocation);
3268 memcpy(internalBuffer, dictBuffer, dictSize);
3269 cdict->dictBuffer = internalBuffer;
3270 cdict->dictContent = internalBuffer;
3271 }
3272 cdict->dictContentSize = dictSize;
3273
3274 { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */,
3275 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */
3276 ZSTD_parameters const params = ZSTD_makeParams(cParams, fParams);
3277 CHECK_F( ZSTD_compressBegin_advanced(cdict->refContext,
3278 cdict->dictContent, dictSize,
3279 params, 0 /* srcSize */) );
3280 }
3281
3282 return 0;
3283}
3284
Yann Collet1f57c2e2016-12-21 16:20:11 +01003285ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
Yann Collet31533ba2017-04-27 00:29:04 -07003286 ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02003287{
Yann Collet8b21ec42017-05-19 19:46:15 -07003288 DEBUGLOG(5, "ZSTD_createCDict_advanced");
Yann Colletae728a42017-05-30 17:11:39 -07003289 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02003290
Yann Collet23b6e052016-08-28 21:05:43 -07003291 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02003292 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
3293
Yann Collet1f57c2e2016-12-21 16:20:11 +01003294 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07003295 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01003296 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02003297 return NULL;
3298 }
Yann Colletcdf7e822017-05-25 18:05:49 -07003299 cdict->refContext = cctx;
Yann Collet81e13ef2016-06-07 00:51:51 +02003300
Yann Colletcdf7e822017-05-25 18:05:49 -07003301 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3302 dictBuffer, dictSize, byReference,
3303 cParams) )) {
3304 ZSTD_freeCDict(cdict);
3305 return NULL;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07003306 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01003307
Yann Collet81e13ef2016-06-07 00:51:51 +02003308 return cdict;
3309 }
3310}
3311
3312ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
3313{
3314 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet31533ba2017-04-27 00:29:04 -07003315 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
3316 return ZSTD_createCDict_advanced(dict, dictSize, 0, cParams, allocator);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003317}
3318
3319ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
3320{
3321 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet31533ba2017-04-27 00:29:04 -07003322 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
3323 return ZSTD_createCDict_advanced(dict, dictSize, 1, cParams, allocator);
Yann Collet81e13ef2016-06-07 00:51:51 +02003324}
3325
3326size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
3327{
Yann Collet23b6e052016-08-28 21:05:43 -07003328 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02003329 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07003330 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01003331 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003332 ZSTD_free(cdict, cMem);
3333 return 0;
3334 }
Yann Collet81e13ef2016-06-07 00:51:51 +02003335}
3336
Yann Colletcdf7e822017-05-25 18:05:49 -07003337/*! ZSTD_initStaticCDict_advanced() :
3338 * Generate a digested dictionary in provided memory area.
3339 * workspace: The memory area to emplace the dictionary into.
3340 * Provided pointer must 8-bytes aligned.
3341 * It must outlive dictionary usage.
3342 * workspaceSize: Use ZSTD_estimateCDictSize()
3343 * to determine how large workspace must be.
3344 * cParams : use ZSTD_getCParams() to transform a compression level
3345 * into its relevants cParams.
3346 * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
3347 * Note : there is no corresponding "free" function.
3348 * Since workspace was allocated externally, it must be freed externally.
3349 */
3350ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
3351 const void* dict, size_t dictSize, unsigned byReference,
3352 ZSTD_compressionParameters cParams)
3353{
3354 size_t const cctxSize = ZSTD_estimateCCtxSize(cParams);
3355 size_t const neededSize = sizeof(ZSTD_CDict) + (byReference ? 0 : dictSize)
3356 + cctxSize;
3357 ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
3358 void* ptr;
3359 DEBUGLOG(2, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7);
3360 if ((size_t)workspace & 7) return NULL; /* 8-aligned */
3361 DEBUGLOG(2, "(workspaceSize < neededSize) : (%u < %u) => %u",
3362 (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize));
3363 if (workspaceSize < neededSize) return NULL;
3364
3365 if (!byReference) {
3366 memcpy(cdict+1, dict, dictSize);
3367 dict = cdict+1;
3368 ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize;
3369 } else {
3370 ptr = cdict+1;
3371 }
3372 cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize);
3373
3374 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
3375 dict, dictSize, 1 /* by Reference */,
3376 cParams) ))
3377 return NULL;
3378
3379 return cdict;
3380}
3381
Yann Collet95162342016-10-25 16:19:52 -07003382static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
3383 return ZSTD_getParamsFromCCtx(cdict->refContext);
3384}
3385
Yann Collet715b9aa2017-04-18 13:55:53 -07003386/* ZSTD_compressBegin_usingCDict_advanced() :
Yann Collet4f818182017-04-17 17:57:35 -07003387 * cdict must be != NULL */
Yann Collet715b9aa2017-04-18 13:55:53 -07003388size_t ZSTD_compressBegin_usingCDict_advanced(
Yann Collet4f818182017-04-17 17:57:35 -07003389 ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
3390 ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003391{
Yann Collet5ac72b42017-05-23 11:18:24 -07003392 if (cdict==NULL) return ERROR(dictionary_wrong);
Yann Collet18803372017-05-22 18:21:51 -07003393 { ZSTD_parameters params = cdict->refContext->appliedParams;
Yann Collet4f818182017-04-17 17:57:35 -07003394 params.fParams = fParams;
Yann Collet18803372017-05-22 18:21:51 -07003395 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced");
Yann Collet5ac72b42017-05-23 11:18:24 -07003396 return ZSTD_compressBegin_internal(cctx, NULL, 0, cdict,
3397 params, pledgedSrcSize, ZSTDb_not_buffered);
Sean Purcell2db72492017-02-09 10:50:43 -08003398 }
Yann Collet4cb21292016-09-15 14:54:07 +02003399}
3400
Yann Collet4f818182017-04-17 17:57:35 -07003401/* ZSTD_compressBegin_usingCDict() :
3402 * pledgedSrcSize=0 means "unknown"
3403 * if pledgedSrcSize>0, it will enable contentSizeFlag */
Yann Collet768df122017-04-26 15:42:10 -07003404size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
Yann Collet4f818182017-04-17 17:57:35 -07003405{
Yann Collet768df122017-04-26 15:42:10 -07003406 ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Collet009d6042017-05-19 10:17:59 -07003407 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
Yann Collet768df122017-04-26 15:42:10 -07003408 return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0);
Yann Collet4f818182017-04-17 17:57:35 -07003409}
3410
Yann Colletf4bd8572017-04-27 11:31:55 -07003411size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
3412 void* dst, size_t dstCapacity,
3413 const void* src, size_t srcSize,
3414 const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
3415{
3416 CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */
3417 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02003418}
3419
Yann Collet07639052016-08-03 01:57:57 +02003420/*! ZSTD_compress_usingCDict() :
Yann Collet4f818182017-04-17 17:57:35 -07003421 * Compression using a digested Dictionary.
3422 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
3423 * Note that compression parameters are decided at CDict creation time
3424 * while frame parameters are hardcoded */
Yann Collet4cb21292016-09-15 14:54:07 +02003425size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
3426 void* dst, size_t dstCapacity,
3427 const void* src, size_t srcSize,
3428 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02003429{
Yann Collet4f818182017-04-17 17:57:35 -07003430 ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Colletf4bd8572017-04-27 11:31:55 -07003431 return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
Yann Collet81e13ef2016-06-07 00:51:51 +02003432}
3433
3434
3435
Yann Collet104e5b02016-08-12 13:04:27 +02003436/* ******************************************************************
3437* Streaming
3438********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003439
Yann Collet5a0c8e22016-08-12 01:20:36 +02003440ZSTD_CStream* ZSTD_createCStream(void)
3441{
Yann Colletae728a42017-05-30 17:11:39 -07003442 return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003443}
3444
3445ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
Yann Colletae728a42017-05-30 17:11:39 -07003446{ /* CStream and CCtx are now same object */
Yann Collet6fb2f242017-05-10 11:06:06 -07003447 return ZSTD_createCCtx_advanced(customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003448}
3449
3450size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
3451{
Yann Collet78553662017-05-08 17:15:00 -07003452 return ZSTD_freeCCtx(zcs); /* same object */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003453}
3454
Yann Collet5a0c8e22016-08-12 01:20:36 +02003455
3456
Yann Collet104e5b02016-08-12 13:04:27 +02003457/*====== Initialization ======*/
3458
Yann Colletfa3671e2017-05-19 10:51:30 -07003459size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003460
Yann Colletc17e0202017-04-20 12:50:02 -07003461size_t ZSTD_CStreamOutSize(void)
3462{
Yann Colletfa3671e2017-05-19 10:51:30 -07003463 return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
Yann Colletc17e0202017-04-20 12:50:02 -07003464}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003465
Yann Collet1ad7c822017-05-22 17:06:04 -07003466static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs,
3467 ZSTD_parameters params,
3468 unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003469{
Yann Collet1ad7c822017-05-22 17:06:04 -07003470 DEBUGLOG(5, "ZSTD_resetCStream_internal");
Yann Collet31533ba2017-04-27 00:29:04 -07003471
Yann Collet5ac72b42017-05-23 11:18:24 -07003472 CHECK_F(ZSTD_compressBegin_internal(zcs, NULL, 0, zcs->cdict,
3473 params, pledgedSrcSize, ZSTDb_buffered));
Yann Collet4cb21292016-09-15 14:54:07 +02003474
3475 zcs->inToCompress = 0;
3476 zcs->inBuffPos = 0;
3477 zcs->inBuffTarget = zcs->blockSize;
3478 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -07003479 zcs->streamStage = zcss_load;
Yann Collet4cb21292016-09-15 14:54:07 +02003480 zcs->frameEnded = 0;
3481 return 0; /* ready to go */
3482}
3483
Yann Collet009d6042017-05-19 10:17:59 -07003484size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
3485{
Yann Collet1ad7c822017-05-22 17:06:04 -07003486 ZSTD_parameters params = zcs->requestedParams;
Yann Collet009d6042017-05-19 10:17:59 -07003487 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
Yann Colletb0739bc2017-05-22 17:45:15 -07003488 DEBUGLOG(5, "ZSTD_resetCStream");
Yann Collet009d6042017-05-19 10:17:59 -07003489 if (zcs->compressionLevel != ZSTD_CLEVEL_CUSTOM) {
3490 params.cParams = ZSTD_getCParams(zcs->compressionLevel, pledgedSrcSize, 0 /* dictSize */);
3491 }
Yann Collet5ac72b42017-05-23 11:18:24 -07003492 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Yann Collet009d6042017-05-19 10:17:59 -07003493}
3494
Yann Collet77bf59e2017-04-27 11:43:04 -07003495/* ZSTD_initCStream_usingCDict_advanced() :
3496 * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
Yann Collet009d6042017-05-19 10:17:59 -07003497size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
3498 const ZSTD_CDict* cdict,
3499 unsigned long long pledgedSrcSize,
3500 ZSTD_frameParameters fParams)
3501{ /* cannot handle NULL cdict (does not know what to do) */
3502 if (!cdict) return ERROR(dictionary_wrong);
Yann Collet4ee6b152017-04-11 11:59:44 -07003503 { ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict);
Yann Collet77bf59e2017-04-27 11:43:04 -07003504 params.fParams = fParams;
Yann Collet1ad7c822017-05-22 17:06:04 -07003505 zcs->requestedParams = params;
3506 zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Collete88034f2017-04-10 22:24:02 -07003507 zcs->cdict = cdict;
Yann Collet5ac72b42017-05-23 11:18:24 -07003508 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Yann Collete88034f2017-04-10 22:24:02 -07003509 }
3510}
3511
Yann Collete88034f2017-04-10 22:24:02 -07003512/* note : cdict must outlive compression session */
3513size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3514{
Yann Colletef738c12017-05-12 13:53:46 -07003515 ZSTD_frameParameters const fParams = { 0 /* contentSize */, 0 /* checksum */, 0 /* hideDictID */ };
Yann Collet1ad7c822017-05-22 17:06:04 -07003516 /* cannot handle NULL cdict (does not know what to do) */
3517 if (!cdict) return ERROR(dictionary_wrong);
Yann Collet77bf59e2017-04-27 11:43:04 -07003518 return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, 0, fParams);
Yann Collete88034f2017-04-10 22:24:02 -07003519}
3520
3521static size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
3522 const void* dict, size_t dictSize,
3523 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3524{
3525 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
3526 zcs->cdict = NULL;
3527
3528 if (dict && dictSize >= 8) {
Yann Colletc7fe2622017-05-23 13:16:00 -07003529 if (zcs->staticSize) { /* static CCtx : never uses malloc */
3530 /* incompatible with internal cdict creation */
3531 return ERROR(memory_allocation);
3532 }
Yann Collete88034f2017-04-10 22:24:02 -07003533 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet31533ba2017-04-27 00:29:04 -07003534 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0 /* copy */, params.cParams, zcs->customMem);
Yann Collete88034f2017-04-10 22:24:02 -07003535 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
3536 zcs->cdict = zcs->cdictLocal;
3537 }
3538
Yann Collet5ac72b42017-05-23 11:18:24 -07003539 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Sean Purcell2db72492017-02-09 10:50:43 -08003540}
3541
Yann Collet5a0c8e22016-08-12 01:20:36 +02003542size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
3543 const void* dict, size_t dictSize,
3544 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3545{
Yann Collet4b987ad2017-04-10 17:50:44 -07003546 CHECK_F( ZSTD_checkCParams(params.cParams) );
Yann Collet1ad7c822017-05-22 17:06:04 -07003547 zcs->requestedParams = params;
3548 zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Collet4b987ad2017-04-10 17:50:44 -07003549 return ZSTD_initCStream_internal(zcs, dict, dictSize, params, pledgedSrcSize);
Yann Collet95162342016-10-25 16:19:52 -07003550}
3551
Yann Collet5a0c8e22016-08-12 01:20:36 +02003552size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3553{
3554 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet1ad7c822017-05-22 17:06:04 -07003555 zcs->compressionLevel = compressionLevel;
Yann Collet4b987ad2017-04-10 17:50:44 -07003556 return ZSTD_initCStream_internal(zcs, dict, dictSize, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003557}
3558
Yann Collete795c8a2016-12-13 16:39:36 +01003559size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3560{
Yann Colletd564faa2016-12-18 21:39:15 +01003561 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
Yann Collete88034f2017-04-10 22:24:02 -07003562 params.fParams.contentSizeFlag = (pledgedSrcSize>0);
Yann Collet4b987ad2017-04-10 17:50:44 -07003563 return ZSTD_initCStream_internal(zcs, NULL, 0, params, pledgedSrcSize);
Yann Collete795c8a2016-12-13 16:39:36 +01003564}
3565
Yann Collet5a0c8e22016-08-12 01:20:36 +02003566size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3567{
Yann Collete88034f2017-04-10 22:24:02 -07003568 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0);
3569 return ZSTD_initCStream_internal(zcs, NULL, 0, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003570}
3571
Yann Collet104e5b02016-08-12 13:04:27 +02003572/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003573
Yann Collet01b15492017-05-30 18:10:26 -07003574MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity,
3575 const void* src, size_t srcSize)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003576{
3577 size_t const length = MIN(dstCapacity, srcSize);
Yann Collet18ab5af2017-05-31 09:59:22 -07003578 if (length) memcpy(dst, src, length);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003579 return length;
3580}
3581
3582static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
Yann Collet01b15492017-05-30 18:10:26 -07003583 ZSTD_outBuffer* output,
3584 ZSTD_inBuffer* input,
3585 ZSTD_EndDirective const flushMode)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003586{
3587 U32 someMoreWork = 1;
Yann Collet01b15492017-05-30 18:10:26 -07003588 const char* const istart = (const char*)input->src;
3589 const char* const iend = istart + input->size;
3590 const char* ip = istart + input->pos;
3591 char* const ostart = (char*)output->dst;
3592 char* const oend = ostart + output->size;
3593 char* op = ostart + output->pos;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003594
Yann Collet01b15492017-05-30 18:10:26 -07003595 /* expected to be already allocated */
Yann Collet6d4fef32017-05-17 18:36:15 -07003596 assert(zcs->inBuff != NULL);
3597 assert(zcs->outBuff!= NULL);
Yann Collet009d6042017-05-19 10:17:59 -07003598
Yann Collet5a0c8e22016-08-12 01:20:36 +02003599 while (someMoreWork) {
Yann Collet0be6fd32017-05-08 16:08:01 -07003600 switch(zcs->streamStage)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003601 {
Yann Collet1ad7c822017-05-22 17:06:04 -07003602 case zcss_init:
3603 /* call ZSTD_initCStream() first ! */
3604 return ERROR(init_missing);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003605
3606 case zcss_load:
3607 /* complete inBuffer */
3608 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
Yann Collet06589fe2017-05-31 10:03:20 -07003609 size_t const loaded = ZSTD_limitCopy(
3610 zcs->inBuff + zcs->inBuffPos, toLoad,
3611 ip, iend-ip);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003612 zcs->inBuffPos += loaded;
3613 ip += loaded;
Yann Collet009d6042017-05-19 10:17:59 -07003614 if ( (flushMode == ZSTD_e_continue)
3615 && (zcs->inBuffPos < zcs->inBuffTarget) ) {
3616 /* not enough input to fill full block : stop here */
3617 someMoreWork = 0; break;
3618 }
3619 if ( (flushMode == ZSTD_e_flush)
3620 && (zcs->inBuffPos == zcs->inToCompress) ) {
3621 /* empty */
3622 someMoreWork = 0; break;
3623 }
3624 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003625 /* compress current block (note : this stage cannot be stopped in the middle) */
Yann Collet009d6042017-05-19 10:17:59 -07003626 DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003627 { void* cDst;
3628 size_t cSize;
3629 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3630 size_t oSize = oend-op;
Yann Collet009d6042017-05-19 10:17:59 -07003631 unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003632 if (oSize >= ZSTD_compressBound(iSize))
Yann Collet009d6042017-05-19 10:17:59 -07003633 cDst = op; /* compress directly into output buffer (skip flush stage) */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003634 else
3635 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
Yann Collet009d6042017-05-19 10:17:59 -07003636 cSize = lastBlock ?
3637 ZSTD_compressEnd(zcs, cDst, oSize,
3638 zcs->inBuff + zcs->inToCompress, iSize) :
3639 ZSTD_compressContinue(zcs, cDst, oSize,
3640 zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003641 if (ZSTD_isError(cSize)) return cSize;
Yann Collet009d6042017-05-19 10:17:59 -07003642 DEBUGLOG(5, "cSize = %u (lastBlock:%u)", (U32)cSize, lastBlock);
3643 zcs->frameEnded = lastBlock;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003644 /* prepare next block */
3645 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3646 if (zcs->inBuffTarget > zcs->inBuffSize)
Yann Collet009d6042017-05-19 10:17:59 -07003647 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
Yann Collet8b21ec42017-05-19 19:46:15 -07003648 DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
3649 (U32)zcs->inBuffTarget, (U32)zcs->inBuffSize);
3650 if (!lastBlock)
3651 assert(zcs->inBuffTarget <= zcs->inBuffSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003652 zcs->inToCompress = zcs->inBuffPos;
Yann Collet009d6042017-05-19 10:17:59 -07003653 if (cDst == op) { /* no need to flush */
3654 op += cSize;
3655 if (zcs->frameEnded) {
3656 DEBUGLOG(5, "Frame directly completed");
3657 someMoreWork = 0;
3658 zcs->streamStage = zcss_init;
3659 }
3660 break;
3661 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003662 zcs->outBuffContentSize = cSize;
3663 zcs->outBuffFlushedSize = 0;
Yann Collet009d6042017-05-19 10:17:59 -07003664 zcs->streamStage = zcss_flush; /* pass-through to flush stage */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003665 }
Jos Collin7cd7a752017-05-11 13:17:20 +05303666 /* fall-through */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003667 case zcss_flush:
Yann Collet009d6042017-05-19 10:17:59 -07003668 DEBUGLOG(5, "flush stage");
Yann Collet5a0c8e22016-08-12 01:20:36 +02003669 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
Yann Collet01b15492017-05-30 18:10:26 -07003670 size_t const flushed = ZSTD_limitCopy(op, oend-op,
3671 zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
Yann Collet009d6042017-05-19 10:17:59 -07003672 DEBUGLOG(5, "toFlush: %u ; flushed: %u", (U32)toFlush, (U32)flushed);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003673 op += flushed;
3674 zcs->outBuffFlushedSize += flushed;
Yann Collet01b15492017-05-30 18:10:26 -07003675 if (toFlush!=flushed) {
3676 /* dst too small to store flushed data : stop there */
3677 someMoreWork = 0;
3678 break;
3679 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003680 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet009d6042017-05-19 10:17:59 -07003681 if (zcs->frameEnded) {
3682 DEBUGLOG(5, "Frame completed");
3683 someMoreWork = 0;
3684 zcs->streamStage = zcss_init;
3685 break;
3686 }
Yann Collet0be6fd32017-05-08 16:08:01 -07003687 zcs->streamStage = zcss_load;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003688 break;
3689 }
3690
3691 case zcss_final:
Yann Collet009d6042017-05-19 10:17:59 -07003692 someMoreWork = 0; break; /* useless */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003693
3694 default:
3695 return ERROR(GENERIC); /* impossible */
3696 }
3697 }
3698
Yann Collet01b15492017-05-30 18:10:26 -07003699 input->pos = ip - istart;
3700 output->pos = op - ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003701 if (zcs->frameEnded) return 0;
3702 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3703 if (hintInSize==0) hintInSize = zcs->blockSize;
3704 return hintInSize;
3705 }
3706}
3707
Yann Collet53e17fb2016-08-17 01:39:22 +02003708size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003709{
Yann Collet01b15492017-05-30 18:10:26 -07003710 /* check conditions */
3711 if (output->pos > output->size) return ERROR(GENERIC);
3712 if (input->pos > input->size) return ERROR(GENERIC);
3713
3714 return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003715}
3716
Yann Colletdeee6e52017-05-30 17:42:00 -07003717size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
3718 ZSTD_outBuffer* output,
3719 ZSTD_inBuffer* input,
3720 ZSTD_EndDirective endOp)
Yann Collet6d4fef32017-05-17 18:36:15 -07003721{
3722 /* check conditions */
Yann Colletdeee6e52017-05-30 17:42:00 -07003723 if (output->pos > output->size) return ERROR(GENERIC);
3724 if (input->pos > input->size) return ERROR(GENERIC);
Yann Collet6d4fef32017-05-17 18:36:15 -07003725 assert(cctx!=NULL);
Yann Collet01b15492017-05-30 18:10:26 -07003726
Yann Collet6d4fef32017-05-17 18:36:15 -07003727 if (cctx->streamStage == zcss_init) {
3728 /* transparent reset */
Yann Collet1ad7c822017-05-22 17:06:04 -07003729 ZSTD_parameters params = cctx->requestedParams;
Yann Colletdeee6e52017-05-30 17:42:00 -07003730 DEBUGLOG(5, "ZSTD_compress_generic : transparent reset");
Yann Collet6d4fef32017-05-17 18:36:15 -07003731 if (cctx->compressionLevel != ZSTD_CLEVEL_CUSTOM)
3732 params.cParams = ZSTD_getCParams(cctx->compressionLevel,
3733 cctx->frameContentSize, 0 /* dictSize */);
Yann Collet5ac72b42017-05-23 11:18:24 -07003734 CHECK_F( ZSTD_resetCStream_internal(cctx, params, cctx->frameContentSize) );
Yann Collet6d4fef32017-05-17 18:36:15 -07003735 }
3736
Yann Collet01b15492017-05-30 18:10:26 -07003737 DEBUGLOG(5, "starting ZSTD_compressStream_generic");
3738 CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
3739
Yann Collet6d4fef32017-05-17 18:36:15 -07003740 DEBUGLOG(5, "completing ZSTD_compress_generic_integral");
Yann Colletdeee6e52017-05-30 17:42:00 -07003741 return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
Yann Collet6d4fef32017-05-17 18:36:15 -07003742}
3743
Yann Colletdeee6e52017-05-30 17:42:00 -07003744size_t ZSTD_compress_generic_simpleArgs (
3745 ZSTD_CCtx* cctx,
3746 void* dst, size_t dstCapacity, size_t* dstPos,
3747 const void* src, size_t srcSize, size_t* srcPos,
3748 ZSTD_EndDirective endOp)
Yann Collet6d4fef32017-05-17 18:36:15 -07003749{
Yann Colletdeee6e52017-05-30 17:42:00 -07003750 ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
3751 ZSTD_inBuffer input = { src, srcSize, *srcPos };
Yann Collet01b15492017-05-30 18:10:26 -07003752 /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
Yann Colletdeee6e52017-05-30 17:42:00 -07003753 size_t const hint = ZSTD_compress_generic(cctx, &output, &input, endOp);
3754 if (ZSTD_isError(hint)) return hint;
3755
3756 *dstPos = output.pos;
3757 *srcPos = input.pos;
3758 return hint;
Yann Collet01b15492017-05-30 18:10:26 -07003759
Yann Collet6d4fef32017-05-17 18:36:15 -07003760}
3761
Yann Collet5a0c8e22016-08-12 01:20:36 +02003762
Yann Collet104e5b02016-08-12 13:04:27 +02003763/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003764
3765/*! ZSTD_flushStream() :
3766* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003767size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003768{
Yann Collet18ab5af2017-05-31 09:59:22 -07003769 ZSTD_inBuffer input = { NULL, 0, 0 };
Yann Collet01b15492017-05-30 18:10:26 -07003770 if (output->pos > output->size) return ERROR(GENERIC);
3771 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_flush) );
3772 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003773}
3774
3775
Yann Collet53e17fb2016-08-17 01:39:22 +02003776size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003777{
Yann Collet18ab5af2017-05-31 09:59:22 -07003778 ZSTD_inBuffer input = { NULL, 0, 0 };
Yann Collet01b15492017-05-30 18:10:26 -07003779 if (output->pos > output->size) return ERROR(GENERIC);
3780 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_end) );
Yann Collet009d6042017-05-19 10:17:59 -07003781
Yann Collet48855fa2017-05-19 10:56:11 -07003782 DEBUGLOG(5, "ZSTD_endStream : remaining to flush : %u",
Yann Collet009d6042017-05-19 10:17:59 -07003783 (unsigned)(zcs->outBuffContentSize - zcs->outBuffFlushedSize));
Yann Collet009d6042017-05-19 10:17:59 -07003784 return zcs->outBuffContentSize - zcs->outBuffFlushedSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003785}
3786
3787
Yann Collet70e8c382016-02-10 13:37:52 +01003788/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003789
inikep2c5eeea2016-04-15 13:44:46 +02003790#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003791int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003792
Yann Collet3b719252016-03-30 19:48:05 +02003793static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003794{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003795 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003796 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003797 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3798 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003799 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3800 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003801 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3802 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3803 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003804 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003805 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3806 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3807 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3808 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3809 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3810 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3811 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3812 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003813 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
Yann Collet29297c62017-04-27 17:44:01 -07003814 { 23, 22, 22, 5, 4, 32, ZSTD_btopt }, /* level 18 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003815 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Nick Terrell374f8682017-05-10 17:48:42 -07003816 { 25, 25, 23, 7, 3, 64, ZSTD_btultra }, /* level 20 */
3817 { 26, 26, 23, 7, 3,256, ZSTD_btultra }, /* level 21 */
3818 { 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003819},
3820{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003821 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003822 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003823 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003824 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3825 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3826 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3827 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3828 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3829 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3830 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3831 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3832 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3833 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3834 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3835 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003836 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003837 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3838 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3839 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003840 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3841 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003842 { 18, 19, 18, 11, 3,512, ZSTD_btultra }, /* level 20.*/
3843 { 18, 19, 18, 12, 3,512, ZSTD_btultra }, /* level 21.*/
3844 { 18, 19, 18, 13, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003845},
3846{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003847 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003848 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3849 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3850 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3851 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3852 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3853 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3854 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3855 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3856 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3857 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3858 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3859 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3860 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3861 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003862 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3863 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3864 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3865 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3866 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3867 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003868 { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/
3869 { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/
3870 { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003871},
3872{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003873 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003874 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003875 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003876 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3877 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3878 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3879 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3880 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3881 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3882 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3883 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003884 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3885 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3886 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3887 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3888 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3889 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3890 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3891 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3892 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3893 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003894 { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/
3895 { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/
3896 { 14, 15, 15, 10, 3,256, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003897},
3898};
3899
Yann Collet236d94f2016-05-18 12:06:33 +02003900/*! ZSTD_getCParams() :
3901* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3902* Size values are optional, provide 0 if not known or unused */
Yann Collet009d6042017-05-19 10:17:59 -07003903ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003904{
Yann Collet15354142016-04-04 04:22:53 +02003905 ZSTD_compressionParameters cp;
Yann Collet009d6042017-05-19 10:17:59 -07003906 size_t const addedSize = srcSizeHint ? 0 : 500;
3907 U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003908 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet6d4fef32017-05-17 18:36:15 -07003909 if (compressionLevel <= 0) compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003910 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003911 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003912 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3913 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003914 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003915 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3916 }
Yann Collet009d6042017-05-19 10:17:59 -07003917 cp = ZSTD_adjustCParams(cp, srcSizeHint, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003918 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003919}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003920
3921/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003922* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003923* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet009d6042017-05-19 10:17:59 -07003924ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003925 ZSTD_parameters params;
Yann Collet009d6042017-05-19 10:17:59 -07003926 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize);
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003927 memset(&params, 0, sizeof(params));
3928 params.cParams = cParams;
3929 return params;
3930}