blob: 59ac3f35dd7f9e4e269d9a9d6c2bb81016567425 [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
Yann Colletbf991502017-06-19 12:56:25 -070018
Yann Colletb0edb7f2017-05-12 15:31:53 -070019/*-*************************************
Yann Colletae7aa062016-02-03 02:46:46 +010020* Dependencies
Yann Colletf3eca252015-10-22 15:31:46 +010021***************************************/
Yann Colletd3b7f8d2016-06-04 19:47:02 +020022#include <string.h> /* memset */
Yann Collet14983e72015-11-11 21:38:21 +010023#include "mem.h"
Yann Collet5a0c8e22016-08-12 01:20:36 +020024#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
Yann Colletd0e2cd12016-06-05 00:58:01 +020025#include "fse.h"
Yann Collet130fe112016-06-05 00:42:28 +020026#define HUF_STATIC_LINKING_ONLY
27#include "huf.h"
Yann Colletd3b7f8d2016-06-04 19:47:02 +020028#include "zstd_internal.h" /* includes zstd.h */
Yann Colletc4a5a212017-06-01 17:56:14 -070029#include "zstdmt_compress.h"
Yann Colletf3eca252015-10-22 15:31:46 +010030
31
Yann Collet7d360282016-02-12 00:07:30 +010032/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010033* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010034***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010035static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Collet731ef162016-07-27 21:05:12 +020036#define HASH_READ_SIZE 8
37typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
Yann Colletf3eca252015-10-22 15:31:46 +010038
Yann Collet71ddeb62017-04-20 22:54:54 -070039/* entropy tables always have same size */
40static size_t const hufCTable_size = HUF_CTABLE_SIZE(255);
Yann Collete42afbc2017-04-26 11:39:35 -070041static size_t const litlengthCTable_size = FSE_CTABLE_SIZE(LLFSELog, MaxLL);
42static size_t const offcodeCTable_size = FSE_CTABLE_SIZE(OffFSELog, MaxOff);
43static size_t const matchlengthCTable_size = FSE_CTABLE_SIZE(MLFSELog, MaxML);
Yann Collet72712032017-04-20 23:21:19 -070044static size_t const entropyScratchSpace_size = HUF_WORKSPACE_SIZE;
Yann Colleta34a39c2017-04-20 18:17:58 -070045
Yann Colletf3eca252015-10-22 15:31:46 +010046
Yann Collet7d360282016-02-12 00:07:30 +010047/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010048* Helper functions
49***************************************/
Yann Collet3f75d522017-03-31 17:11:38 -070050size_t ZSTD_compressBound(size_t srcSize) {
Yann Collet30c76982017-03-31 18:27:03 -070051 size_t const lowLimit = 256 KB;
52 size_t const margin = (srcSize < lowLimit) ? (lowLimit-srcSize) >> 12 : 0; /* from 64 to 0 */
Yann Collet3f75d522017-03-31 17:11:38 -070053 return srcSize + (srcSize >> 8) + margin;
54}
Yann Collet59d1f792016-01-23 19:28:41 +010055
56
Yann Collet7d360282016-02-12 00:07:30 +010057/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010058* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010059***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010060static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
61{
Yann Collet14983e72015-11-11 21:38:21 +010062 ssPtr->lit = ssPtr->litStart;
Yann Colletc0ce4f12016-07-30 00:55:13 +020063 ssPtr->sequences = ssPtr->sequencesStart;
Yann Collet5d393572016-04-07 17:19:00 +020064 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010065}
66
67
Yann Collet7d360282016-02-12 00:07:30 +010068/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010069* Context memory management
70***************************************/
Yann Collet466f92e2017-06-20 16:25:29 -070071typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
Yann Collet0be6fd32017-05-08 16:08:01 -070072
Yann Collet18803372017-05-22 18:21:51 -070073struct ZSTD_CDict_s {
74 void* dictBuffer;
75 const void* dictContent;
76 size_t dictContentSize;
77 ZSTD_CCtx* refContext;
Yann Collet8c910d22017-06-03 01:15:02 -070078}; /* typedef'd to ZSTD_CDict within "zstd.h" */
Yann Collet18803372017-05-22 18:21:51 -070079
Yann Colletaca113f2016-12-23 22:25:03 +010080struct ZSTD_CCtx_s {
Yann Collet89db5e02015-11-13 11:27:46 +010081 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010082 const BYTE* base; /* All regular indexes relative to this position */
83 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010084 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010085 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010086 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010087 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +010088 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Colletbb002742017-01-25 16:25:38 -080089 U32 loadedDictEnd; /* index of end of dictionary */
90 U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
Yann Collet7bd1a292017-06-21 11:50:33 -070091 ZSTD_dictMode_e dictMode; /* select restricting dictionary to "rawContent" or "fullDict" only */
Yann Collet731ef162016-07-27 21:05:12 +020092 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +020093 U32 rep[ZSTD_REP_NUM];
Yann Colletb459aad2017-01-19 17:33:37 -080094 U32 repToConfirm[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +020095 U32 dictID;
Yann Colletb0edb7f2017-05-12 15:31:53 -070096 int compressionLevel;
Yann Collet1ad7c822017-05-22 17:06:04 -070097 ZSTD_parameters requestedParams;
98 ZSTD_parameters appliedParams;
Yann Collet712def92015-10-29 18:41:45 +010099 void* workSpace;
100 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100101 size_t blockSize;
Yann Colleta0ba8492017-06-16 13:29:17 -0700102 U64 pledgedSrcSizePlusOne; /* this way, 0 (default) == unknown */
Yann Collet20d5e032017-04-11 18:34:02 -0700103 U64 consumedSrcSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200104 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +0200105 ZSTD_customMem customMem;
Yann Colletc7fe2622017-05-23 13:16:00 -0700106 size_t staticSize;
Yann Colletecd651b2016-01-07 15:35:18 +0100107
Yann Collet712def92015-10-29 18:41:45 +0100108 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100109 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +0100110 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +0200111 U32* chainTable;
Yann Collet71ddeb62017-04-20 22:54:54 -0700112 HUF_repeat hufCTable_repeatMode;
113 HUF_CElt* hufCTable;
114 U32 fseCTables_ready;
Yann Collet71aaa322017-04-20 23:03:38 -0700115 FSE_CTable* offcodeCTable;
116 FSE_CTable* matchlengthCTable;
117 FSE_CTable* litlengthCTable;
Yann Collete42afbc2017-04-26 11:39:35 -0700118 unsigned* entropyScratchSpace;
Yann Collet0be6fd32017-05-08 16:08:01 -0700119
120 /* streaming */
121 ZSTD_CDict* cdictLocal;
122 const ZSTD_CDict* cdict;
123 char* inBuff;
124 size_t inBuffSize;
125 size_t inToCompress;
126 size_t inBuffPos;
127 size_t inBuffTarget;
128 char* outBuff;
129 size_t outBuffSize;
130 size_t outBuffContentSize;
131 size_t outBuffFlushedSize;
132 ZSTD_cStreamStage streamStage;
133 U32 frameEnded;
Yann Colletc4a5a212017-06-01 17:56:14 -0700134
135 /* Multi-threading */
Yann Colletc35e5352017-06-01 18:44:06 -0700136 U32 nbThreads;
Yann Colletc4a5a212017-06-01 17:56:14 -0700137 ZSTDMT_CCtx* mtctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100138};
139
Yann Colletc4a5a212017-06-01 17:56:14 -0700140
Yann Collet5be2dd22015-11-11 13:43:58 +0100141ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100142{
Yann Colletae728a42017-05-30 17:11:39 -0700143 return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
inikep50e82c02016-05-23 15:49:09 +0200144}
145
146ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
147{
Yann Collet69c2cdb2016-07-14 16:52:45 +0200148 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +0200149
Yann Colletae728a42017-05-30 17:11:39 -0700150 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200151
Yann Colletc4f46b92017-05-30 17:45:37 -0700152 cctx = (ZSTD_CCtx*) ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200153 if (!cctx) return NULL;
Yann Colletbb002742017-01-25 16:25:38 -0800154 cctx->customMem = customMem;
Yann Collet6d4fef32017-05-17 18:36:15 -0700155 cctx->compressionLevel = ZSTD_CLEVEL_DEFAULT;
Yann Colleta0ba8492017-06-16 13:29:17 -0700156 ZSTD_STATIC_ASSERT(zcss_init==0);
Yann Colletd3de3d52017-06-16 16:51:33 -0700157 ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
Yann Collet69c2cdb2016-07-14 16:52:45 +0200158 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100159}
160
Yann Colletc7fe2622017-05-23 13:16:00 -0700161ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
162{
163 ZSTD_CCtx* cctx = (ZSTD_CCtx*) workspace;
164 if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
165 if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
Yann Collet7bd1a292017-06-21 11:50:33 -0700166 memset(workspace, 0, workspaceSize); /* may be a bit generous, could memset be smaller ? */
Yann Colletc7fe2622017-05-23 13:16:00 -0700167 cctx->staticSize = workspaceSize;
168 cctx->workSpace = (void*)(cctx+1);
169 cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
170
171 /* entropy space (never moves) */
Yann Collet7bd1a292017-06-21 11:50:33 -0700172 /* note : this code should be shared with resetCCtx, rather than copy/pasted */
Yann Colletc7fe2622017-05-23 13:16:00 -0700173 { void* ptr = cctx->workSpace;
174 cctx->hufCTable = (HUF_CElt*)ptr;
Yann Collet0fdc71c2017-05-24 17:41:41 -0700175 ptr = (char*)cctx->hufCTable + hufCTable_size;
Yann Colletc7fe2622017-05-23 13:16:00 -0700176 cctx->offcodeCTable = (FSE_CTable*) ptr;
177 ptr = (char*)ptr + offcodeCTable_size;
178 cctx->matchlengthCTable = (FSE_CTable*) ptr;
179 ptr = (char*)ptr + matchlengthCTable_size;
180 cctx->litlengthCTable = (FSE_CTable*) ptr;
181 ptr = (char*)ptr + litlengthCTable_size;
182 assert(((size_t)ptr & 3) == 0); /* ensure correct alignment */
183 cctx->entropyScratchSpace = (unsigned*) ptr;
184 }
185
186 return cctx;
187}
188
Yann Collet5be2dd22015-11-11 13:43:58 +0100189size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100190{
inikep36403962016-06-03 16:36:50 +0200191 if (cctx==NULL) return 0; /* support free on NULL */
Yann Colletc4a5a212017-06-01 17:56:14 -0700192 if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */
Yann Collet23b6e052016-08-28 21:05:43 -0700193 ZSTD_free(cctx->workSpace, cctx->customMem);
Yann Collet78553662017-05-08 17:15:00 -0700194 cctx->workSpace = NULL;
195 ZSTD_freeCDict(cctx->cdictLocal);
196 cctx->cdictLocal = NULL;
Yann Colletc4a5a212017-06-01 17:56:14 -0700197 ZSTDMT_freeCCtx(cctx->mtctx);
198 cctx->mtctx = NULL;
Yann Collet23b6e052016-08-28 21:05:43 -0700199 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100200 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100201}
202
Yann Collet70e3b312016-08-23 01:18:06 +0200203size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200204{
Yann Colletd7c65892016-09-15 02:50:27 +0200205 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet7bd1a292017-06-21 11:50:33 -0700206 DEBUGLOG(5, "sizeof(*cctx) : %u", (U32)sizeof(*cctx));
207 DEBUGLOG(5, "workSpaceSize : %u", (U32)cctx->workSpaceSize);
208 DEBUGLOG(5, "streaming buffers : %u", (U32)(cctx->outBuffSize + cctx->inBuffSize));
209 DEBUGLOG(5, "inner MTCTX : %u", (U32)ZSTDMT_sizeof_CCtx(cctx->mtctx));
Yann Collet791d7442017-05-08 16:17:30 -0700210 return sizeof(*cctx) + cctx->workSpaceSize
211 + ZSTD_sizeof_CDict(cctx->cdictLocal)
Yann Colletc4a5a212017-06-01 17:56:14 -0700212 + cctx->outBuffSize + cctx->inBuffSize
213 + ZSTDMT_sizeof_CCtx(cctx->mtctx);
Yann Collet3ae543c2016-07-11 03:12:17 +0200214}
215
Yann Collet009d6042017-05-19 10:17:59 -0700216size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
217{
218 return ZSTD_sizeof_CCtx(zcs); /* same object */
219}
220
Yann Colletb0edb7f2017-05-12 15:31:53 -0700221/* private API call, for dictBuilder only */
222const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
223
Yann Collet1ad7c822017-05-22 17:06:04 -0700224static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return cctx->appliedParams; }
Yann Colletb0edb7f2017-05-12 15:31:53 -0700225
Yann Colletef738c12017-05-12 13:53:46 -0700226/* older variant; will be deprecated */
Yann Colletbb002742017-01-25 16:25:38 -0800227size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
228{
229 switch(param)
230 {
Yann Collet06e76972017-01-25 16:39:03 -0800231 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
Yann Collet7bd1a292017-06-21 11:50:33 -0700232 ZSTD_STATIC_ASSERT(ZSTD_dm_auto==0);
233 ZSTD_STATIC_ASSERT(ZSTD_dm_rawContent==1);
234 case ZSTD_p_forceRawDict : cctx->dictMode = (ZSTD_dictMode_e)(value>0); return 0;
Yann Colletbb002742017-01-25 16:25:38 -0800235 default: return ERROR(parameter_unknown);
236 }
237}
238
Yann Colletadd66f82017-05-12 15:59:48 -0700239
Yann Collet6d4fef32017-05-17 18:36:15 -0700240#define ZSTD_CLEVEL_CUSTOM 999
Yann Colletadd66f82017-05-12 15:59:48 -0700241static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx)
242{
Yann Collet1ad7c822017-05-22 17:06:04 -0700243 if (cctx->compressionLevel==ZSTD_CLEVEL_CUSTOM) return;
244 cctx->requestedParams.cParams = ZSTD_getCParams(cctx->compressionLevel,
Yann Colleta0ba8492017-06-16 13:29:17 -0700245 cctx->pledgedSrcSizePlusOne-1, 0);
Yann Collet6d4fef32017-05-17 18:36:15 -0700246 cctx->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Colletadd66f82017-05-12 15:59:48 -0700247}
248
Yann Colletc3bce242017-06-20 16:09:11 -0700249#define CLAMPCHECK(val,min,max) { \
250 if (((val)<(min)) | ((val)>(max))) { \
251 return ERROR(compressionParameter_outOfBound); \
252} }
253
Yann Colletb0edb7f2017-05-12 15:31:53 -0700254size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value)
Yann Collet7d360282016-02-12 00:07:30 +0100255{
Yann Collet24de7b02017-05-22 13:05:45 -0700256 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700257
258 switch(param)
259 {
260 case ZSTD_p_compressionLevel :
Yann Colletcd2892f2017-06-01 09:44:54 -0700261 if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel(); /* cap max compression level */
262 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700263 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700264 cctx->compressionLevel = value;
265 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700266
267 case ZSTD_p_windowLog :
Yann Colletd7a3bff2017-06-19 11:53:01 -0700268 DEBUGLOG(5, "setting ZSTD_p_windowLog = %u (cdict:%u)",
269 value, (cctx->cdict!=NULL));
Yann Colletcd2892f2017-06-01 09:44:54 -0700270 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700271 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700272 CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
273 ZSTD_cLevelToCParams(cctx);
274 cctx->requestedParams.cParams.windowLog = value;
275 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700276
277 case ZSTD_p_hashLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700278 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700279 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700280 CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
281 ZSTD_cLevelToCParams(cctx);
282 cctx->requestedParams.cParams.hashLog = value;
283 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700284
285 case ZSTD_p_chainLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700286 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700287 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700288 CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
289 ZSTD_cLevelToCParams(cctx);
290 cctx->requestedParams.cParams.chainLog = value;
291 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700292
293 case ZSTD_p_searchLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700294 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700295 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700296 CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
297 ZSTD_cLevelToCParams(cctx);
298 cctx->requestedParams.cParams.searchLog = value;
299 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700300
Yann Collet6d4fef32017-05-17 18:36:15 -0700301 case ZSTD_p_minMatch :
Yann Colletcd2892f2017-06-01 09:44:54 -0700302 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700303 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700304 CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
305 ZSTD_cLevelToCParams(cctx);
306 cctx->requestedParams.cParams.searchLength = value;
307 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700308
309 case ZSTD_p_targetLength :
Yann Colletcd2892f2017-06-01 09:44:54 -0700310 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700311 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700312 CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
313 ZSTD_cLevelToCParams(cctx);
314 cctx->requestedParams.cParams.targetLength = value;
315 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700316
317 case ZSTD_p_compressionStrategy :
Yann Colletcd2892f2017-06-01 09:44:54 -0700318 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700319 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700320 CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
321 ZSTD_cLevelToCParams(cctx);
322 cctx->requestedParams.cParams.strategy = (ZSTD_strategy)value;
323 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700324
325#if 0
326 case ZSTD_p_windowSize : /* to be done later */
Yann Colletcd2892f2017-06-01 09:44:54 -0700327 return ERROR(compressionParameter_unsupported);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700328#endif
329
Yann Colletcd2892f2017-06-01 09:44:54 -0700330 case ZSTD_p_contentSizeFlag :
Yann Collet2cf77552017-06-16 12:34:41 -0700331 DEBUGLOG(5, "set content size flag = %u", (value>0));
Yann Colletcd2892f2017-06-01 09:44:54 -0700332 /* Content size written in frame header _when known_ (default:1) */
333 cctx->requestedParams.fParams.contentSizeFlag = value>0;
334 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700335
Yann Colletcd2892f2017-06-01 09:44:54 -0700336 case ZSTD_p_checksumFlag :
337 /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
338 cctx->requestedParams.fParams.checksumFlag = value>0;
339 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700340
Yann Collet1ad7c822017-05-22 17:06:04 -0700341 case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
Yann Colletcd2892f2017-06-01 09:44:54 -0700342 DEBUGLOG(5, "set dictIDFlag = %u", (value>0));
343 cctx->requestedParams.fParams.noDictIDFlag = (value==0);
344 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700345
346 case ZSTD_p_refDictContent : /* to be done later */
Yann Colletcd2892f2017-06-01 09:44:54 -0700347 return ERROR(compressionParameter_unsupported);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700348
Yann Collet7bd1a292017-06-21 11:50:33 -0700349 case ZSTD_p_dictMode :
350 /* restrict dictionary mode, to "rawContent" or "fullDict" only */
351 ZSTD_STATIC_ASSERT((U32)ZSTD_dm_fullDict > (U32)ZSTD_dm_rawContent);
352 if (value > (unsigned)ZSTD_dm_fullDict)
353 return ERROR(compressionParameter_outOfBound);
354 cctx->dictMode = (ZSTD_dictMode_e)value;
355 return 0;
356
Yann Colletb0edb7f2017-05-12 15:31:53 -0700357 case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize,
358 * even when referencing into Dictionary content
359 * default : 0 when using a CDict, 1 when using a Prefix */
Yann Colletc35e5352017-06-01 18:44:06 -0700360 cctx->forceWindow = value>0;
361 cctx->loadedDictEnd = 0;
362 return 0;
363
364 case ZSTD_p_nbThreads:
365 if (value==0) return 0;
Yann Collet33873f02017-06-16 12:04:21 -0700366 DEBUGLOG(5, " setting nbThreads : %u", value);
Yann Colletc35e5352017-06-01 18:44:06 -0700367#ifndef ZSTD_MULTITHREAD
368 if (value > 1) return ERROR(compressionParameter_unsupported);
369#endif
370 if ((value>1) && (cctx->nbThreads != value)) {
Yann Collet05ae4b22017-06-15 18:03:34 -0700371 if (cctx->staticSize) /* MT not compatible with static alloc */
372 return ERROR(compressionParameter_unsupported);
Yann Colletc35e5352017-06-01 18:44:06 -0700373 ZSTDMT_freeCCtx(cctx->mtctx);
Yann Collet559ee822017-06-16 11:58:21 -0700374 cctx->nbThreads = 1;
Yann Colletc35e5352017-06-01 18:44:06 -0700375 cctx->mtctx = ZSTDMT_createCCtx(value);
376 if (cctx->mtctx == NULL) return ERROR(memory_allocation);
Yann Collet33873f02017-06-16 12:04:21 -0700377 }
378 cctx->nbThreads = value;
Yann Colletc35e5352017-06-01 18:44:06 -0700379 return 0;
380
Yann Collet559ee822017-06-16 11:58:21 -0700381 case ZSTD_p_jobSize:
Yann Colletc35e5352017-06-01 18:44:06 -0700382 if (cctx->nbThreads <= 1) return ERROR(compressionParameter_unsupported);
383 assert(cctx->mtctx != NULL);
384 return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_sectionSize, value);
385
Yann Collet559ee822017-06-16 11:58:21 -0700386 case ZSTD_p_overlapSizeLog:
Yann Collet33873f02017-06-16 12:04:21 -0700387 DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->nbThreads);
Yann Colletc35e5352017-06-01 18:44:06 -0700388 if (cctx->nbThreads <= 1) return ERROR(compressionParameter_unsupported);
389 assert(cctx->mtctx != NULL);
390 return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_overlapSectionLog, value);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700391
Yann Colletb0edb7f2017-05-12 15:31:53 -0700392 default: return ERROR(parameter_unknown);
393 }
Yann Collet7d360282016-02-12 00:07:30 +0100394}
395
Yann Colletb0edb7f2017-05-12 15:31:53 -0700396ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
Yann Collet95162342016-10-25 16:19:52 -0700397{
Yann Collet2cf77552017-06-16 12:34:41 -0700398 DEBUGLOG(5, " setting pledgedSrcSize to %u", (U32)pledgedSrcSize);
Yann Collet24de7b02017-05-22 13:05:45 -0700399 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colleta0ba8492017-06-16 13:29:17 -0700400 cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700401 return 0;
402}
403
Yann Collet6d4fef32017-05-17 18:36:15 -0700404ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
405{
Yann Collet24de7b02017-05-22 13:05:45 -0700406 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletc7fe2622017-05-23 13:16:00 -0700407 if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700408 DEBUGLOG(5, "load dictionary of size %u", (U32)dictSize);
Yann Collet6d4fef32017-05-17 18:36:15 -0700409 ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */
410 if (dict==NULL || dictSize==0) { /* no dictionary mode */
411 cctx->cdictLocal = NULL;
412 cctx->cdict = NULL;
413 } else {
Yann Collet8b21ec42017-05-19 19:46:15 -0700414 ZSTD_compressionParameters const cParams =
415 cctx->compressionLevel == ZSTD_CLEVEL_CUSTOM ?
Yann Collet1ad7c822017-05-22 17:06:04 -0700416 cctx->requestedParams.cParams :
Yann Collet8b21ec42017-05-19 19:46:15 -0700417 ZSTD_getCParams(cctx->compressionLevel, 0, dictSize);
Yann Collet6d4fef32017-05-17 18:36:15 -0700418 cctx->cdictLocal = ZSTD_createCDict_advanced(
419 dict, dictSize,
Yann Collet7bd1a292017-06-21 11:50:33 -0700420 0 /* byReference */, cctx->dictMode,
Yann Collet8b21ec42017-05-19 19:46:15 -0700421 cParams, cctx->customMem);
Yann Collet6d4fef32017-05-17 18:36:15 -0700422 cctx->cdict = cctx->cdictLocal;
423 if (cctx->cdictLocal == NULL)
424 return ERROR(memory_allocation);
425 }
426 return 0;
427}
428
Yann Colletb0edb7f2017-05-12 15:31:53 -0700429/* Not ready yet ! */
Yann Colletbd18c882017-06-16 10:17:50 -0700430size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
Yann Colletb0edb7f2017-05-12 15:31:53 -0700431{
432 (void)cctx; (void)prefix; (void)prefixSize; /* to be done later */
Yann Collet24de7b02017-05-22 13:05:45 -0700433 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700434 return ERROR(compressionParameter_unsupported);
435}
436
Yann Colletbd18c882017-06-16 10:17:50 -0700437size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
Yann Colletb0edb7f2017-05-12 15:31:53 -0700438{
Yann Collet24de7b02017-05-22 13:05:45 -0700439 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
440 cctx->cdict = cdict;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700441 return ERROR(compressionParameter_unsupported);
Yann Collet95162342016-10-25 16:19:52 -0700442}
443
Yann Colletb26728c2017-06-16 14:00:46 -0700444static void ZSTD_startNewCompression(ZSTD_CCtx* cctx)
Yann Colletbd18c882017-06-16 10:17:50 -0700445{
446 cctx->streamStage = zcss_init;
Yann Colleta0ba8492017-06-16 13:29:17 -0700447 cctx->pledgedSrcSizePlusOne = 0;
Yann Colletb26728c2017-06-16 14:00:46 -0700448}
449
450/*! ZSTD_CCtx_reset() :
451 * Also dumps dictionary */
452void ZSTD_CCtx_reset(ZSTD_CCtx* cctx)
453{
454 ZSTD_startNewCompression(cctx);
Yann Colletbd18c882017-06-16 10:17:50 -0700455 cctx->cdict = NULL;
456}
457
Yann Collet381e66c2017-06-16 17:29:35 -0700458/** ZSTD_checkCParams() :
459 control CParam values remain within authorized range.
Yann Collet21588e32016-03-30 16:50:44 +0200460 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200461size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200462{
Yann Collet15354142016-04-04 04:22:53 +0200463 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200464 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200465 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
466 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Collet2e2e78d2017-03-29 16:02:47 -0700467 CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200468 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800469 if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200470 return 0;
471}
472
Yann Collet381e66c2017-06-16 17:29:35 -0700473/** ZSTD_clampCParams() :
474 * make CParam values within valid range.
475 * @return : valid CParams */
476static ZSTD_compressionParameters ZSTD_clampCParams(ZSTD_compressionParameters cParams)
477{
478# define CLAMP(val,min,max) { \
479 if (val<min) val=min; \
480 else if (val>max) val=max; \
481 }
482 CLAMP(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
483 CLAMP(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
484 CLAMP(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
485 CLAMP(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
486 CLAMP(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
487 CLAMP(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
488 if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) cParams.strategy = ZSTD_btultra;
489 return cParams;
490}
491
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100492/** ZSTD_cycleLog() :
493 * condition for correct operation : hashLog > 1 */
494static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
495{
496 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
497 return hashLog - btScale;
498}
499
Yann Collet381e66c2017-06-16 17:29:35 -0700500/** ZSTD_adjustCParams_internal() :
Yann Colletcf409a72016-09-26 16:41:05 +0200501 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200502 mostly downsizing to reduce memory consumption and initialization.
503 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
504 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200505 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet381e66c2017-06-16 17:29:35 -0700506ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100507{
Yann Collet381e66c2017-06-16 17:29:35 -0700508 assert(ZSTD_checkCParams(cPar)==0);
Yann Collet70d13012016-06-01 18:45:34 +0200509 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100510
Yann Collet70e45772016-03-19 18:08:32 +0100511 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200512 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
513 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200514 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200515 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200516 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200517 } }
Yann Collet70d13012016-06-01 18:45:34 +0200518 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100519 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
520 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
521 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100522
Yann Collet70d13012016-06-01 18:45:34 +0200523 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200524
525 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100526}
527
Yann Collet381e66c2017-06-16 17:29:35 -0700528ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
529{
530 cPar = ZSTD_clampCParams(cPar);
531 return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
532}
533
Yann Collet59d70632015-11-04 12:05:27 +0100534
Yann Collet88472382016-07-14 17:05:38 +0200535size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100536{
Yann Colletfa3671e2017-05-19 10:51:30 -0700537 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
Yann Collet731ef162016-07-27 21:05:12 +0200538 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
539 size_t const maxNbSeq = blockSize / divider;
540 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200541
Yann Collet731ef162016-07-27 21:05:12 +0200542 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
543 size_t const hSize = ((size_t)1) << cParams.hashLog;
544 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
545 size_t const h3Size = ((size_t)1) << hashLog3;
Yann Collet71ddeb62017-04-20 22:54:54 -0700546 size_t const entropySpace = hufCTable_size + litlengthCTable_size
Yann Colleta4086452017-04-20 23:09:39 -0700547 + offcodeCTable_size + matchlengthCTable_size
Yann Collet72712032017-04-20 23:21:19 -0700548 + entropyScratchSpace_size;
Yann Collet731ef162016-07-27 21:05:12 +0200549 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200550
Yann Colletfc514592017-05-08 17:07:59 -0700551 size_t const optBudget = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
Yann Collet3ae543c2016-07-11 03:12:17 +0200552 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
Nick Terrell5f2c7212017-05-10 16:49:58 -0700553 size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
Yann Colletfc514592017-05-08 17:07:59 -0700554 size_t const neededSpace = entropySpace + tableSpace + tokenSpace + optSpace;
Yann Collet3ae543c2016-07-11 03:12:17 +0200555
Yann Collet7bd1a292017-06-21 11:50:33 -0700556 DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
557 DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace);
Yann Collet3ae543c2016-07-11 03:12:17 +0200558 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100559}
560
Yann Colletc7fe2622017-05-23 13:16:00 -0700561size_t ZSTD_estimateCStreamSize(ZSTD_compressionParameters cParams)
562{
563 size_t const CCtxSize = ZSTD_estimateCCtxSize(cParams);
564 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
565 size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
566 size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
567 size_t const streamingSize = inBuffSize + outBuffSize;
568
569 return CCtxSize + streamingSize;
570}
571
Yann Colleta7737f62016-09-06 09:44:59 +0200572
Yann Collet009d6042017-05-19 10:17:59 -0700573static U32 ZSTD_equivalentParams(ZSTD_compressionParameters cParams1,
574 ZSTD_compressionParameters cParams2)
Yann Colleta7737f62016-09-06 09:44:59 +0200575{
Yann Colletfa3671e2017-05-19 10:51:30 -0700576 U32 bslog1 = MIN(cParams1.windowLog, ZSTD_BLOCKSIZELOG_MAX);
577 U32 bslog2 = MIN(cParams2.windowLog, ZSTD_BLOCKSIZELOG_MAX);
Yann Collet009d6042017-05-19 10:17:59 -0700578 return (bslog1 == bslog2) /* same block size */
579 & (cParams1.hashLog == cParams2.hashLog)
580 & (cParams1.chainLog == cParams2.chainLog)
581 & (cParams1.strategy == cParams2.strategy) /* opt parser space */
582 & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */
Yann Colleta7737f62016-09-06 09:44:59 +0200583}
584
585/*! ZSTD_continueCCtx() :
Yann Colletc08e6492017-06-19 18:25:35 -0700586 * reuse CCtx without reset (note : requires no dictionary) */
Yann Colletb26728c2017-06-16 14:00:46 -0700587static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colleta7737f62016-09-06 09:44:59 +0200588{
589 U32 const end = (U32)(cctx->nextSrc - cctx->base);
Yann Collet2cf77552017-06-16 12:34:41 -0700590 DEBUGLOG(5, "continue mode");
Yann Collet1ad7c822017-05-22 17:06:04 -0700591 cctx->appliedParams = params;
Yann Colletb26728c2017-06-16 14:00:46 -0700592 cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
Yann Collet20d5e032017-04-11 18:34:02 -0700593 cctx->consumedSrcSize = 0;
Yann Colletb26728c2017-06-16 14:00:46 -0700594 if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
Yann Collet2cf77552017-06-16 12:34:41 -0700595 cctx->appliedParams.fParams.contentSizeFlag = 0;
Yann Colletb26728c2017-06-16 14:00:46 -0700596 DEBUGLOG(5, "pledged content size : %u ; flag : %u",
597 (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
Yann Colleta7737f62016-09-06 09:44:59 +0200598 cctx->lowLimit = end;
599 cctx->dictLimit = end;
600 cctx->nextToUpdate = end+1;
601 cctx->stage = ZSTDcs_init;
602 cctx->dictID = 0;
603 cctx->loadedDictEnd = 0;
604 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200605 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
606 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200607 return 0;
608}
609
Yann Colletb0739bc2017-05-22 17:45:15 -0700610typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
Yann Colleta7737f62016-09-06 09:44:59 +0200611
Yann Collet30fb4992017-04-18 14:08:50 -0700612/*! ZSTD_resetCCtx_internal() :
Yann Collet5ac72b42017-05-23 11:18:24 -0700613 note : `params` are assumed fully validated at this stage */
614static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
Yann Colleta0ba8492017-06-16 13:29:17 -0700615 ZSTD_parameters params, U64 pledgedSrcSize,
Yann Collet5ac72b42017-05-23 11:18:24 -0700616 ZSTD_compResetPolicy_e const crp,
617 ZSTD_buffered_policy_e const zbuff)
Yann Colleta7737f62016-09-06 09:44:59 +0200618{
Yann Collet5ac72b42017-05-23 11:18:24 -0700619 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet0be6fd32017-05-08 16:08:01 -0700620
Yann Colletb0739bc2017-05-22 17:45:15 -0700621 if (crp == ZSTDcrp_continue) {
Yann Collet1ad7c822017-05-22 17:06:04 -0700622 if (ZSTD_equivalentParams(params.cParams, zc->appliedParams.cParams)) {
Yann Collet009d6042017-05-19 10:17:59 -0700623 DEBUGLOG(5, "ZSTD_equivalentParams()==1");
Yann Collet71ddeb62017-04-20 22:54:54 -0700624 zc->fseCTables_ready = 0;
625 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta0ba8492017-06-16 13:29:17 -0700626 return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
Yann Colletb0739bc2017-05-22 17:45:15 -0700627 } }
inikep87d4f3d2016-03-02 15:56:24 +0100628
Yann Colletfa3671e2017-05-19 10:51:30 -0700629 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200630 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
631 size_t const maxNbSeq = blockSize / divider;
632 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet5ac72b42017-05-23 11:18:24 -0700633 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ?
634 0 : (1 << params.cParams.chainLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200635 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
Yann Collet5ac72b42017-05-23 11:18:24 -0700636 U32 const hashLog3 = (params.cParams.searchLength>3) ?
637 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200638 size_t const h3Size = ((size_t)1) << hashLog3;
639 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet7bd1a292017-06-21 11:50:33 -0700640 size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
641 size_t const buffInSize = (zbuff==ZSTDb_buffered) ? ((size_t)1 << params.cParams.windowLog) + blockSize : 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200642 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100643
Yann Colleta7737f62016-09-06 09:44:59 +0200644 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Collet71ddeb62017-04-20 22:54:54 -0700645 { size_t const entropySpace = hufCTable_size + litlengthCTable_size
Yann Colleta4086452017-04-20 23:09:39 -0700646 + offcodeCTable_size + matchlengthCTable_size
Yann Collet72712032017-04-20 23:21:19 -0700647 + entropyScratchSpace_size;
Yann Collet71ddeb62017-04-20 22:54:54 -0700648 size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
Yann Collete6fa70a2017-04-20 17:28:31 -0700649 + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
Yann Collet5ac72b42017-05-23 11:18:24 -0700650 size_t const optSpace = ( (params.cParams.strategy == ZSTD_btopt)
651 || (params.cParams.strategy == ZSTD_btultra)) ?
652 optPotentialSpace : 0;
Yann Collet7bd1a292017-06-21 11:50:33 -0700653 size_t const bufferSpace = buffInSize + buffOutSize;
Yann Collet5ac72b42017-05-23 11:18:24 -0700654 size_t const neededSpace = entropySpace + optSpace + tableSpace
655 + tokenSpace + bufferSpace;
Yann Colletc7fe2622017-05-23 13:16:00 -0700656
657 if (zc->workSpaceSize < neededSpace) { /* too small : resize /*/
Yann Collet0be6fd32017-05-08 16:08:01 -0700658 DEBUGLOG(5, "Need to update workSpaceSize from %uK to %uK \n",
Yann Colletc7fe2622017-05-23 13:16:00 -0700659 (unsigned)zc->workSpaceSize>>10,
660 (unsigned)neededSpace>>10);
661 /* static cctx : no resize, error out */
662 if (zc->staticSize) return ERROR(memory_allocation);
663
Yann Collet0181fef2017-04-06 01:25:26 -0700664 zc->workSpaceSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200665 ZSTD_free(zc->workSpace, zc->customMem);
666 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
667 if (zc->workSpace == NULL) return ERROR(memory_allocation);
668 zc->workSpaceSize = neededSpace;
Yann Collet7bb60b12017-04-20 17:38:56 -0700669 ptr = zc->workSpace;
670
671 /* entropy space */
Yann Collet71ddeb62017-04-20 22:54:54 -0700672 zc->hufCTable = (HUF_CElt*)ptr;
673 ptr = (char*)zc->hufCTable + hufCTable_size; /* note : HUF_CElt* is incomplete type, size is estimated via macro */
Yann Collet71aaa322017-04-20 23:03:38 -0700674 zc->offcodeCTable = (FSE_CTable*) ptr;
675 ptr = (char*)ptr + offcodeCTable_size;
Yann Collet72712032017-04-20 23:21:19 -0700676 zc->matchlengthCTable = (FSE_CTable*) ptr;
Yann Collet71aaa322017-04-20 23:03:38 -0700677 ptr = (char*)ptr + matchlengthCTable_size;
Yann Collet72712032017-04-20 23:21:19 -0700678 zc->litlengthCTable = (FSE_CTable*) ptr;
679 ptr = (char*)ptr + litlengthCTable_size;
680 assert(((size_t)ptr & 3) == 0); /* ensure correct alignment */
Yann Collete42afbc2017-04-26 11:39:35 -0700681 zc->entropyScratchSpace = (unsigned*) ptr;
Yann Colleta7737f62016-09-06 09:44:59 +0200682 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100683
Yann Collete6fa70a2017-04-20 17:28:31 -0700684 /* init params */
Yann Collet1ad7c822017-05-22 17:06:04 -0700685 zc->appliedParams = params;
Yann Colleta0ba8492017-06-16 13:29:17 -0700686 zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
Yann Collete6fa70a2017-04-20 17:28:31 -0700687 zc->consumedSrcSize = 0;
Yann Colleta0ba8492017-06-16 13:29:17 -0700688 if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
Yann Colletcc9f9b72017-06-15 18:17:10 -0700689 zc->appliedParams.fParams.contentSizeFlag = 0;
Yann Colletb26728c2017-06-16 14:00:46 -0700690 DEBUGLOG(5, "pledged content size : %u ; flag : %u",
691 (U32)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag);
Yann Colletcc9f9b72017-06-15 18:17:10 -0700692 zc->blockSize = blockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100693
Yann Collet083fcc82015-10-25 14:06:35 +0100694 XXH64_reset(&zc->xxhState, 0);
Yann Collete6fa70a2017-04-20 17:28:31 -0700695 zc->stage = ZSTDcs_init;
696 zc->dictID = 0;
697 zc->loadedDictEnd = 0;
Yann Collet71ddeb62017-04-20 22:54:54 -0700698 zc->fseCTables_ready = 0;
699 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200700 zc->nextToUpdate = 1;
701 zc->nextSrc = NULL;
702 zc->base = NULL;
703 zc->dictBase = NULL;
704 zc->dictLimit = 0;
705 zc->lowLimit = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200706 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
Yann Collete6fa70a2017-04-20 17:28:31 -0700707 zc->hashLog3 = hashLog3;
708 zc->seqStore.litLengthSum = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200709
Yann Collet71aaa322017-04-20 23:03:38 -0700710 /* ensure entropy tables are close together at the beginning */
711 assert((void*)zc->hufCTable == zc->workSpace);
712 assert((char*)zc->offcodeCTable == (char*)zc->hufCTable + hufCTable_size);
713 assert((char*)zc->matchlengthCTable == (char*)zc->offcodeCTable + offcodeCTable_size);
714 assert((char*)zc->litlengthCTable == (char*)zc->matchlengthCTable + matchlengthCTable_size);
Yann Collete42afbc2017-04-26 11:39:35 -0700715 assert((char*)zc->entropyScratchSpace == (char*)zc->litlengthCTable + litlengthCTable_size);
716 ptr = (char*)zc->entropyScratchSpace + entropyScratchSpace_size;
Yann Collete6fa70a2017-04-20 17:28:31 -0700717
718 /* opt parser space */
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800719 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) {
Yann Collet009d6042017-05-19 10:17:59 -0700720 DEBUGLOG(5, "reserving optimal parser space");
Yann Collete6fa70a2017-04-20 17:28:31 -0700721 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
Yann Colleta7737f62016-09-06 09:44:59 +0200722 zc->seqStore.litFreq = (U32*)ptr;
723 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
724 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
725 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
726 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
727 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
728 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
729 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
730 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
Yann Colleta7737f62016-09-06 09:44:59 +0200731 }
Yann Collete6fa70a2017-04-20 17:28:31 -0700732
733 /* table Space */
734 if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
735 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
736 zc->hashTable = (U32*)(ptr);
737 zc->chainTable = zc->hashTable + hSize;
738 zc->hashTable3 = zc->chainTable + chainSize;
739 ptr = zc->hashTable3 + h3Size;
740
741 /* sequences storage */
Yann Colleta7737f62016-09-06 09:44:59 +0200742 zc->seqStore.sequencesStart = (seqDef*)ptr;
743 ptr = zc->seqStore.sequencesStart + maxNbSeq;
744 zc->seqStore.llCode = (BYTE*) ptr;
745 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
746 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
747 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
Yann Collet5ac72b42017-05-23 11:18:24 -0700748 ptr = zc->seqStore.litStart + blockSize;
749
750 /* buffers */
751 zc->inBuffSize = buffInSize;
752 zc->inBuff = (char*)ptr;
753 zc->outBuffSize = buffOutSize;
754 zc->outBuff = zc->inBuff + buffInSize;
Yann Colleta7737f62016-09-06 09:44:59 +0200755
Yann Colleta7737f62016-09-06 09:44:59 +0200756 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100757 }
Yann Colletf3eca252015-10-22 15:31:46 +0100758}
759
Yann Collet32dfae62017-01-19 10:32:55 -0800760/* ZSTD_invalidateRepCodes() :
761 * ensures next compression will not use repcodes from previous block.
762 * Note : only works with regular variant;
763 * do not use with extDict variant ! */
764void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
765 int i;
766 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0;
767}
Yann Collet083fcc82015-10-25 14:06:35 +0100768
Yann Collet7b51a292016-01-26 15:58:49 +0100769
Yann Colleta4cab802017-04-18 14:54:54 -0700770/*! ZSTD_copyCCtx_internal() :
771 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
772 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
773 * pledgedSrcSize=0 means "empty" if fParams.contentSizeFlag=1
774 * @return : 0, or an error code */
Yann Collet1ad7c822017-05-22 17:06:04 -0700775static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
776 const ZSTD_CCtx* srcCCtx,
777 ZSTD_frameParameters fParams,
778 unsigned long long pledgedSrcSize)
Yann Collet7b51a292016-01-26 15:58:49 +0100779{
Yann Collet009d6042017-05-19 10:17:59 -0700780 DEBUGLOG(5, "ZSTD_copyCCtx_internal");
Yann Collet7b51a292016-01-26 15:58:49 +0100781 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Sean Purcell2db72492017-02-09 10:50:43 -0800782
inikep28669512016-06-02 13:04:18 +0200783 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Yann Collet5ac72b42017-05-23 11:18:24 -0700784 { ZSTD_buffered_policy_e const zbuff = srcCCtx->inBuffSize ?
785 ZSTDb_buffered : ZSTDb_not_buffered;
786 ZSTD_parameters params = srcCCtx->appliedParams;
Yann Colleta4cab802017-04-18 14:54:54 -0700787 params.fParams = fParams;
Yann Collet5ac72b42017-05-23 11:18:24 -0700788 ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
789 ZSTDcrp_noMemset, zbuff);
Sean Purcell2db72492017-02-09 10:50:43 -0800790 }
Yann Collet7b51a292016-01-26 15:58:49 +0100791
792 /* copy tables */
Yann Collet1ad7c822017-05-22 17:06:04 -0700793 { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->appliedParams.cParams.chainLog);
794 size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +0200795 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
796 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collete6fa70a2017-04-20 17:28:31 -0700797 assert((U32*)dstCCtx->chainTable == (U32*)dstCCtx->hashTable + hSize); /* chainTable must follow hashTable */
798 assert((U32*)dstCCtx->hashTable3 == (U32*)dstCCtx->chainTable + chainSize);
799 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); /* presumes all tables follow each other */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100800 }
Yann Collet7b51a292016-01-26 15:58:49 +0100801
Yann Colletc46fb922016-05-29 05:01:04 +0200802 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100803 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
804 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
805 dstCCtx->nextSrc = srcCCtx->nextSrc;
806 dstCCtx->base = srcCCtx->base;
807 dstCCtx->dictBase = srcCCtx->dictBase;
808 dstCCtx->dictLimit = srcCCtx->dictLimit;
809 dstCCtx->lowLimit = srcCCtx->lowLimit;
810 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200811 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100812
Yann Colletfb810d62016-01-28 00:18:06 +0100813 /* copy entropy tables */
Yann Collet71ddeb62017-04-20 22:54:54 -0700814 dstCCtx->fseCTables_ready = srcCCtx->fseCTables_ready;
815 if (srcCCtx->fseCTables_ready) {
Yann Colleta34a39c2017-04-20 18:17:58 -0700816 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, litlengthCTable_size);
817 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, matchlengthCTable_size);
818 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, offcodeCTable_size);
Yann Colletfb810d62016-01-28 00:18:06 +0100819 }
Yann Collet71ddeb62017-04-20 22:54:54 -0700820 dstCCtx->hufCTable_repeatMode = srcCCtx->hufCTable_repeatMode;
821 if (srcCCtx->hufCTable_repeatMode) {
822 memcpy(dstCCtx->hufCTable, srcCCtx->hufCTable, hufCTable_size);
Nick Terrella4197772017-03-01 17:51:56 -0800823 }
Yann Collet7b51a292016-01-26 15:58:49 +0100824
825 return 0;
826}
827
Yann Colleta4cab802017-04-18 14:54:54 -0700828/*! ZSTD_copyCCtx() :
829 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
830 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
831 * pledgedSrcSize==0 means "unknown".
832* @return : 0, or an error code */
833size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
834{
835 ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
836 fParams.contentSizeFlag = pledgedSrcSize>0;
837
838 return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, fParams, pledgedSrcSize);
839}
840
Yann Collet7b51a292016-01-26 15:58:49 +0100841
Yann Colletecabfe32016-03-20 16:20:06 +0100842/*! ZSTD_reduceTable() :
Yann Colleta4cab802017-04-18 14:54:54 -0700843 * reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100844static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100845{
Yann Colletecabfe32016-03-20 16:20:06 +0100846 U32 u;
847 for (u=0 ; u < size ; u++) {
848 if (table[u] < reducerValue) table[u] = 0;
849 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100850 }
851}
852
Yann Colletecabfe32016-03-20 16:20:06 +0100853/*! ZSTD_reduceIndex() :
854* rescale all indexes to avoid future overflow (indexes are U32) */
855static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
856{
Yann Collet1ad7c822017-05-22 17:06:04 -0700857 { U32 const hSize = 1 << zc->appliedParams.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100858 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
859
Yann Collet1ad7c822017-05-22 17:06:04 -0700860 { U32 const chainSize = (zc->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->appliedParams.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200861 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100862
Yann Collet731ef162016-07-27 21:05:12 +0200863 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100864 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
865}
866
Yann Collet89db5e02015-11-13 11:27:46 +0100867
Yann Collet863ec402016-01-28 17:56:33 +0100868/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100869* Block entropic compression
870*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100871
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200872/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100873
Yann Colletd1b26842016-03-15 01:24:33 +0100874size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100875{
Yann Colletd1b26842016-03-15 01:24:33 +0100876 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200877 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
878 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100879 return ZSTD_blockHeaderSize+srcSize;
880}
881
882
Yann Colletd1b26842016-03-15 01:24:33 +0100883static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100884{
885 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200886 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100887
Yann Colletd1b26842016-03-15 01:24:33 +0100888 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100889
Yann Collet59d1f792016-01-23 19:28:41 +0100890 switch(flSize)
891 {
892 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200893 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100894 break;
895 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200896 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100897 break;
Yann Collet59d1f792016-01-23 19:28:41 +0100898 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200899 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100900 break;
Yann Colletcd2892f2017-06-01 09:44:54 -0700901 default: /* not necessary : flSize is {1,2,3} */
902 assert(0);
Yann Collet59d1f792016-01-23 19:28:41 +0100903 }
904
905 memcpy(ostart + flSize, src, srcSize);
906 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100907}
908
Yann Colletd1b26842016-03-15 01:24:33 +0100909static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100910{
911 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200912 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100913
Yann Collet198e6aa2016-07-20 20:12:24 +0200914 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100915
916 switch(flSize)
917 {
918 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200919 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100920 break;
921 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200922 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100923 break;
Yann Collet59d1f792016-01-23 19:28:41 +0100924 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200925 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100926 break;
Yann Colletcd2892f2017-06-01 09:44:54 -0700927 default: /* not necessary : flSize is {1,2,3} */
928 assert(0);
Yann Collet59d1f792016-01-23 19:28:41 +0100929 }
930
931 ostart[flSize] = *(const BYTE*)src;
932 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100933}
934
Yann Collet59d1f792016-01-23 19:28:41 +0100935
Yann Colleta5c2c082016-03-20 01:09:18 +0100936static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100937
Yann Colletb923f652016-01-26 03:14:20 +0100938static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100939 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100940 const void* src, size_t srcSize)
941{
Yann Colleta910dc82016-03-18 12:37:45 +0100942 size_t const minGain = ZSTD_minGain(srcSize);
943 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200944 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100945 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200946 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100947 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100948
Yann Collet14983e72015-11-11 21:38:21 +0100949
Yann Colleta5c2c082016-03-20 01:09:18 +0100950 /* small ? don't even attempt compression (speed opt) */
951# define LITERAL_NOENTROPY 63
Yann Collet71ddeb62017-04-20 22:54:54 -0700952 { size_t const minLitSize = zc->hufCTable_repeatMode == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
Yann Colleta5c2c082016-03-20 01:09:18 +0100953 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
954 }
955
956 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Collet71ddeb62017-04-20 22:54:54 -0700957 { HUF_repeat repeat = zc->hufCTable_repeatMode;
Yann Collet1ad7c822017-05-22 17:06:04 -0700958 int const preferRepeat = zc->appliedParams.cParams.strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
Nick Terrella4197772017-03-01 17:51:56 -0800959 if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
Yann Collete348dad2017-04-20 11:14:13 -0700960 cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Yann Collete42afbc2017-04-26 11:39:35 -0700961 zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat)
Yann Collete348dad2017-04-20 11:14:13 -0700962 : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Yann Collete42afbc2017-04-26 11:39:35 -0700963 zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat);
Nick Terrella4197772017-03-01 17:51:56 -0800964 if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
Yann Collet71ddeb62017-04-20 22:54:54 -0700965 else { zc->hufCTable_repeatMode = HUF_repeat_check; } /* now have a table to reuse */
Yann Colletb923f652016-01-26 03:14:20 +0100966 }
Yann Collet14983e72015-11-11 21:38:21 +0100967
Nick Terrella4197772017-03-01 17:51:56 -0800968 if ((cLitSize==0) | (cLitSize >= srcSize - minGain)) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700969 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100970 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800971 }
972 if (cLitSize==1) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700973 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100974 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800975 }
Yann Collet14983e72015-11-11 21:38:21 +0100976
977 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100978 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100979 {
Yann Collet59d1f792016-01-23 19:28:41 +0100980 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200981 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200982 MEM_writeLE24(ostart, lhc);
983 break;
984 }
Yann Collet59d1f792016-01-23 19:28:41 +0100985 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200986 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200987 MEM_writeLE32(ostart, lhc);
988 break;
989 }
Yann Collet59d1f792016-01-23 19:28:41 +0100990 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200991 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200992 MEM_writeLE32(ostart, lhc);
993 ostart[4] = (BYTE)(cLitSize >> 10);
994 break;
995 }
Yann Colletcd2892f2017-06-01 09:44:54 -0700996 default: /* not possible : lhSize is {3,4,5} */
997 assert(0);
Yann Collet14983e72015-11-11 21:38:21 +0100998 }
Yann Colleta910dc82016-03-18 12:37:45 +0100999 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +01001000}
1001
Yann Collet3b2bd1d2016-07-30 13:21:41 +02001002static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
1003 8, 9, 10, 11, 12, 13, 14, 15,
1004 16, 16, 17, 17, 18, 18, 19, 19,
1005 20, 20, 20, 20, 21, 21, 21, 21,
1006 22, 22, 22, 22, 22, 22, 22, 22,
1007 23, 23, 23, 23, 23, 23, 23, 23,
1008 24, 24, 24, 24, 24, 24, 24, 24,
1009 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +01001010
Yann Collet3b2bd1d2016-07-30 13:21:41 +02001011static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1012 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
1013 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
1014 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
1015 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
1016 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
1017 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
1018 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +02001019
1020
1021void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +01001022{
Yann Colleted57d852016-07-29 21:22:17 +02001023 BYTE const LL_deltaCode = 19;
1024 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +02001025 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +02001026 BYTE* const llCodeTable = seqStorePtr->llCode;
1027 BYTE* const ofCodeTable = seqStorePtr->ofCode;
1028 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +02001029 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +02001030 U32 u;
1031 for (u=0; u<nbSeq; u++) {
1032 U32 const llv = sequences[u].litLength;
1033 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +02001034 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +02001035 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +02001036 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +02001037 }
Yann Colleted57d852016-07-29 21:22:17 +02001038 if (seqStorePtr->longLengthID==1)
1039 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
1040 if (seqStorePtr->longLengthID==2)
1041 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +01001042}
1043
Sean Purcell553f67e2017-03-02 15:15:31 -08001044MEM_STATIC size_t ZSTD_compressSequences (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +01001045 void* dst, size_t dstCapacity,
Sean Purcell553f67e2017-03-02 15:15:31 -08001046 size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +01001047{
Yann Collet1ad7c822017-05-22 17:06:04 -07001048 const int longOffsets = zc->appliedParams.cParams.windowLog > STREAM_ACCUMULATOR_MIN;
Yann Colletb923f652016-01-26 03:14:20 +01001049 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +01001050 U32 count[MaxSeq+1];
1051 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +01001052 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
1053 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
1054 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +01001055 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +02001056 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +02001057 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
1058 const BYTE* const llCodeTable = seqStorePtr->llCode;
1059 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +01001060 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +01001061 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +01001062 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +02001063 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +01001064 BYTE* seqHead;
Yann Colletd79a9a02016-11-30 15:52:20 -08001065 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Collet14983e72015-11-11 21:38:21 +01001066
Yann Collet14983e72015-11-11 21:38:21 +01001067 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +01001068 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +01001069 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +01001070 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +01001071 if (ZSTD_isError(cSize)) return cSize;
1072 op += cSize;
1073 }
1074
1075 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +01001076 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +01001077 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
1078 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
1079 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +01001080 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +01001081
Yann Colletbe391432016-03-22 23:19:28 +01001082 /* seqHead : flags for FSE encoding type */
1083 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +01001084
Yann Colletfb810d62016-01-28 00:18:06 +01001085#define MIN_SEQ_FOR_DYNAMIC_FSE 64
1086#define MAX_SEQ_FOR_STATIC_FSE 1000
1087
Yann Colletb44be742016-03-26 20:52:14 +01001088 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +02001089 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +01001090
Yann Collet14983e72015-11-11 21:38:21 +01001091 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +01001092 { U32 max = MaxLL;
Yann Collete42afbc2017-04-26 11:39:35 -07001093 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +01001094 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
1095 *op++ = llCodeTable[0];
1096 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +02001097 LLtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -07001098 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +02001099 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +01001100 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -08001101 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001102 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +01001103 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +01001104 size_t nbSeq_1 = nbSeq;
1105 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
1106 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
1107 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +01001108 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -07001109 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +01001110 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -08001111 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001112 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +01001113 } }
Yann Collet14983e72015-11-11 21:38:21 +01001114
Yann Colletb44be742016-03-26 20:52:14 +01001115 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +01001116 { U32 max = MaxOff;
Yann Collete42afbc2017-04-26 11:39:35 -07001117 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +01001118 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +01001119 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +01001120 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +02001121 Offtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -07001122 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +02001123 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +02001124 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -08001125 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001126 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +01001127 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +01001128 size_t nbSeq_1 = nbSeq;
1129 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +01001130 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +01001131 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +01001132 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -07001133 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +01001134 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -08001135 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001136 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +01001137 } }
1138
Yann Collet14983e72015-11-11 21:38:21 +01001139 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +01001140 { U32 max = MaxML;
Yann Collete42afbc2017-04-26 11:39:35 -07001141 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +01001142 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +01001143 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +01001144 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +02001145 MLtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -07001146 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +02001147 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +01001148 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -08001149 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001150 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +01001151 } else {
1152 size_t nbSeq_1 = nbSeq;
1153 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
1154 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
1155 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
1156 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -07001157 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletfadda6c2016-03-22 12:14:26 +01001158 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -08001159 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +02001160 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +01001161 } }
Yann Collet14983e72015-11-11 21:38:21 +01001162
Yann Colletbe391432016-03-22 23:19:28 +01001163 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Collet71ddeb62017-04-20 22:54:54 -07001164 zc->fseCTables_ready = 0;
Yann Collet14983e72015-11-11 21:38:21 +01001165
1166 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +01001167 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +01001168 FSE_CState_t stateMatchLength;
1169 FSE_CState_t stateOffsetBits;
1170 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +01001171
Yann Collet95d07d72016-09-06 16:38:51 +02001172 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +01001173
Yann Collet597847a2016-03-20 19:14:22 +01001174 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +01001175 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +01001176 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +01001177 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +02001178 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +01001179 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +02001180 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +01001181 if (MEM_32bits()) BIT_flushBits(&blockStream);
Sean Purcelld44703d2017-03-01 14:36:25 -08001182 if (longOffsets) {
1183 U32 const ofBits = ofCodeTable[nbSeq-1];
1184 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1185 if (extraBits) {
1186 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
1187 BIT_flushBits(&blockStream);
1188 }
1189 BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
1190 ofBits - extraBits);
1191 } else {
1192 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
1193 }
Yann Collet597847a2016-03-20 19:14:22 +01001194 BIT_flushBits(&blockStream);
1195
Yann Colletfadda6c2016-03-22 12:14:26 +01001196 { size_t n;
1197 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +02001198 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +02001199 BYTE const ofCode = ofCodeTable[n];
1200 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +02001201 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +02001202 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +02001203 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +01001204 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +01001205 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
1206 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
1207 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
1208 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +02001209 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +01001210 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +02001211 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +01001212 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +02001213 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +01001214 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Sean Purcelld44703d2017-03-01 14:36:25 -08001215 if (longOffsets) {
1216 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1217 if (extraBits) {
1218 BIT_addBits(&blockStream, sequences[n].offset, extraBits);
1219 BIT_flushBits(&blockStream); /* (7)*/
1220 }
1221 BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
1222 ofBits - extraBits); /* 31 */
1223 } else {
1224 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
1225 }
Yann Colletb9151402016-03-26 17:18:11 +01001226 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +01001227 } }
Yann Collet14983e72015-11-11 21:38:21 +01001228
1229 FSE_flushCState(&blockStream, &stateMatchLength);
1230 FSE_flushCState(&blockStream, &stateOffsetBits);
1231 FSE_flushCState(&blockStream, &stateLitLength);
1232
Yann Colletb9151402016-03-26 17:18:11 +01001233 { size_t const streamSize = BIT_closeCStream(&blockStream);
1234 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
1235 op += streamSize;
1236 } }
Yann Collet14983e72015-11-11 21:38:21 +01001237
1238 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +01001239_check_compressibility:
Nick Terrella4197772017-03-01 17:51:56 -08001240 { size_t const minGain = ZSTD_minGain(srcSize);
1241 size_t const maxCSize = srcSize - minGain;
1242 if ((size_t)(op-ostart) >= maxCSize) {
Yann Collet71ddeb62017-04-20 22:54:54 -07001243 zc->hufCTable_repeatMode = HUF_repeat_none;
Nick Terrella4197772017-03-01 17:51:56 -08001244 return 0;
1245 } }
Yann Collet14983e72015-11-11 21:38:21 +01001246
Yann Collet4266c0a2016-06-14 01:49:25 +02001247 /* confirm repcodes */
Yann Colletb459aad2017-01-19 17:33:37 -08001248 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; }
Yann Collet4266c0a2016-06-14 01:49:25 +02001249
Yann Collet5054ee02015-11-23 13:34:21 +01001250 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +01001251}
1252
Yann Colletbb002742017-01-25 16:25:38 -08001253
Yann Collet95cd0c22016-03-08 18:24:21 +01001254/*! ZSTD_storeSeq() :
1255 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
1256 `offsetCode` : distance to match, or 0 == repCode.
1257 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +01001258*/
Yann Colletd57dffb2016-07-03 01:48:26 +02001259MEM_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 +01001260{
Yann Collet009d6042017-05-19 10:17:59 -07001261#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
1262 static const BYTE* g_start = NULL;
1263 U32 const pos = (U32)((const BYTE*)literals - g_start);
1264 if (g_start==NULL) g_start = (const BYTE*)literals;
1265 if ((pos > 0) && (pos < 1000000000))
1266 DEBUGLOG(6, "Cpos %6u :%5u literals & match %3u bytes at distance %6u",
1267 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +01001268#endif
Yann Collet14983e72015-11-11 21:38:21 +01001269 /* copy Literals */
Yann Collet009d6042017-05-19 10:17:59 -07001270 assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB);
Yann Collet14983e72015-11-11 21:38:21 +01001271 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
1272 seqStorePtr->lit += litLength;
1273
1274 /* literal Length */
Yann Collete6fa70a2017-04-20 17:28:31 -07001275 if (litLength>0xFFFF) {
1276 seqStorePtr->longLengthID = 1;
1277 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
1278 }
Yann Colletc0ce4f12016-07-30 00:55:13 +02001279 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +01001280
1281 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +02001282 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +01001283
1284 /* match Length */
Yann Collete6fa70a2017-04-20 17:28:31 -07001285 if (matchCode>0xFFFF) {
1286 seqStorePtr->longLengthID = 2;
1287 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
1288 }
Yann Colletc0ce4f12016-07-30 00:55:13 +02001289 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +02001290
Yann Colletc0ce4f12016-07-30 00:55:13 +02001291 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +01001292}
1293
1294
Yann Collet7d360282016-02-12 00:07:30 +01001295/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001296* Match length counter
1297***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +01001298static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +01001299{
Yann Collet863ec402016-01-28 17:56:33 +01001300 if (MEM_isLittleEndian()) {
1301 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +01001302# if defined(_MSC_VER) && defined(_WIN64)
1303 unsigned long r = 0;
1304 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +01001305 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +01001306# elif defined(__GNUC__) && (__GNUC__ >= 3)
1307 return (__builtin_ctzll((U64)val) >> 3);
1308# else
Yann Collete348dad2017-04-20 11:14:13 -07001309 static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
1310 0, 3, 1, 3, 1, 4, 2, 7,
1311 0, 2, 3, 6, 1, 5, 3, 5,
1312 1, 3, 4, 4, 2, 5, 6, 7,
1313 7, 0, 1, 2, 3, 3, 4, 6,
1314 2, 6, 5, 5, 3, 4, 5, 6,
1315 7, 1, 2, 4, 6, 4, 4, 5,
1316 7, 2, 6, 5, 7, 6, 7, 7 };
Yann Collet14983e72015-11-11 21:38:21 +01001317 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
1318# endif
Yann Collet863ec402016-01-28 17:56:33 +01001319 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +01001320# if defined(_MSC_VER)
1321 unsigned long r=0;
1322 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +01001323 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +01001324# elif defined(__GNUC__) && (__GNUC__ >= 3)
1325 return (__builtin_ctz((U32)val) >> 3);
1326# else
Yann Collete348dad2017-04-20 11:14:13 -07001327 static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
1328 3, 2, 2, 1, 3, 2, 0, 1,
1329 3, 3, 1, 2, 2, 2, 2, 0,
1330 3, 1, 2, 0, 1, 0, 1, 1 };
Yann Collet14983e72015-11-11 21:38:21 +01001331 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
1332# endif
1333 }
Yann Collet863ec402016-01-28 17:56:33 +01001334 } else { /* Big Endian CPU */
1335 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +01001336# if defined(_MSC_VER) && defined(_WIN64)
1337 unsigned long r = 0;
1338 _BitScanReverse64( &r, val );
1339 return (unsigned)(r>>3);
1340# elif defined(__GNUC__) && (__GNUC__ >= 3)
1341 return (__builtin_clzll(val) >> 3);
1342# else
1343 unsigned r;
1344 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
1345 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
1346 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
1347 r += (!val);
1348 return r;
1349# endif
Yann Collet863ec402016-01-28 17:56:33 +01001350 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +01001351# if defined(_MSC_VER)
1352 unsigned long r = 0;
1353 _BitScanReverse( &r, (unsigned long)val );
1354 return (unsigned)(r>>3);
1355# elif defined(__GNUC__) && (__GNUC__ >= 3)
1356 return (__builtin_clz((U32)val) >> 3);
1357# else
1358 unsigned r;
1359 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
1360 r += (!val);
1361 return r;
1362# endif
Yann Collet863ec402016-01-28 17:56:33 +01001363 } }
Yann Collet14983e72015-11-11 21:38:21 +01001364}
1365
1366
Yann Colleta436a522016-06-20 23:34:04 +02001367static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +01001368{
1369 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +02001370 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +01001371
Yann Colleta436a522016-06-20 23:34:04 +02001372 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +02001373 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +01001374 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
1375 pIn += ZSTD_NbCommonBytes(diff);
1376 return (size_t)(pIn - pStart);
1377 }
Yann Collet14983e72015-11-11 21:38:21 +01001378 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
1379 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
1380 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
1381 return (size_t)(pIn - pStart);
1382}
1383
Yann Collet04b12d82016-02-11 06:23:24 +01001384/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +01001385* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +01001386* convention : on reaching mEnd, match count continue starting from iStart
1387*/
1388static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
1389{
Yann Collet7591a7f2016-05-20 11:44:43 +02001390 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +02001391 size_t const matchLength = ZSTD_count(ip, match, vEnd);
1392 if (match + matchLength != mEnd) return matchLength;
1393 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +01001394}
1395
Yann Collet14983e72015-11-11 21:38:21 +01001396
Yann Collet863ec402016-01-28 17:56:33 +01001397/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001398* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +01001399***************************************/
inikepcc52a972016-02-19 10:09:35 +01001400static const U32 prime3bytes = 506832829U;
1401static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Collete6fa70a2017-04-20 17:28:31 -07001402MEM_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 +01001403
Yann Collet4b100f42015-10-30 15:49:48 +01001404static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +01001405static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +01001406static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +01001407
Yann Collet4b100f42015-10-30 15:49:48 +01001408static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001409static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001410static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001411
1412static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001413static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001414static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001415
Yann Collet14983e72015-11-11 21:38:21 +01001416static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001417static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001418static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001419
Yann Collet45dc3562016-07-12 09:47:31 +02001420static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
1421static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
1422static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
1423
Yann Collet5be2dd22015-11-11 13:43:58 +01001424static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001425{
1426 switch(mls)
1427 {
1428 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001429 case 4: return ZSTD_hash4Ptr(p, hBits);
1430 case 5: return ZSTD_hash5Ptr(p, hBits);
1431 case 6: return ZSTD_hash6Ptr(p, hBits);
1432 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +02001433 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001434 }
1435}
Yann Collet2acb5d32015-10-29 16:49:43 +01001436
Yann Collet863ec402016-01-28 17:56:33 +01001437
Yann Collet2ce49232016-02-02 14:36:49 +01001438/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001439* Fast Scan
1440***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001441static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1442{
1443 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001444 U32 const hBits = zc->appliedParams.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001445 const BYTE* const base = zc->base;
1446 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001447 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001448 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001449
Yann Colletfb810d62016-01-28 00:18:06 +01001450 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001451 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001452 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001453 }
1454}
1455
1456
Yann Collet1f44b3f2015-11-05 17:32:18 +01001457FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +02001458void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +02001459 const void* src, size_t srcSize,
1460 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001461{
Yann Collet4266c0a2016-06-14 01:49:25 +02001462 U32* const hashTable = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001463 U32 const hBits = cctx->appliedParams.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +02001464 seqStore_t* seqStorePtr = &(cctx->seqStore);
1465 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001466 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001467 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001468 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +02001469 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +02001470 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001471 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001472 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +02001473 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1474 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001475
Yann Collet1f44b3f2015-11-05 17:32:18 +01001476 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001477 ip += (ip==lowest);
1478 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +02001479 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1480 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +02001481 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001482
1483 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +02001484 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +02001485 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +02001486 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
1487 U32 const current = (U32)(ip-base);
1488 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +01001489 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001490 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001491
Yann Collet280f9a82016-08-08 00:44:00 +02001492 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +02001493 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +01001494 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001495 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1496 } else {
Yann Collet92d75662016-07-03 01:10:53 +02001497 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001498 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001499 ip += ((ip-anchor) >> g_searchStrength) + 1;
1500 continue;
1501 }
Yann Collet45dc3562016-07-12 09:47:31 +02001502 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001503 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001504 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001505 offset_2 = offset_1;
1506 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001507
Yann Colleta436a522016-06-20 23:34:04 +02001508 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001509 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001510
Yann Collet402fdcf2015-11-20 12:46:08 +01001511 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001512 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001513 anchor = ip;
1514
Yann Colletfb810d62016-01-28 00:18:06 +01001515 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001516 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001517 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 +01001518 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1519 /* check immediate repcode */
1520 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001521 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001522 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001523 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001524 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001525 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001526 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001527 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1528 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001529 anchor = ip;
1530 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001531 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001532
Yann Collet4266c0a2016-06-14 01:49:25 +02001533 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001534 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1535 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001536
Yann Collet70e45772016-03-19 18:08:32 +01001537 /* Last Literals */
1538 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001539 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1540 seqStorePtr->lit += lastLLSize;
1541 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001542}
1543
1544
Yann Collet82260dd2016-02-11 07:14:25 +01001545static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001546 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001547{
Yann Collet1ad7c822017-05-22 17:06:04 -07001548 const U32 mls = ctx->appliedParams.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001549 switch(mls)
1550 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001551 default: /* includes case 3 */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001552 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001553 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001554 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001555 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001556 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001557 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001558 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001559 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001560 }
1561}
Yann Colletf3eca252015-10-22 15:31:46 +01001562
Yann Colletf3eca252015-10-22 15:31:46 +01001563
Yann Collet82260dd2016-02-11 07:14:25 +01001564static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001565 const void* src, size_t srcSize,
1566 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001567{
1568 U32* hashTable = ctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001569 const U32 hBits = ctx->appliedParams.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001570 seqStore_t* seqStorePtr = &(ctx->seqStore);
1571 const BYTE* const base = ctx->base;
1572 const BYTE* const dictBase = ctx->dictBase;
1573 const BYTE* const istart = (const BYTE*)src;
1574 const BYTE* ip = istart;
1575 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001576 const U32 lowestIndex = ctx->lowLimit;
1577 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001578 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001579 const BYTE* const lowPrefixPtr = base + dictLimit;
1580 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001581 const BYTE* const iend = istart + srcSize;
1582 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001583 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001584
Yann Colleta436a522016-06-20 23:34:04 +02001585 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001586 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001587 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001588 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001589 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001590 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001591 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001592 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001593 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001594 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001595 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001596 hashTable[h] = current; /* update hash table */
1597
Yann Colleta436a522016-06-20 23:34:04 +02001598 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001599 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001600 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001601 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
Yann Collet743402c2015-11-20 12:03:53 +01001602 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001603 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001604 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001605 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001606 (MEM_read32(match) != MEM_read32(ip)) ) {
1607 ip += ((ip-anchor) >> g_searchStrength) + 1;
1608 continue;
1609 }
1610 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001611 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001612 U32 offset;
Yann Collete6fa70a2017-04-20 17:28:31 -07001613 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
Yann Colleta436a522016-06-20 23:34:04 +02001614 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001615 offset = current - matchIndex;
1616 offset_2 = offset_1;
1617 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001618 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001619 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001620
Yann Collet5054ee02015-11-23 13:34:21 +01001621 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001622 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001623 anchor = ip;
1624
Yann Colletfb810d62016-01-28 00:18:06 +01001625 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001626 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001627 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001628 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1629 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001630 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001631 U32 const current2 = (U32)(ip-base);
1632 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001633 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001634 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1635 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001636 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001637 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet5054ee02015-11-23 13:34:21 +01001638 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001639 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001640 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001641 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001642 anchor = ip;
1643 continue;
1644 }
Yann Collet743402c2015-11-20 12:03:53 +01001645 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001646 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001647
Yann Collet4266c0a2016-06-14 01:49:25 +02001648 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001649 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001650
Yann Collet89db5e02015-11-13 11:27:46 +01001651 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001652 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001653 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1654 seqStorePtr->lit += lastLLSize;
1655 }
Yann Collet89db5e02015-11-13 11:27:46 +01001656}
1657
1658
Yann Collet82260dd2016-02-11 07:14:25 +01001659static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001660 const void* src, size_t srcSize)
1661{
Yann Collet1ad7c822017-05-22 17:06:04 -07001662 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001663 switch(mls)
1664 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001665 default: /* includes case 3 */
Yann Collet89db5e02015-11-13 11:27:46 +01001666 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001667 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001668 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001669 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001670 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001671 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001672 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001673 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001674 }
1675}
1676
1677
Yann Collet04b12d82016-02-11 06:23:24 +01001678/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001679* Double Fast
1680***************************************/
1681static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1682{
1683 U32* const hashLarge = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001684 U32 const hBitsL = cctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001685 U32* const hashSmall = cctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001686 U32 const hBitsS = cctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001687 const BYTE* const base = cctx->base;
1688 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001689 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001690 const size_t fastHashFillStep = 3;
1691
1692 while(ip <= iend) {
1693 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1694 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1695 ip += fastHashFillStep;
1696 }
1697}
1698
1699
1700FORCE_INLINE
1701void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1702 const void* src, size_t srcSize,
1703 const U32 mls)
1704{
1705 U32* const hashLong = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001706 const U32 hBitsL = cctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001707 U32* const hashSmall = cctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001708 const U32 hBitsS = cctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001709 seqStore_t* seqStorePtr = &(cctx->seqStore);
1710 const BYTE* const base = cctx->base;
1711 const BYTE* const istart = (const BYTE*)src;
1712 const BYTE* ip = istart;
1713 const BYTE* anchor = istart;
1714 const U32 lowestIndex = cctx->dictLimit;
1715 const BYTE* const lowest = base + lowestIndex;
1716 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001717 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001718 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1719 U32 offsetSaved = 0;
1720
1721 /* init */
1722 ip += (ip==lowest);
1723 { U32 const maxRep = (U32)(ip-lowest);
1724 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1725 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1726 }
1727
1728 /* Main Search Loop */
1729 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1730 size_t mLength;
1731 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1732 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1733 U32 const current = (U32)(ip-base);
1734 U32 const matchIndexL = hashLong[h2];
1735 U32 const matchIndexS = hashSmall[h];
1736 const BYTE* matchLong = base + matchIndexL;
1737 const BYTE* match = base + matchIndexS;
1738 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1739
Yann Colletc17e0202017-04-20 12:50:02 -07001740 assert(offset_1 <= current); /* supposed guaranteed by construction */
1741 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001742 /* favor repcode */
Yann Collet45dc3562016-07-12 09:47:31 +02001743 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1744 ip++;
1745 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1746 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001747 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001748 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1749 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001750 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001751 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1752 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001753 size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1754 U32 const matchIndexL3 = hashLong[hl3];
1755 const BYTE* matchL3 = base + matchIndexL3;
1756 hashLong[hl3] = current + 1;
1757 if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
1758 mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
Yann Colletc54692f2016-08-24 01:10:42 +02001759 ip++;
Yann Collete6fa70a2017-04-20 17:28:31 -07001760 offset = (U32)(ip-matchL3);
1761 while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
Yann Colletc54692f2016-08-24 01:10:42 +02001762 } else {
1763 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1764 offset = (U32)(ip-match);
1765 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1766 }
Yann Collet45dc3562016-07-12 09:47:31 +02001767 } else {
1768 ip += ((ip-anchor) >> g_searchStrength) + 1;
1769 continue;
1770 }
1771
1772 offset_2 = offset_1;
1773 offset_1 = offset;
1774
1775 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1776 }
1777
1778 /* match found */
1779 ip += mLength;
1780 anchor = ip;
1781
1782 if (ip <= ilimit) {
1783 /* Fill Table */
1784 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1785 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1786 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1787 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1788
1789 /* check immediate repcode */
1790 while ( (ip <= ilimit)
1791 && ( (offset_2>0)
1792 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1793 /* store sequence */
1794 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001795 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001796 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1797 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1798 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1799 ip += rLength;
1800 anchor = ip;
1801 continue; /* faster when present ... (?) */
1802 } } }
1803
1804 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001805 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1806 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet45dc3562016-07-12 09:47:31 +02001807
1808 /* Last Literals */
1809 { size_t const lastLLSize = iend - anchor;
1810 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1811 seqStorePtr->lit += lastLLSize;
1812 }
1813}
1814
1815
1816static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1817{
Yann Collet1ad7c822017-05-22 17:06:04 -07001818 const U32 mls = ctx->appliedParams.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001819 switch(mls)
1820 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001821 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001822 case 4 :
1823 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1824 case 5 :
1825 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1826 case 6 :
1827 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1828 case 7 :
1829 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1830 }
1831}
1832
1833
1834static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1835 const void* src, size_t srcSize,
1836 const U32 mls)
1837{
1838 U32* const hashLong = ctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001839 U32 const hBitsL = ctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001840 U32* const hashSmall = ctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001841 U32 const hBitsS = ctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001842 seqStore_t* seqStorePtr = &(ctx->seqStore);
1843 const BYTE* const base = ctx->base;
1844 const BYTE* const dictBase = ctx->dictBase;
1845 const BYTE* const istart = (const BYTE*)src;
1846 const BYTE* ip = istart;
1847 const BYTE* anchor = istart;
1848 const U32 lowestIndex = ctx->lowLimit;
1849 const BYTE* const dictStart = dictBase + lowestIndex;
1850 const U32 dictLimit = ctx->dictLimit;
1851 const BYTE* const lowPrefixPtr = base + dictLimit;
1852 const BYTE* const dictEnd = dictBase + dictLimit;
1853 const BYTE* const iend = istart + srcSize;
1854 const BYTE* const ilimit = iend - 8;
1855 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1856
1857 /* Search Loop */
1858 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1859 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1860 const U32 matchIndex = hashSmall[hSmall];
1861 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1862 const BYTE* match = matchBase + matchIndex;
1863
1864 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1865 const U32 matchLongIndex = hashLong[hLong];
1866 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1867 const BYTE* matchLong = matchLongBase + matchLongIndex;
1868
1869 const U32 current = (U32)(ip-base);
1870 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1871 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1872 const BYTE* repMatch = repBase + repIndex;
1873 size_t mLength;
1874 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1875
1876 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1877 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1878 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1879 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1880 ip++;
1881 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1882 } else {
1883 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1884 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1885 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1886 U32 offset;
1887 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1888 offset = current - matchLongIndex;
1889 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1890 offset_2 = offset_1;
1891 offset_1 = offset;
1892 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001893
Yann Collet73d74a02016-07-12 13:03:48 +02001894 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001895 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1896 U32 const matchIndex3 = hashLong[h3];
1897 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1898 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001899 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001900 hashLong[h3] = current + 1;
1901 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1902 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1903 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1904 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1905 ip++;
1906 offset = current+1 - matchIndex3;
1907 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1908 } else {
1909 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1910 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1911 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1912 offset = current - matchIndex;
1913 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1914 }
Yann Collet45dc3562016-07-12 09:47:31 +02001915 offset_2 = offset_1;
1916 offset_1 = offset;
1917 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001918
Yann Collet45dc3562016-07-12 09:47:31 +02001919 } else {
1920 ip += ((ip-anchor) >> g_searchStrength) + 1;
1921 continue;
1922 } }
1923
1924 /* found a match : store it */
1925 ip += mLength;
1926 anchor = ip;
1927
1928 if (ip <= ilimit) {
1929 /* Fill Table */
Nick Terrellf35ef5c2017-03-09 12:51:33 -08001930 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1931 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
Yann Collet45dc3562016-07-12 09:47:31 +02001932 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1933 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1934 /* check immediate repcode */
1935 while (ip <= ilimit) {
1936 U32 const current2 = (U32)(ip-base);
1937 U32 const repIndex2 = current2 - offset_2;
1938 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1939 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1940 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1941 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07001942 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet45dc3562016-07-12 09:47:31 +02001943 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1944 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1945 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1946 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1947 ip += repLength2;
1948 anchor = ip;
1949 continue;
1950 }
1951 break;
1952 } } }
1953
1954 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001955 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet45dc3562016-07-12 09:47:31 +02001956
1957 /* Last Literals */
1958 { size_t const lastLLSize = iend - anchor;
1959 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1960 seqStorePtr->lit += lastLLSize;
1961 }
1962}
1963
1964
1965static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1966 const void* src, size_t srcSize)
1967{
Yann Collet1ad7c822017-05-22 17:06:04 -07001968 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001969 switch(mls)
1970 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001971 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001972 case 4 :
1973 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1974 case 5 :
1975 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1976 case 6 :
1977 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1978 case 7 :
1979 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1980 }
1981}
1982
1983
1984/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001985* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001986***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001987/** ZSTD_insertBt1() : add one or multiple positions to tree.
1988* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001989* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001990static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1991 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001992{
Yann Collet731ef162016-07-27 21:05:12 +02001993 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001994 U32 const hashLog = zc->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +02001995 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1996 U32* const bt = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001997 U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
Yann Collet731ef162016-07-27 21:05:12 +02001998 U32 const btMask = (1 << btLog) - 1;
1999 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01002000 size_t commonLengthSmaller=0, commonLengthLarger=0;
2001 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01002002 const BYTE* const dictBase = zc->dictBase;
2003 const U32 dictLimit = zc->dictLimit;
2004 const BYTE* const dictEnd = dictBase + dictLimit;
2005 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07002006 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002007 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01002008 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002009 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01002010 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01002011 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02002012 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01002013 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01002014 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02002015#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01002016 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
2017 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
2018 predictedSmall += (predictedSmall>0);
2019 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02002020#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01002021
Yann Collet6c3e2e72015-12-11 10:44:07 +01002022 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002023
Yann Colletfb810d62016-01-28 00:18:06 +01002024 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08002025 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01002026 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08002027
Yann Colletc0932082016-06-30 14:07:30 +02002028#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01002029 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01002030 if (matchIndex == predictedSmall) {
2031 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01002032 *smallerPtr = matchIndex;
2033 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2034 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
2035 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01002036 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01002037 continue;
2038 }
Yann Colletfb810d62016-01-28 00:18:06 +01002039 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01002040 *largerPtr = matchIndex;
2041 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2042 largerPtr = nextPtr;
2043 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01002044 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01002045 continue;
2046 }
Yann Collet04b12d82016-02-11 06:23:24 +01002047#endif
Yann Colletfb810d62016-01-28 00:18:06 +01002048 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01002049 match = base + matchIndex;
2050 if (match[matchLength] == ip[matchLength])
2051 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01002052 } else {
Yann Collet1358f912016-01-01 07:29:39 +01002053 match = dictBase + matchIndex;
2054 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
2055 if (matchIndex+matchLength >= dictLimit)
Nick Terrellf35ef5c2017-03-09 12:51:33 -08002056 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet1358f912016-01-01 07:29:39 +01002057 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002058
Yann Colletb8a6f682016-02-15 17:06:29 +01002059 if (matchLength > bestLength) {
2060 bestLength = matchLength;
2061 if (matchLength > matchEndIdx - matchIndex)
2062 matchEndIdx = matchIndex + (U32)matchLength;
2063 }
Yann Colletee3f4512015-12-29 22:26:09 +01002064
Yann Collet59d70632015-11-04 12:05:27 +01002065 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01002066 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002067
Yann Colletfb810d62016-01-28 00:18:06 +01002068 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002069 /* match is smaller than current */
2070 *smallerPtr = matchIndex; /* update smaller idx */
2071 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01002072 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002073 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01002074 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01002075 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01002076 /* match is larger than current */
2077 *largerPtr = matchIndex;
2078 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01002079 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002080 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01002081 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01002082 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002083
Yann Collet59d70632015-11-04 12:05:27 +01002084 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02002085 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01002086 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
2087 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002088}
2089
2090
Yann Collet82260dd2016-02-11 07:14:25 +01002091static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01002092 ZSTD_CCtx* zc,
2093 const BYTE* const ip, const BYTE* const iend,
2094 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01002095 U32 nbCompares, const U32 mls,
2096 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01002097{
Yann Collet731ef162016-07-27 21:05:12 +02002098 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002099 U32 const hashLog = zc->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +02002100 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
2101 U32* const bt = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002102 U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
Yann Collet731ef162016-07-27 21:05:12 +02002103 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01002104 U32 matchIndex = hashTable[h];
2105 size_t commonLengthSmaller=0, commonLengthLarger=0;
2106 const BYTE* const base = zc->base;
2107 const BYTE* const dictBase = zc->dictBase;
2108 const U32 dictLimit = zc->dictLimit;
2109 const BYTE* const dictEnd = dictBase + dictLimit;
2110 const BYTE* const prefixStart = base + dictLimit;
2111 const U32 current = (U32)(ip-base);
2112 const U32 btLow = btMask >= current ? 0 : current - btMask;
2113 const U32 windowLow = zc->lowLimit;
2114 U32* smallerPtr = bt + 2*(current&btMask);
2115 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01002116 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01002117 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02002118 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01002119
Yann Collet6c3e2e72015-12-11 10:44:07 +01002120 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01002121
Yann Colletfb810d62016-01-28 00:18:06 +01002122 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08002123 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01002124 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
2125 const BYTE* match;
2126
Yann Colletfb810d62016-01-28 00:18:06 +01002127 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01002128 match = base + matchIndex;
2129 if (match[matchLength] == ip[matchLength])
2130 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01002131 } else {
Yann Collet03526e12015-11-23 15:29:15 +01002132 match = dictBase + matchIndex;
2133 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01002134 if (matchIndex+matchLength >= dictLimit)
Nick Terrellf35ef5c2017-03-09 12:51:33 -08002135 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01002136 }
2137
Yann Colletfb810d62016-01-28 00:18:06 +01002138 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01002139 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01002140 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02002141 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02002142 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01002143 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
2144 break; /* drop, to guarantee consistency (miss a little bit of compression) */
2145 }
2146
Yann Colletfb810d62016-01-28 00:18:06 +01002147 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01002148 /* match is smaller than current */
2149 *smallerPtr = matchIndex; /* update smaller idx */
2150 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
2151 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2152 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
2153 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01002154 } else {
Yann Collet03526e12015-11-23 15:29:15 +01002155 /* match is larger than current */
2156 *largerPtr = matchIndex;
2157 commonLengthLarger = matchLength;
2158 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2159 largerPtr = nextPtr;
2160 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01002161 } }
Yann Collet03526e12015-11-23 15:29:15 +01002162
2163 *smallerPtr = *largerPtr = 0;
2164
Yann Collet72e84cf2015-12-31 19:08:44 +01002165 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02002166 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01002167}
2168
Yann Collet2cc12cb2016-01-01 07:47:58 +01002169
Yann Colletb8a6f682016-02-15 17:06:29 +01002170static 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 +01002171{
2172 const BYTE* const base = zc->base;
2173 const U32 target = (U32)(ip - base);
2174 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01002175
2176 while(idx < target)
2177 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01002178}
2179
Yann Collet52447382016-03-20 16:00:00 +01002180/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01002181static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01002182 ZSTD_CCtx* zc,
2183 const BYTE* const ip, const BYTE* const iLimit,
2184 size_t* offsetPtr,
2185 const U32 maxNbAttempts, const U32 mls)
2186{
2187 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01002188 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01002189 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
2190}
2191
2192
Yann Collet768c6bc2016-02-10 14:01:49 +01002193static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01002194 ZSTD_CCtx* zc, /* Index table will be updated */
2195 const BYTE* ip, const BYTE* const iLimit,
2196 size_t* offsetPtr,
2197 const U32 maxNbAttempts, const U32 matchLengthSearch)
2198{
2199 switch(matchLengthSearch)
2200 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002201 default : /* includes case 3 */
Yann Collet2cc12cb2016-01-01 07:47:58 +01002202 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
2203 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07002204 case 7 :
Yann Collet2cc12cb2016-01-01 07:47:58 +01002205 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
2206 }
2207}
2208
2209
Yann Colletb8a6f682016-02-15 17:06:29 +01002210static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
2211{
2212 const BYTE* const base = zc->base;
2213 const U32 target = (U32)(ip - base);
2214 U32 idx = zc->nextToUpdate;
2215
2216 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
2217}
2218
inikep64d7bcb2016-04-07 19:14:09 +02002219
Yann Collet03526e12015-11-23 15:29:15 +01002220/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01002221static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01002222 ZSTD_CCtx* zc,
2223 const BYTE* const ip, const BYTE* const iLimit,
2224 size_t* offsetPtr,
2225 const U32 maxNbAttempts, const U32 mls)
2226{
Yann Colletee3f4512015-12-29 22:26:09 +01002227 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01002228 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01002229 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01002230}
2231
2232
Yann Collet82260dd2016-02-11 07:14:25 +01002233static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01002234 ZSTD_CCtx* zc, /* Index table will be updated */
2235 const BYTE* ip, const BYTE* const iLimit,
2236 size_t* offsetPtr,
2237 const U32 maxNbAttempts, const U32 matchLengthSearch)
2238{
2239 switch(matchLengthSearch)
2240 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002241 default : /* includes case 3 */
Yann Collet03526e12015-11-23 15:29:15 +01002242 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
2243 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07002244 case 7 :
Yann Collet03526e12015-11-23 15:29:15 +01002245 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
2246 }
2247}
2248
2249
Yann Collet5106a762015-11-05 15:00:24 +01002250
Yann Collet731ef162016-07-27 21:05:12 +02002251/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02002252* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02002253***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02002254#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
2255
2256/* Update chains up to ip (excluded)
Anders Oleson517577b2017-02-20 12:08:59 -08002257 Assumption : always within prefix (i.e. not within extDict) */
inikep64d7bcb2016-04-07 19:14:09 +02002258FORCE_INLINE
2259U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
2260{
2261 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002262 const U32 hashLog = zc->appliedParams.cParams.hashLog;
inikep64d7bcb2016-04-07 19:14:09 +02002263 U32* const chainTable = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002264 const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1;
inikep64d7bcb2016-04-07 19:14:09 +02002265 const BYTE* const base = zc->base;
2266 const U32 target = (U32)(ip - base);
2267 U32 idx = zc->nextToUpdate;
2268
Yann Collet22d76322016-06-21 08:01:51 +02002269 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002270 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
2271 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
2272 hashTable[h] = idx;
2273 idx++;
2274 }
2275
2276 zc->nextToUpdate = target;
2277 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
2278}
2279
2280
Nick Terrell55fc1f92017-05-24 13:50:10 -07002281/* inlining is important to hardwire a hot branch (template emulation) */
2282FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002283size_t ZSTD_HcFindBestMatch_generic (
2284 ZSTD_CCtx* zc, /* Index table will be updated */
2285 const BYTE* const ip, const BYTE* const iLimit,
2286 size_t* offsetPtr,
2287 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
2288{
2289 U32* const chainTable = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002290 const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog);
inikep64d7bcb2016-04-07 19:14:09 +02002291 const U32 chainMask = chainSize-1;
2292 const BYTE* const base = zc->base;
2293 const BYTE* const dictBase = zc->dictBase;
2294 const U32 dictLimit = zc->dictLimit;
2295 const BYTE* const prefixStart = base + dictLimit;
2296 const BYTE* const dictEnd = dictBase + dictLimit;
2297 const U32 lowLimit = zc->lowLimit;
2298 const U32 current = (U32)(ip-base);
2299 const U32 minChain = current > chainSize ? current - chainSize : 0;
2300 int nbAttempts=maxNbAttempts;
Yann Collete42afbc2017-04-26 11:39:35 -07002301 size_t ml=4-1;
inikep64d7bcb2016-04-07 19:14:09 +02002302
2303 /* HC4 match finder */
2304 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
2305
Yann Collet22d76322016-06-21 08:01:51 +02002306 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02002307 const BYTE* match;
2308 size_t currentMl=0;
2309 if ((!extDict) || matchIndex >= dictLimit) {
2310 match = base + matchIndex;
2311 if (match[ml] == ip[ml]) /* potentially better */
2312 currentMl = ZSTD_count(ip, match, iLimit);
2313 } else {
2314 match = dictBase + matchIndex;
2315 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
Yann Collete42afbc2017-04-26 11:39:35 -07002316 currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002317 }
2318
2319 /* save best solution */
Yann Colletc17e0202017-04-20 12:50:02 -07002320 if (currentMl > ml) {
2321 ml = currentMl;
2322 *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
2323 if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
2324 }
inikep64d7bcb2016-04-07 19:14:09 +02002325
2326 if (matchIndex <= minChain) break;
2327 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
2328 }
2329
2330 return ml;
2331}
2332
2333
2334FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
2335 ZSTD_CCtx* zc,
2336 const BYTE* ip, const BYTE* const iLimit,
2337 size_t* offsetPtr,
2338 const U32 maxNbAttempts, const U32 matchLengthSearch)
2339{
2340 switch(matchLengthSearch)
2341 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002342 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02002343 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
2344 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
Yann Collet933ce4a2017-03-29 14:32:15 -07002345 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02002346 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
2347 }
2348}
2349
2350
2351FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
2352 ZSTD_CCtx* zc,
2353 const BYTE* ip, const BYTE* const iLimit,
2354 size_t* offsetPtr,
2355 const U32 maxNbAttempts, const U32 matchLengthSearch)
2356{
2357 switch(matchLengthSearch)
2358 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002359 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02002360 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
2361 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
Yann Collet933ce4a2017-03-29 14:32:15 -07002362 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02002363 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
2364 }
2365}
2366
inikep64d7bcb2016-04-07 19:14:09 +02002367
Yann Collet287b7d92015-11-22 13:24:05 +01002368/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02002369* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02002370*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01002371FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002372void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
2373 const void* src, size_t srcSize,
2374 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01002375{
inikepfaa8d8a2016-04-05 19:01:10 +02002376 seqStore_t* seqStorePtr = &(ctx->seqStore);
2377 const BYTE* const istart = (const BYTE*)src;
2378 const BYTE* ip = istart;
2379 const BYTE* anchor = istart;
2380 const BYTE* const iend = istart + srcSize;
2381 const BYTE* const ilimit = iend - 8;
2382 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002383
Yann Collet1ad7c822017-05-22 17:06:04 -07002384 U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
2385 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002386
inikep64d7bcb2016-04-07 19:14:09 +02002387 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2388 size_t* offsetPtr,
2389 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02002390 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02002391 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02002392
inikepfaa8d8a2016-04-05 19:01:10 +02002393 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02002394 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02002395 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02002396 { U32 const maxRep = (U32)(ip-base);
2397 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
2398 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
2399 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002400
inikepfaa8d8a2016-04-05 19:01:10 +02002401 /* Match Loop */
2402 while (ip < ilimit) {
2403 size_t matchLength=0;
2404 size_t offset=0;
2405 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01002406
inikepfaa8d8a2016-04-05 19:01:10 +02002407 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02002408 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02002409 /* repcode : we take it */
Yann Collete42afbc2017-04-26 11:39:35 -07002410 matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002411 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01002412 }
Yann Collet5be2dd22015-11-11 13:43:58 +01002413
inikepfaa8d8a2016-04-05 19:01:10 +02002414 /* first search (depth 0) */
2415 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002416 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002417 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002418 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002419 }
Yann Collet5106a762015-11-05 15:00:24 +01002420
Yann Collete42afbc2017-04-26 11:39:35 -07002421 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002422 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2423 continue;
2424 }
2425
inikep64d7bcb2016-04-07 19:14:09 +02002426 /* let's try to find a better solution */
2427 if (depth>=1)
2428 while (ip<ilimit) {
2429 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002430 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002431 size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002432 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002433 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002434 if ((mlRep >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002435 matchLength = mlRep, offset = 0, start = ip;
2436 }
2437 { size_t offset2=99999999;
2438 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002439 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2440 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002441 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002442 matchLength = ml2, offset = offset2, start = ip;
2443 continue; /* search a better one */
2444 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002445
inikep64d7bcb2016-04-07 19:14:09 +02002446 /* let's find an even better one */
2447 if ((depth==2) && (ip<ilimit)) {
2448 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002449 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002450 size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002451 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002452 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002453 if ((ml2 >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002454 matchLength = ml2, offset = 0, start = ip;
2455 }
2456 { size_t offset2=99999999;
2457 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002458 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2459 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002460 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002461 matchLength = ml2, offset = offset2, start = ip;
2462 continue;
2463 } } }
2464 break; /* nothing found : store previous solution */
2465 }
2466
2467 /* catch up */
2468 if (offset) {
Yann Colletc17e0202017-04-20 12:50:02 -07002469 while ( (start > anchor)
2470 && (start > base+offset-ZSTD_REP_MOVE)
2471 && (start[-1] == start[-1-offset+ZSTD_REP_MOVE]) ) /* only search for offset within prefix */
inikep64d7bcb2016-04-07 19:14:09 +02002472 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02002473 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02002474 }
2475
inikepfaa8d8a2016-04-05 19:01:10 +02002476 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002477_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002478 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002479 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002480 anchor = ip = start + matchLength;
2481 }
Yann Collet48537162016-04-07 15:24:29 +02002482
inikepfaa8d8a2016-04-05 19:01:10 +02002483 /* check immediate repcode */
2484 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02002485 && ((offset_2>0)
2486 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02002487 /* store sequence */
Yann Collete42afbc2017-04-26 11:39:35 -07002488 matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet9634f672016-07-03 01:23:58 +02002489 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02002490 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2491 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002492 anchor = ip;
2493 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02002494 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002495
Yann Collet4266c0a2016-06-14 01:49:25 +02002496 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002497 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
2498 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02002499
inikepfaa8d8a2016-04-05 19:01:10 +02002500 /* Last Literals */
2501 { size_t const lastLLSize = iend - anchor;
2502 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2503 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002504 }
Yann Collet5106a762015-11-05 15:00:24 +01002505}
2506
Yann Collet5be2dd22015-11-11 13:43:58 +01002507
inikep64d7bcb2016-04-07 19:14:09 +02002508static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2509{
2510 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2511}
2512
2513static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2514{
2515 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2516}
2517
2518static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2519{
2520 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2521}
2522
2523static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2524{
2525 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2526}
2527
2528
inikepfaa8d8a2016-04-05 19:01:10 +02002529FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002530void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2531 const void* src, size_t srcSize,
2532 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002533{
inikepfaa8d8a2016-04-05 19:01:10 +02002534 seqStore_t* seqStorePtr = &(ctx->seqStore);
2535 const BYTE* const istart = (const BYTE*)src;
2536 const BYTE* ip = istart;
2537 const BYTE* anchor = istart;
2538 const BYTE* const iend = istart + srcSize;
2539 const BYTE* const ilimit = iend - 8;
2540 const BYTE* const base = ctx->base;
2541 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002542 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002543 const BYTE* const prefixStart = base + dictLimit;
2544 const BYTE* const dictBase = ctx->dictBase;
2545 const BYTE* const dictEnd = dictBase + dictLimit;
2546 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2547
Yann Collet1ad7c822017-05-22 17:06:04 -07002548 const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
2549 const U32 mls = ctx->appliedParams.cParams.searchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002550
inikep64d7bcb2016-04-07 19:14:09 +02002551 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2552 size_t* offsetPtr,
2553 U32 maxNbAttempts, U32 matchLengthSearch);
2554 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2555
Yann Collet302ff032016-07-03 01:28:16 +02002556 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002557
Yann Collet302ff032016-07-03 01:28:16 +02002558 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002559 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002560 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002561
2562 /* Match Loop */
2563 while (ip < ilimit) {
2564 size_t matchLength=0;
2565 size_t offset=0;
2566 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002567 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002568
2569 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002570 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002571 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2572 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002573 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002574 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002575 /* repcode detected we should take it */
2576 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002577 matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002578 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002579 } }
2580
2581 /* first search (depth 0) */
2582 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002583 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002584 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002585 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002586 }
2587
Yann Collete42afbc2017-04-26 11:39:35 -07002588 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002589 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2590 continue;
2591 }
2592
inikep64d7bcb2016-04-07 19:14:09 +02002593 /* let's try to find a better solution */
2594 if (depth>=1)
2595 while (ip<ilimit) {
2596 ip ++;
2597 current++;
2598 /* check repCode */
2599 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002600 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002601 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2602 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002603 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002604 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2605 /* repcode detected */
2606 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002607 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002608 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002609 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002610 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002611 matchLength = repLength, offset = 0, start = ip;
2612 } }
2613
2614 /* search match, depth 1 */
2615 { size_t offset2=99999999;
2616 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002617 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2618 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002619 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002620 matchLength = ml2, offset = offset2, start = ip;
2621 continue; /* search a better one */
2622 } }
2623
2624 /* let's find an even better one */
2625 if ((depth==2) && (ip<ilimit)) {
2626 ip ++;
2627 current++;
2628 /* check repCode */
2629 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002630 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002631 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2632 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002633 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002634 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2635 /* repcode detected */
2636 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002637 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Colletc17e0202017-04-20 12:50:02 -07002638 int const gain2 = (int)(repLength * 4);
2639 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002640 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002641 matchLength = repLength, offset = 0, start = ip;
2642 } }
2643
2644 /* search match, depth 2 */
2645 { size_t offset2=99999999;
2646 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002647 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2648 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002649 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002650 matchLength = ml2, offset = offset2, start = ip;
2651 continue;
2652 } } }
2653 break; /* nothing found : store previous solution */
2654 }
2655
inikepfaa8d8a2016-04-05 19:01:10 +02002656 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002657 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002658 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002659 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2660 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002661 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002662 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002663 }
inikepfaa8d8a2016-04-05 19:01:10 +02002664
inikepfaa8d8a2016-04-05 19:01:10 +02002665 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002666_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002667 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002668 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002669 anchor = ip = start + matchLength;
2670 }
2671
2672 /* check immediate repcode */
2673 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002674 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002675 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2676 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002677 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002678 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2679 /* repcode detected we should take it */
2680 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002681 matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Collet302ff032016-07-03 01:28:16 +02002682 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002683 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2684 ip += matchLength;
2685 anchor = ip;
2686 continue; /* faster when present ... (?) */
2687 }
2688 break;
2689 } }
2690
Yann Collet4266c0a2016-06-14 01:49:25 +02002691 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002692 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002693
inikepfaa8d8a2016-04-05 19:01:10 +02002694 /* Last Literals */
2695 { size_t const lastLLSize = iend - anchor;
2696 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2697 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002698 }
2699}
2700
2701
Yann Collet59d1f792016-01-23 19:28:41 +01002702void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002703{
inikep64d7bcb2016-04-07 19:14:09 +02002704 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002705}
2706
Yann Collet59d1f792016-01-23 19:28:41 +01002707static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002708{
Yann Colleta1249dc2016-01-25 04:22:03 +01002709 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002710}
Yann Collet9a24e592015-11-22 02:53:43 +01002711
Yann Collet59d1f792016-01-23 19:28:41 +01002712static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002713{
Yann Colleta1249dc2016-01-25 04:22:03 +01002714 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002715}
2716
Yann Collet59d1f792016-01-23 19:28:41 +01002717static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002718{
Yann Colleta1249dc2016-01-25 04:22:03 +01002719 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002720}
2721
inikepef519412016-04-21 11:08:43 +02002722
inikepef519412016-04-21 11:08:43 +02002723/* The optimal parser */
2724#include "zstd_opt.h"
2725
2726static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2727{
Yann Colletd4f4e582016-06-27 01:31:35 +02002728#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002729 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2730#else
2731 (void)ctx; (void)src; (void)srcSize;
2732 return;
2733#endif
2734}
2735
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002736static void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002737{
2738#ifdef ZSTD_OPT_H_91842398743
2739 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002740#else
2741 (void)ctx; (void)src; (void)srcSize;
2742 return;
2743#endif
inikepef519412016-04-21 11:08:43 +02002744}
2745
inikepd3b8d7a2016-02-22 10:06:17 +01002746static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002747{
Yann Colletd4f4e582016-06-27 01:31:35 +02002748#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002749 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2750#else
2751 (void)ctx; (void)src; (void)srcSize;
2752 return;
2753#endif
2754}
2755
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002756static void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002757{
2758#ifdef ZSTD_OPT_H_91842398743
2759 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002760#else
2761 (void)ctx; (void)src; (void)srcSize;
2762 return;
2763#endif
inikepe2bfe242016-01-31 11:25:48 +01002764}
2765
Yann Collet7a231792015-11-21 15:27:35 +01002766
Yann Colletb44ab822017-06-20 14:11:49 -07002767/* ZSTD_selectBlockCompressor() :
2768 * assumption : strat is a valid strategy */
Yann Collet59d1f792016-01-23 19:28:41 +01002769typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Colletb923f652016-01-26 03:14:20 +01002770static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002771{
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002772 static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
Yann Colletb44ab822017-06-20 14:11:49 -07002773 { ZSTD_compressBlock_fast /* default for 0 */,
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002774 ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy,
Yann Colletc17e0202017-04-20 12:50:02 -07002775 ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002776 ZSTD_compressBlock_btopt, ZSTD_compressBlock_btultra },
Yann Colletb44ab822017-06-20 14:11:49 -07002777 { ZSTD_compressBlock_fast_extDict /* default for 0 */,
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002778 ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict,
Yann Colletc17e0202017-04-20 12:50:02 -07002779 ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002780 ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01002781 };
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002782 ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
Yann Colletb44ab822017-06-20 14:11:49 -07002783 assert((U32)strat >= (U32)ZSTD_fast);
2784 assert((U32)strat <= (U32)ZSTD_btultra);
Yann Collet7fe531e2015-11-29 02:38:09 +01002785
Yann Colletb44ab822017-06-20 14:11:49 -07002786 return blockCompressor[extDict!=0][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002787}
2788
2789
Yann Colletd1b26842016-03-15 01:24:33 +01002790static 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 +01002791{
Yann Collet1ad7c822017-05-22 17:06:04 -07002792 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002793 const BYTE* const base = zc->base;
2794 const BYTE* const istart = (const BYTE*)src;
2795 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002796 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 +02002797 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002798 if (current > zc->nextToUpdate + 384)
Yann Colletc17e0202017-04-20 12:50:02 -07002799 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 +01002800 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002801 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002802}
2803
2804
Yann Colletdb8e21d2017-05-12 13:46:49 -07002805/*! ZSTD_compress_frameChunk() :
Yann Colletc991cc12016-07-28 00:55:43 +02002806* Compress a chunk of data into one or multiple blocks.
2807* All blocks will be terminated, all input will be consumed.
2808* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2809* Frame is supposed already started (header already produced)
2810* @return : compressed size, or an error code
2811*/
Yann Colletdb8e21d2017-05-12 13:46:49 -07002812static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002813 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002814 const void* src, size_t srcSize,
2815 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002816{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002817 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002818 size_t remaining = srcSize;
2819 const BYTE* ip = (const BYTE*)src;
2820 BYTE* const ostart = (BYTE*)dst;
2821 BYTE* op = ostart;
Yann Collet1ad7c822017-05-22 17:06:04 -07002822 U32 const maxDist = 1 << cctx->appliedParams.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002823
Yann Collet1ad7c822017-05-22 17:06:04 -07002824 if (cctx->appliedParams.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002825 XXH64_update(&cctx->xxhState, src, srcSize);
2826
Yann Collet2ce49232016-02-02 14:36:49 +01002827 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002828 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002829 size_t cSize;
2830
Yann Colletc17e0202017-04-20 12:50:02 -07002831 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
2832 return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01002833 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002834
Yann Collet346efcc2016-08-02 14:26:00 +02002835 /* preemptive overflow correction */
Sean Purcell881abe42017-03-07 16:52:23 -08002836 if (cctx->lowLimit > (3U<<29)) {
Yann Collet1ad7c822017-05-22 17:06:04 -07002837 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->appliedParams.cParams.hashLog, cctx->appliedParams.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002838 U32 const current = (U32)(ip - cctx->base);
Yann Collet1ad7c822017-05-22 17:06:04 -07002839 U32 const newCurrent = (current & cycleMask) + (1 << cctx->appliedParams.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002840 U32 const correction = current - newCurrent;
2841 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002842 ZSTD_reduceIndex(cctx, correction);
2843 cctx->base += correction;
2844 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002845 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002846 cctx->dictLimit -= correction;
2847 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2848 else cctx->nextToUpdate -= correction;
2849 }
2850
Yann Collet06e76972017-01-25 16:39:03 -08002851 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002852 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002853 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2854 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2855 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002856 }
Yann Collet89db5e02015-11-13 11:27:46 +01002857
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002858 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002859 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002860
Yann Collet2ce49232016-02-02 14:36:49 +01002861 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002862 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2863 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2864 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2865 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2866 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002867 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002868 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002869 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002870 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002871 }
2872
2873 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002874 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002875 ip += blockSize;
2876 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002877 }
2878
Yann Collet62470b42016-07-28 15:29:08 +02002879 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002880 return op-ostart;
2881}
2882
2883
Yann Collet6236eba2016-04-12 15:52:33 +02002884static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002885 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002886{ BYTE* const op = (BYTE*)dst;
Yann Collet31533ba2017-04-27 00:29:04 -07002887 U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2888 U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002889 U32 const checksumFlag = params.fParams.checksumFlag>0;
2890 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002891 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002892 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2893 U32 const fcsCode = params.fParams.contentSizeFlag ?
Nick Terrell55fc1f92017-05-24 13:50:10 -07002894 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002895 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002896 size_t pos;
2897
2898 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet009d6042017-05-19 10:17:59 -07002899 DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
Yann Collet0be6fd32017-05-08 16:08:01 -07002900 !params.fParams.noDictIDFlag, dictID, dictIDSizeCode);
Yann Collet6236eba2016-04-12 15:52:33 +02002901
2902 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002903 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002904 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002905 switch(dictIDSizeCode)
2906 {
Yann Colletcd2892f2017-06-01 09:44:54 -07002907 default: assert(0); /* impossible */
Yann Colletc46fb922016-05-29 05:01:04 +02002908 case 0 : break;
2909 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002910 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002911 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2912 }
Yann Collet673f0d72016-06-06 00:26:38 +02002913 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002914 {
Yann Colletcd2892f2017-06-01 09:44:54 -07002915 default: assert(0); /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002916 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002917 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2918 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002919 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002920 }
Yann Colletc46fb922016-05-29 05:01:04 +02002921 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002922}
2923
2924
Yann Collet346efcc2016-08-02 14:26:00 +02002925static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002926 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002927 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002928 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002929{
Yann Collet2acb5d32015-10-29 16:49:43 +01002930 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002931 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002932
Yann Collet346efcc2016-08-02 14:26:00 +02002933 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002934
Yann Collet346efcc2016-08-02 14:26:00 +02002935 if (frame && (cctx->stage==ZSTDcs_init)) {
Yann Colleta0ba8492017-06-16 13:29:17 -07002936 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams,
2937 cctx->pledgedSrcSizePlusOne-1, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002938 if (ZSTD_isError(fhSize)) return fhSize;
2939 dstCapacity -= fhSize;
2940 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002941 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002942 }
Yann Colletf3eca252015-10-22 15:31:46 +01002943
Yann Collet417890c2015-12-04 17:16:37 +01002944 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002945 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002946 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002947 ptrdiff_t const delta = cctx->nextSrc - ip;
2948 cctx->lowLimit = cctx->dictLimit;
2949 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2950 cctx->dictBase = cctx->base;
2951 cctx->base -= delta;
2952 cctx->nextToUpdate = cctx->dictLimit;
2953 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002954 }
2955
Yann Collet346efcc2016-08-02 14:26:00 +02002956 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2957 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2958 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2959 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2960 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002961 }
2962
Yann Collet346efcc2016-08-02 14:26:00 +02002963 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002964
Yann Collet5eb749e2017-01-11 18:21:25 +01002965 if (srcSize) {
2966 size_t const cSize = frame ?
Yann Colletdb8e21d2017-05-12 13:46:49 -07002967 ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
Yann Collet346efcc2016-08-02 14:26:00 +02002968 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002969 if (ZSTD_isError(cSize)) return cSize;
Yann Collet20d5e032017-04-11 18:34:02 -07002970 cctx->consumedSrcSize += srcSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002971 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01002972 } else
2973 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002974}
2975
Yann Colletbf42c8e2016-01-09 01:08:23 +01002976
Yann Collet5b567392016-07-28 01:17:22 +02002977size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002978 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002979 const void* src, size_t srcSize)
2980{
Yann Collet20d5e032017-04-11 18:34:02 -07002981 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
Yann Collet5b567392016-07-28 01:17:22 +02002982}
2983
2984
Yann Colletfa3671e2017-05-19 10:51:30 -07002985size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002986{
Yann Colletfa3671e2017-05-19 10:51:30 -07002987 U32 const cLevel = cctx->compressionLevel;
2988 ZSTD_compressionParameters cParams = (cLevel == ZSTD_CLEVEL_CUSTOM) ?
Yann Collet1ad7c822017-05-22 17:06:04 -07002989 cctx->appliedParams.cParams :
Yann Colletfa3671e2017-05-19 10:51:30 -07002990 ZSTD_getCParams(cLevel, 0, 0);
2991 return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog);
Yann Colletcf05b9d2016-07-18 16:52:10 +02002992}
2993
2994size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2995{
Yann Colletfa3671e2017-05-19 10:51:30 -07002996 size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002997 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07002998 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002999}
3000
Yann Collet16a0b102017-03-24 12:46:46 -07003001/*! ZSTD_loadDictionaryContent() :
3002 * @return : 0, or an error code
3003 */
Yann Colletb923f652016-01-26 03:14:20 +01003004static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01003005{
3006 const BYTE* const ip = (const BYTE*) src;
3007 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01003008
Yann Collet417890c2015-12-04 17:16:37 +01003009 /* input becomes current prefix */
3010 zc->lowLimit = zc->dictLimit;
3011 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
3012 zc->dictBase = zc->base;
3013 zc->base += ip - zc->nextSrc;
3014 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08003015 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01003016
3017 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02003018 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01003019
Yann Collet1ad7c822017-05-22 17:06:04 -07003020 switch(zc->appliedParams.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01003021 {
3022 case ZSTD_fast:
Yann Collet1ad7c822017-05-22 17:06:04 -07003023 ZSTD_fillHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01003024 break;
3025
Yann Collet45dc3562016-07-12 09:47:31 +02003026 case ZSTD_dfast:
Yann Collet1ad7c822017-05-22 17:06:04 -07003027 ZSTD_fillDoubleHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
Yann Collet45dc3562016-07-12 09:47:31 +02003028 break;
3029
Yann Collet417890c2015-12-04 17:16:37 +01003030 case ZSTD_greedy:
3031 case ZSTD_lazy:
3032 case ZSTD_lazy2:
Yann Collet16a0b102017-03-24 12:46:46 -07003033 if (srcSize >= HASH_READ_SIZE)
Yann Collet1ad7c822017-05-22 17:06:04 -07003034 ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01003035 break;
3036
3037 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01003038 case ZSTD_btopt:
Nick Terrelleeb31ee2017-03-09 11:44:25 -08003039 case ZSTD_btultra:
Yann Collet16a0b102017-03-24 12:46:46 -07003040 if (srcSize >= HASH_READ_SIZE)
Yann Collet1ad7c822017-05-22 17:06:04 -07003041 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01003042 break;
3043
3044 default:
Yann Colletcd2892f2017-06-01 09:44:54 -07003045 assert(0); /* not possible : not a valid strategy id */
Yann Collet417890c2015-12-04 17:16:37 +01003046 }
3047
Nick Terrellecf90ca2017-02-13 18:27:34 -08003048 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01003049 return 0;
3050}
3051
3052
Nick Terrellf9c9af32016-10-19 17:22:08 -07003053/* Dictionaries that assign zero probability to symbols that show up causes problems
3054 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
3055 that we may encounter during compression.
3056 NOTE: This behavior is not standard and could be improved in the future. */
3057static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
3058 U32 s;
3059 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
3060 for (s = 0; s <= maxSymbolValue; ++s) {
3061 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
3062 }
3063 return 0;
3064}
3065
3066
Yann Colletb923f652016-01-26 03:14:20 +01003067/* Dictionary format :
Yann Colletbea78e82017-03-22 18:09:11 -07003068 * See :
3069 * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
3070 */
Yann Collet16a0b102017-03-24 12:46:46 -07003071/*! ZSTD_loadZstdDictionary() :
3072 * @return : 0, or an error code
3073 * assumptions : magic number supposed already checked
3074 * dictSize supposed > 8
Yann Colletbea78e82017-03-22 18:09:11 -07003075 */
Yann Collet16a0b102017-03-24 12:46:46 -07003076static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01003077{
Yann Collet52a06222016-06-15 13:53:34 +02003078 const BYTE* dictPtr = (const BYTE*)dict;
3079 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07003080 short offcodeNCount[MaxOff+1];
3081 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08003082 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01003083
Yann Colletbea78e82017-03-22 18:09:11 -07003084 dictPtr += 4; /* skip magic number */
Yann Collet1ad7c822017-05-22 17:06:04 -07003085 cctx->dictID = cctx->appliedParams.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
Yann Colletbea78e82017-03-22 18:09:11 -07003086 dictPtr += 4;
3087
Yann Collet71ddeb62017-04-20 22:54:54 -07003088 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufCTable, 255, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003089 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003090 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003091 }
Yann Colletfb810d62016-01-28 00:18:06 +01003092
Nick Terrellf9c9af32016-10-19 17:22:08 -07003093 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02003094 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003095 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003096 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003097 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Colletc17e0202017-04-20 12:50:02 -07003098 CHECK_E( FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)),
3099 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003100 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003101 }
Yann Colletfb810d62016-01-28 00:18:06 +01003102
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003103 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07003104 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02003105 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003106 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003107 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003108 /* Every match length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07003109 CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
3110 CHECK_E( FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)),
3111 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003112 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003113 }
Yann Colletfb810d62016-01-28 00:18:06 +01003114
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003115 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07003116 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02003117 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003118 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003119 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003120 /* Every literal length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07003121 CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
3122 CHECK_E( FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)),
3123 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003124 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003125 }
Yann Colletfb810d62016-01-28 00:18:06 +01003126
Yann Collet52a06222016-06-15 13:53:34 +02003127 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07003128 cctx->rep[0] = MEM_readLE32(dictPtr+0);
3129 cctx->rep[1] = MEM_readLE32(dictPtr+4);
3130 cctx->rep[2] = MEM_readLE32(dictPtr+8);
Yann Collet52a06222016-06-15 13:53:34 +02003131 dictPtr += 12;
3132
Yann Colletbea78e82017-03-22 18:09:11 -07003133 { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
3134 U32 offcodeMax = MaxOff;
3135 if (dictContentSize <= ((U32)-1) - 128 KB) {
3136 U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
3137 offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
Nick Terrellb2c39a22016-10-24 14:11:27 -07003138 }
Yann Colletbea78e82017-03-22 18:09:11 -07003139 /* All offset values <= dictContentSize + 128 KB must be representable */
Nick Terrellf9c9af32016-10-19 17:22:08 -07003140 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
Yann Colletbea78e82017-03-22 18:09:11 -07003141 /* All repCodes must be <= dictContentSize and != 0*/
3142 { U32 u;
3143 for (u=0; u<3; u++) {
3144 if (cctx->rep[u] == 0) return ERROR(dictionary_corrupted);
3145 if (cctx->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07003146 } }
Nick Terrellf9c9af32016-10-19 17:22:08 -07003147
Yann Collet71ddeb62017-04-20 22:54:54 -07003148 cctx->fseCTables_ready = 1;
3149 cctx->hufCTable_repeatMode = HUF_repeat_valid;
Yann Collet16a0b102017-03-24 12:46:46 -07003150 return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
3151 }
Yann Colletb923f652016-01-26 03:14:20 +01003152}
3153
Yann Colletd1b26842016-03-15 01:24:33 +01003154/** ZSTD_compress_insertDictionary() :
3155* @return : 0, or an error code */
Yann Collet7bd1a292017-06-21 11:50:33 -07003156static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
3157 const void* dict, size_t dictSize,
3158 ZSTD_dictMode_e dictMode)
Yann Colletb923f652016-01-26 03:14:20 +01003159{
Yann Colletc46fb922016-05-29 05:01:04 +02003160 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01003161
Yann Collet7bd1a292017-06-21 11:50:33 -07003162 /* dict restricted modes */
3163 if (dictMode==ZSTD_dm_rawContent)
Yann Collet16a0b102017-03-24 12:46:46 -07003164 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
Yann Colletd1b26842016-03-15 01:24:33 +01003165
Yann Collet7bd1a292017-06-21 11:50:33 -07003166 if (MEM_readLE32(dict) != ZSTD_DICT_MAGIC) {
3167 if (dictMode == ZSTD_dm_auto)
3168 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
3169 if (dictMode == ZSTD_dm_fullDict)
3170 return ERROR(dictionary_wrong);
3171 assert(0); /* impossible */
3172 }
3173
3174 /* dict as full zstd dictionary */
Yann Collet16a0b102017-03-24 12:46:46 -07003175 return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
Yann Colletecd651b2016-01-07 15:35:18 +01003176}
3177
Yann Collet27caf2a2016-04-01 15:48:48 +02003178/*! ZSTD_compressBegin_internal() :
Yann Colletc3bce242017-06-20 16:09:11 -07003179 * @return : 0, or an error code */
Yann Collet7bd1a292017-06-21 11:50:33 -07003180static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01003181 const void* dict, size_t dictSize,
Yann Collet7bd1a292017-06-21 11:50:33 -07003182 ZSTD_dictMode_e dictMode,
Yann Collet18803372017-05-22 18:21:51 -07003183 const ZSTD_CDict* cdict,
Yann Collet5ac72b42017-05-23 11:18:24 -07003184 ZSTD_parameters params, U64 pledgedSrcSize,
3185 ZSTD_buffered_policy_e zbuff)
Yann Colletf3eca252015-10-22 15:31:46 +01003186{
Yann Collet5ac72b42017-05-23 11:18:24 -07003187 /* params are supposed to be fully validated at this point */
Yann Colletab9162e2017-04-11 10:46:20 -07003188 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet18803372017-05-22 18:21:51 -07003189 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
3190
3191 if (cdict && cdict->dictContentSize>0)
Yann Collet5ac72b42017-05-23 11:18:24 -07003192 return ZSTD_copyCCtx_internal(cctx, cdict->refContext,
3193 params.fParams, pledgedSrcSize);
Yann Collet18803372017-05-22 18:21:51 -07003194
Yann Collet5ac72b42017-05-23 11:18:24 -07003195 CHECK_F(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
3196 ZSTDcrp_continue, zbuff));
Yann Collet7bd1a292017-06-21 11:50:33 -07003197 return ZSTD_compress_insertDictionary(cctx, dict, dictSize, dictMode);
Yann Collet88fcd292015-11-25 14:42:45 +01003198}
3199
3200
Yann Collet27caf2a2016-04-01 15:48:48 +02003201/*! ZSTD_compressBegin_advanced() :
3202* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02003203size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02003204 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02003205 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02003206{
3207 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02003208 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet7bd1a292017-06-21 11:50:33 -07003209 return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
Yann Collet5ac72b42017-05-23 11:18:24 -07003210 params, pledgedSrcSize, ZSTDb_not_buffered);
Yann Collet27caf2a2016-04-01 15:48:48 +02003211}
3212
3213
Yann Collet81e13ef2016-06-07 00:51:51 +02003214size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01003215{
Yann Collet6c6e1752016-06-27 15:28:45 +02003216 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet7bd1a292017-06-21 11:50:33 -07003217 return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
Yann Collet5ac72b42017-05-23 11:18:24 -07003218 params, 0, ZSTDb_not_buffered);
Yann Collet1c8e1942016-01-26 16:31:22 +01003219}
Yann Collet083fcc82015-10-25 14:06:35 +01003220
inikep19bd48f2016-04-04 12:10:00 +02003221
Yann Colletb05c4822017-01-12 02:01:28 +01003222size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01003223{
Yann Colletb05c4822017-01-12 02:01:28 +01003224 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01003225}
3226
3227
Yann Collet62470b42016-07-28 15:29:08 +02003228/*! ZSTD_writeEpilogue() :
3229* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01003230* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02003231static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01003232{
Yann Colletc991cc12016-07-28 00:55:43 +02003233 BYTE* const ostart = (BYTE*)dst;
3234 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02003235 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01003236
Yann Collet009d6042017-05-19 10:17:59 -07003237 DEBUGLOG(5, "ZSTD_writeEpilogue");
Yann Collet87c18b22016-08-26 01:43:47 +02003238 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02003239
3240 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02003241 if (cctx->stage == ZSTDcs_init) {
Yann Collet1ad7c822017-05-22 17:06:04 -07003242 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02003243 if (ZSTD_isError(fhSize)) return fhSize;
3244 dstCapacity -= fhSize;
3245 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02003246 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01003247 }
3248
Yann Colletc991cc12016-07-28 00:55:43 +02003249 if (cctx->stage != ZSTDcs_ending) {
3250 /* write one last empty block, make it the "last" block */
3251 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
3252 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
3253 MEM_writeLE32(op, cBlockHeader24);
3254 op += ZSTD_blockHeaderSize;
3255 dstCapacity -= ZSTD_blockHeaderSize;
3256 }
3257
Yann Collet1ad7c822017-05-22 17:06:04 -07003258 if (cctx->appliedParams.fParams.checksumFlag) {
Yann Colletc991cc12016-07-28 00:55:43 +02003259 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
3260 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
3261 MEM_writeLE32(op, checksum);
3262 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003263 }
Yann Collet2acb5d32015-10-29 16:49:43 +01003264
Yann Collet731ef162016-07-27 21:05:12 +02003265 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02003266 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01003267}
3268
Yann Colletfd416f12016-01-30 03:14:15 +01003269
Yann Collet62470b42016-07-28 15:29:08 +02003270size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
3271 void* dst, size_t dstCapacity,
3272 const void* src, size_t srcSize)
3273{
3274 size_t endResult;
Yann Collet009d6042017-05-19 10:17:59 -07003275 size_t const cSize = ZSTD_compressContinue_internal(cctx,
3276 dst, dstCapacity, src, srcSize,
3277 1 /* frame mode */, 1 /* last chunk */);
Yann Collet62470b42016-07-28 15:29:08 +02003278 if (ZSTD_isError(cSize)) return cSize;
3279 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
3280 if (ZSTD_isError(endResult)) return endResult;
Yann Collet1ad7c822017-05-22 17:06:04 -07003281 if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */
Yann Collet2cf77552017-06-16 12:34:41 -07003282 DEBUGLOG(5, "end of frame : controlling src size");
Yann Colleta0ba8492017-06-16 13:29:17 -07003283 if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) {
Yann Collet2cf77552017-06-16 12:34:41 -07003284 DEBUGLOG(5, "error : pledgedSrcSize = %u, while realSrcSize = %u",
Yann Colletaee916e2017-06-16 17:01:46 -07003285 (U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize);
Yann Collet0be6fd32017-05-08 16:08:01 -07003286 return ERROR(srcSize_wrong);
Yann Collet9e73f2f2017-06-16 12:24:01 -07003287 } }
Yann Collet62470b42016-07-28 15:29:08 +02003288 return cSize + endResult;
3289}
3290
3291
Yann Collet19c10022016-07-28 01:25:46 +02003292static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01003293 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01003294 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01003295 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01003296 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01003297{
Yann Collet7bd1a292017-06-21 11:50:33 -07003298 CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
3299 params, srcSize, ZSTDb_not_buffered) );
Yann Collet62470b42016-07-28 15:29:08 +02003300 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01003301}
3302
Yann Collet21588e32016-03-30 16:50:44 +02003303size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
3304 void* dst, size_t dstCapacity,
3305 const void* src, size_t srcSize,
3306 const void* dict,size_t dictSize,
3307 ZSTD_parameters params)
3308{
Yann Colletcf409a72016-09-26 16:41:05 +02003309 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02003310 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
3311}
3312
Yann Colletc17e0202017-04-20 12:50:02 -07003313size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
3314 const void* dict, size_t dictSize, int compressionLevel)
Yann Collet31683c02015-12-18 01:26:48 +01003315{
Yann Collet407a11f2016-11-03 15:52:01 -07003316 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02003317 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02003318 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01003319}
3320
Yann Colletd1b26842016-03-15 01:24:33 +01003321size_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 +01003322{
Yann Collet21588e32016-03-30 16:50:44 +02003323 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01003324}
3325
Yann Colletd1b26842016-03-15 01:24:33 +01003326size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01003327{
Yann Collet44fe9912015-10-29 22:02:40 +01003328 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01003329 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01003330 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Colletae728a42017-05-30 17:11:39 -07003331 ctxBody.customMem = ZSTD_defaultCMem;
Yann Colletd1b26842016-03-15 01:24:33 +01003332 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Colletae728a42017-05-30 17:11:39 -07003333 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 +01003334 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01003335}
Yann Colletfdcad6d2015-12-17 23:50:15 +01003336
Yann Colletfd416f12016-01-30 03:14:15 +01003337
Yann Collet81e13ef2016-06-07 00:51:51 +02003338/* ===== Dictionary API ===== */
3339
Yann Colleta1d67042017-05-08 17:51:49 -07003340/*! ZSTD_estimateCDictSize() :
3341 * Estimate amount of memory that will be needed to create a dictionary with following arguments */
Yann Collet25989e32017-05-25 15:07:37 -07003342size_t ZSTD_estimateCDictSize(ZSTD_compressionParameters cParams, size_t dictSize, unsigned byReference)
Yann Colleta1d67042017-05-08 17:51:49 -07003343{
Yann Collet7bd1a292017-06-21 11:50:33 -07003344 DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict));
3345 DEBUGLOG(5, "CCtx estimate : %u", (U32)ZSTD_estimateCCtxSize(cParams));
Yann Collet25989e32017-05-25 15:07:37 -07003346 return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize(cParams)
3347 + (byReference ? 0 : dictSize);
Yann Colleta1d67042017-05-08 17:51:49 -07003348}
3349
Yann Colletd7c65892016-09-15 02:50:27 +02003350size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
3351{
3352 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Collet7bd1a292017-06-21 11:50:33 -07003353 DEBUGLOG(5, "sizeof(*cdict) : %u", (U32)sizeof(*cdict));
3354 DEBUGLOG(5, "ZSTD_sizeof_CCtx : %u", (U32)ZSTD_sizeof_CCtx(cdict->refContext));
Yann Colletaca113f2016-12-23 22:25:03 +01003355 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02003356}
3357
Yann Collet1c3ab0c2017-04-27 12:57:11 -07003358static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_frameParameters fParams)
3359{
3360 ZSTD_parameters params;
3361 params.cParams = cParams;
3362 params.fParams = fParams;
3363 return params;
3364}
3365
Yann Colletcdf7e822017-05-25 18:05:49 -07003366static size_t ZSTD_initCDict_internal(
3367 ZSTD_CDict* cdict,
Yann Collet7bd1a292017-06-21 11:50:33 -07003368 const void* dictBuffer, size_t dictSize,
3369 unsigned byReference, ZSTD_dictMode_e dictMode,
Yann Colletcdf7e822017-05-25 18:05:49 -07003370 ZSTD_compressionParameters cParams)
3371{
3372 if ((byReference) || (!dictBuffer) || (!dictSize)) {
3373 cdict->dictBuffer = NULL;
3374 cdict->dictContent = dictBuffer;
3375 } else {
3376 void* const internalBuffer = ZSTD_malloc(dictSize, cdict->refContext->customMem);
Yann Colletcdf7e822017-05-25 18:05:49 -07003377 cdict->dictBuffer = internalBuffer;
3378 cdict->dictContent = internalBuffer;
Yann Colletc3bce242017-06-20 16:09:11 -07003379 if (!internalBuffer) return ERROR(memory_allocation);
3380 memcpy(internalBuffer, dictBuffer, dictSize);
Yann Colletcdf7e822017-05-25 18:05:49 -07003381 }
3382 cdict->dictContentSize = dictSize;
3383
3384 { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */,
3385 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */
3386 ZSTD_parameters const params = ZSTD_makeParams(cParams, fParams);
Yann Collet7bd1a292017-06-21 11:50:33 -07003387 CHECK_F( ZSTD_compressBegin_internal(cdict->refContext,
3388 cdict->dictContent, dictSize, dictMode,
3389 NULL,
3390 params, ZSTD_CONTENTSIZE_UNKNOWN,
3391 ZSTDb_not_buffered) );
Yann Colletcdf7e822017-05-25 18:05:49 -07003392 }
3393
3394 return 0;
3395}
3396
Yann Collet7bd1a292017-06-21 11:50:33 -07003397ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
3398 unsigned byReference, ZSTD_dictMode_e dictMode,
Yann Collet31533ba2017-04-27 00:29:04 -07003399 ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02003400{
Yann Collet8b21ec42017-05-19 19:46:15 -07003401 DEBUGLOG(5, "ZSTD_createCDict_advanced");
Yann Colletae728a42017-05-30 17:11:39 -07003402 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02003403
Yann Collet466f92e2017-06-20 16:25:29 -07003404 { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02003405 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
3406
Yann Collet1f57c2e2016-12-21 16:20:11 +01003407 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07003408 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01003409 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02003410 return NULL;
3411 }
Yann Colletcdf7e822017-05-25 18:05:49 -07003412 cdict->refContext = cctx;
Yann Collet81e13ef2016-06-07 00:51:51 +02003413
Yann Colletcdf7e822017-05-25 18:05:49 -07003414 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
Yann Collet7bd1a292017-06-21 11:50:33 -07003415 dictBuffer, dictSize,
3416 byReference, dictMode,
Yann Colletcdf7e822017-05-25 18:05:49 -07003417 cParams) )) {
3418 ZSTD_freeCDict(cdict);
3419 return NULL;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07003420 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01003421
Yann Collet81e13ef2016-06-07 00:51:51 +02003422 return cdict;
3423 }
3424}
3425
3426ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
3427{
Yann Collet31533ba2017-04-27 00:29:04 -07003428 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
Yann Collet7bd1a292017-06-21 11:50:33 -07003429 return ZSTD_createCDict_advanced(dict, dictSize,
3430 0 /* byReference */, ZSTD_dm_auto,
3431 cParams, ZSTD_defaultCMem);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003432}
3433
3434ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
3435{
Yann Collet31533ba2017-04-27 00:29:04 -07003436 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
Yann Collet7bd1a292017-06-21 11:50:33 -07003437 return ZSTD_createCDict_advanced(dict, dictSize,
3438 1 /* byReference */, ZSTD_dm_auto,
3439 cParams, ZSTD_defaultCMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02003440}
3441
3442size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
3443{
Yann Collet23b6e052016-08-28 21:05:43 -07003444 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02003445 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07003446 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01003447 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003448 ZSTD_free(cdict, cMem);
3449 return 0;
3450 }
Yann Collet81e13ef2016-06-07 00:51:51 +02003451}
3452
Yann Colletcdf7e822017-05-25 18:05:49 -07003453/*! ZSTD_initStaticCDict_advanced() :
3454 * Generate a digested dictionary in provided memory area.
3455 * workspace: The memory area to emplace the dictionary into.
3456 * Provided pointer must 8-bytes aligned.
3457 * It must outlive dictionary usage.
3458 * workspaceSize: Use ZSTD_estimateCDictSize()
3459 * to determine how large workspace must be.
3460 * cParams : use ZSTD_getCParams() to transform a compression level
3461 * into its relevants cParams.
3462 * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
3463 * Note : there is no corresponding "free" function.
3464 * Since workspace was allocated externally, it must be freed externally.
3465 */
3466ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
Yann Collet7bd1a292017-06-21 11:50:33 -07003467 const void* dict, size_t dictSize,
3468 unsigned byReference, ZSTD_dictMode_e dictMode,
Yann Colletcdf7e822017-05-25 18:05:49 -07003469 ZSTD_compressionParameters cParams)
3470{
3471 size_t const cctxSize = ZSTD_estimateCCtxSize(cParams);
3472 size_t const neededSize = sizeof(ZSTD_CDict) + (byReference ? 0 : dictSize)
3473 + cctxSize;
3474 ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
3475 void* ptr;
Yann Collet2cf77552017-06-16 12:34:41 -07003476 DEBUGLOG(5, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7);
Yann Colletcdf7e822017-05-25 18:05:49 -07003477 if ((size_t)workspace & 7) return NULL; /* 8-aligned */
Yann Collet2cf77552017-06-16 12:34:41 -07003478 DEBUGLOG(5, "(workspaceSize < neededSize) : (%u < %u) => %u",
Yann Colletcdf7e822017-05-25 18:05:49 -07003479 (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize));
3480 if (workspaceSize < neededSize) return NULL;
3481
3482 if (!byReference) {
3483 memcpy(cdict+1, dict, dictSize);
3484 dict = cdict+1;
3485 ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize;
3486 } else {
3487 ptr = cdict+1;
3488 }
3489 cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize);
3490
3491 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
Yann Collet7bd1a292017-06-21 11:50:33 -07003492 dict, dictSize,
3493 1 /* byReference */, dictMode,
3494 cParams) ))
Yann Colletcdf7e822017-05-25 18:05:49 -07003495 return NULL;
3496
3497 return cdict;
3498}
3499
Yann Collet8c910d22017-06-03 01:15:02 -07003500ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
Yann Collet95162342016-10-25 16:19:52 -07003501 return ZSTD_getParamsFromCCtx(cdict->refContext);
3502}
3503
Yann Collet715b9aa2017-04-18 13:55:53 -07003504/* ZSTD_compressBegin_usingCDict_advanced() :
Yann Collet4f818182017-04-17 17:57:35 -07003505 * cdict must be != NULL */
Yann Collet715b9aa2017-04-18 13:55:53 -07003506size_t ZSTD_compressBegin_usingCDict_advanced(
Yann Collet4f818182017-04-17 17:57:35 -07003507 ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
3508 ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003509{
Yann Collet5ac72b42017-05-23 11:18:24 -07003510 if (cdict==NULL) return ERROR(dictionary_wrong);
Yann Collet18803372017-05-22 18:21:51 -07003511 { ZSTD_parameters params = cdict->refContext->appliedParams;
Yann Collet4f818182017-04-17 17:57:35 -07003512 params.fParams = fParams;
Yann Collet18803372017-05-22 18:21:51 -07003513 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced");
Yann Collet7bd1a292017-06-21 11:50:33 -07003514 return ZSTD_compressBegin_internal(cctx,
3515 NULL, 0, ZSTD_dm_auto,
3516 cdict,
3517 params, pledgedSrcSize,
3518 ZSTDb_not_buffered);
Sean Purcell2db72492017-02-09 10:50:43 -08003519 }
Yann Collet4cb21292016-09-15 14:54:07 +02003520}
3521
Yann Collet4f818182017-04-17 17:57:35 -07003522/* ZSTD_compressBegin_usingCDict() :
3523 * pledgedSrcSize=0 means "unknown"
3524 * if pledgedSrcSize>0, it will enable contentSizeFlag */
Yann Collet768df122017-04-26 15:42:10 -07003525size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
Yann Collet4f818182017-04-17 17:57:35 -07003526{
Yann Collet768df122017-04-26 15:42:10 -07003527 ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Collet009d6042017-05-19 10:17:59 -07003528 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
Yann Collet768df122017-04-26 15:42:10 -07003529 return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0);
Yann Collet4f818182017-04-17 17:57:35 -07003530}
3531
Yann Colletf4bd8572017-04-27 11:31:55 -07003532size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
3533 void* dst, size_t dstCapacity,
3534 const void* src, size_t srcSize,
3535 const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
3536{
3537 CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */
3538 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02003539}
3540
Yann Collet07639052016-08-03 01:57:57 +02003541/*! ZSTD_compress_usingCDict() :
Yann Collet4f818182017-04-17 17:57:35 -07003542 * Compression using a digested Dictionary.
3543 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
3544 * Note that compression parameters are decided at CDict creation time
3545 * while frame parameters are hardcoded */
Yann Collet4cb21292016-09-15 14:54:07 +02003546size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
3547 void* dst, size_t dstCapacity,
3548 const void* src, size_t srcSize,
3549 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02003550{
Yann Collet4f818182017-04-17 17:57:35 -07003551 ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Colletf4bd8572017-04-27 11:31:55 -07003552 return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
Yann Collet81e13ef2016-06-07 00:51:51 +02003553}
3554
3555
3556
Yann Collet104e5b02016-08-12 13:04:27 +02003557/* ******************************************************************
3558* Streaming
3559********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003560
Yann Collet5a0c8e22016-08-12 01:20:36 +02003561ZSTD_CStream* ZSTD_createCStream(void)
3562{
Yann Colletae728a42017-05-30 17:11:39 -07003563 return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003564}
3565
3566ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
Yann Colletae728a42017-05-30 17:11:39 -07003567{ /* CStream and CCtx are now same object */
Yann Collet6fb2f242017-05-10 11:06:06 -07003568 return ZSTD_createCCtx_advanced(customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003569}
3570
3571size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
3572{
Yann Collet78553662017-05-08 17:15:00 -07003573 return ZSTD_freeCCtx(zcs); /* same object */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003574}
3575
Yann Collet5a0c8e22016-08-12 01:20:36 +02003576
3577
Yann Collet104e5b02016-08-12 13:04:27 +02003578/*====== Initialization ======*/
3579
Yann Colletfa3671e2017-05-19 10:51:30 -07003580size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003581
Yann Colletc17e0202017-04-20 12:50:02 -07003582size_t ZSTD_CStreamOutSize(void)
3583{
Yann Colletfa3671e2017-05-19 10:51:30 -07003584 return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
Yann Colletc17e0202017-04-20 12:50:02 -07003585}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003586
Yann Collet1ad7c822017-05-22 17:06:04 -07003587static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs,
3588 ZSTD_parameters params,
3589 unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003590{
Yann Collet1ad7c822017-05-22 17:06:04 -07003591 DEBUGLOG(5, "ZSTD_resetCStream_internal");
Yann Collet31533ba2017-04-27 00:29:04 -07003592
Yann Collet7bd1a292017-06-21 11:50:33 -07003593 CHECK_F( ZSTD_compressBegin_internal(zcs,
3594 NULL, 0, ZSTD_dm_auto,
3595 zcs->cdict,
3596 params, pledgedSrcSize,
3597 ZSTDb_buffered) );
Yann Collet4cb21292016-09-15 14:54:07 +02003598
3599 zcs->inToCompress = 0;
3600 zcs->inBuffPos = 0;
3601 zcs->inBuffTarget = zcs->blockSize;
3602 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -07003603 zcs->streamStage = zcss_load;
Yann Collet4cb21292016-09-15 14:54:07 +02003604 zcs->frameEnded = 0;
3605 return 0; /* ready to go */
3606}
3607
Yann Collet009d6042017-05-19 10:17:59 -07003608size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
3609{
Yann Collet1ad7c822017-05-22 17:06:04 -07003610 ZSTD_parameters params = zcs->requestedParams;
Yann Collet009d6042017-05-19 10:17:59 -07003611 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
Yann Colletb0739bc2017-05-22 17:45:15 -07003612 DEBUGLOG(5, "ZSTD_resetCStream");
Yann Collet009d6042017-05-19 10:17:59 -07003613 if (zcs->compressionLevel != ZSTD_CLEVEL_CUSTOM) {
3614 params.cParams = ZSTD_getCParams(zcs->compressionLevel, pledgedSrcSize, 0 /* dictSize */);
3615 }
Yann Collet5ac72b42017-05-23 11:18:24 -07003616 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Yann Collet009d6042017-05-19 10:17:59 -07003617}
3618
Yann Collet8c910d22017-06-03 01:15:02 -07003619size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
3620 const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
3621 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collete88034f2017-04-10 22:24:02 -07003622{
3623 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet8c910d22017-06-03 01:15:02 -07003624 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
Yann Collete88034f2017-04-10 22:24:02 -07003625
3626 if (dict && dictSize >= 8) {
Yann Colletc7fe2622017-05-23 13:16:00 -07003627 if (zcs->staticSize) { /* static CCtx : never uses malloc */
3628 /* incompatible with internal cdict creation */
3629 return ERROR(memory_allocation);
3630 }
Yann Collete88034f2017-04-10 22:24:02 -07003631 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet7bd1a292017-06-21 11:50:33 -07003632 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
3633 0 /* byReference */, ZSTD_dm_auto,
3634 params.cParams, zcs->customMem);
Yann Collete88034f2017-04-10 22:24:02 -07003635 zcs->cdict = zcs->cdictLocal;
Yann Collet466f92e2017-06-20 16:25:29 -07003636 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
Yann Collet8c910d22017-06-03 01:15:02 -07003637 } else {
3638 if (cdict) {
3639 ZSTD_parameters const cdictParams = ZSTD_getParamsFromCDict(cdict);
3640 params.cParams = cdictParams.cParams; /* cParams are enforced from cdict */
3641 }
Yann Collet466f92e2017-06-20 16:25:29 -07003642 ZSTD_freeCDict(zcs->cdictLocal);
3643 zcs->cdictLocal = NULL;
Yann Collet8c910d22017-06-03 01:15:02 -07003644 zcs->cdict = cdict;
Yann Collete88034f2017-04-10 22:24:02 -07003645 }
3646
Yann Collet8c910d22017-06-03 01:15:02 -07003647 zcs->requestedParams = params;
3648 zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Collet5ac72b42017-05-23 11:18:24 -07003649 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Sean Purcell2db72492017-02-09 10:50:43 -08003650}
3651
Yann Collet8c910d22017-06-03 01:15:02 -07003652/* ZSTD_initCStream_usingCDict_advanced() :
3653 * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
3654size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
3655 const ZSTD_CDict* cdict,
3656 ZSTD_frameParameters fParams,
3657 unsigned long long pledgedSrcSize)
3658{ /* cannot handle NULL cdict (does not know what to do) */
3659 if (!cdict) return ERROR(dictionary_wrong);
3660 { ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict);
3661 params.fParams = fParams;
3662 return ZSTD_initCStream_internal(zcs,
3663 NULL, 0, cdict,
3664 params, pledgedSrcSize);
3665 }
3666}
3667
3668/* note : cdict must outlive compression session */
3669size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3670{
3671 ZSTD_frameParameters const fParams = { 0 /* contentSize */, 0 /* checksum */, 0 /* hideDictID */ };
3672 return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, 0); /* note : will check that cdict != NULL */
3673}
3674
Yann Collet5a0c8e22016-08-12 01:20:36 +02003675size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
3676 const void* dict, size_t dictSize,
3677 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3678{
Yann Collet4b987ad2017-04-10 17:50:44 -07003679 CHECK_F( ZSTD_checkCParams(params.cParams) );
Yann Collet1ad7c822017-05-22 17:06:04 -07003680 zcs->requestedParams = params;
3681 zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Collet8c910d22017-06-03 01:15:02 -07003682 return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, pledgedSrcSize);
Yann Collet95162342016-10-25 16:19:52 -07003683}
3684
Yann Collet5a0c8e22016-08-12 01:20:36 +02003685size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3686{
3687 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet1ad7c822017-05-22 17:06:04 -07003688 zcs->compressionLevel = compressionLevel;
Yann Collet8c910d22017-06-03 01:15:02 -07003689 return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003690}
3691
Yann Collete795c8a2016-12-13 16:39:36 +01003692size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3693{
Yann Colletd564faa2016-12-18 21:39:15 +01003694 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
Yann Collete88034f2017-04-10 22:24:02 -07003695 params.fParams.contentSizeFlag = (pledgedSrcSize>0);
Yann Collet8c910d22017-06-03 01:15:02 -07003696 return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, params, pledgedSrcSize);
Yann Collete795c8a2016-12-13 16:39:36 +01003697}
3698
Yann Collet5a0c8e22016-08-12 01:20:36 +02003699size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3700{
Yann Collete88034f2017-04-10 22:24:02 -07003701 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0);
Yann Collet8c910d22017-06-03 01:15:02 -07003702 return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003703}
3704
Yann Collet104e5b02016-08-12 13:04:27 +02003705/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003706
Yann Collet01b15492017-05-30 18:10:26 -07003707MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity,
3708 const void* src, size_t srcSize)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003709{
3710 size_t const length = MIN(dstCapacity, srcSize);
Yann Collet18ab5af2017-05-31 09:59:22 -07003711 if (length) memcpy(dst, src, length);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003712 return length;
3713}
3714
3715static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
Yann Collet01b15492017-05-30 18:10:26 -07003716 ZSTD_outBuffer* output,
3717 ZSTD_inBuffer* input,
3718 ZSTD_EndDirective const flushMode)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003719{
Yann Collet01b15492017-05-30 18:10:26 -07003720 const char* const istart = (const char*)input->src;
3721 const char* const iend = istart + input->size;
3722 const char* ip = istart + input->pos;
3723 char* const ostart = (char*)output->dst;
3724 char* const oend = ostart + output->size;
3725 char* op = ostart + output->pos;
Yann Collet58e8d792017-06-02 18:20:48 -07003726 U32 someMoreWork = 1;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003727
Yann Collet58e8d792017-06-02 18:20:48 -07003728 /* check expectations */
Yann Collet8c910d22017-06-03 01:15:02 -07003729 DEBUGLOG(5, "ZSTD_compressStream_generic");
Yann Collet6d4fef32017-05-17 18:36:15 -07003730 assert(zcs->inBuff != NULL);
3731 assert(zcs->outBuff!= NULL);
Yann Collet58e8d792017-06-02 18:20:48 -07003732 assert(output->pos <= output->size);
3733 assert(input->pos <= input->size);
Yann Collet009d6042017-05-19 10:17:59 -07003734
Yann Collet5a0c8e22016-08-12 01:20:36 +02003735 while (someMoreWork) {
Yann Collet0be6fd32017-05-08 16:08:01 -07003736 switch(zcs->streamStage)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003737 {
Yann Collet1ad7c822017-05-22 17:06:04 -07003738 case zcss_init:
3739 /* call ZSTD_initCStream() first ! */
3740 return ERROR(init_missing);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003741
3742 case zcss_load:
3743 /* complete inBuffer */
3744 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
Yann Collet06589fe2017-05-31 10:03:20 -07003745 size_t const loaded = ZSTD_limitCopy(
3746 zcs->inBuff + zcs->inBuffPos, toLoad,
3747 ip, iend-ip);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003748 zcs->inBuffPos += loaded;
3749 ip += loaded;
Yann Collet009d6042017-05-19 10:17:59 -07003750 if ( (flushMode == ZSTD_e_continue)
3751 && (zcs->inBuffPos < zcs->inBuffTarget) ) {
3752 /* not enough input to fill full block : stop here */
3753 someMoreWork = 0; break;
3754 }
3755 if ( (flushMode == ZSTD_e_flush)
3756 && (zcs->inBuffPos == zcs->inToCompress) ) {
3757 /* empty */
3758 someMoreWork = 0; break;
Yann Collet559ee822017-06-16 11:58:21 -07003759 }
3760 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003761 /* compress current block (note : this stage cannot be stopped in the middle) */
Yann Collet009d6042017-05-19 10:17:59 -07003762 DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003763 { void* cDst;
3764 size_t cSize;
3765 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3766 size_t oSize = oend-op;
Yann Collet009d6042017-05-19 10:17:59 -07003767 unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003768 if (oSize >= ZSTD_compressBound(iSize))
Yann Collet559ee822017-06-16 11:58:21 -07003769 cDst = op; /* compress into output buffer, to skip flush stage */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003770 else
3771 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
Yann Collet009d6042017-05-19 10:17:59 -07003772 cSize = lastBlock ?
3773 ZSTD_compressEnd(zcs, cDst, oSize,
3774 zcs->inBuff + zcs->inToCompress, iSize) :
3775 ZSTD_compressContinue(zcs, cDst, oSize,
3776 zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003777 if (ZSTD_isError(cSize)) return cSize;
Yann Collet009d6042017-05-19 10:17:59 -07003778 zcs->frameEnded = lastBlock;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003779 /* prepare next block */
3780 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3781 if (zcs->inBuffTarget > zcs->inBuffSize)
Yann Collet009d6042017-05-19 10:17:59 -07003782 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
Yann Collet8b21ec42017-05-19 19:46:15 -07003783 DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
3784 (U32)zcs->inBuffTarget, (U32)zcs->inBuffSize);
3785 if (!lastBlock)
3786 assert(zcs->inBuffTarget <= zcs->inBuffSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003787 zcs->inToCompress = zcs->inBuffPos;
Yann Collet009d6042017-05-19 10:17:59 -07003788 if (cDst == op) { /* no need to flush */
3789 op += cSize;
3790 if (zcs->frameEnded) {
Yann Collet559ee822017-06-16 11:58:21 -07003791 DEBUGLOG(5, "Frame completed directly in outBuffer");
Yann Collet009d6042017-05-19 10:17:59 -07003792 someMoreWork = 0;
Yann Colletb26728c2017-06-16 14:00:46 -07003793 ZSTD_startNewCompression(zcs);
Yann Collet009d6042017-05-19 10:17:59 -07003794 }
3795 break;
3796 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003797 zcs->outBuffContentSize = cSize;
3798 zcs->outBuffFlushedSize = 0;
Yann Collet009d6042017-05-19 10:17:59 -07003799 zcs->streamStage = zcss_flush; /* pass-through to flush stage */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003800 }
Jos Collin7cd7a752017-05-11 13:17:20 +05303801 /* fall-through */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003802 case zcss_flush:
Yann Collet009d6042017-05-19 10:17:59 -07003803 DEBUGLOG(5, "flush stage");
Yann Collet5a0c8e22016-08-12 01:20:36 +02003804 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
Yann Collet01b15492017-05-30 18:10:26 -07003805 size_t const flushed = ZSTD_limitCopy(op, oend-op,
3806 zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
Yann Collet009d6042017-05-19 10:17:59 -07003807 DEBUGLOG(5, "toFlush: %u ; flushed: %u", (U32)toFlush, (U32)flushed);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003808 op += flushed;
3809 zcs->outBuffFlushedSize += flushed;
Yann Collet01b15492017-05-30 18:10:26 -07003810 if (toFlush!=flushed) {
3811 /* dst too small to store flushed data : stop there */
3812 someMoreWork = 0;
3813 break;
3814 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003815 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet009d6042017-05-19 10:17:59 -07003816 if (zcs->frameEnded) {
Yann Collet559ee822017-06-16 11:58:21 -07003817 DEBUGLOG(5, "Frame completed on flush");
Yann Collet009d6042017-05-19 10:17:59 -07003818 someMoreWork = 0;
Yann Colletb26728c2017-06-16 14:00:46 -07003819 ZSTD_startNewCompression(zcs);
Yann Collet009d6042017-05-19 10:17:59 -07003820 break;
3821 }
Yann Collet0be6fd32017-05-08 16:08:01 -07003822 zcs->streamStage = zcss_load;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003823 break;
3824 }
3825
Yann Colletcd2892f2017-06-01 09:44:54 -07003826 default: /* impossible */
3827 assert(0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003828 }
3829 }
3830
Yann Collet01b15492017-05-30 18:10:26 -07003831 input->pos = ip - istart;
3832 output->pos = op - ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003833 if (zcs->frameEnded) return 0;
3834 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3835 if (hintInSize==0) hintInSize = zcs->blockSize;
3836 return hintInSize;
3837 }
3838}
3839
Yann Collet53e17fb2016-08-17 01:39:22 +02003840size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003841{
Yann Collet01b15492017-05-30 18:10:26 -07003842 /* check conditions */
3843 if (output->pos > output->size) return ERROR(GENERIC);
3844 if (input->pos > input->size) return ERROR(GENERIC);
3845
3846 return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003847}
3848
Yann Colletf35e2de2017-06-05 18:32:48 -07003849/*! ZSTDMT_initCStream_internal() :
3850 * Private use only. Init streaming operation.
3851 * expects params to be valid.
3852 * must receive dict, or cdict, or none, but not both.
3853 * @return : 0, or an error code */
3854size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
3855 const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
3856 ZSTD_parameters params, unsigned long long pledgedSrcSize);
3857
3858
Yann Colletdeee6e52017-05-30 17:42:00 -07003859size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
3860 ZSTD_outBuffer* output,
3861 ZSTD_inBuffer* input,
3862 ZSTD_EndDirective endOp)
Yann Collet6d4fef32017-05-17 18:36:15 -07003863{
3864 /* check conditions */
Yann Colletdeee6e52017-05-30 17:42:00 -07003865 if (output->pos > output->size) return ERROR(GENERIC);
3866 if (input->pos > input->size) return ERROR(GENERIC);
Yann Collet6d4fef32017-05-17 18:36:15 -07003867 assert(cctx!=NULL);
Yann Collet01b15492017-05-30 18:10:26 -07003868
Yann Collet6d4fef32017-05-17 18:36:15 -07003869 if (cctx->streamStage == zcss_init) {
3870 /* transparent reset */
Yann Collet1ad7c822017-05-22 17:06:04 -07003871 ZSTD_parameters params = cctx->requestedParams;
Yann Collet6d4fef32017-05-17 18:36:15 -07003872 if (cctx->compressionLevel != ZSTD_CLEVEL_CUSTOM)
3873 params.cParams = ZSTD_getCParams(cctx->compressionLevel,
Yann Colletaee916e2017-06-16 17:01:46 -07003874 cctx->pledgedSrcSizePlusOne-1, 0 /* dictSize */);
Yann Colletf129fd32017-06-11 18:46:09 -07003875
3876#ifdef ZSTD_MULTITHREAD
Yann Colletf35e2de2017-06-05 18:32:48 -07003877 if (cctx->nbThreads > 1) {
Yann Colletc08e6492017-06-19 18:25:35 -07003878 DEBUGLOG(4, "call ZSTDMT_initCStream_internal");
Yann Colleta0ba8492017-06-16 13:29:17 -07003879 CHECK_F( ZSTDMT_initCStream_internal(cctx->mtctx, NULL, 0, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
Yann Collet23aace92017-06-11 18:32:36 -07003880 cctx->streamStage = zcss_load;
Yann Colletf129fd32017-06-11 18:46:09 -07003881 } else
3882#endif
3883 {
Yann Colletaee916e2017-06-16 17:01:46 -07003884 CHECK_F( ZSTD_resetCStream_internal(cctx, params, cctx->pledgedSrcSizePlusOne-1) );
Yann Colletf35e2de2017-06-05 18:32:48 -07003885 } }
3886
Yann Colletf129fd32017-06-11 18:46:09 -07003887#ifdef ZSTD_MULTITHREAD
Yann Colletf35e2de2017-06-05 18:32:48 -07003888 if (cctx->nbThreads > 1) {
Yann Collet23aace92017-06-11 18:32:36 -07003889 size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
Yann Colletc08e6492017-06-19 18:25:35 -07003890 DEBUGLOG(4, "ZSTDMT_compressStream_generic : %u", (U32)flushMin);
Yann Colletb26728c2017-06-16 14:00:46 -07003891 if ( ZSTD_isError(flushMin)
3892 || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
3893 ZSTD_startNewCompression(cctx);
Yann Collet9e73f2f2017-06-16 12:24:01 -07003894 }
Yann Collet23aace92017-06-11 18:32:36 -07003895 return flushMin;
Yann Collet6d4fef32017-05-17 18:36:15 -07003896 }
Yann Colletf129fd32017-06-11 18:46:09 -07003897#endif
Yann Collet6d4fef32017-05-17 18:36:15 -07003898
Yann Collet559ee822017-06-16 11:58:21 -07003899 DEBUGLOG(5, "calling ZSTD_compressStream_generic(%i,...)", endOp);
Yann Collet01b15492017-05-30 18:10:26 -07003900 CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
Yann Collet559ee822017-06-16 11:58:21 -07003901 DEBUGLOG(5, "completed ZSTD_compress_generic");
Yann Colletdeee6e52017-05-30 17:42:00 -07003902 return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
Yann Collet6d4fef32017-05-17 18:36:15 -07003903}
3904
Yann Colletdeee6e52017-05-30 17:42:00 -07003905size_t ZSTD_compress_generic_simpleArgs (
3906 ZSTD_CCtx* cctx,
3907 void* dst, size_t dstCapacity, size_t* dstPos,
3908 const void* src, size_t srcSize, size_t* srcPos,
3909 ZSTD_EndDirective endOp)
Yann Collet6d4fef32017-05-17 18:36:15 -07003910{
Yann Colletdeee6e52017-05-30 17:42:00 -07003911 ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
3912 ZSTD_inBuffer input = { src, srcSize, *srcPos };
Yann Collet01b15492017-05-30 18:10:26 -07003913 /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
Yann Collet58e8d792017-06-02 18:20:48 -07003914 size_t const cErr = ZSTD_compress_generic(cctx, &output, &input, endOp);
Yann Colletdeee6e52017-05-30 17:42:00 -07003915 *dstPos = output.pos;
3916 *srcPos = input.pos;
Yann Collet58e8d792017-06-02 18:20:48 -07003917 return cErr;
Yann Collet6d4fef32017-05-17 18:36:15 -07003918}
3919
Yann Collet5a0c8e22016-08-12 01:20:36 +02003920
Yann Collet104e5b02016-08-12 13:04:27 +02003921/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003922
3923/*! ZSTD_flushStream() :
3924* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003925size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003926{
Yann Collet18ab5af2017-05-31 09:59:22 -07003927 ZSTD_inBuffer input = { NULL, 0, 0 };
Yann Collet01b15492017-05-30 18:10:26 -07003928 if (output->pos > output->size) return ERROR(GENERIC);
3929 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_flush) );
3930 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003931}
3932
3933
Yann Collet53e17fb2016-08-17 01:39:22 +02003934size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003935{
Yann Collet18ab5af2017-05-31 09:59:22 -07003936 ZSTD_inBuffer input = { NULL, 0, 0 };
Yann Collet01b15492017-05-30 18:10:26 -07003937 if (output->pos > output->size) return ERROR(GENERIC);
3938 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_end) );
Yann Collet009d6042017-05-19 10:17:59 -07003939
Yann Collet48855fa2017-05-19 10:56:11 -07003940 DEBUGLOG(5, "ZSTD_endStream : remaining to flush : %u",
Yann Collet009d6042017-05-19 10:17:59 -07003941 (unsigned)(zcs->outBuffContentSize - zcs->outBuffFlushedSize));
Yann Collet009d6042017-05-19 10:17:59 -07003942 return zcs->outBuffContentSize - zcs->outBuffFlushedSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003943}
3944
3945
Yann Collet70e8c382016-02-10 13:37:52 +01003946/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003947
inikep2c5eeea2016-04-15 13:44:46 +02003948#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003949int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003950
Yann Collet3b719252016-03-30 19:48:05 +02003951static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003952{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003953 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003954 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003955 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3956 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003957 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3958 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003959 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3960 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3961 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003962 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003963 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3964 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3965 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3966 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3967 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3968 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3969 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3970 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003971 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
Yann Collet29297c62017-04-27 17:44:01 -07003972 { 23, 22, 22, 5, 4, 32, ZSTD_btopt }, /* level 18 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003973 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Nick Terrell374f8682017-05-10 17:48:42 -07003974 { 25, 25, 23, 7, 3, 64, ZSTD_btultra }, /* level 20 */
3975 { 26, 26, 23, 7, 3,256, ZSTD_btultra }, /* level 21 */
3976 { 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003977},
3978{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003979 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003980 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003981 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003982 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3983 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3984 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3985 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3986 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3987 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3988 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3989 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3990 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3991 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3992 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3993 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003994 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003995 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3996 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3997 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003998 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3999 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07004000 { 18, 19, 18, 11, 3,512, ZSTD_btultra }, /* level 20.*/
4001 { 18, 19, 18, 12, 3,512, ZSTD_btultra }, /* level 21.*/
4002 { 18, 19, 18, 13, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01004003},
4004{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02004005 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02004006 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
4007 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
4008 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
4009 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
4010 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
4011 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
4012 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
4013 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
4014 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
4015 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
4016 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
4017 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
4018 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
4019 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02004020 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
4021 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
4022 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
4023 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
4024 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
4025 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07004026 { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/
4027 { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/
4028 { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01004029},
4030{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02004031 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02004032 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02004033 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02004034 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
4035 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
4036 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
4037 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
4038 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
4039 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
4040 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
4041 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02004042 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
4043 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
4044 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
4045 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
4046 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
4047 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
4048 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
4049 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
4050 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
4051 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07004052 { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/
4053 { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/
4054 { 14, 15, 15, 10, 3,256, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01004055},
4056};
4057
Yann Collet236d94f2016-05-18 12:06:33 +02004058/*! ZSTD_getCParams() :
4059* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
4060* Size values are optional, provide 0 if not known or unused */
Yann Collet009d6042017-05-19 10:17:59 -07004061ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01004062{
Yann Collet009d6042017-05-19 10:17:59 -07004063 size_t const addedSize = srcSizeHint ? 0 : 500;
4064 U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02004065 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet6d4fef32017-05-17 18:36:15 -07004066 if (compressionLevel <= 0) compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01004067 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collete51d51b2017-06-20 17:44:55 -07004068 { ZSTD_compressionParameters const cp = ZSTD_defaultCParameters[tableID][compressionLevel];
4069 return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); }
Yann Colletfd416f12016-01-30 03:14:15 +01004070}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02004071
4072/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02004073* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02004074* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet009d6042017-05-19 10:17:59 -07004075ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02004076 ZSTD_parameters params;
Yann Collet009d6042017-05-19 10:17:59 -07004077 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize);
Yann Collet3d2cd7f2016-06-27 15:12:26 +02004078 memset(&params, 0, sizeof(params));
4079 params.cParams = cParams;
4080 return params;
4081}