blob: 0a7a98a96ca905624e45774ad64940059f7853c4 [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 Collet31533ba2017-04-27 00:29:04 -070030
31
32/*-*************************************
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 Colletf3eca252015-10-22 15:31:46 +010039
Yann Collet7d360282016-02-12 00:07:30 +010040/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010041* Helper functions
42***************************************/
Yann Collet3f75d522017-03-31 17:11:38 -070043size_t ZSTD_compressBound(size_t srcSize) {
Yann Collet30c76982017-03-31 18:27:03 -070044 size_t const lowLimit = 256 KB;
45 size_t const margin = (srcSize < lowLimit) ? (lowLimit-srcSize) >> 12 : 0; /* from 64 to 0 */
Yann Collet3f75d522017-03-31 17:11:38 -070046 return srcSize + (srcSize >> 8) + margin;
47}
Yann Collet59d1f792016-01-23 19:28:41 +010048
49
Yann Collet7d360282016-02-12 00:07:30 +010050/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010051* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010052***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010053static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
54{
Yann Collet14983e72015-11-11 21:38:21 +010055 ssPtr->lit = ssPtr->litStart;
Yann Colletc0ce4f12016-07-30 00:55:13 +020056 ssPtr->sequences = ssPtr->sequencesStart;
Yann Collet5d393572016-04-07 17:19:00 +020057 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010058}
59
60
Yann Collet7d360282016-02-12 00:07:30 +010061/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010062* Context memory management
63***************************************/
Yann Collet466f92e2017-06-20 16:25:29 -070064typedef enum { zcss_init=0, zcss_load, zcss_flush } ZSTD_cStreamStage;
Yann Collet0be6fd32017-05-08 16:08:01 -070065
Yann Collet18803372017-05-22 18:21:51 -070066struct ZSTD_CDict_s {
67 void* dictBuffer;
68 const void* dictContent;
69 size_t dictContentSize;
70 ZSTD_CCtx* refContext;
Yann Collet8c910d22017-06-03 01:15:02 -070071}; /* typedef'd to ZSTD_CDict within "zstd.h" */
Yann Colletf3eca252015-10-22 15:31:46 +010072
Yann Colletaca113f2016-12-23 22:25:03 +010073struct ZSTD_CCtx_s {
Yann Collet89db5e02015-11-13 11:27:46 +010074 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010075 const BYTE* base; /* All regular indexes relative to this position */
76 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010077 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010078 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010079 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010080 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +010081 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Colletbb002742017-01-25 16:25:38 -080082 U32 loadedDictEnd; /* index of end of dictionary */
83 U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
Yann Collet731ef162016-07-27 21:05:12 +020084 ZSTD_compressionStage_e stage;
Yann Colletc46fb922016-05-29 05:01:04 +020085 U32 dictID;
Yann Colletb0edb7f2017-05-12 15:31:53 -070086 int compressionLevel;
Yann Collet1ad7c822017-05-22 17:06:04 -070087 ZSTD_parameters requestedParams;
88 ZSTD_parameters appliedParams;
Yann Collet712def92015-10-29 18:41:45 +010089 void* workSpace;
90 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +010091 size_t blockSize;
Yann Colleta0ba8492017-06-16 13:29:17 -070092 U64 pledgedSrcSizePlusOne; /* this way, 0 (default) == unknown */
Yann Collet20d5e032017-04-11 18:34:02 -070093 U64 consumedSrcSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +020094 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +020095 ZSTD_customMem customMem;
Yann Colletc7fe2622017-05-23 13:16:00 -070096 size_t staticSize;
Yann Colletecd651b2016-01-07 15:35:18 +010097
Yann Collet712def92015-10-29 18:41:45 +010098 seqStore_t seqStore; /* sequences storage ptrs */
Nick Terrell7a28b9e2017-07-17 15:29:11 -070099 optState_t optState;
Yann Collet083fcc82015-10-25 14:06:35 +0100100 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +0100101 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +0200102 U32* chainTable;
Nick Terrellde0414b2017-07-12 19:08:24 -0700103 ZSTD_entropyCTables_t* entropy;
Yann Collet0be6fd32017-05-08 16:08:01 -0700104
105 /* streaming */
Yann Collet0be6fd32017-05-08 16:08:01 -0700106 char* inBuff;
107 size_t inBuffSize;
108 size_t inToCompress;
109 size_t inBuffPos;
110 size_t inBuffTarget;
111 char* outBuff;
112 size_t outBuffSize;
113 size_t outBuffContentSize;
114 size_t outBuffFlushedSize;
115 ZSTD_cStreamStage streamStage;
116 U32 frameEnded;
Yann Colletc4a5a212017-06-01 17:56:14 -0700117
Yann Colletb7372932017-06-27 15:49:12 -0700118 /* Dictionary */
119 ZSTD_dictMode_e dictMode; /* select restricting dictionary to "rawContent" or "fullDict" only */
120 U32 dictContentByRef;
121 ZSTD_CDict* cdictLocal;
122 const ZSTD_CDict* cdict;
123 const void* prefix;
124 size_t prefixSize;
125
Yann Colletc4a5a212017-06-01 17:56:14 -0700126 /* Multi-threading */
Yann Colletc35e5352017-06-01 18:44:06 -0700127 U32 nbThreads;
Yann Colletc4a5a212017-06-01 17:56:14 -0700128 ZSTDMT_CCtx* mtctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100129};
130
Yann Colletc4a5a212017-06-01 17:56:14 -0700131
Yann Collet5be2dd22015-11-11 13:43:58 +0100132ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100133{
Yann Colletae728a42017-05-30 17:11:39 -0700134 return ZSTD_createCCtx_advanced(ZSTD_defaultCMem);
inikep50e82c02016-05-23 15:49:09 +0200135}
136
137ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
138{
Yann Collet69c2cdb2016-07-14 16:52:45 +0200139 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +0200140
Yann Colletae728a42017-05-30 17:11:39 -0700141 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200142
Yann Colletc4f46b92017-05-30 17:45:37 -0700143 cctx = (ZSTD_CCtx*) ZSTD_calloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200144 if (!cctx) return NULL;
Yann Colletbb002742017-01-25 16:25:38 -0800145 cctx->customMem = customMem;
Yann Collet6d4fef32017-05-17 18:36:15 -0700146 cctx->compressionLevel = ZSTD_CLEVEL_DEFAULT;
Yann Colleta0ba8492017-06-16 13:29:17 -0700147 ZSTD_STATIC_ASSERT(zcss_init==0);
Yann Colletd3de3d52017-06-16 16:51:33 -0700148 ZSTD_STATIC_ASSERT(ZSTD_CONTENTSIZE_UNKNOWN==(0ULL - 1));
Yann Collet69c2cdb2016-07-14 16:52:45 +0200149 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100150}
151
Yann Colletc7fe2622017-05-23 13:16:00 -0700152ZSTD_CCtx* ZSTD_initStaticCCtx(void *workspace, size_t workspaceSize)
153{
154 ZSTD_CCtx* cctx = (ZSTD_CCtx*) workspace;
155 if (workspaceSize <= sizeof(ZSTD_CCtx)) return NULL; /* minimum size */
156 if ((size_t)workspace & 7) return NULL; /* must be 8-aligned */
Yann Collet7bd1a292017-06-21 11:50:33 -0700157 memset(workspace, 0, workspaceSize); /* may be a bit generous, could memset be smaller ? */
Yann Colletc7fe2622017-05-23 13:16:00 -0700158 cctx->staticSize = workspaceSize;
159 cctx->workSpace = (void*)(cctx+1);
160 cctx->workSpaceSize = workspaceSize - sizeof(ZSTD_CCtx);
161
162 /* entropy space (never moves) */
Nick Terrellde0414b2017-07-12 19:08:24 -0700163 if (cctx->workSpaceSize < sizeof(ZSTD_entropyCTables_t)) return NULL;
164 assert(((size_t)cctx->workSpace & 7) == 0); /* ensure correct alignment */
165 cctx->entropy = (ZSTD_entropyCTables_t*)cctx->workSpace;
Yann Colletc7fe2622017-05-23 13:16:00 -0700166
Yann Colletf3eca252015-10-22 15:31:46 +0100167 return cctx;
168}
169
Yann Collet5be2dd22015-11-11 13:43:58 +0100170size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100171{
inikep36403962016-06-03 16:36:50 +0200172 if (cctx==NULL) return 0; /* support free on NULL */
Yann Colletc4a5a212017-06-01 17:56:14 -0700173 if (cctx->staticSize) return ERROR(memory_allocation); /* not compatible with static CCtx */
Yann Collet23b6e052016-08-28 21:05:43 -0700174 ZSTD_free(cctx->workSpace, cctx->customMem);
Yann Collet78553662017-05-08 17:15:00 -0700175 cctx->workSpace = NULL;
176 ZSTD_freeCDict(cctx->cdictLocal);
177 cctx->cdictLocal = NULL;
Yann Colletc4a5a212017-06-01 17:56:14 -0700178 ZSTDMT_freeCCtx(cctx->mtctx);
179 cctx->mtctx = NULL;
Yann Collet23b6e052016-08-28 21:05:43 -0700180 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100181 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100182}
183
Yann Collet70e3b312016-08-23 01:18:06 +0200184size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200185{
Yann Colletd7c65892016-09-15 02:50:27 +0200186 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet7bd1a292017-06-21 11:50:33 -0700187 DEBUGLOG(5, "sizeof(*cctx) : %u", (U32)sizeof(*cctx));
188 DEBUGLOG(5, "workSpaceSize : %u", (U32)cctx->workSpaceSize);
189 DEBUGLOG(5, "streaming buffers : %u", (U32)(cctx->outBuffSize + cctx->inBuffSize));
190 DEBUGLOG(5, "inner MTCTX : %u", (U32)ZSTDMT_sizeof_CCtx(cctx->mtctx));
Yann Collet791d7442017-05-08 16:17:30 -0700191 return sizeof(*cctx) + cctx->workSpaceSize
192 + ZSTD_sizeof_CDict(cctx->cdictLocal)
Yann Colletc4a5a212017-06-01 17:56:14 -0700193 + cctx->outBuffSize + cctx->inBuffSize
194 + ZSTDMT_sizeof_CCtx(cctx->mtctx);
Yann Collet3ae543c2016-07-11 03:12:17 +0200195}
196
Yann Collet009d6042017-05-19 10:17:59 -0700197size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
198{
199 return ZSTD_sizeof_CCtx(zcs); /* same object */
200}
201
Yann Colletb0edb7f2017-05-12 15:31:53 -0700202/* private API call, for dictBuilder only */
203const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) { return &(ctx->seqStore); }
204
Yann Collet1ad7c822017-05-22 17:06:04 -0700205static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx) { return cctx->appliedParams; }
Yann Colletb0edb7f2017-05-12 15:31:53 -0700206
Yann Colletef738c12017-05-12 13:53:46 -0700207/* older variant; will be deprecated */
Yann Colletbb002742017-01-25 16:25:38 -0800208size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
209{
210 switch(param)
211 {
Yann Collet06e76972017-01-25 16:39:03 -0800212 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
Yann Collet7bd1a292017-06-21 11:50:33 -0700213 ZSTD_STATIC_ASSERT(ZSTD_dm_auto==0);
214 ZSTD_STATIC_ASSERT(ZSTD_dm_rawContent==1);
215 case ZSTD_p_forceRawDict : cctx->dictMode = (ZSTD_dictMode_e)(value>0); return 0;
Yann Collet2bd64402017-07-13 17:12:16 -0700216 default: return ERROR(parameter_unsupported);
Yann Colletbb002742017-01-25 16:25:38 -0800217 }
218}
219
Yann Colletadd66f82017-05-12 15:59:48 -0700220
Yann Collet6d4fef32017-05-17 18:36:15 -0700221#define ZSTD_CLEVEL_CUSTOM 999
Yann Colletadd66f82017-05-12 15:59:48 -0700222static void ZSTD_cLevelToCParams(ZSTD_CCtx* cctx)
Yann Collet7d360282016-02-12 00:07:30 +0100223{
Yann Collet1ad7c822017-05-22 17:06:04 -0700224 if (cctx->compressionLevel==ZSTD_CLEVEL_CUSTOM) return;
225 cctx->requestedParams.cParams = ZSTD_getCParams(cctx->compressionLevel,
Yann Colleta0ba8492017-06-16 13:29:17 -0700226 cctx->pledgedSrcSizePlusOne-1, 0);
Yann Collet6d4fef32017-05-17 18:36:15 -0700227 cctx->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Collet7d360282016-02-12 00:07:30 +0100228}
229
Yann Collet2bd64402017-07-13 17:12:16 -0700230#define CLAMPCHECK(val,min,max) { \
231 if (((val)<(min)) | ((val)>(max))) { \
232 return ERROR(parameter_outOfBound); \
Yann Colletc3bce242017-06-20 16:09:11 -0700233} }
234
Yann Colletb0edb7f2017-05-12 15:31:53 -0700235size_t ZSTD_CCtx_setParameter(ZSTD_CCtx* cctx, ZSTD_cParameter param, unsigned value)
Yann Collet95162342016-10-25 16:19:52 -0700236{
Yann Collet24de7b02017-05-22 13:05:45 -0700237 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700238
239 switch(param)
240 {
241 case ZSTD_p_compressionLevel :
Yann Colletcd2892f2017-06-01 09:44:54 -0700242 if ((int)value > ZSTD_maxCLevel()) value = ZSTD_maxCLevel(); /* cap max compression level */
243 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700244 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700245 cctx->compressionLevel = value;
246 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700247
248 case ZSTD_p_windowLog :
Yann Colletd7a3bff2017-06-19 11:53:01 -0700249 DEBUGLOG(5, "setting ZSTD_p_windowLog = %u (cdict:%u)",
250 value, (cctx->cdict!=NULL));
Yann Colletcd2892f2017-06-01 09:44:54 -0700251 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700252 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700253 CLAMPCHECK(value, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
254 ZSTD_cLevelToCParams(cctx);
255 cctx->requestedParams.cParams.windowLog = value;
256 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700257
258 case ZSTD_p_hashLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700259 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700260 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700261 CLAMPCHECK(value, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
262 ZSTD_cLevelToCParams(cctx);
263 cctx->requestedParams.cParams.hashLog = value;
264 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700265
266 case ZSTD_p_chainLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700267 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700268 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700269 CLAMPCHECK(value, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
270 ZSTD_cLevelToCParams(cctx);
271 cctx->requestedParams.cParams.chainLog = value;
272 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700273
274 case ZSTD_p_searchLog :
Yann Colletcd2892f2017-06-01 09:44:54 -0700275 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700276 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700277 CLAMPCHECK(value, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
278 ZSTD_cLevelToCParams(cctx);
279 cctx->requestedParams.cParams.searchLog = value;
280 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700281
Yann Collet6d4fef32017-05-17 18:36:15 -0700282 case ZSTD_p_minMatch :
Yann Colletcd2892f2017-06-01 09:44:54 -0700283 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700284 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700285 CLAMPCHECK(value, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
286 ZSTD_cLevelToCParams(cctx);
287 cctx->requestedParams.cParams.searchLength = value;
288 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700289
290 case ZSTD_p_targetLength :
Yann Colletcd2892f2017-06-01 09:44:54 -0700291 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700292 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700293 CLAMPCHECK(value, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
294 ZSTD_cLevelToCParams(cctx);
295 cctx->requestedParams.cParams.targetLength = value;
296 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700297
298 case ZSTD_p_compressionStrategy :
Yann Colletcd2892f2017-06-01 09:44:54 -0700299 if (value == 0) return 0; /* special value : 0 means "don't change anything" */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700300 if (cctx->cdict) return ERROR(stage_wrong);
Yann Colletcd2892f2017-06-01 09:44:54 -0700301 CLAMPCHECK(value, (unsigned)ZSTD_fast, (unsigned)ZSTD_btultra);
302 ZSTD_cLevelToCParams(cctx);
303 cctx->requestedParams.cParams.strategy = (ZSTD_strategy)value;
304 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700305
Yann Colletcd2892f2017-06-01 09:44:54 -0700306 case ZSTD_p_contentSizeFlag :
Yann Collet2cf77552017-06-16 12:34:41 -0700307 DEBUGLOG(5, "set content size flag = %u", (value>0));
Yann Colletcd2892f2017-06-01 09:44:54 -0700308 /* Content size written in frame header _when known_ (default:1) */
309 cctx->requestedParams.fParams.contentSizeFlag = value>0;
310 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700311
Yann Colletcd2892f2017-06-01 09:44:54 -0700312 case ZSTD_p_checksumFlag :
313 /* A 32-bits content checksum will be calculated and written at end of frame (default:0) */
314 cctx->requestedParams.fParams.checksumFlag = value>0;
315 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700316
Yann Collet1ad7c822017-05-22 17:06:04 -0700317 case ZSTD_p_dictIDFlag : /* When applicable, dictionary's dictID is provided in frame header (default:1) */
Yann Colletcd2892f2017-06-01 09:44:54 -0700318 DEBUGLOG(5, "set dictIDFlag = %u", (value>0));
319 cctx->requestedParams.fParams.noDictIDFlag = (value==0);
320 return 0;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700321
Yann Colletfecc7212017-06-27 11:46:39 -0700322 /* Dictionary parameters */
Yann Collet7bd1a292017-06-21 11:50:33 -0700323 case ZSTD_p_dictMode :
Yann Colletfecc7212017-06-27 11:46:39 -0700324 if (cctx->cdict) return ERROR(stage_wrong); /* must be set before loading */
Yann Collet7bd1a292017-06-21 11:50:33 -0700325 /* restrict dictionary mode, to "rawContent" or "fullDict" only */
326 ZSTD_STATIC_ASSERT((U32)ZSTD_dm_fullDict > (U32)ZSTD_dm_rawContent);
327 if (value > (unsigned)ZSTD_dm_fullDict)
Yann Collet2bd64402017-07-13 17:12:16 -0700328 return ERROR(parameter_outOfBound);
Yann Collet7bd1a292017-06-21 11:50:33 -0700329 cctx->dictMode = (ZSTD_dictMode_e)value;
330 return 0;
331
Yann Colletfecc7212017-06-27 11:46:39 -0700332 case ZSTD_p_refDictContent :
333 if (cctx->cdict) return ERROR(stage_wrong); /* must be set before loading */
334 /* dictionary content will be referenced, instead of copied */
335 cctx->dictContentByRef = value>0;
336 return 0;
337
Yann Colletb0edb7f2017-05-12 15:31:53 -0700338 case ZSTD_p_forceMaxWindow : /* Force back-references to remain < windowSize,
339 * even when referencing into Dictionary content
340 * default : 0 when using a CDict, 1 when using a Prefix */
Yann Colletc35e5352017-06-01 18:44:06 -0700341 cctx->forceWindow = value>0;
342 cctx->loadedDictEnd = 0;
343 return 0;
344
345 case ZSTD_p_nbThreads:
346 if (value==0) return 0;
Yann Collet33873f02017-06-16 12:04:21 -0700347 DEBUGLOG(5, " setting nbThreads : %u", value);
Yann Colletc35e5352017-06-01 18:44:06 -0700348#ifndef ZSTD_MULTITHREAD
Yann Collet2bd64402017-07-13 17:12:16 -0700349 if (value > 1) return ERROR(parameter_unsupported);
Yann Colletc35e5352017-06-01 18:44:06 -0700350#endif
351 if ((value>1) && (cctx->nbThreads != value)) {
Yann Collet05ae4b22017-06-15 18:03:34 -0700352 if (cctx->staticSize) /* MT not compatible with static alloc */
Yann Collet2bd64402017-07-13 17:12:16 -0700353 return ERROR(parameter_unsupported);
Yann Colletc35e5352017-06-01 18:44:06 -0700354 ZSTDMT_freeCCtx(cctx->mtctx);
Yann Collet559ee822017-06-16 11:58:21 -0700355 cctx->nbThreads = 1;
Yann Collet88da8f12017-07-10 14:02:33 -0700356 cctx->mtctx = ZSTDMT_createCCtx_advanced(value, cctx->customMem);
Yann Colletc35e5352017-06-01 18:44:06 -0700357 if (cctx->mtctx == NULL) return ERROR(memory_allocation);
Yann Collet33873f02017-06-16 12:04:21 -0700358 }
359 cctx->nbThreads = value;
Yann Colletc35e5352017-06-01 18:44:06 -0700360 return 0;
361
Yann Collet559ee822017-06-16 11:58:21 -0700362 case ZSTD_p_jobSize:
Yann Collet2bd64402017-07-13 17:12:16 -0700363 if (cctx->nbThreads <= 1) return ERROR(parameter_unsupported);
Yann Colletc35e5352017-06-01 18:44:06 -0700364 assert(cctx->mtctx != NULL);
365 return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_sectionSize, value);
366
Yann Collet559ee822017-06-16 11:58:21 -0700367 case ZSTD_p_overlapSizeLog:
Yann Collet33873f02017-06-16 12:04:21 -0700368 DEBUGLOG(5, " setting overlap with nbThreads == %u", cctx->nbThreads);
Yann Collet2bd64402017-07-13 17:12:16 -0700369 if (cctx->nbThreads <= 1) return ERROR(parameter_unsupported);
Yann Colletc35e5352017-06-01 18:44:06 -0700370 assert(cctx->mtctx != NULL);
371 return ZSTDMT_setMTCtxParameter(cctx->mtctx, ZSTDMT_p_overlapSectionLog, value);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700372
Yann Collet2bd64402017-07-13 17:12:16 -0700373 default: return ERROR(parameter_unsupported);
Yann Colletb0edb7f2017-05-12 15:31:53 -0700374 }
Yann Collet95162342016-10-25 16:19:52 -0700375}
376
Yann Colletb0edb7f2017-05-12 15:31:53 -0700377ZSTDLIB_API size_t ZSTD_CCtx_setPledgedSrcSize(ZSTD_CCtx* cctx, unsigned long long pledgedSrcSize)
Yann Collet083fcc82015-10-25 14:06:35 +0100378{
Yann Collet2cf77552017-06-16 12:34:41 -0700379 DEBUGLOG(5, " setting pledgedSrcSize to %u", (U32)pledgedSrcSize);
Yann Collet24de7b02017-05-22 13:05:45 -0700380 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colleta0ba8492017-06-16 13:29:17 -0700381 cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
Yann Colletb0edb7f2017-05-12 15:31:53 -0700382 return 0;
383}
Yann Collet59d70632015-11-04 12:05:27 +0100384
Yann Collet6d4fef32017-05-17 18:36:15 -0700385ZSTDLIB_API size_t ZSTD_CCtx_loadDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
386{
Yann Collet24de7b02017-05-22 13:05:45 -0700387 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
Yann Colletc7fe2622017-05-23 13:16:00 -0700388 if (cctx->staticSize) return ERROR(memory_allocation); /* no malloc for static CCtx */
Yann Colletd7a3bff2017-06-19 11:53:01 -0700389 DEBUGLOG(5, "load dictionary of size %u", (U32)dictSize);
Yann Collet6d4fef32017-05-17 18:36:15 -0700390 ZSTD_freeCDict(cctx->cdictLocal); /* in case one already exists */
391 if (dict==NULL || dictSize==0) { /* no dictionary mode */
392 cctx->cdictLocal = NULL;
393 cctx->cdict = NULL;
394 } else {
Yann Collet8b21ec42017-05-19 19:46:15 -0700395 ZSTD_compressionParameters const cParams =
396 cctx->compressionLevel == ZSTD_CLEVEL_CUSTOM ?
Yann Collet1ad7c822017-05-22 17:06:04 -0700397 cctx->requestedParams.cParams :
Yann Collet8b21ec42017-05-19 19:46:15 -0700398 ZSTD_getCParams(cctx->compressionLevel, 0, dictSize);
Yann Collet6d4fef32017-05-17 18:36:15 -0700399 cctx->cdictLocal = ZSTD_createCDict_advanced(
400 dict, dictSize,
Yann Colletfecc7212017-06-27 11:46:39 -0700401 cctx->dictContentByRef, cctx->dictMode,
Yann Collet8b21ec42017-05-19 19:46:15 -0700402 cParams, cctx->customMem);
Yann Collet6d4fef32017-05-17 18:36:15 -0700403 cctx->cdict = cctx->cdictLocal;
404 if (cctx->cdictLocal == NULL)
405 return ERROR(memory_allocation);
406 }
407 return 0;
408}
409
Yann Colletbd18c882017-06-16 10:17:50 -0700410size_t ZSTD_CCtx_refCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
Yann Colletb0edb7f2017-05-12 15:31:53 -0700411{
Yann Collet24de7b02017-05-22 13:05:45 -0700412 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
413 cctx->cdict = cdict;
Yann Colletb7372932017-06-27 15:49:12 -0700414 cctx->prefix = NULL; /* exclusive */
415 cctx->prefixSize = 0;
416 return 0;
417}
418
419size_t ZSTD_CCtx_refPrefix(ZSTD_CCtx* cctx, const void* prefix, size_t prefixSize)
420{
421 if (cctx->streamStage != zcss_init) return ERROR(stage_wrong);
422 cctx->cdict = NULL; /* prefix discards any prior cdict */
423 cctx->prefix = prefix;
424 cctx->prefixSize = prefixSize;
425 return 0;
Yann Collet083fcc82015-10-25 14:06:35 +0100426}
427
Yann Colletb26728c2017-06-16 14:00:46 -0700428static void ZSTD_startNewCompression(ZSTD_CCtx* cctx)
Yann Colletbd18c882017-06-16 10:17:50 -0700429{
430 cctx->streamStage = zcss_init;
Yann Colleta0ba8492017-06-16 13:29:17 -0700431 cctx->pledgedSrcSizePlusOne = 0;
Yann Colletb26728c2017-06-16 14:00:46 -0700432}
433
434/*! ZSTD_CCtx_reset() :
435 * Also dumps dictionary */
436void ZSTD_CCtx_reset(ZSTD_CCtx* cctx)
437{
438 ZSTD_startNewCompression(cctx);
Yann Colletbd18c882017-06-16 10:17:50 -0700439 cctx->cdict = NULL;
440}
441
Yann Collet381e66c2017-06-16 17:29:35 -0700442/** ZSTD_checkCParams() :
443 control CParam values remain within authorized range.
Yann Collet21588e32016-03-30 16:50:44 +0200444 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200445size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200446{
Yann Collet15354142016-04-04 04:22:53 +0200447 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200448 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200449 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
450 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Collet2e2e78d2017-03-29 16:02:47 -0700451 CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200452 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Yann Collet2bd64402017-07-13 17:12:16 -0700453 if ((U32)(cParams.strategy) > (U32)ZSTD_btultra)
454 return ERROR(parameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200455 return 0;
456}
457
Yann Collet381e66c2017-06-16 17:29:35 -0700458/** ZSTD_clampCParams() :
459 * make CParam values within valid range.
460 * @return : valid CParams */
461static ZSTD_compressionParameters ZSTD_clampCParams(ZSTD_compressionParameters cParams)
462{
463# define CLAMP(val,min,max) { \
464 if (val<min) val=min; \
465 else if (val>max) val=max; \
466 }
467 CLAMP(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
468 CLAMP(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
469 CLAMP(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
470 CLAMP(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
471 CLAMP(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
472 CLAMP(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
473 if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) cParams.strategy = ZSTD_btultra;
474 return cParams;
475}
Yann Collet21588e32016-03-30 16:50:44 +0200476
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100477/** ZSTD_cycleLog() :
478 * condition for correct operation : hashLog > 1 */
479static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
480{
481 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
482 return hashLog - btScale;
483}
484
Yann Collet381e66c2017-06-16 17:29:35 -0700485/** ZSTD_adjustCParams_internal() :
Yann Colletcf409a72016-09-26 16:41:05 +0200486 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200487 mostly downsizing to reduce memory consumption and initialization.
488 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
489 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200490 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet381e66c2017-06-16 17:29:35 -0700491ZSTD_compressionParameters ZSTD_adjustCParams_internal(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100492{
Yann Collet381e66c2017-06-16 17:29:35 -0700493 assert(ZSTD_checkCParams(cPar)==0);
Yann Collet70d13012016-06-01 18:45:34 +0200494 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100495
Yann Collet70e45772016-03-19 18:08:32 +0100496 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200497 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
498 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200499 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200500 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200501 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200502 } }
Yann Collet70d13012016-06-01 18:45:34 +0200503 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100504 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
505 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
506 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100507
Yann Collet70d13012016-06-01 18:45:34 +0200508 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200509
510 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100511}
512
Yann Collet381e66c2017-06-16 17:29:35 -0700513ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
514{
515 cPar = ZSTD_clampCParams(cPar);
516 return ZSTD_adjustCParams_internal(cPar, srcSize, dictSize);
517}
518
Yann Collet59d70632015-11-04 12:05:27 +0100519
Yann Collet31af8292017-06-26 15:52:39 -0700520size_t ZSTD_estimateCCtxSize_advanced(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100521{
Yann Colletfa3671e2017-05-19 10:51:30 -0700522 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
Yann Collet731ef162016-07-27 21:05:12 +0200523 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
524 size_t const maxNbSeq = blockSize / divider;
525 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200526
Yann Collet731ef162016-07-27 21:05:12 +0200527 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
528 size_t const hSize = ((size_t)1) << cParams.hashLog;
529 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
530 size_t const h3Size = ((size_t)1) << hashLog3;
Nick Terrellde0414b2017-07-12 19:08:24 -0700531 size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
Yann Collet731ef162016-07-27 21:05:12 +0200532 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200533
Yann Colletfc514592017-05-08 17:07:59 -0700534 size_t const optBudget = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
Yann Collet3ae543c2016-07-11 03:12:17 +0200535 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
Nick Terrell5f2c7212017-05-10 16:49:58 -0700536 size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
Yann Colletfc514592017-05-08 17:07:59 -0700537 size_t const neededSpace = entropySpace + tableSpace + tokenSpace + optSpace;
Yann Collet3ae543c2016-07-11 03:12:17 +0200538
Yann Collet7bd1a292017-06-21 11:50:33 -0700539 DEBUGLOG(5, "sizeof(ZSTD_CCtx) : %u", (U32)sizeof(ZSTD_CCtx));
540 DEBUGLOG(5, "estimate workSpace : %u", (U32)neededSpace);
Yann Collet3ae543c2016-07-11 03:12:17 +0200541 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100542}
543
Yann Collet31af8292017-06-26 15:52:39 -0700544size_t ZSTD_estimateCCtxSize(int compressionLevel)
545{
546 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
547 return ZSTD_estimateCCtxSize_advanced(cParams);
548}
549
Yann Collet0c9a9152017-06-26 16:02:25 -0700550size_t ZSTD_estimateCStreamSize_advanced(ZSTD_compressionParameters cParams)
Yann Colleta7737f62016-09-06 09:44:59 +0200551{
Yann Collet31af8292017-06-26 15:52:39 -0700552 size_t const CCtxSize = ZSTD_estimateCCtxSize_advanced(cParams);
Yann Colletc7fe2622017-05-23 13:16:00 -0700553 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << cParams.windowLog);
554 size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
555 size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
556 size_t const streamingSize = inBuffSize + outBuffSize;
557
558 return CCtxSize + streamingSize;
559}
560
Yann Collet0c9a9152017-06-26 16:02:25 -0700561size_t ZSTD_estimateCStreamSize(int compressionLevel) {
562 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, 0);
563 return ZSTD_estimateCStreamSize_advanced(cParams);
564}
565
Yann Colleta7737f62016-09-06 09:44:59 +0200566
Yann Collet009d6042017-05-19 10:17:59 -0700567static U32 ZSTD_equivalentParams(ZSTD_compressionParameters cParams1,
568 ZSTD_compressionParameters cParams2)
Yann Colleta7737f62016-09-06 09:44:59 +0200569{
Yann Colletfa3671e2017-05-19 10:51:30 -0700570 U32 bslog1 = MIN(cParams1.windowLog, ZSTD_BLOCKSIZELOG_MAX);
571 U32 bslog2 = MIN(cParams2.windowLog, ZSTD_BLOCKSIZELOG_MAX);
Yann Collet009d6042017-05-19 10:17:59 -0700572 return (bslog1 == bslog2) /* same block size */
573 & (cParams1.hashLog == cParams2.hashLog)
574 & (cParams1.chainLog == cParams2.chainLog)
575 & (cParams1.strategy == cParams2.strategy) /* opt parser space */
576 & ((cParams1.searchLength==3) == (cParams2.searchLength==3)); /* hashlog3 space */
Yann Colleta7737f62016-09-06 09:44:59 +0200577}
578
579/*! ZSTD_continueCCtx() :
Yann Colletc08e6492017-06-19 18:25:35 -0700580 * reuse CCtx without reset (note : requires no dictionary) */
Yann Colletb26728c2017-06-16 14:00:46 -0700581static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colleta7737f62016-09-06 09:44:59 +0200582{
583 U32 const end = (U32)(cctx->nextSrc - cctx->base);
Yann Collet2cf77552017-06-16 12:34:41 -0700584 DEBUGLOG(5, "continue mode");
Yann Collet1ad7c822017-05-22 17:06:04 -0700585 cctx->appliedParams = params;
Yann Colletb26728c2017-06-16 14:00:46 -0700586 cctx->pledgedSrcSizePlusOne = pledgedSrcSize+1;
Yann Collet20d5e032017-04-11 18:34:02 -0700587 cctx->consumedSrcSize = 0;
Yann Colletb26728c2017-06-16 14:00:46 -0700588 if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
Yann Collet2cf77552017-06-16 12:34:41 -0700589 cctx->appliedParams.fParams.contentSizeFlag = 0;
Yann Colletb26728c2017-06-16 14:00:46 -0700590 DEBUGLOG(5, "pledged content size : %u ; flag : %u",
591 (U32)pledgedSrcSize, cctx->appliedParams.fParams.contentSizeFlag);
Yann Colleta7737f62016-09-06 09:44:59 +0200592 cctx->lowLimit = end;
593 cctx->dictLimit = end;
594 cctx->nextToUpdate = end+1;
595 cctx->stage = ZSTDcs_init;
596 cctx->dictID = 0;
597 cctx->loadedDictEnd = 0;
Nick Terrelle1982302017-07-17 12:27:24 -0700598 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->seqStore.rep[i] = repStartValue[i]; }
Nick Terrell7a28b9e2017-07-17 15:29:11 -0700599 cctx->optState.litLengthSum = 0; /* force reset of btopt stats */
Yann Colletb6249222016-09-06 09:54:22 +0200600 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200601 return 0;
602}
603
Yann Colletb0739bc2017-05-22 17:45:15 -0700604typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset } ZSTD_compResetPolicy_e;
Yann Collet5a773612017-07-03 15:21:24 -0700605typedef enum { ZSTDb_not_buffered, ZSTDb_buffered } ZSTD_buffered_policy_e;
Yann Colleta7737f62016-09-06 09:44:59 +0200606
Yann Collet30fb4992017-04-18 14:08:50 -0700607/*! ZSTD_resetCCtx_internal() :
Yann Collet5ac72b42017-05-23 11:18:24 -0700608 note : `params` are assumed fully validated at this stage */
609static size_t ZSTD_resetCCtx_internal(ZSTD_CCtx* zc,
Yann Colleta0ba8492017-06-16 13:29:17 -0700610 ZSTD_parameters params, U64 pledgedSrcSize,
Yann Collet5ac72b42017-05-23 11:18:24 -0700611 ZSTD_compResetPolicy_e const crp,
612 ZSTD_buffered_policy_e const zbuff)
Yann Colleta7737f62016-09-06 09:44:59 +0200613{
Yann Collet5ac72b42017-05-23 11:18:24 -0700614 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet0be6fd32017-05-08 16:08:01 -0700615
Yann Colletb0739bc2017-05-22 17:45:15 -0700616 if (crp == ZSTDcrp_continue) {
Yann Collet1ad7c822017-05-22 17:06:04 -0700617 if (ZSTD_equivalentParams(params.cParams, zc->appliedParams.cParams)) {
Yann Collet009d6042017-05-19 10:17:59 -0700618 DEBUGLOG(5, "ZSTD_equivalentParams()==1");
Nick Terrellde0414b2017-07-12 19:08:24 -0700619 zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
Nick Terrell830ef412017-07-13 12:45:39 -0700620 zc->entropy->offcode_repeatMode = FSE_repeat_none;
621 zc->entropy->matchlength_repeatMode = FSE_repeat_none;
622 zc->entropy->litlength_repeatMode = FSE_repeat_none;
Yann Colleta0ba8492017-06-16 13:29:17 -0700623 return ZSTD_continueCCtx(zc, params, pledgedSrcSize);
Yann Colletb0739bc2017-05-22 17:45:15 -0700624 } }
inikep87d4f3d2016-03-02 15:56:24 +0100625
Yann Colletfa3671e2017-05-19 10:51:30 -0700626 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_MAX, (size_t)1 << params.cParams.windowLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200627 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
628 size_t const maxNbSeq = blockSize / divider;
629 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet5ac72b42017-05-23 11:18:24 -0700630 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ?
631 0 : (1 << params.cParams.chainLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200632 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
Yann Collet5ac72b42017-05-23 11:18:24 -0700633 U32 const hashLog3 = (params.cParams.searchLength>3) ?
634 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
Yann Colleta7737f62016-09-06 09:44:59 +0200635 size_t const h3Size = ((size_t)1) << hashLog3;
636 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet7bd1a292017-06-21 11:50:33 -0700637 size_t const buffOutSize = (zbuff==ZSTDb_buffered) ? ZSTD_compressBound(blockSize)+1 : 0;
638 size_t const buffInSize = (zbuff==ZSTDb_buffered) ? ((size_t)1 << params.cParams.windowLog) + blockSize : 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200639 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100640
Yann Colleta7737f62016-09-06 09:44:59 +0200641 /* Check if workSpace is large enough, alloc a new one if needed */
Nick Terrellde0414b2017-07-12 19:08:24 -0700642 { size_t const entropySpace = sizeof(ZSTD_entropyCTables_t);
Yann Collet71ddeb62017-04-20 22:54:54 -0700643 size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
Yann Collete6fa70a2017-04-20 17:28:31 -0700644 + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
Yann Collet5ac72b42017-05-23 11:18:24 -0700645 size_t const optSpace = ( (params.cParams.strategy == ZSTD_btopt)
646 || (params.cParams.strategy == ZSTD_btultra)) ?
647 optPotentialSpace : 0;
Yann Collet7bd1a292017-06-21 11:50:33 -0700648 size_t const bufferSpace = buffInSize + buffOutSize;
Yann Collet5ac72b42017-05-23 11:18:24 -0700649 size_t const neededSpace = entropySpace + optSpace + tableSpace
650 + tokenSpace + bufferSpace;
Yann Colletc7fe2622017-05-23 13:16:00 -0700651
652 if (zc->workSpaceSize < neededSpace) { /* too small : resize /*/
Yann Collet0be6fd32017-05-08 16:08:01 -0700653 DEBUGLOG(5, "Need to update workSpaceSize from %uK to %uK \n",
Yann Colletc7fe2622017-05-23 13:16:00 -0700654 (unsigned)zc->workSpaceSize>>10,
655 (unsigned)neededSpace>>10);
656 /* static cctx : no resize, error out */
657 if (zc->staticSize) return ERROR(memory_allocation);
658
Yann Collet0181fef2017-04-06 01:25:26 -0700659 zc->workSpaceSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200660 ZSTD_free(zc->workSpace, zc->customMem);
661 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
662 if (zc->workSpace == NULL) return ERROR(memory_allocation);
663 zc->workSpaceSize = neededSpace;
Yann Collet7bb60b12017-04-20 17:38:56 -0700664 ptr = zc->workSpace;
665
666 /* entropy space */
Nick Terrellde0414b2017-07-12 19:08:24 -0700667 assert(((size_t)zc->workSpace & 3) == 0); /* ensure correct alignment */
668 assert(zc->workSpaceSize >= sizeof(ZSTD_entropyCTables_t));
669 zc->entropy = (ZSTD_entropyCTables_t*)zc->workSpace;
Yann Colleta7737f62016-09-06 09:44:59 +0200670 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100671
Yann Collete6fa70a2017-04-20 17:28:31 -0700672 /* init params */
Yann Collet1ad7c822017-05-22 17:06:04 -0700673 zc->appliedParams = params;
Yann Colleta0ba8492017-06-16 13:29:17 -0700674 zc->pledgedSrcSizePlusOne = pledgedSrcSize+1;
Yann Collete6fa70a2017-04-20 17:28:31 -0700675 zc->consumedSrcSize = 0;
Yann Colleta0ba8492017-06-16 13:29:17 -0700676 if (pledgedSrcSize == ZSTD_CONTENTSIZE_UNKNOWN)
Yann Colletcc9f9b72017-06-15 18:17:10 -0700677 zc->appliedParams.fParams.contentSizeFlag = 0;
Yann Colletb26728c2017-06-16 14:00:46 -0700678 DEBUGLOG(5, "pledged content size : %u ; flag : %u",
679 (U32)pledgedSrcSize, zc->appliedParams.fParams.contentSizeFlag);
Yann Colletcc9f9b72017-06-15 18:17:10 -0700680 zc->blockSize = blockSize;
Yann Collet70e8c382016-02-10 13:37:52 +0100681
Yann Collet083fcc82015-10-25 14:06:35 +0100682 XXH64_reset(&zc->xxhState, 0);
Yann Collete6fa70a2017-04-20 17:28:31 -0700683 zc->stage = ZSTDcs_init;
684 zc->dictID = 0;
685 zc->loadedDictEnd = 0;
Nick Terrellde0414b2017-07-12 19:08:24 -0700686 zc->entropy->hufCTable_repeatMode = HUF_repeat_none;
Nick Terrell830ef412017-07-13 12:45:39 -0700687 zc->entropy->offcode_repeatMode = FSE_repeat_none;
688 zc->entropy->matchlength_repeatMode = FSE_repeat_none;
689 zc->entropy->litlength_repeatMode = FSE_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200690 zc->nextToUpdate = 1;
691 zc->nextSrc = NULL;
692 zc->base = NULL;
693 zc->dictBase = NULL;
694 zc->dictLimit = 0;
695 zc->lowLimit = 0;
Nick Terrelle1982302017-07-17 12:27:24 -0700696 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->seqStore.rep[i] = repStartValue[i]; }
Yann Collete6fa70a2017-04-20 17:28:31 -0700697 zc->hashLog3 = hashLog3;
Nick Terrell7a28b9e2017-07-17 15:29:11 -0700698 zc->optState.litLengthSum = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200699
Nick Terrellde0414b2017-07-12 19:08:24 -0700700 ptr = zc->entropy + 1;
Yann Collete6fa70a2017-04-20 17:28:31 -0700701
702 /* opt parser space */
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800703 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) {
Yann Collet009d6042017-05-19 10:17:59 -0700704 DEBUGLOG(5, "reserving optimal parser space");
Yann Collete6fa70a2017-04-20 17:28:31 -0700705 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
Nick Terrell7a28b9e2017-07-17 15:29:11 -0700706 zc->optState.litFreq = (U32*)ptr;
707 zc->optState.litLengthFreq = zc->optState.litFreq + (1<<Litbits);
708 zc->optState.matchLengthFreq = zc->optState.litLengthFreq + (MaxLL+1);
709 zc->optState.offCodeFreq = zc->optState.matchLengthFreq + (MaxML+1);
710 ptr = zc->optState.offCodeFreq + (MaxOff+1);
711 zc->optState.matchTable = (ZSTD_match_t*)ptr;
712 ptr = zc->optState.matchTable + ZSTD_OPT_NUM+1;
713 zc->optState.priceTable = (ZSTD_optimal_t*)ptr;
714 ptr = zc->optState.priceTable + ZSTD_OPT_NUM+1;
Yann Colleta7737f62016-09-06 09:44:59 +0200715 }
Yann Collete6fa70a2017-04-20 17:28:31 -0700716
717 /* table Space */
718 if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
719 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
720 zc->hashTable = (U32*)(ptr);
721 zc->chainTable = zc->hashTable + hSize;
722 zc->hashTable3 = zc->chainTable + chainSize;
723 ptr = zc->hashTable3 + h3Size;
724
725 /* sequences storage */
Yann Colleta7737f62016-09-06 09:44:59 +0200726 zc->seqStore.sequencesStart = (seqDef*)ptr;
727 ptr = zc->seqStore.sequencesStart + maxNbSeq;
728 zc->seqStore.llCode = (BYTE*) ptr;
729 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
730 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
731 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
Yann Collet5ac72b42017-05-23 11:18:24 -0700732 ptr = zc->seqStore.litStart + blockSize;
733
734 /* buffers */
735 zc->inBuffSize = buffInSize;
736 zc->inBuff = (char*)ptr;
737 zc->outBuffSize = buffOutSize;
738 zc->outBuff = zc->inBuff + buffInSize;
Yann Colleta7737f62016-09-06 09:44:59 +0200739
Yann Colleta7737f62016-09-06 09:44:59 +0200740 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100741 }
Yann Colletf3eca252015-10-22 15:31:46 +0100742}
743
Yann Collet32dfae62017-01-19 10:32:55 -0800744/* ZSTD_invalidateRepCodes() :
745 * ensures next compression will not use repcodes from previous block.
746 * Note : only works with regular variant;
747 * do not use with extDict variant ! */
748void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
749 int i;
Nick Terrelle1982302017-07-17 12:27:24 -0700750 for (i=0; i<ZSTD_REP_NUM; i++) cctx->seqStore.rep[i] = 0;
Yann Collet32dfae62017-01-19 10:32:55 -0800751}
Yann Collet083fcc82015-10-25 14:06:35 +0100752
Yann Collet7b51a292016-01-26 15:58:49 +0100753
Yann Colleta4cab802017-04-18 14:54:54 -0700754/*! ZSTD_copyCCtx_internal() :
755 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
756 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
757 * pledgedSrcSize=0 means "empty" if fParams.contentSizeFlag=1
758 * @return : 0, or an error code */
Yann Collet1ad7c822017-05-22 17:06:04 -0700759static size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx,
760 const ZSTD_CCtx* srcCCtx,
761 ZSTD_frameParameters fParams,
Yann Collet204b6b72017-06-21 15:13:00 -0700762 unsigned long long pledgedSrcSize,
763 ZSTD_buffered_policy_e zbuff)
Yann Collet7b51a292016-01-26 15:58:49 +0100764{
Yann Collet009d6042017-05-19 10:17:59 -0700765 DEBUGLOG(5, "ZSTD_copyCCtx_internal");
Yann Collet7b51a292016-01-26 15:58:49 +0100766 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Sean Purcell2db72492017-02-09 10:50:43 -0800767
inikep28669512016-06-02 13:04:18 +0200768 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Yann Collet204b6b72017-06-21 15:13:00 -0700769 { ZSTD_parameters params = srcCCtx->appliedParams;
Yann Colleta4cab802017-04-18 14:54:54 -0700770 params.fParams = fParams;
Yann Collet5ac72b42017-05-23 11:18:24 -0700771 ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize,
772 ZSTDcrp_noMemset, zbuff);
Sean Purcell2db72492017-02-09 10:50:43 -0800773 }
Yann Collet7b51a292016-01-26 15:58:49 +0100774
775 /* copy tables */
Yann Collet1ad7c822017-05-22 17:06:04 -0700776 { size_t const chainSize = (srcCCtx->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->appliedParams.cParams.chainLog);
777 size_t const hSize = (size_t)1 << srcCCtx->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +0200778 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
779 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collete6fa70a2017-04-20 17:28:31 -0700780 assert((U32*)dstCCtx->chainTable == (U32*)dstCCtx->hashTable + hSize); /* chainTable must follow hashTable */
781 assert((U32*)dstCCtx->hashTable3 == (U32*)dstCCtx->chainTable + chainSize);
782 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); /* presumes all tables follow each other */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100783 }
Yann Collet7b51a292016-01-26 15:58:49 +0100784
Yann Colletc46fb922016-05-29 05:01:04 +0200785 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100786 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
787 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
788 dstCCtx->nextSrc = srcCCtx->nextSrc;
789 dstCCtx->base = srcCCtx->base;
790 dstCCtx->dictBase = srcCCtx->dictBase;
791 dstCCtx->dictLimit = srcCCtx->dictLimit;
792 dstCCtx->lowLimit = srcCCtx->lowLimit;
793 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200794 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100795
Yann Colletfb810d62016-01-28 00:18:06 +0100796 /* copy entropy tables */
Nick Terrellde0414b2017-07-12 19:08:24 -0700797 memcpy(dstCCtx->entropy, srcCCtx->entropy, sizeof(ZSTD_entropyCTables_t));
Yann Collet7b51a292016-01-26 15:58:49 +0100798
799 return 0;
800}
801
Yann Colleta4cab802017-04-18 14:54:54 -0700802/*! ZSTD_copyCCtx() :
803 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
804 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
805 * pledgedSrcSize==0 means "unknown".
806* @return : 0, or an error code */
807size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
808{
809 ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Collet204b6b72017-06-21 15:13:00 -0700810 ZSTD_buffered_policy_e const zbuff = (ZSTD_buffered_policy_e)(srcCCtx->inBuffSize>0);
811 ZSTD_STATIC_ASSERT((U32)ZSTDb_buffered==1);
Yann Colleta4cab802017-04-18 14:54:54 -0700812 fParams.contentSizeFlag = pledgedSrcSize>0;
813
Yann Collet204b6b72017-06-21 15:13:00 -0700814 return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, fParams, pledgedSrcSize, zbuff);
Yann Colleta4cab802017-04-18 14:54:54 -0700815}
816
Yann Collet7b51a292016-01-26 15:58:49 +0100817
Yann Colletecabfe32016-03-20 16:20:06 +0100818/*! ZSTD_reduceTable() :
Yann Colleta4cab802017-04-18 14:54:54 -0700819 * reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100820static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100821{
Yann Colletecabfe32016-03-20 16:20:06 +0100822 U32 u;
823 for (u=0 ; u < size ; u++) {
824 if (table[u] < reducerValue) table[u] = 0;
825 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100826 }
827}
828
Yann Colletecabfe32016-03-20 16:20:06 +0100829/*! ZSTD_reduceIndex() :
830* rescale all indexes to avoid future overflow (indexes are U32) */
831static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
832{
Yann Collet1ad7c822017-05-22 17:06:04 -0700833 { U32 const hSize = 1 << zc->appliedParams.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100834 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
835
Yann Collet1ad7c822017-05-22 17:06:04 -0700836 { U32 const chainSize = (zc->appliedParams.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->appliedParams.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200837 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100838
Yann Collet731ef162016-07-27 21:05:12 +0200839 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100840 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
841}
842
Yann Collet89db5e02015-11-13 11:27:46 +0100843
Yann Collet863ec402016-01-28 17:56:33 +0100844/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100845* Block entropic compression
846*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100847
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200848/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100849
Yann Colletd1b26842016-03-15 01:24:33 +0100850size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100851{
Yann Colletd1b26842016-03-15 01:24:33 +0100852 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200853 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
854 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100855 return ZSTD_blockHeaderSize+srcSize;
856}
857
858
Yann Colletd1b26842016-03-15 01:24:33 +0100859static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100860{
861 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200862 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100863
Yann Colletd1b26842016-03-15 01:24:33 +0100864 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100865
Yann Collet59d1f792016-01-23 19:28:41 +0100866 switch(flSize)
867 {
868 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200869 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100870 break;
871 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200872 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100873 break;
Yann Collet59d1f792016-01-23 19:28:41 +0100874 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200875 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100876 break;
Yann Colletcd2892f2017-06-01 09:44:54 -0700877 default: /* not necessary : flSize is {1,2,3} */
878 assert(0);
Yann Collet59d1f792016-01-23 19:28:41 +0100879 }
880
881 memcpy(ostart + flSize, src, srcSize);
882 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100883}
884
Yann Colletd1b26842016-03-15 01:24:33 +0100885static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100886{
887 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200888 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100889
Yann Collet198e6aa2016-07-20 20:12:24 +0200890 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100891
892 switch(flSize)
893 {
894 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200895 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100896 break;
897 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200898 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100899 break;
Yann Collet59d1f792016-01-23 19:28:41 +0100900 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200901 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100902 break;
Yann Colletcd2892f2017-06-01 09:44:54 -0700903 default: /* not necessary : flSize is {1,2,3} */
904 assert(0);
Yann Collet59d1f792016-01-23 19:28:41 +0100905 }
906
907 ostart[flSize] = *(const BYTE*)src;
908 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100909}
910
Yann Collet59d1f792016-01-23 19:28:41 +0100911
Yann Colleta5c2c082016-03-20 01:09:18 +0100912static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100913
Nick Terrelle1982302017-07-17 12:27:24 -0700914static size_t ZSTD_compressLiterals (ZSTD_entropyCTables_t * entropy,
915 ZSTD_strategy strategy,
Yann Colletd1b26842016-03-15 01:24:33 +0100916 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100917 const void* src, size_t srcSize)
918{
Yann Colleta910dc82016-03-18 12:37:45 +0100919 size_t const minGain = ZSTD_minGain(srcSize);
920 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200921 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100922 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200923 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100924 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100925
Yann Collet14983e72015-11-11 21:38:21 +0100926
Yann Colleta5c2c082016-03-20 01:09:18 +0100927 /* small ? don't even attempt compression (speed opt) */
928# define LITERAL_NOENTROPY 63
Nick Terrelle1982302017-07-17 12:27:24 -0700929 { size_t const minLitSize = entropy->hufCTable_repeatMode == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
Yann Colleta5c2c082016-03-20 01:09:18 +0100930 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
931 }
932
933 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Nick Terrelle1982302017-07-17 12:27:24 -0700934 { HUF_repeat repeat = entropy->hufCTable_repeatMode;
935 int const preferRepeat = strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
Nick Terrella4197772017-03-01 17:51:56 -0800936 if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
Yann Collete348dad2017-04-20 11:14:13 -0700937 cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Nick Terrelle1982302017-07-17 12:27:24 -0700938 entropy->workspace, sizeof(entropy->workspace), (HUF_CElt*)entropy->hufCTable, &repeat, preferRepeat)
Yann Collete348dad2017-04-20 11:14:13 -0700939 : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Nick Terrelle1982302017-07-17 12:27:24 -0700940 entropy->workspace, sizeof(entropy->workspace), (HUF_CElt*)entropy->hufCTable, &repeat, preferRepeat);
Nick Terrella4197772017-03-01 17:51:56 -0800941 if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
Nick Terrelle1982302017-07-17 12:27:24 -0700942 else { entropy->hufCTable_repeatMode = HUF_repeat_check; } /* now have a table to reuse */
Yann Colletb923f652016-01-26 03:14:20 +0100943 }
Yann Collet14983e72015-11-11 21:38:21 +0100944
Nick Terrell308047e2017-08-03 14:05:01 -0700945 if ((cLitSize==0) | (cLitSize >= srcSize - minGain) | ERR_isError(cLitSize)) {
Nick Terrelle1982302017-07-17 12:27:24 -0700946 entropy->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100947 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800948 }
949 if (cLitSize==1) {
Nick Terrelle1982302017-07-17 12:27:24 -0700950 entropy->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100951 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800952 }
Yann Collet14983e72015-11-11 21:38:21 +0100953
954 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100955 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100956 {
Yann Collet59d1f792016-01-23 19:28:41 +0100957 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200958 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200959 MEM_writeLE24(ostart, lhc);
960 break;
961 }
Yann Collet59d1f792016-01-23 19:28:41 +0100962 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200963 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200964 MEM_writeLE32(ostart, lhc);
965 break;
966 }
Yann Collet59d1f792016-01-23 19:28:41 +0100967 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200968 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200969 MEM_writeLE32(ostart, lhc);
970 ostart[4] = (BYTE)(cLitSize >> 10);
971 break;
972 }
Yann Colletcd2892f2017-06-01 09:44:54 -0700973 default: /* not possible : lhSize is {3,4,5} */
974 assert(0);
Yann Collet14983e72015-11-11 21:38:21 +0100975 }
Yann Colleta910dc82016-03-18 12:37:45 +0100976 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100977}
978
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200979static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
980 8, 9, 10, 11, 12, 13, 14, 15,
981 16, 16, 17, 17, 18, 18, 19, 19,
982 20, 20, 20, 20, 21, 21, 21, 21,
983 22, 22, 22, 22, 22, 22, 22, 22,
984 23, 23, 23, 23, 23, 23, 23, 23,
985 24, 24, 24, 24, 24, 24, 24, 24,
986 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100987
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200988static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
989 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
990 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
991 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
992 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
993 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
994 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
995 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200996
997
998void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100999{
Yann Colleted57d852016-07-29 21:22:17 +02001000 BYTE const LL_deltaCode = 19;
1001 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +02001002 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +02001003 BYTE* const llCodeTable = seqStorePtr->llCode;
1004 BYTE* const ofCodeTable = seqStorePtr->ofCode;
1005 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +02001006 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +02001007 U32 u;
1008 for (u=0; u<nbSeq; u++) {
1009 U32 const llv = sequences[u].litLength;
1010 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +02001011 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +02001012 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +02001013 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +02001014 }
Yann Colleted57d852016-07-29 21:22:17 +02001015 if (seqStorePtr->longLengthID==1)
1016 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
1017 if (seqStorePtr->longLengthID==2)
1018 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +01001019}
1020
Nick Terrell634f0122017-07-14 19:11:58 -07001021MEM_STATIC symbolEncodingType_e ZSTD_selectEncodingType(FSE_repeat* repeatMode,
1022 size_t const mostFrequent, size_t nbSeq, U32 defaultNormLog)
1023{
1024#define MIN_SEQ_FOR_DYNAMIC_FSE 64
1025#define MAX_SEQ_FOR_STATIC_FSE 1000
1026
1027 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
1028 *repeatMode = FSE_repeat_check;
1029 return set_rle;
1030 }
1031 if ((*repeatMode == FSE_repeat_valid) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
1032 return set_repeat;
1033 }
1034 if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (defaultNormLog-1)))) {
1035 *repeatMode = FSE_repeat_valid;
1036 return set_basic;
1037 }
1038 *repeatMode = FSE_repeat_check;
1039 return set_compressed;
1040}
1041
1042MEM_STATIC size_t ZSTD_buildCTable(void* dst, size_t dstCapacity,
1043 FSE_CTable* CTable, U32 FSELog, symbolEncodingType_e type,
1044 U32* count, U32 max,
1045 BYTE const* codeTable, size_t nbSeq,
1046 S16 const* defaultNorm, U32 defaultNormLog, U32 defaultMax,
1047 void* workspace, size_t workspaceSize)
1048{
1049 BYTE* op = (BYTE*)dst;
1050 BYTE const* const oend = op + dstCapacity;
1051
1052 switch (type) {
1053 case set_rle:
1054 *op = codeTable[0];
1055 CHECK_F(FSE_buildCTable_rle(CTable, (BYTE)max));
1056 return 1;
1057 case set_repeat:
1058 return 0;
1059 case set_basic:
1060 CHECK_F(FSE_buildCTable_wksp(CTable, defaultNorm, defaultMax, defaultNormLog, workspace, workspaceSize));
1061 return 0;
1062 case set_compressed: {
1063 S16 norm[MaxSeq + 1];
1064 size_t nbSeq_1 = nbSeq;
1065 const U32 tableLog = FSE_optimalTableLog(FSELog, nbSeq, max);
1066 if (count[codeTable[nbSeq-1]] > 1) {
1067 count[codeTable[nbSeq-1]]--;
1068 nbSeq_1--;
1069 }
1070 CHECK_F(FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max));
1071 { size_t const NCountSize = FSE_writeNCount(op, oend - op, norm, max, tableLog); /* overflow protected */
1072 if (FSE_isError(NCountSize)) return NCountSize;
1073 CHECK_F(FSE_buildCTable_wksp(CTable, norm, max, tableLog, workspace, workspaceSize));
1074 return NCountSize;
1075 }
1076 }
1077 default: return assert(0), ERROR(GENERIC);
1078 }
1079}
1080
1081MEM_STATIC size_t ZSTD_encodeSequences(void* dst, size_t dstCapacity,
1082 FSE_CTable const* CTable_MatchLength, BYTE const* mlCodeTable,
1083 FSE_CTable const* CTable_OffsetBits, BYTE const* ofCodeTable,
1084 FSE_CTable const* CTable_LitLength, BYTE const* llCodeTable,
1085 seqDef const* sequences, size_t nbSeq, int longOffsets)
1086{
1087 BIT_CStream_t blockStream;
1088 FSE_CState_t stateMatchLength;
1089 FSE_CState_t stateOffsetBits;
1090 FSE_CState_t stateLitLength;
1091
1092 CHECK_E(BIT_initCStream(&blockStream, dst, dstCapacity), dstSize_tooSmall); /* not enough space remaining */
1093
1094 /* first symbols */
1095 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
1096 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
1097 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
1098 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
1099 if (MEM_32bits()) BIT_flushBits(&blockStream);
1100 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
1101 if (MEM_32bits()) BIT_flushBits(&blockStream);
1102 if (longOffsets) {
1103 U32 const ofBits = ofCodeTable[nbSeq-1];
1104 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1105 if (extraBits) {
1106 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
1107 BIT_flushBits(&blockStream);
1108 }
1109 BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
1110 ofBits - extraBits);
1111 } else {
1112 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
1113 }
1114 BIT_flushBits(&blockStream);
1115
1116 { size_t n;
1117 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
1118 BYTE const llCode = llCodeTable[n];
1119 BYTE const ofCode = ofCodeTable[n];
1120 BYTE const mlCode = mlCodeTable[n];
1121 U32 const llBits = LL_bits[llCode];
1122 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
1123 U32 const mlBits = ML_bits[mlCode];
1124 /* (7)*/ /* (7)*/
1125 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
1126 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
1127 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
1128 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
1129 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
1130 BIT_flushBits(&blockStream); /* (7)*/
1131 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
1132 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
1133 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
1134 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
1135 if (longOffsets) {
1136 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
1137 if (extraBits) {
1138 BIT_addBits(&blockStream, sequences[n].offset, extraBits);
1139 BIT_flushBits(&blockStream); /* (7)*/
1140 }
1141 BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
1142 ofBits - extraBits); /* 31 */
1143 } else {
1144 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
1145 }
1146 BIT_flushBits(&blockStream); /* (7)*/
1147 } }
1148
1149 FSE_flushCState(&blockStream, &stateMatchLength);
1150 FSE_flushCState(&blockStream, &stateOffsetBits);
1151 FSE_flushCState(&blockStream, &stateLitLength);
1152
1153 { size_t const streamSize = BIT_closeCStream(&blockStream);
1154 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
1155 return streamSize;
1156 }
1157}
1158
Nick Terrell308047e2017-08-03 14:05:01 -07001159MEM_STATIC size_t ZSTD_compressSequences_internal(seqStore_t* seqStorePtr,
Nick Terrelle1982302017-07-17 12:27:24 -07001160 ZSTD_entropyCTables_t* entropy,
1161 ZSTD_compressionParameters const* cParams,
Nick Terrell308047e2017-08-03 14:05:01 -07001162 void* dst, size_t dstCapacity)
Yann Collet14983e72015-11-11 21:38:21 +01001163{
Nick Terrelle1982302017-07-17 12:27:24 -07001164 const int longOffsets = cParams->windowLog > STREAM_ACCUMULATOR_MIN;
Yann Collet14983e72015-11-11 21:38:21 +01001165 U32 count[MaxSeq+1];
Nick Terrelle1982302017-07-17 12:27:24 -07001166 FSE_CTable* CTable_LitLength = entropy->litlengthCTable;
1167 FSE_CTable* CTable_OffsetBits = entropy->offcodeCTable;
1168 FSE_CTable* CTable_MatchLength = entropy->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +01001169 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +02001170 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +02001171 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
1172 const BYTE* const llCodeTable = seqStorePtr->llCode;
1173 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +01001174 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +01001175 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +01001176 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +02001177 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +01001178 BYTE* seqHead;
Nick Terrell634f0122017-07-14 19:11:58 -07001179
Nick Terrelle1982302017-07-17 12:27:24 -07001180 ZSTD_STATIC_ASSERT(sizeof(entropy->workspace) >= (1<<MAX(MLFSELog,LLFSELog)));
Yann Collet14983e72015-11-11 21:38:21 +01001181
Yann Collet14983e72015-11-11 21:38:21 +01001182 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +01001183 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +01001184 size_t const litSize = seqStorePtr->lit - literals;
Nick Terrelle1982302017-07-17 12:27:24 -07001185 size_t const cSize = ZSTD_compressLiterals(
1186 entropy, cParams->strategy, op, dstCapacity, literals, litSize);
1187 if (ZSTD_isError(cSize))
1188 return cSize;
Yann Collet14983e72015-11-11 21:38:21 +01001189 op += cSize;
1190 }
1191
1192 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +01001193 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +01001194 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
1195 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
1196 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Nick Terrell308047e2017-08-03 14:05:01 -07001197 if (nbSeq==0) return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +01001198
Yann Colletbe391432016-03-22 23:19:28 +01001199 /* seqHead : flags for FSE encoding type */
1200 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +01001201
Yann Colletb44be742016-03-26 20:52:14 +01001202 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +02001203 ZSTD_seqToCodes(seqStorePtr);
Yann Collet14983e72015-11-11 21:38:21 +01001204 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +01001205 { U32 max = MaxLL;
Nick Terrelle1982302017-07-17 12:27:24 -07001206 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, entropy->workspace);
1207 LLtype = ZSTD_selectEncodingType(&entropy->litlength_repeatMode, mostFrequent, nbSeq, LL_defaultNormLog);
Nick Terrell634f0122017-07-14 19:11:58 -07001208 { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_LitLength, LLFSELog, (symbolEncodingType_e)LLtype,
1209 count, max, llCodeTable, nbSeq, LL_defaultNorm, LL_defaultNormLog, MaxLL,
Nick Terrelle1982302017-07-17 12:27:24 -07001210 entropy->workspace, sizeof(entropy->workspace));
Nick Terrell634f0122017-07-14 19:11:58 -07001211 if (ZSTD_isError(countSize)) return countSize;
1212 op += countSize;
Yann Colletfadda6c2016-03-22 12:14:26 +01001213 } }
Yann Colletb44be742016-03-26 20:52:14 +01001214 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +01001215 { U32 max = MaxOff;
Nick Terrelle1982302017-07-17 12:27:24 -07001216 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, entropy->workspace);
1217 Offtype = ZSTD_selectEncodingType(&entropy->offcode_repeatMode, mostFrequent, nbSeq, OF_defaultNormLog);
Nick Terrell634f0122017-07-14 19:11:58 -07001218 { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_OffsetBits, OffFSELog, (symbolEncodingType_e)Offtype,
1219 count, max, ofCodeTable, nbSeq, OF_defaultNorm, OF_defaultNormLog, MaxOff,
Nick Terrelle1982302017-07-17 12:27:24 -07001220 entropy->workspace, sizeof(entropy->workspace));
Nick Terrell634f0122017-07-14 19:11:58 -07001221 if (ZSTD_isError(countSize)) return countSize;
1222 op += countSize;
Yann Colletfadda6c2016-03-22 12:14:26 +01001223 } }
Yann Collet14983e72015-11-11 21:38:21 +01001224 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +01001225 { U32 max = MaxML;
Nick Terrelle1982302017-07-17 12:27:24 -07001226 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, entropy->workspace);
1227 MLtype = ZSTD_selectEncodingType(&entropy->matchlength_repeatMode, mostFrequent, nbSeq, ML_defaultNormLog);
Nick Terrell634f0122017-07-14 19:11:58 -07001228 { size_t const countSize = ZSTD_buildCTable(op, oend - op, CTable_MatchLength, MLFSELog, (symbolEncodingType_e)MLtype,
1229 count, max, mlCodeTable, nbSeq, ML_defaultNorm, ML_defaultNormLog, MaxML,
Nick Terrelle1982302017-07-17 12:27:24 -07001230 entropy->workspace, sizeof(entropy->workspace));
Nick Terrell634f0122017-07-14 19:11:58 -07001231 if (ZSTD_isError(countSize)) return countSize;
1232 op += countSize;
Yann Colletfadda6c2016-03-22 12:14:26 +01001233 } }
Yann Collet14983e72015-11-11 21:38:21 +01001234
Yann Colletbe391432016-03-22 23:19:28 +01001235 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Collet14983e72015-11-11 21:38:21 +01001236
Nick Terrell634f0122017-07-14 19:11:58 -07001237 { size_t const streamSize = ZSTD_encodeSequences(op, oend - op,
1238 CTable_MatchLength, mlCodeTable,
1239 CTable_OffsetBits, ofCodeTable,
1240 CTable_LitLength, llCodeTable,
1241 sequences, nbSeq, longOffsets);
1242 if (ZSTD_isError(streamSize)) return streamSize;
1243 op += streamSize;
1244 }
Yann Collet14983e72015-11-11 21:38:21 +01001245
Nick Terrell308047e2017-08-03 14:05:01 -07001246 return op - ostart;
1247}
Yann Collet14983e72015-11-11 21:38:21 +01001248
Nick Terrell308047e2017-08-03 14:05:01 -07001249MEM_STATIC size_t ZSTD_compressSequences(seqStore_t* seqStorePtr,
1250 ZSTD_entropyCTables_t* entropy,
1251 ZSTD_compressionParameters const* cParams,
1252 void* dst, size_t dstCapacity,
1253 size_t srcSize)
1254{
1255 size_t const cSize = ZSTD_compressSequences_internal(seqStorePtr, entropy, cParams,
1256 dst, dstCapacity);
1257 size_t const minGain = ZSTD_minGain(srcSize);
1258 size_t const maxCSize = srcSize - minGain;
1259 /* If the srcSize <= dstCapacity, then there is enough space to write a
1260 * raw uncompressed block. Since we ran out of space, the block must not
1261 * be compressible, so fall back to a raw uncompressed block.
1262 */
1263 int const uncompressibleError = cSize == ERROR(dstSize_tooSmall) && srcSize <= dstCapacity;
1264
1265 if (ZSTD_isError(cSize) && !uncompressibleError)
1266 return cSize;
1267 /* Check compressibility */
1268 if (cSize >= maxCSize || uncompressibleError) {
1269 entropy->hufCTable_repeatMode = HUF_repeat_none;
1270 entropy->offcode_repeatMode = FSE_repeat_none;
1271 entropy->matchlength_repeatMode = FSE_repeat_none;
1272 entropy->litlength_repeatMode = FSE_repeat_none;
1273 return 0;
1274 }
1275 assert(!ZSTD_isError(cSize));
Yann Collet14983e72015-11-11 21:38:21 +01001276
Yann Collet4266c0a2016-06-14 01:49:25 +02001277 /* confirm repcodes */
Nick Terrelle1982302017-07-17 12:27:24 -07001278 { int i; for (i=0; i<ZSTD_REP_NUM; i++) seqStorePtr->rep[i] = seqStorePtr->repToConfirm[i]; }
Nick Terrell308047e2017-08-03 14:05:01 -07001279 return cSize;
Yann Collet14983e72015-11-11 21:38:21 +01001280}
1281
Yann Colletbb002742017-01-25 16:25:38 -08001282
Yann Collet95cd0c22016-03-08 18:24:21 +01001283/*! ZSTD_storeSeq() :
1284 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
1285 `offsetCode` : distance to match, or 0 == repCode.
1286 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +01001287*/
Yann Colletd57dffb2016-07-03 01:48:26 +02001288MEM_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 +01001289{
Yann Collet009d6042017-05-19 10:17:59 -07001290#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG >= 6)
1291 static const BYTE* g_start = NULL;
1292 U32 const pos = (U32)((const BYTE*)literals - g_start);
1293 if (g_start==NULL) g_start = (const BYTE*)literals;
1294 if ((pos > 0) && (pos < 1000000000))
1295 DEBUGLOG(6, "Cpos %6u :%5u literals & match %3u bytes at distance %6u",
1296 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
Yann Collet14983e72015-11-11 21:38:21 +01001297#endif
Yann Collet14983e72015-11-11 21:38:21 +01001298 /* copy Literals */
Yann Collet009d6042017-05-19 10:17:59 -07001299 assert(seqStorePtr->lit + litLength <= seqStorePtr->litStart + 128 KB);
Yann Collet14983e72015-11-11 21:38:21 +01001300 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
1301 seqStorePtr->lit += litLength;
1302
1303 /* literal Length */
Yann Collete6fa70a2017-04-20 17:28:31 -07001304 if (litLength>0xFFFF) {
1305 seqStorePtr->longLengthID = 1;
1306 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
1307 }
Yann Colletc0ce4f12016-07-30 00:55:13 +02001308 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +01001309
1310 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +02001311 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +01001312
1313 /* match Length */
Yann Collete6fa70a2017-04-20 17:28:31 -07001314 if (matchCode>0xFFFF) {
1315 seqStorePtr->longLengthID = 2;
1316 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
1317 }
Yann Colletc0ce4f12016-07-30 00:55:13 +02001318 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +02001319
Yann Colletc0ce4f12016-07-30 00:55:13 +02001320 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +01001321}
1322
1323
Yann Collet7d360282016-02-12 00:07:30 +01001324/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001325* Match length counter
1326***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +01001327static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +01001328{
Yann Collet863ec402016-01-28 17:56:33 +01001329 if (MEM_isLittleEndian()) {
1330 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +01001331# if defined(_MSC_VER) && defined(_WIN64)
1332 unsigned long r = 0;
1333 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +01001334 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +01001335# elif defined(__GNUC__) && (__GNUC__ >= 3)
1336 return (__builtin_ctzll((U64)val) >> 3);
1337# else
Yann Collete348dad2017-04-20 11:14:13 -07001338 static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
1339 0, 3, 1, 3, 1, 4, 2, 7,
1340 0, 2, 3, 6, 1, 5, 3, 5,
1341 1, 3, 4, 4, 2, 5, 6, 7,
1342 7, 0, 1, 2, 3, 3, 4, 6,
1343 2, 6, 5, 5, 3, 4, 5, 6,
1344 7, 1, 2, 4, 6, 4, 4, 5,
1345 7, 2, 6, 5, 7, 6, 7, 7 };
Yann Collet14983e72015-11-11 21:38:21 +01001346 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
1347# endif
Yann Collet863ec402016-01-28 17:56:33 +01001348 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +01001349# if defined(_MSC_VER)
1350 unsigned long r=0;
1351 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +01001352 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +01001353# elif defined(__GNUC__) && (__GNUC__ >= 3)
1354 return (__builtin_ctz((U32)val) >> 3);
1355# else
Yann Collete348dad2017-04-20 11:14:13 -07001356 static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
1357 3, 2, 2, 1, 3, 2, 0, 1,
1358 3, 3, 1, 2, 2, 2, 2, 0,
1359 3, 1, 2, 0, 1, 0, 1, 1 };
Yann Collet14983e72015-11-11 21:38:21 +01001360 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
1361# endif
1362 }
Yann Collet863ec402016-01-28 17:56:33 +01001363 } else { /* Big Endian CPU */
1364 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +01001365# if defined(_MSC_VER) && defined(_WIN64)
1366 unsigned long r = 0;
1367 _BitScanReverse64( &r, val );
1368 return (unsigned)(r>>3);
1369# elif defined(__GNUC__) && (__GNUC__ >= 3)
1370 return (__builtin_clzll(val) >> 3);
1371# else
1372 unsigned r;
1373 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
1374 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
1375 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
1376 r += (!val);
1377 return r;
1378# endif
Yann Collet863ec402016-01-28 17:56:33 +01001379 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +01001380# if defined(_MSC_VER)
1381 unsigned long r = 0;
1382 _BitScanReverse( &r, (unsigned long)val );
1383 return (unsigned)(r>>3);
1384# elif defined(__GNUC__) && (__GNUC__ >= 3)
1385 return (__builtin_clz((U32)val) >> 3);
1386# else
1387 unsigned r;
1388 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
1389 r += (!val);
1390 return r;
1391# endif
Yann Collet863ec402016-01-28 17:56:33 +01001392 } }
Yann Collet14983e72015-11-11 21:38:21 +01001393}
1394
1395
Yann Colleta436a522016-06-20 23:34:04 +02001396static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +01001397{
1398 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +02001399 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +01001400
Yann Colleta436a522016-06-20 23:34:04 +02001401 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +02001402 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +01001403 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
1404 pIn += ZSTD_NbCommonBytes(diff);
1405 return (size_t)(pIn - pStart);
1406 }
Yann Collet14983e72015-11-11 21:38:21 +01001407 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
1408 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
1409 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
1410 return (size_t)(pIn - pStart);
1411}
1412
Yann Collet04b12d82016-02-11 06:23:24 +01001413/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +01001414* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +01001415* convention : on reaching mEnd, match count continue starting from iStart
1416*/
1417static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
1418{
Yann Collet7591a7f2016-05-20 11:44:43 +02001419 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +02001420 size_t const matchLength = ZSTD_count(ip, match, vEnd);
1421 if (match + matchLength != mEnd) return matchLength;
1422 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +01001423}
1424
Yann Collet14983e72015-11-11 21:38:21 +01001425
Yann Collet863ec402016-01-28 17:56:33 +01001426/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001427* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +01001428***************************************/
inikepcc52a972016-02-19 10:09:35 +01001429static const U32 prime3bytes = 506832829U;
1430static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Collete6fa70a2017-04-20 17:28:31 -07001431MEM_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 +01001432
Yann Collet4b100f42015-10-30 15:49:48 +01001433static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +01001434static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +01001435static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +01001436
Yann Collet4b100f42015-10-30 15:49:48 +01001437static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001438static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001439static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001440
1441static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001442static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001443static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001444
Yann Collet14983e72015-11-11 21:38:21 +01001445static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001446static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001447static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001448
Yann Collet45dc3562016-07-12 09:47:31 +02001449static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
1450static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
1451static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
1452
Yann Collet5be2dd22015-11-11 13:43:58 +01001453static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001454{
1455 switch(mls)
1456 {
1457 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001458 case 4: return ZSTD_hash4Ptr(p, hBits);
1459 case 5: return ZSTD_hash5Ptr(p, hBits);
1460 case 6: return ZSTD_hash6Ptr(p, hBits);
1461 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +02001462 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001463 }
1464}
Yann Collet2acb5d32015-10-29 16:49:43 +01001465
Yann Collet863ec402016-01-28 17:56:33 +01001466
Yann Collet2ce49232016-02-02 14:36:49 +01001467/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001468* Fast Scan
1469***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001470static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1471{
1472 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001473 U32 const hBits = zc->appliedParams.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001474 const BYTE* const base = zc->base;
1475 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001476 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001477 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001478
Yann Colletfb810d62016-01-28 00:18:06 +01001479 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001480 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001481 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001482 }
1483}
1484
1485
Nick Terrell565e9252017-08-14 17:20:50 -07001486FORCE_INLINE_TEMPLATE
Yann Collet4266c0a2016-06-14 01:49:25 +02001487void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +02001488 const void* src, size_t srcSize,
1489 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001490{
Yann Collet4266c0a2016-06-14 01:49:25 +02001491 U32* const hashTable = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001492 U32 const hBits = cctx->appliedParams.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +02001493 seqStore_t* seqStorePtr = &(cctx->seqStore);
1494 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001495 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001496 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001497 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +02001498 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +02001499 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001500 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001501 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Nick Terrelle1982302017-07-17 12:27:24 -07001502 U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
Yann Collet92d75662016-07-03 01:10:53 +02001503 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001504
Yann Collet1f44b3f2015-11-05 17:32:18 +01001505 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001506 ip += (ip==lowest);
1507 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +02001508 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1509 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +02001510 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001511
1512 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +02001513 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +02001514 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +02001515 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
1516 U32 const current = (U32)(ip-base);
1517 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +01001518 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001519 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001520
Yann Collet280f9a82016-08-08 00:44:00 +02001521 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +02001522 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +01001523 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001524 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1525 } else {
Yann Collet92d75662016-07-03 01:10:53 +02001526 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001527 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001528 ip += ((ip-anchor) >> g_searchStrength) + 1;
1529 continue;
1530 }
Yann Collet45dc3562016-07-12 09:47:31 +02001531 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001532 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001533 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001534 offset_2 = offset_1;
1535 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001536
Yann Colleta436a522016-06-20 23:34:04 +02001537 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001538 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001539
Yann Collet402fdcf2015-11-20 12:46:08 +01001540 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001541 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001542 anchor = ip;
1543
Yann Colletfb810d62016-01-28 00:18:06 +01001544 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001545 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001546 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 +01001547 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1548 /* check immediate repcode */
1549 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001550 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001551 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001552 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001553 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001554 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001555 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001556 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1557 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001558 anchor = ip;
1559 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001560 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001561
Yann Collet4266c0a2016-06-14 01:49:25 +02001562 /* save reps for next block */
Nick Terrelle1982302017-07-17 12:27:24 -07001563 seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1564 seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001565
Yann Collet70e45772016-03-19 18:08:32 +01001566 /* Last Literals */
1567 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001568 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1569 seqStorePtr->lit += lastLLSize;
1570 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001571}
1572
1573
Yann Collet82260dd2016-02-11 07:14:25 +01001574static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001575 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001576{
Yann Collet1ad7c822017-05-22 17:06:04 -07001577 const U32 mls = ctx->appliedParams.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001578 switch(mls)
1579 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001580 default: /* includes case 3 */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001581 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001582 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001583 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001584 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001585 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001586 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001587 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001588 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001589 }
1590}
Yann Colletf3eca252015-10-22 15:31:46 +01001591
Yann Colletf3eca252015-10-22 15:31:46 +01001592
Yann Collet82260dd2016-02-11 07:14:25 +01001593static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001594 const void* src, size_t srcSize,
1595 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001596{
1597 U32* hashTable = ctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001598 const U32 hBits = ctx->appliedParams.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001599 seqStore_t* seqStorePtr = &(ctx->seqStore);
1600 const BYTE* const base = ctx->base;
1601 const BYTE* const dictBase = ctx->dictBase;
1602 const BYTE* const istart = (const BYTE*)src;
1603 const BYTE* ip = istart;
1604 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001605 const U32 lowestIndex = ctx->lowLimit;
1606 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001607 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001608 const BYTE* const lowPrefixPtr = base + dictLimit;
1609 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001610 const BYTE* const iend = istart + srcSize;
1611 const BYTE* const ilimit = iend - 8;
Nick Terrelle1982302017-07-17 12:27:24 -07001612 U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001613
Yann Colleta436a522016-06-20 23:34:04 +02001614 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001615 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001616 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001617 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001618 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001619 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001620 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001621 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001622 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001623 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001624 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001625 hashTable[h] = current; /* update hash table */
1626
Yann Colleta436a522016-06-20 23:34:04 +02001627 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001628 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001629 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001630 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
Yann Collet743402c2015-11-20 12:03:53 +01001631 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001632 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001633 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001634 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001635 (MEM_read32(match) != MEM_read32(ip)) ) {
1636 ip += ((ip-anchor) >> g_searchStrength) + 1;
1637 continue;
1638 }
1639 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001640 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001641 U32 offset;
Yann Collete6fa70a2017-04-20 17:28:31 -07001642 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
Yann Colleta436a522016-06-20 23:34:04 +02001643 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001644 offset = current - matchIndex;
1645 offset_2 = offset_1;
1646 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001647 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001648 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001649
Yann Collet5054ee02015-11-23 13:34:21 +01001650 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001651 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001652 anchor = ip;
1653
Yann Colletfb810d62016-01-28 00:18:06 +01001654 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001655 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001656 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001657 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1658 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001659 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001660 U32 const current2 = (U32)(ip-base);
1661 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001662 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001663 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1664 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001665 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001666 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet5054ee02015-11-23 13:34:21 +01001667 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001668 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001669 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001670 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001671 anchor = ip;
1672 continue;
1673 }
Yann Collet743402c2015-11-20 12:03:53 +01001674 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001675 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001676
Yann Collet4266c0a2016-06-14 01:49:25 +02001677 /* save reps for next block */
Nick Terrelle1982302017-07-17 12:27:24 -07001678 seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001679
Yann Collet89db5e02015-11-13 11:27:46 +01001680 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001681 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001682 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1683 seqStorePtr->lit += lastLLSize;
1684 }
Yann Collet89db5e02015-11-13 11:27:46 +01001685}
1686
1687
Yann Collet82260dd2016-02-11 07:14:25 +01001688static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001689 const void* src, size_t srcSize)
1690{
Yann Collet1ad7c822017-05-22 17:06:04 -07001691 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001692 switch(mls)
1693 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001694 default: /* includes case 3 */
Yann Collet89db5e02015-11-13 11:27:46 +01001695 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001696 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001697 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001698 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001699 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001700 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001701 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001702 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001703 }
1704}
1705
1706
Yann Collet04b12d82016-02-11 06:23:24 +01001707/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001708* Double Fast
1709***************************************/
1710static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1711{
1712 U32* const hashLarge = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001713 U32 const hBitsL = cctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001714 U32* const hashSmall = cctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001715 U32 const hBitsS = cctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001716 const BYTE* const base = cctx->base;
1717 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001718 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001719 const size_t fastHashFillStep = 3;
1720
1721 while(ip <= iend) {
1722 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1723 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1724 ip += fastHashFillStep;
1725 }
1726}
1727
1728
Nick Terrell565e9252017-08-14 17:20:50 -07001729FORCE_INLINE_TEMPLATE
Yann Collet45dc3562016-07-12 09:47:31 +02001730void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1731 const void* src, size_t srcSize,
1732 const U32 mls)
1733{
1734 U32* const hashLong = cctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001735 const U32 hBitsL = cctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001736 U32* const hashSmall = cctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001737 const U32 hBitsS = cctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001738 seqStore_t* seqStorePtr = &(cctx->seqStore);
1739 const BYTE* const base = cctx->base;
1740 const BYTE* const istart = (const BYTE*)src;
1741 const BYTE* ip = istart;
1742 const BYTE* anchor = istart;
1743 const U32 lowestIndex = cctx->dictLimit;
1744 const BYTE* const lowest = base + lowestIndex;
1745 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001746 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Nick Terrelle1982302017-07-17 12:27:24 -07001747 U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
Yann Collet45dc3562016-07-12 09:47:31 +02001748 U32 offsetSaved = 0;
1749
1750 /* init */
1751 ip += (ip==lowest);
1752 { U32 const maxRep = (U32)(ip-lowest);
1753 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1754 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1755 }
1756
1757 /* Main Search Loop */
1758 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1759 size_t mLength;
1760 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1761 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1762 U32 const current = (U32)(ip-base);
1763 U32 const matchIndexL = hashLong[h2];
1764 U32 const matchIndexS = hashSmall[h];
1765 const BYTE* matchLong = base + matchIndexL;
1766 const BYTE* match = base + matchIndexS;
1767 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1768
Yann Colletc17e0202017-04-20 12:50:02 -07001769 assert(offset_1 <= current); /* supposed guaranteed by construction */
1770 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001771 /* favor repcode */
Yann Collet45dc3562016-07-12 09:47:31 +02001772 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1773 ip++;
1774 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1775 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001776 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001777 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1778 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001779 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001780 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1781 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001782 size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1783 U32 const matchIndexL3 = hashLong[hl3];
1784 const BYTE* matchL3 = base + matchIndexL3;
1785 hashLong[hl3] = current + 1;
1786 if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
1787 mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
Yann Colletc54692f2016-08-24 01:10:42 +02001788 ip++;
Yann Collete6fa70a2017-04-20 17:28:31 -07001789 offset = (U32)(ip-matchL3);
1790 while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
Yann Colletc54692f2016-08-24 01:10:42 +02001791 } else {
1792 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1793 offset = (U32)(ip-match);
1794 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1795 }
Yann Collet45dc3562016-07-12 09:47:31 +02001796 } else {
1797 ip += ((ip-anchor) >> g_searchStrength) + 1;
1798 continue;
1799 }
1800
1801 offset_2 = offset_1;
1802 offset_1 = offset;
1803
1804 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1805 }
1806
1807 /* match found */
1808 ip += mLength;
1809 anchor = ip;
1810
1811 if (ip <= ilimit) {
1812 /* Fill Table */
1813 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1814 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1815 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1816 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1817
1818 /* check immediate repcode */
1819 while ( (ip <= ilimit)
1820 && ( (offset_2>0)
1821 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1822 /* store sequence */
1823 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001824 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001825 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1826 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1827 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1828 ip += rLength;
1829 anchor = ip;
1830 continue; /* faster when present ... (?) */
1831 } } }
1832
1833 /* save reps for next block */
Nick Terrelle1982302017-07-17 12:27:24 -07001834 seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1835 seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet45dc3562016-07-12 09:47:31 +02001836
1837 /* Last Literals */
1838 { size_t const lastLLSize = iend - anchor;
1839 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1840 seqStorePtr->lit += lastLLSize;
1841 }
1842}
1843
1844
1845static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1846{
Yann Collet1ad7c822017-05-22 17:06:04 -07001847 const U32 mls = ctx->appliedParams.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001848 switch(mls)
1849 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001850 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001851 case 4 :
1852 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1853 case 5 :
1854 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1855 case 6 :
1856 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1857 case 7 :
1858 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1859 }
1860}
1861
1862
1863static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1864 const void* src, size_t srcSize,
1865 const U32 mls)
1866{
1867 U32* const hashLong = ctx->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001868 U32 const hBitsL = ctx->appliedParams.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001869 U32* const hashSmall = ctx->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07001870 U32 const hBitsS = ctx->appliedParams.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001871 seqStore_t* seqStorePtr = &(ctx->seqStore);
1872 const BYTE* const base = ctx->base;
1873 const BYTE* const dictBase = ctx->dictBase;
1874 const BYTE* const istart = (const BYTE*)src;
1875 const BYTE* ip = istart;
1876 const BYTE* anchor = istart;
1877 const U32 lowestIndex = ctx->lowLimit;
1878 const BYTE* const dictStart = dictBase + lowestIndex;
1879 const U32 dictLimit = ctx->dictLimit;
1880 const BYTE* const lowPrefixPtr = base + dictLimit;
1881 const BYTE* const dictEnd = dictBase + dictLimit;
1882 const BYTE* const iend = istart + srcSize;
1883 const BYTE* const ilimit = iend - 8;
Nick Terrelle1982302017-07-17 12:27:24 -07001884 U32 offset_1=seqStorePtr->rep[0], offset_2=seqStorePtr->rep[1];
Yann Collet45dc3562016-07-12 09:47:31 +02001885
1886 /* Search Loop */
1887 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1888 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1889 const U32 matchIndex = hashSmall[hSmall];
1890 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1891 const BYTE* match = matchBase + matchIndex;
1892
1893 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1894 const U32 matchLongIndex = hashLong[hLong];
1895 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1896 const BYTE* matchLong = matchLongBase + matchLongIndex;
1897
1898 const U32 current = (U32)(ip-base);
1899 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1900 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1901 const BYTE* repMatch = repBase + repIndex;
1902 size_t mLength;
1903 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1904
1905 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1906 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1907 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1908 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1909 ip++;
1910 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1911 } else {
1912 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1913 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1914 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1915 U32 offset;
1916 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1917 offset = current - matchLongIndex;
1918 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1919 offset_2 = offset_1;
1920 offset_1 = offset;
1921 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001922
Yann Collet73d74a02016-07-12 13:03:48 +02001923 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001924 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1925 U32 const matchIndex3 = hashLong[h3];
1926 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1927 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001928 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001929 hashLong[h3] = current + 1;
1930 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1931 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1932 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1933 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1934 ip++;
1935 offset = current+1 - matchIndex3;
1936 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1937 } else {
1938 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1939 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1940 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1941 offset = current - matchIndex;
1942 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1943 }
Yann Collet45dc3562016-07-12 09:47:31 +02001944 offset_2 = offset_1;
1945 offset_1 = offset;
1946 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001947
Yann Collet45dc3562016-07-12 09:47:31 +02001948 } else {
1949 ip += ((ip-anchor) >> g_searchStrength) + 1;
1950 continue;
1951 } }
1952
1953 /* found a match : store it */
1954 ip += mLength;
1955 anchor = ip;
1956
1957 if (ip <= ilimit) {
1958 /* Fill Table */
Nick Terrellf35ef5c2017-03-09 12:51:33 -08001959 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1960 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
Yann Collet45dc3562016-07-12 09:47:31 +02001961 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1962 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1963 /* check immediate repcode */
1964 while (ip <= ilimit) {
1965 U32 const current2 = (U32)(ip-base);
1966 U32 const repIndex2 = current2 - offset_2;
1967 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1968 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1969 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1970 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07001971 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet45dc3562016-07-12 09:47:31 +02001972 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1973 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1974 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1975 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1976 ip += repLength2;
1977 anchor = ip;
1978 continue;
1979 }
1980 break;
1981 } } }
1982
1983 /* save reps for next block */
Nick Terrelle1982302017-07-17 12:27:24 -07001984 seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
Yann Collet45dc3562016-07-12 09:47:31 +02001985
1986 /* Last Literals */
1987 { size_t const lastLLSize = iend - anchor;
1988 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1989 seqStorePtr->lit += lastLLSize;
1990 }
1991}
1992
1993
1994static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1995 const void* src, size_t srcSize)
1996{
Yann Collet1ad7c822017-05-22 17:06:04 -07001997 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001998 switch(mls)
1999 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002000 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02002001 case 4 :
2002 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
2003 case 5 :
2004 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
2005 case 6 :
2006 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
2007 case 7 :
2008 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
2009 }
2010}
2011
2012
2013/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01002014* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01002015***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01002016/** ZSTD_insertBt1() : add one or multiple positions to tree.
2017* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01002018* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01002019static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
2020 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01002021{
Yann Collet731ef162016-07-27 21:05:12 +02002022 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002023 U32 const hashLog = zc->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +02002024 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
2025 U32* const bt = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002026 U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
Yann Collet731ef162016-07-27 21:05:12 +02002027 U32 const btMask = (1 << btLog) - 1;
2028 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01002029 size_t commonLengthSmaller=0, commonLengthLarger=0;
2030 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01002031 const BYTE* const dictBase = zc->dictBase;
2032 const U32 dictLimit = zc->dictLimit;
2033 const BYTE* const dictEnd = dictBase + dictLimit;
2034 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07002035 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01002036 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01002037 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002038 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01002039 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01002040 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02002041 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01002042 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01002043 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02002044#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01002045 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
2046 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
2047 predictedSmall += (predictedSmall>0);
2048 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02002049#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01002050
Yann Collet6c3e2e72015-12-11 10:44:07 +01002051 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002052
Yann Colletfb810d62016-01-28 00:18:06 +01002053 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08002054 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01002055 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08002056
Yann Colletc0932082016-06-30 14:07:30 +02002057#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01002058 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01002059 if (matchIndex == predictedSmall) {
2060 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01002061 *smallerPtr = matchIndex;
2062 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2063 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
2064 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01002065 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01002066 continue;
2067 }
Yann Colletfb810d62016-01-28 00:18:06 +01002068 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01002069 *largerPtr = matchIndex;
2070 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2071 largerPtr = nextPtr;
2072 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01002073 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01002074 continue;
2075 }
Yann Collet04b12d82016-02-11 06:23:24 +01002076#endif
Yann Colletfb810d62016-01-28 00:18:06 +01002077 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01002078 match = base + matchIndex;
2079 if (match[matchLength] == ip[matchLength])
2080 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01002081 } else {
Yann Collet1358f912016-01-01 07:29:39 +01002082 match = dictBase + matchIndex;
2083 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
2084 if (matchIndex+matchLength >= dictLimit)
Nick Terrellf35ef5c2017-03-09 12:51:33 -08002085 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet1358f912016-01-01 07:29:39 +01002086 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002087
Yann Colletb8a6f682016-02-15 17:06:29 +01002088 if (matchLength > bestLength) {
2089 bestLength = matchLength;
2090 if (matchLength > matchEndIdx - matchIndex)
2091 matchEndIdx = matchIndex + (U32)matchLength;
2092 }
Yann Colletee3f4512015-12-29 22:26:09 +01002093
Yann Collet59d70632015-11-04 12:05:27 +01002094 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01002095 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002096
Yann Colletfb810d62016-01-28 00:18:06 +01002097 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002098 /* match is smaller than current */
2099 *smallerPtr = matchIndex; /* update smaller idx */
2100 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01002101 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002102 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01002103 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01002104 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01002105 /* match is larger than current */
2106 *largerPtr = matchIndex;
2107 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01002108 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01002109 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01002110 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01002111 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002112
Yann Collet59d70632015-11-04 12:05:27 +01002113 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02002114 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01002115 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
2116 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002117}
2118
2119
Yann Collet82260dd2016-02-11 07:14:25 +01002120static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01002121 ZSTD_CCtx* zc,
2122 const BYTE* const ip, const BYTE* const iend,
2123 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01002124 U32 nbCompares, const U32 mls,
2125 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01002126{
Yann Collet731ef162016-07-27 21:05:12 +02002127 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002128 U32 const hashLog = zc->appliedParams.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +02002129 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
2130 U32* const bt = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002131 U32 const btLog = zc->appliedParams.cParams.chainLog - 1;
Yann Collet731ef162016-07-27 21:05:12 +02002132 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01002133 U32 matchIndex = hashTable[h];
2134 size_t commonLengthSmaller=0, commonLengthLarger=0;
2135 const BYTE* const base = zc->base;
2136 const BYTE* const dictBase = zc->dictBase;
2137 const U32 dictLimit = zc->dictLimit;
2138 const BYTE* const dictEnd = dictBase + dictLimit;
2139 const BYTE* const prefixStart = base + dictLimit;
2140 const U32 current = (U32)(ip-base);
2141 const U32 btLow = btMask >= current ? 0 : current - btMask;
2142 const U32 windowLow = zc->lowLimit;
2143 U32* smallerPtr = bt + 2*(current&btMask);
2144 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01002145 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01002146 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02002147 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01002148
Yann Collet6c3e2e72015-12-11 10:44:07 +01002149 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01002150
Yann Colletfb810d62016-01-28 00:18:06 +01002151 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08002152 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01002153 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
2154 const BYTE* match;
2155
Yann Colletfb810d62016-01-28 00:18:06 +01002156 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01002157 match = base + matchIndex;
2158 if (match[matchLength] == ip[matchLength])
2159 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01002160 } else {
Yann Collet03526e12015-11-23 15:29:15 +01002161 match = dictBase + matchIndex;
2162 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01002163 if (matchIndex+matchLength >= dictLimit)
Nick Terrellf35ef5c2017-03-09 12:51:33 -08002164 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01002165 }
2166
Yann Colletfb810d62016-01-28 00:18:06 +01002167 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01002168 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01002169 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02002170 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02002171 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01002172 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
2173 break; /* drop, to guarantee consistency (miss a little bit of compression) */
2174 }
2175
Yann Colletfb810d62016-01-28 00:18:06 +01002176 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01002177 /* match is smaller than current */
2178 *smallerPtr = matchIndex; /* update smaller idx */
2179 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
2180 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2181 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
2182 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01002183 } else {
Yann Collet03526e12015-11-23 15:29:15 +01002184 /* match is larger than current */
2185 *largerPtr = matchIndex;
2186 commonLengthLarger = matchLength;
2187 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
2188 largerPtr = nextPtr;
2189 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01002190 } }
Yann Collet03526e12015-11-23 15:29:15 +01002191
2192 *smallerPtr = *largerPtr = 0;
2193
Yann Collet72e84cf2015-12-31 19:08:44 +01002194 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02002195 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01002196}
2197
Yann Collet2cc12cb2016-01-01 07:47:58 +01002198
Yann Colletb8a6f682016-02-15 17:06:29 +01002199static 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 +01002200{
2201 const BYTE* const base = zc->base;
2202 const U32 target = (U32)(ip - base);
2203 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01002204
2205 while(idx < target)
2206 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01002207}
2208
Yann Collet52447382016-03-20 16:00:00 +01002209/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01002210static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01002211 ZSTD_CCtx* zc,
2212 const BYTE* const ip, const BYTE* const iLimit,
2213 size_t* offsetPtr,
2214 const U32 maxNbAttempts, const U32 mls)
2215{
2216 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01002217 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01002218 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
2219}
2220
2221
Yann Collet768c6bc2016-02-10 14:01:49 +01002222static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01002223 ZSTD_CCtx* zc, /* Index table will be updated */
2224 const BYTE* ip, const BYTE* const iLimit,
2225 size_t* offsetPtr,
2226 const U32 maxNbAttempts, const U32 matchLengthSearch)
2227{
2228 switch(matchLengthSearch)
2229 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002230 default : /* includes case 3 */
Yann Collet2cc12cb2016-01-01 07:47:58 +01002231 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
2232 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07002233 case 7 :
Yann Collet2cc12cb2016-01-01 07:47:58 +01002234 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
2235 }
2236}
2237
2238
Yann Colletb8a6f682016-02-15 17:06:29 +01002239static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
2240{
2241 const BYTE* const base = zc->base;
2242 const U32 target = (U32)(ip - base);
2243 U32 idx = zc->nextToUpdate;
2244
2245 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
2246}
2247
inikep64d7bcb2016-04-07 19:14:09 +02002248
Yann Collet03526e12015-11-23 15:29:15 +01002249/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01002250static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01002251 ZSTD_CCtx* zc,
2252 const BYTE* const ip, const BYTE* const iLimit,
2253 size_t* offsetPtr,
2254 const U32 maxNbAttempts, const U32 mls)
2255{
Yann Colletee3f4512015-12-29 22:26:09 +01002256 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01002257 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01002258 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01002259}
2260
2261
Yann Collet82260dd2016-02-11 07:14:25 +01002262static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01002263 ZSTD_CCtx* zc, /* Index table will be updated */
2264 const BYTE* ip, const BYTE* const iLimit,
2265 size_t* offsetPtr,
2266 const U32 maxNbAttempts, const U32 matchLengthSearch)
2267{
2268 switch(matchLengthSearch)
2269 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002270 default : /* includes case 3 */
Yann Collet03526e12015-11-23 15:29:15 +01002271 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
2272 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07002273 case 7 :
Yann Collet03526e12015-11-23 15:29:15 +01002274 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
2275 }
2276}
2277
2278
Yann Collet5106a762015-11-05 15:00:24 +01002279
Yann Collet731ef162016-07-27 21:05:12 +02002280/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02002281* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02002282***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02002283#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
2284
2285/* Update chains up to ip (excluded)
Anders Oleson517577b2017-02-20 12:08:59 -08002286 Assumption : always within prefix (i.e. not within extDict) */
Nick Terrell565e9252017-08-14 17:20:50 -07002287FORCE_INLINE_TEMPLATE
inikep64d7bcb2016-04-07 19:14:09 +02002288U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
2289{
2290 U32* const hashTable = zc->hashTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002291 const U32 hashLog = zc->appliedParams.cParams.hashLog;
inikep64d7bcb2016-04-07 19:14:09 +02002292 U32* const chainTable = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002293 const U32 chainMask = (1 << zc->appliedParams.cParams.chainLog) - 1;
inikep64d7bcb2016-04-07 19:14:09 +02002294 const BYTE* const base = zc->base;
2295 const U32 target = (U32)(ip - base);
2296 U32 idx = zc->nextToUpdate;
2297
Yann Collet22d76322016-06-21 08:01:51 +02002298 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002299 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
2300 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
2301 hashTable[h] = idx;
2302 idx++;
2303 }
2304
2305 zc->nextToUpdate = target;
2306 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
2307}
2308
2309
Nick Terrell55fc1f92017-05-24 13:50:10 -07002310/* inlining is important to hardwire a hot branch (template emulation) */
Nick Terrell565e9252017-08-14 17:20:50 -07002311FORCE_INLINE_TEMPLATE
inikep64d7bcb2016-04-07 19:14:09 +02002312size_t ZSTD_HcFindBestMatch_generic (
2313 ZSTD_CCtx* zc, /* Index table will be updated */
2314 const BYTE* const ip, const BYTE* const iLimit,
2315 size_t* offsetPtr,
2316 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
2317{
2318 U32* const chainTable = zc->chainTable;
Yann Collet1ad7c822017-05-22 17:06:04 -07002319 const U32 chainSize = (1 << zc->appliedParams.cParams.chainLog);
inikep64d7bcb2016-04-07 19:14:09 +02002320 const U32 chainMask = chainSize-1;
2321 const BYTE* const base = zc->base;
2322 const BYTE* const dictBase = zc->dictBase;
2323 const U32 dictLimit = zc->dictLimit;
2324 const BYTE* const prefixStart = base + dictLimit;
2325 const BYTE* const dictEnd = dictBase + dictLimit;
2326 const U32 lowLimit = zc->lowLimit;
2327 const U32 current = (U32)(ip-base);
2328 const U32 minChain = current > chainSize ? current - chainSize : 0;
2329 int nbAttempts=maxNbAttempts;
Yann Collete42afbc2017-04-26 11:39:35 -07002330 size_t ml=4-1;
inikep64d7bcb2016-04-07 19:14:09 +02002331
2332 /* HC4 match finder */
2333 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
2334
Yann Collet22d76322016-06-21 08:01:51 +02002335 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02002336 const BYTE* match;
2337 size_t currentMl=0;
2338 if ((!extDict) || matchIndex >= dictLimit) {
2339 match = base + matchIndex;
2340 if (match[ml] == ip[ml]) /* potentially better */
2341 currentMl = ZSTD_count(ip, match, iLimit);
2342 } else {
2343 match = dictBase + matchIndex;
2344 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
Yann Collete42afbc2017-04-26 11:39:35 -07002345 currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002346 }
2347
2348 /* save best solution */
Yann Colletc17e0202017-04-20 12:50:02 -07002349 if (currentMl > ml) {
2350 ml = currentMl;
2351 *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
2352 if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
2353 }
inikep64d7bcb2016-04-07 19:14:09 +02002354
2355 if (matchIndex <= minChain) break;
2356 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
2357 }
2358
2359 return ml;
2360}
2361
2362
Nick Terrell565e9252017-08-14 17:20:50 -07002363FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_selectMLS (
inikep64d7bcb2016-04-07 19:14:09 +02002364 ZSTD_CCtx* zc,
2365 const BYTE* ip, const BYTE* const iLimit,
2366 size_t* offsetPtr,
2367 const U32 maxNbAttempts, const U32 matchLengthSearch)
2368{
2369 switch(matchLengthSearch)
2370 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002371 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02002372 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
2373 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
Yann Collet933ce4a2017-03-29 14:32:15 -07002374 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02002375 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
2376 }
2377}
2378
2379
Nick Terrell565e9252017-08-14 17:20:50 -07002380FORCE_INLINE_TEMPLATE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
inikep64d7bcb2016-04-07 19:14:09 +02002381 ZSTD_CCtx* zc,
2382 const BYTE* ip, const BYTE* const iLimit,
2383 size_t* offsetPtr,
2384 const U32 maxNbAttempts, const U32 matchLengthSearch)
2385{
2386 switch(matchLengthSearch)
2387 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002388 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02002389 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
2390 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
Yann Collet933ce4a2017-03-29 14:32:15 -07002391 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02002392 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
2393 }
2394}
2395
inikep64d7bcb2016-04-07 19:14:09 +02002396
Yann Collet287b7d92015-11-22 13:24:05 +01002397/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02002398* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02002399*********************************/
Nick Terrell565e9252017-08-14 17:20:50 -07002400FORCE_INLINE_TEMPLATE
inikep64d7bcb2016-04-07 19:14:09 +02002401void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
2402 const void* src, size_t srcSize,
2403 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01002404{
inikepfaa8d8a2016-04-05 19:01:10 +02002405 seqStore_t* seqStorePtr = &(ctx->seqStore);
2406 const BYTE* const istart = (const BYTE*)src;
2407 const BYTE* ip = istart;
2408 const BYTE* anchor = istart;
2409 const BYTE* const iend = istart + srcSize;
2410 const BYTE* const ilimit = iend - 8;
2411 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002412
Yann Collet1ad7c822017-05-22 17:06:04 -07002413 U32 const maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
2414 U32 const mls = ctx->appliedParams.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002415
inikep64d7bcb2016-04-07 19:14:09 +02002416 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2417 size_t* offsetPtr,
2418 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02002419 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Nick Terrelle1982302017-07-17 12:27:24 -07002420 U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02002421
inikepfaa8d8a2016-04-05 19:01:10 +02002422 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02002423 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02002424 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02002425 { U32 const maxRep = (U32)(ip-base);
2426 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
2427 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
2428 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002429
inikepfaa8d8a2016-04-05 19:01:10 +02002430 /* Match Loop */
2431 while (ip < ilimit) {
2432 size_t matchLength=0;
2433 size_t offset=0;
2434 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01002435
inikepfaa8d8a2016-04-05 19:01:10 +02002436 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02002437 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02002438 /* repcode : we take it */
Yann Collete42afbc2017-04-26 11:39:35 -07002439 matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002440 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01002441 }
Yann Collet5be2dd22015-11-11 13:43:58 +01002442
inikepfaa8d8a2016-04-05 19:01:10 +02002443 /* first search (depth 0) */
2444 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002445 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002446 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002447 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002448 }
Yann Collet5106a762015-11-05 15:00:24 +01002449
Yann Collete42afbc2017-04-26 11:39:35 -07002450 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002451 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2452 continue;
2453 }
2454
inikep64d7bcb2016-04-07 19:14:09 +02002455 /* let's try to find a better solution */
2456 if (depth>=1)
2457 while (ip<ilimit) {
2458 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002459 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002460 size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002461 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002462 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002463 if ((mlRep >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002464 matchLength = mlRep, offset = 0, start = ip;
2465 }
2466 { size_t offset2=99999999;
2467 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002468 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2469 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002470 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002471 matchLength = ml2, offset = offset2, start = ip;
2472 continue; /* search a better one */
2473 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002474
inikep64d7bcb2016-04-07 19:14:09 +02002475 /* let's find an even better one */
2476 if ((depth==2) && (ip<ilimit)) {
2477 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002478 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002479 size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002480 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002481 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002482 if ((ml2 >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002483 matchLength = ml2, offset = 0, start = ip;
2484 }
2485 { size_t offset2=99999999;
2486 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002487 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2488 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002489 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002490 matchLength = ml2, offset = offset2, start = ip;
2491 continue;
2492 } } }
2493 break; /* nothing found : store previous solution */
2494 }
2495
Nick Terrell55f9cd42017-06-19 15:12:28 -07002496 /* NOTE:
2497 * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
2498 * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
2499 * overflows the pointer, which is undefined behavior.
2500 */
inikep64d7bcb2016-04-07 19:14:09 +02002501 /* catch up */
2502 if (offset) {
Yann Colletc17e0202017-04-20 12:50:02 -07002503 while ( (start > anchor)
2504 && (start > base+offset-ZSTD_REP_MOVE)
Nick Terrell55f9cd42017-06-19 15:12:28 -07002505 && (start[-1] == (start-offset+ZSTD_REP_MOVE)[-1]) ) /* only search for offset within prefix */
inikep64d7bcb2016-04-07 19:14:09 +02002506 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02002507 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02002508 }
inikepfaa8d8a2016-04-05 19:01:10 +02002509 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002510_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002511 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002512 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002513 anchor = ip = start + matchLength;
2514 }
Yann Collet48537162016-04-07 15:24:29 +02002515
inikepfaa8d8a2016-04-05 19:01:10 +02002516 /* check immediate repcode */
2517 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02002518 && ((offset_2>0)
2519 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02002520 /* store sequence */
Yann Collete42afbc2017-04-26 11:39:35 -07002521 matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet9634f672016-07-03 01:23:58 +02002522 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02002523 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2524 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002525 anchor = ip;
2526 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02002527 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002528
Yann Collet4266c0a2016-06-14 01:49:25 +02002529 /* Save reps for next block */
Nick Terrelle1982302017-07-17 12:27:24 -07002530 seqStorePtr->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
2531 seqStorePtr->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02002532
inikepfaa8d8a2016-04-05 19:01:10 +02002533 /* Last Literals */
2534 { size_t const lastLLSize = iend - anchor;
2535 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2536 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002537 }
Yann Collet5106a762015-11-05 15:00:24 +01002538}
2539
Yann Collet5be2dd22015-11-11 13:43:58 +01002540
inikep64d7bcb2016-04-07 19:14:09 +02002541static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2542{
2543 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2544}
2545
2546static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2547{
2548 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2549}
2550
2551static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2552{
2553 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2554}
2555
2556static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2557{
2558 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2559}
2560
2561
Nick Terrell565e9252017-08-14 17:20:50 -07002562FORCE_INLINE_TEMPLATE
inikep64d7bcb2016-04-07 19:14:09 +02002563void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2564 const void* src, size_t srcSize,
2565 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002566{
inikepfaa8d8a2016-04-05 19:01:10 +02002567 seqStore_t* seqStorePtr = &(ctx->seqStore);
2568 const BYTE* const istart = (const BYTE*)src;
2569 const BYTE* ip = istart;
2570 const BYTE* anchor = istart;
2571 const BYTE* const iend = istart + srcSize;
2572 const BYTE* const ilimit = iend - 8;
2573 const BYTE* const base = ctx->base;
2574 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002575 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002576 const BYTE* const prefixStart = base + dictLimit;
2577 const BYTE* const dictBase = ctx->dictBase;
2578 const BYTE* const dictEnd = dictBase + dictLimit;
2579 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2580
Yann Collet1ad7c822017-05-22 17:06:04 -07002581 const U32 maxSearches = 1 << ctx->appliedParams.cParams.searchLog;
2582 const U32 mls = ctx->appliedParams.cParams.searchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002583
inikep64d7bcb2016-04-07 19:14:09 +02002584 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2585 size_t* offsetPtr,
2586 U32 maxNbAttempts, U32 matchLengthSearch);
2587 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2588
Nick Terrelle1982302017-07-17 12:27:24 -07002589 U32 offset_1 = seqStorePtr->rep[0], offset_2 = seqStorePtr->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002590
Yann Collet302ff032016-07-03 01:28:16 +02002591 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002592 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002593 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002594
2595 /* Match Loop */
2596 while (ip < ilimit) {
2597 size_t matchLength=0;
2598 size_t offset=0;
2599 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002600 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002601
2602 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002603 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002604 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2605 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002606 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002607 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002608 /* repcode detected we should take it */
2609 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002610 matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002611 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002612 } }
2613
2614 /* first search (depth 0) */
2615 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002616 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002617 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002618 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002619 }
2620
Yann Collete42afbc2017-04-26 11:39:35 -07002621 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002622 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2623 continue;
2624 }
2625
inikep64d7bcb2016-04-07 19:14:09 +02002626 /* let's try to find a better solution */
2627 if (depth>=1)
2628 while (ip<ilimit) {
2629 ip ++;
2630 current++;
2631 /* check repCode */
2632 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002633 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002634 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2635 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002636 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002637 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2638 /* repcode detected */
2639 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002640 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002641 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002642 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002643 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002644 matchLength = repLength, offset = 0, start = ip;
2645 } }
2646
2647 /* search match, depth 1 */
2648 { size_t offset2=99999999;
2649 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002650 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2651 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002652 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002653 matchLength = ml2, offset = offset2, start = ip;
2654 continue; /* search a better one */
2655 } }
2656
2657 /* let's find an even better one */
2658 if ((depth==2) && (ip<ilimit)) {
2659 ip ++;
2660 current++;
2661 /* check repCode */
2662 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002663 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002664 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2665 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002666 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002667 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2668 /* repcode detected */
2669 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002670 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Colletc17e0202017-04-20 12:50:02 -07002671 int const gain2 = (int)(repLength * 4);
2672 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002673 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002674 matchLength = repLength, offset = 0, start = ip;
2675 } }
2676
2677 /* search match, depth 2 */
2678 { size_t offset2=99999999;
2679 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002680 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2681 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002682 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002683 matchLength = ml2, offset = offset2, start = ip;
2684 continue;
2685 } } }
2686 break; /* nothing found : store previous solution */
2687 }
2688
inikepfaa8d8a2016-04-05 19:01:10 +02002689 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002690 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002691 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002692 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2693 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002694 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002695 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002696 }
inikepfaa8d8a2016-04-05 19:01:10 +02002697
inikepfaa8d8a2016-04-05 19:01:10 +02002698 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002699_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002700 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002701 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002702 anchor = ip = start + matchLength;
2703 }
2704
2705 /* check immediate repcode */
2706 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002707 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002708 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2709 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002710 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002711 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2712 /* repcode detected we should take it */
2713 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002714 matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Collet302ff032016-07-03 01:28:16 +02002715 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002716 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2717 ip += matchLength;
2718 anchor = ip;
2719 continue; /* faster when present ... (?) */
2720 }
2721 break;
2722 } }
2723
Yann Collet4266c0a2016-06-14 01:49:25 +02002724 /* Save reps for next block */
Nick Terrelle1982302017-07-17 12:27:24 -07002725 seqStorePtr->repToConfirm[0] = offset_1; seqStorePtr->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002726
inikepfaa8d8a2016-04-05 19:01:10 +02002727 /* Last Literals */
2728 { size_t const lastLLSize = iend - anchor;
2729 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2730 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002731 }
2732}
2733
2734
Yann Collet59d1f792016-01-23 19:28:41 +01002735void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002736{
inikep64d7bcb2016-04-07 19:14:09 +02002737 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002738}
2739
Yann Collet59d1f792016-01-23 19:28:41 +01002740static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002741{
Yann Colleta1249dc2016-01-25 04:22:03 +01002742 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002743}
Yann Collet9a24e592015-11-22 02:53:43 +01002744
Yann Collet59d1f792016-01-23 19:28:41 +01002745static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002746{
Yann Colleta1249dc2016-01-25 04:22:03 +01002747 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002748}
2749
Yann Collet59d1f792016-01-23 19:28:41 +01002750static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002751{
Yann Colleta1249dc2016-01-25 04:22:03 +01002752 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002753}
2754
inikepef519412016-04-21 11:08:43 +02002755
inikepef519412016-04-21 11:08:43 +02002756/* The optimal parser */
2757#include "zstd_opt.h"
2758
2759static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2760{
Yann Colletd4f4e582016-06-27 01:31:35 +02002761#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002762 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2763#else
2764 (void)ctx; (void)src; (void)srcSize;
2765 return;
2766#endif
2767}
2768
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002769static void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002770{
2771#ifdef ZSTD_OPT_H_91842398743
2772 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002773#else
2774 (void)ctx; (void)src; (void)srcSize;
2775 return;
2776#endif
inikepef519412016-04-21 11:08:43 +02002777}
2778
inikepd3b8d7a2016-02-22 10:06:17 +01002779static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002780{
Yann Colletd4f4e582016-06-27 01:31:35 +02002781#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002782 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2783#else
2784 (void)ctx; (void)src; (void)srcSize;
2785 return;
2786#endif
2787}
2788
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002789static void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002790{
2791#ifdef ZSTD_OPT_H_91842398743
2792 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002793#else
2794 (void)ctx; (void)src; (void)srcSize;
2795 return;
2796#endif
inikepe2bfe242016-01-31 11:25:48 +01002797}
2798
Yann Collet7a231792015-11-21 15:27:35 +01002799
Yann Colletb44ab822017-06-20 14:11:49 -07002800/* ZSTD_selectBlockCompressor() :
2801 * assumption : strat is a valid strategy */
Yann Collet59d1f792016-01-23 19:28:41 +01002802typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Colletb923f652016-01-26 03:14:20 +01002803static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002804{
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002805 static const ZSTD_blockCompressor blockCompressor[2][(unsigned)ZSTD_btultra+1] = {
Yann Colletb44ab822017-06-20 14:11:49 -07002806 { ZSTD_compressBlock_fast /* default for 0 */,
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002807 ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy,
Yann Colletc17e0202017-04-20 12:50:02 -07002808 ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002809 ZSTD_compressBlock_btopt, ZSTD_compressBlock_btultra },
Yann Colletb44ab822017-06-20 14:11:49 -07002810 { ZSTD_compressBlock_fast_extDict /* default for 0 */,
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002811 ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict,
Yann Colletc17e0202017-04-20 12:50:02 -07002812 ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002813 ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01002814 };
Yann Colleta5ffe3d2017-05-12 16:29:19 -07002815 ZSTD_STATIC_ASSERT((unsigned)ZSTD_fast == 1);
Yann Colletb44ab822017-06-20 14:11:49 -07002816 assert((U32)strat >= (U32)ZSTD_fast);
2817 assert((U32)strat <= (U32)ZSTD_btultra);
Yann Collet7fe531e2015-11-29 02:38:09 +01002818
Yann Colletb44ab822017-06-20 14:11:49 -07002819 return blockCompressor[extDict!=0][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002820}
2821
2822
Yann Colletd1b26842016-03-15 01:24:33 +01002823static 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 +01002824{
Yann Collet1ad7c822017-05-22 17:06:04 -07002825 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->appliedParams.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002826 const BYTE* const base = zc->base;
2827 const BYTE* const istart = (const BYTE*)src;
2828 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002829 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 +02002830 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002831 if (current > zc->nextToUpdate + 384)
Yann Colletc17e0202017-04-20 12:50:02 -07002832 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 +01002833 blockCompressor(zc, src, srcSize);
Nick Terrelle1982302017-07-17 12:27:24 -07002834 return ZSTD_compressSequences(&zc->seqStore, zc->entropy, &zc->appliedParams.cParams, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002835}
2836
2837
Yann Colletdb8e21d2017-05-12 13:46:49 -07002838/*! ZSTD_compress_frameChunk() :
Yann Colletc991cc12016-07-28 00:55:43 +02002839* Compress a chunk of data into one or multiple blocks.
2840* All blocks will be terminated, all input will be consumed.
2841* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2842* Frame is supposed already started (header already produced)
2843* @return : compressed size, or an error code
2844*/
Yann Colletdb8e21d2017-05-12 13:46:49 -07002845static size_t ZSTD_compress_frameChunk (ZSTD_CCtx* cctx,
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002846 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002847 const void* src, size_t srcSize,
2848 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002849{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002850 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002851 size_t remaining = srcSize;
2852 const BYTE* ip = (const BYTE*)src;
2853 BYTE* const ostart = (BYTE*)dst;
2854 BYTE* op = ostart;
Yann Collet1ad7c822017-05-22 17:06:04 -07002855 U32 const maxDist = 1 << cctx->appliedParams.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002856
Yann Collet1ad7c822017-05-22 17:06:04 -07002857 if (cctx->appliedParams.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002858 XXH64_update(&cctx->xxhState, src, srcSize);
2859
Yann Collet2ce49232016-02-02 14:36:49 +01002860 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002861 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002862 size_t cSize;
2863
Yann Colletc17e0202017-04-20 12:50:02 -07002864 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
2865 return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01002866 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002867
Yann Collet346efcc2016-08-02 14:26:00 +02002868 /* preemptive overflow correction */
Sean Purcell881abe42017-03-07 16:52:23 -08002869 if (cctx->lowLimit > (3U<<29)) {
Yann Collet1ad7c822017-05-22 17:06:04 -07002870 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->appliedParams.cParams.hashLog, cctx->appliedParams.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002871 U32 const current = (U32)(ip - cctx->base);
Yann Collet1ad7c822017-05-22 17:06:04 -07002872 U32 const newCurrent = (current & cycleMask) + (1 << cctx->appliedParams.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002873 U32 const correction = current - newCurrent;
2874 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002875 ZSTD_reduceIndex(cctx, correction);
2876 cctx->base += correction;
2877 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002878 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002879 cctx->dictLimit -= correction;
2880 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2881 else cctx->nextToUpdate -= correction;
2882 }
2883
Yann Collet06e76972017-01-25 16:39:03 -08002884 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002885 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002886 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2887 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2888 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002889 }
Yann Collet89db5e02015-11-13 11:27:46 +01002890
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002891 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002892 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002893
Yann Collet2ce49232016-02-02 14:36:49 +01002894 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002895 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2896 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2897 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2898 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2899 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002900 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002901 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002902 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002903 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002904 }
2905
2906 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002907 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002908 ip += blockSize;
2909 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002910 }
2911
Yann Collet62470b42016-07-28 15:29:08 +02002912 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002913 return op-ostart;
2914}
2915
2916
Yann Collet6236eba2016-04-12 15:52:33 +02002917static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002918 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002919{ BYTE* const op = (BYTE*)dst;
Yann Collet31533ba2017-04-27 00:29:04 -07002920 U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2921 U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002922 U32 const checksumFlag = params.fParams.checksumFlag>0;
2923 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002924 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002925 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2926 U32 const fcsCode = params.fParams.contentSizeFlag ?
Nick Terrell55fc1f92017-05-24 13:50:10 -07002927 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002928 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002929 size_t pos;
2930
2931 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet009d6042017-05-19 10:17:59 -07002932 DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u",
Yann Collet0be6fd32017-05-08 16:08:01 -07002933 !params.fParams.noDictIDFlag, dictID, dictIDSizeCode);
Yann Collet6236eba2016-04-12 15:52:33 +02002934
2935 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002936 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002937 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002938 switch(dictIDSizeCode)
2939 {
Yann Colletcd2892f2017-06-01 09:44:54 -07002940 default: assert(0); /* impossible */
Yann Colletc46fb922016-05-29 05:01:04 +02002941 case 0 : break;
2942 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002943 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002944 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2945 }
Yann Collet673f0d72016-06-06 00:26:38 +02002946 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002947 {
Yann Colletcd2892f2017-06-01 09:44:54 -07002948 default: assert(0); /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002949 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002950 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2951 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002952 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002953 }
Yann Colletc46fb922016-05-29 05:01:04 +02002954 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002955}
2956
2957
Yann Collet346efcc2016-08-02 14:26:00 +02002958static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002959 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002960 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002961 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002962{
Yann Collet2acb5d32015-10-29 16:49:43 +01002963 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002964 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002965
Yann Colleta3d99262017-06-29 14:44:49 -07002966 DEBUGLOG(5, "ZSTD_compressContinue_internal");
2967 DEBUGLOG(5, "stage: %u", cctx->stage);
Yann Collet346efcc2016-08-02 14:26:00 +02002968 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002969
Yann Collet346efcc2016-08-02 14:26:00 +02002970 if (frame && (cctx->stage==ZSTDcs_init)) {
Yann Colleta0ba8492017-06-16 13:29:17 -07002971 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams,
2972 cctx->pledgedSrcSizePlusOne-1, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002973 if (ZSTD_isError(fhSize)) return fhSize;
2974 dstCapacity -= fhSize;
2975 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002976 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002977 }
Yann Colletf3eca252015-10-22 15:31:46 +01002978
Yann Collet417890c2015-12-04 17:16:37 +01002979 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002980 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002981 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002982 ptrdiff_t const delta = cctx->nextSrc - ip;
2983 cctx->lowLimit = cctx->dictLimit;
2984 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2985 cctx->dictBase = cctx->base;
2986 cctx->base -= delta;
2987 cctx->nextToUpdate = cctx->dictLimit;
2988 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002989 }
2990
Yann Collet346efcc2016-08-02 14:26:00 +02002991 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2992 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2993 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2994 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2995 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002996 }
2997
Yann Collet346efcc2016-08-02 14:26:00 +02002998 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002999
Yann Collet5eb749e2017-01-11 18:21:25 +01003000 if (srcSize) {
3001 size_t const cSize = frame ?
Yann Colletdb8e21d2017-05-12 13:46:49 -07003002 ZSTD_compress_frameChunk (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
Yann Collet346efcc2016-08-02 14:26:00 +02003003 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01003004 if (ZSTD_isError(cSize)) return cSize;
Yann Collet20d5e032017-04-11 18:34:02 -07003005 cctx->consumedSrcSize += srcSize;
Yann Collet6236eba2016-04-12 15:52:33 +02003006 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01003007 } else
3008 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01003009}
3010
Yann Collet5b567392016-07-28 01:17:22 +02003011size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01003012 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01003013 const void* src, size_t srcSize)
3014{
Yann Collet20d5e032017-04-11 18:34:02 -07003015 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
Yann Collet5b567392016-07-28 01:17:22 +02003016}
3017
3018
Yann Colletfa3671e2017-05-19 10:51:30 -07003019size_t ZSTD_getBlockSize(const ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01003020{
Yann Colletfa3671e2017-05-19 10:51:30 -07003021 U32 const cLevel = cctx->compressionLevel;
3022 ZSTD_compressionParameters cParams = (cLevel == ZSTD_CLEVEL_CUSTOM) ?
Yann Collet1ad7c822017-05-22 17:06:04 -07003023 cctx->appliedParams.cParams :
Yann Colletfa3671e2017-05-19 10:51:30 -07003024 ZSTD_getCParams(cLevel, 0, 0);
3025 return MIN (ZSTD_BLOCKSIZE_MAX, 1 << cParams.windowLog);
Yann Colletcf05b9d2016-07-18 16:52:10 +02003026}
3027
3028size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
3029{
Yann Colletfa3671e2017-05-19 10:51:30 -07003030 size_t const blockSizeMax = ZSTD_getBlockSize(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02003031 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07003032 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
Yann Colletbf42c8e2016-01-09 01:08:23 +01003033}
3034
Yann Collet16a0b102017-03-24 12:46:46 -07003035/*! ZSTD_loadDictionaryContent() :
3036 * @return : 0, or an error code
3037 */
Yann Colletb923f652016-01-26 03:14:20 +01003038static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01003039{
3040 const BYTE* const ip = (const BYTE*) src;
3041 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01003042
Yann Collet417890c2015-12-04 17:16:37 +01003043 /* input becomes current prefix */
3044 zc->lowLimit = zc->dictLimit;
3045 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
3046 zc->dictBase = zc->base;
3047 zc->base += ip - zc->nextSrc;
3048 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08003049 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01003050
3051 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02003052 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01003053
Yann Collet1ad7c822017-05-22 17:06:04 -07003054 switch(zc->appliedParams.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01003055 {
3056 case ZSTD_fast:
Yann Collet1ad7c822017-05-22 17:06:04 -07003057 ZSTD_fillHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01003058 break;
3059
Yann Collet45dc3562016-07-12 09:47:31 +02003060 case ZSTD_dfast:
Yann Collet1ad7c822017-05-22 17:06:04 -07003061 ZSTD_fillDoubleHashTable (zc, iend, zc->appliedParams.cParams.searchLength);
Yann Collet45dc3562016-07-12 09:47:31 +02003062 break;
3063
Yann Collet417890c2015-12-04 17:16:37 +01003064 case ZSTD_greedy:
3065 case ZSTD_lazy:
3066 case ZSTD_lazy2:
Yann Collet16a0b102017-03-24 12:46:46 -07003067 if (srcSize >= HASH_READ_SIZE)
Yann Collet1ad7c822017-05-22 17:06:04 -07003068 ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01003069 break;
3070
3071 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01003072 case ZSTD_btopt:
Nick Terrelleeb31ee2017-03-09 11:44:25 -08003073 case ZSTD_btultra:
Yann Collet16a0b102017-03-24 12:46:46 -07003074 if (srcSize >= HASH_READ_SIZE)
Yann Collet1ad7c822017-05-22 17:06:04 -07003075 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->appliedParams.cParams.searchLog, zc->appliedParams.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01003076 break;
3077
3078 default:
Yann Colletcd2892f2017-06-01 09:44:54 -07003079 assert(0); /* not possible : not a valid strategy id */
Yann Collet417890c2015-12-04 17:16:37 +01003080 }
3081
Nick Terrellecf90ca2017-02-13 18:27:34 -08003082 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01003083 return 0;
3084}
3085
3086
Nick Terrellf9c9af32016-10-19 17:22:08 -07003087/* Dictionaries that assign zero probability to symbols that show up causes problems
3088 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
3089 that we may encounter during compression.
3090 NOTE: This behavior is not standard and could be improved in the future. */
3091static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
3092 U32 s;
3093 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
3094 for (s = 0; s <= maxSymbolValue; ++s) {
3095 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
3096 }
3097 return 0;
3098}
3099
3100
Yann Colletb923f652016-01-26 03:14:20 +01003101/* Dictionary format :
Yann Colletbea78e82017-03-22 18:09:11 -07003102 * See :
3103 * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
3104 */
Yann Collet16a0b102017-03-24 12:46:46 -07003105/*! ZSTD_loadZstdDictionary() :
3106 * @return : 0, or an error code
3107 * assumptions : magic number supposed already checked
3108 * dictSize supposed > 8
Yann Colletbea78e82017-03-22 18:09:11 -07003109 */
Yann Collet16a0b102017-03-24 12:46:46 -07003110static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01003111{
Yann Collet52a06222016-06-15 13:53:34 +02003112 const BYTE* dictPtr = (const BYTE*)dict;
3113 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07003114 short offcodeNCount[MaxOff+1];
3115 unsigned offcodeMaxValue = MaxOff;
Nick Terrellde0414b2017-07-12 19:08:24 -07003116
3117 ZSTD_STATIC_ASSERT(sizeof(cctx->entropy->workspace) >= (1<<MAX(MLFSELog,LLFSELog)));
Yann Colletfb810d62016-01-28 00:18:06 +01003118
Yann Colletbea78e82017-03-22 18:09:11 -07003119 dictPtr += 4; /* skip magic number */
Yann Collet1ad7c822017-05-22 17:06:04 -07003120 cctx->dictID = cctx->appliedParams.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
Yann Colletbea78e82017-03-22 18:09:11 -07003121 dictPtr += 4;
3122
Nick Terrellde0414b2017-07-12 19:08:24 -07003123 { size_t const hufHeaderSize = HUF_readCTable((HUF_CElt*)cctx->entropy->hufCTable, 255, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003124 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003125 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003126 }
Yann Colletfb810d62016-01-28 00:18:06 +01003127
Nick Terrellf9c9af32016-10-19 17:22:08 -07003128 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02003129 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003130 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003131 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003132 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Nick Terrellde0414b2017-07-12 19:08:24 -07003133 CHECK_E( FSE_buildCTable_wksp(cctx->entropy->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, cctx->entropy->workspace, sizeof(cctx->entropy->workspace)),
Yann Colletc17e0202017-04-20 12:50:02 -07003134 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003135 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003136 }
Yann Colletfb810d62016-01-28 00:18:06 +01003137
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003138 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07003139 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02003140 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003141 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003142 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003143 /* Every match length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07003144 CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
Nick Terrellde0414b2017-07-12 19:08:24 -07003145 CHECK_E( FSE_buildCTable_wksp(cctx->entropy->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, cctx->entropy->workspace, sizeof(cctx->entropy->workspace)),
Yann Colletc17e0202017-04-20 12:50:02 -07003146 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003147 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003148 }
Yann Colletfb810d62016-01-28 00:18:06 +01003149
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003150 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07003151 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02003152 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003153 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07003154 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07003155 /* Every literal length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07003156 CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
Nick Terrellde0414b2017-07-12 19:08:24 -07003157 CHECK_E( FSE_buildCTable_wksp(cctx->entropy->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, cctx->entropy->workspace, sizeof(cctx->entropy->workspace)),
Yann Colletc17e0202017-04-20 12:50:02 -07003158 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02003159 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003160 }
Yann Colletfb810d62016-01-28 00:18:06 +01003161
Yann Collet52a06222016-06-15 13:53:34 +02003162 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Nick Terrelle1982302017-07-17 12:27:24 -07003163 cctx->seqStore.rep[0] = MEM_readLE32(dictPtr+0);
3164 cctx->seqStore.rep[1] = MEM_readLE32(dictPtr+4);
3165 cctx->seqStore.rep[2] = MEM_readLE32(dictPtr+8);
Yann Collet52a06222016-06-15 13:53:34 +02003166 dictPtr += 12;
3167
Yann Colletbea78e82017-03-22 18:09:11 -07003168 { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
3169 U32 offcodeMax = MaxOff;
3170 if (dictContentSize <= ((U32)-1) - 128 KB) {
3171 U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
3172 offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
Nick Terrellb2c39a22016-10-24 14:11:27 -07003173 }
Yann Colletbea78e82017-03-22 18:09:11 -07003174 /* All offset values <= dictContentSize + 128 KB must be representable */
Nick Terrellf9c9af32016-10-19 17:22:08 -07003175 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
Yann Colletbea78e82017-03-22 18:09:11 -07003176 /* All repCodes must be <= dictContentSize and != 0*/
3177 { U32 u;
3178 for (u=0; u<3; u++) {
Nick Terrelle1982302017-07-17 12:27:24 -07003179 if (cctx->seqStore.rep[u] == 0) return ERROR(dictionary_corrupted);
3180 if (cctx->seqStore.rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07003181 } }
Nick Terrellf9c9af32016-10-19 17:22:08 -07003182
Nick Terrellde0414b2017-07-12 19:08:24 -07003183 cctx->entropy->hufCTable_repeatMode = HUF_repeat_valid;
Nick Terrell830ef412017-07-13 12:45:39 -07003184 cctx->entropy->offcode_repeatMode = FSE_repeat_valid;
3185 cctx->entropy->matchlength_repeatMode = FSE_repeat_valid;
3186 cctx->entropy->litlength_repeatMode = FSE_repeat_valid;
Yann Collet16a0b102017-03-24 12:46:46 -07003187 return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
3188 }
Yann Colletb923f652016-01-26 03:14:20 +01003189}
3190
Yann Colletd1b26842016-03-15 01:24:33 +01003191/** ZSTD_compress_insertDictionary() :
3192* @return : 0, or an error code */
Yann Collet7bd1a292017-06-21 11:50:33 -07003193static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx,
3194 const void* dict, size_t dictSize,
3195 ZSTD_dictMode_e dictMode)
Yann Colletb923f652016-01-26 03:14:20 +01003196{
Yann Collet204b6b72017-06-21 15:13:00 -07003197 DEBUGLOG(5, "ZSTD_compress_insertDictionary");
Yann Colletc46fb922016-05-29 05:01:04 +02003198 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01003199
Yann Collet7bd1a292017-06-21 11:50:33 -07003200 /* dict restricted modes */
3201 if (dictMode==ZSTD_dm_rawContent)
Yann Collet16a0b102017-03-24 12:46:46 -07003202 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
Yann Colletd1b26842016-03-15 01:24:33 +01003203
Yann Collet7d381612017-06-27 13:50:34 -07003204 if (MEM_readLE32(dict) != ZSTD_MAGIC_DICTIONARY) {
Yann Collet204b6b72017-06-21 15:13:00 -07003205 if (dictMode == ZSTD_dm_auto) {
3206 DEBUGLOG(5, "raw content dictionary detected");
Yann Collet7bd1a292017-06-21 11:50:33 -07003207 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
Yann Collet204b6b72017-06-21 15:13:00 -07003208 }
Yann Collet7bd1a292017-06-21 11:50:33 -07003209 if (dictMode == ZSTD_dm_fullDict)
3210 return ERROR(dictionary_wrong);
3211 assert(0); /* impossible */
3212 }
3213
3214 /* dict as full zstd dictionary */
Yann Collet16a0b102017-03-24 12:46:46 -07003215 return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
Yann Colletecd651b2016-01-07 15:35:18 +01003216}
3217
Yann Collet27caf2a2016-04-01 15:48:48 +02003218/*! ZSTD_compressBegin_internal() :
Yann Colletc3bce242017-06-20 16:09:11 -07003219 * @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02003220static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01003221 const void* dict, size_t dictSize,
Yann Collet7bd1a292017-06-21 11:50:33 -07003222 ZSTD_dictMode_e dictMode,
Yann Collet18803372017-05-22 18:21:51 -07003223 const ZSTD_CDict* cdict,
Yann Collet5ac72b42017-05-23 11:18:24 -07003224 ZSTD_parameters params, U64 pledgedSrcSize,
3225 ZSTD_buffered_policy_e zbuff)
Yann Colletf3eca252015-10-22 15:31:46 +01003226{
Yann Colleta3d99262017-06-29 14:44:49 -07003227 DEBUGLOG(4, "ZSTD_compressBegin_internal");
Yann Collet2084b042017-07-03 15:52:19 -07003228 DEBUGLOG(4, "dict ? %s", dict ? "dict" : (cdict ? "cdict" : "none"));
Yann Colleta3d99262017-06-29 14:44:49 -07003229 DEBUGLOG(4, "dictMode : %u", (U32)dictMode);
Yann Collet5ac72b42017-05-23 11:18:24 -07003230 /* params are supposed to be fully validated at this point */
Yann Colletab9162e2017-04-11 10:46:20 -07003231 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet18803372017-05-22 18:21:51 -07003232 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
3233
Yann Collet204b6b72017-06-21 15:13:00 -07003234 if (cdict && cdict->dictContentSize>0) {
Yann Collet5ac72b42017-05-23 11:18:24 -07003235 return ZSTD_copyCCtx_internal(cctx, cdict->refContext,
Yann Collet204b6b72017-06-21 15:13:00 -07003236 params.fParams, pledgedSrcSize,
3237 zbuff);
3238 }
Yann Collet18803372017-05-22 18:21:51 -07003239
Yann Collet204b6b72017-06-21 15:13:00 -07003240 CHECK_F( ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize,
3241 ZSTDcrp_continue, zbuff) );
Yann Collet7bd1a292017-06-21 11:50:33 -07003242 return ZSTD_compress_insertDictionary(cctx, dict, dictSize, dictMode);
Yann Collet88fcd292015-11-25 14:42:45 +01003243}
3244
3245
Yann Collet27caf2a2016-04-01 15:48:48 +02003246/*! ZSTD_compressBegin_advanced() :
3247* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02003248size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02003249 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02003250 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02003251{
3252 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02003253 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet7bd1a292017-06-21 11:50:33 -07003254 return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
Yann Collet5ac72b42017-05-23 11:18:24 -07003255 params, pledgedSrcSize, ZSTDb_not_buffered);
Yann Collet27caf2a2016-04-01 15:48:48 +02003256}
3257
3258
Yann Collet81e13ef2016-06-07 00:51:51 +02003259size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01003260{
Yann Collet6c6e1752016-06-27 15:28:45 +02003261 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet7bd1a292017-06-21 11:50:33 -07003262 return ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
Yann Collet5ac72b42017-05-23 11:18:24 -07003263 params, 0, ZSTDb_not_buffered);
Yann Collet1c8e1942016-01-26 16:31:22 +01003264}
Yann Collet083fcc82015-10-25 14:06:35 +01003265
inikep19bd48f2016-04-04 12:10:00 +02003266
Yann Colletb05c4822017-01-12 02:01:28 +01003267size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01003268{
Yann Colletb05c4822017-01-12 02:01:28 +01003269 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01003270}
3271
3272
Yann Collet62470b42016-07-28 15:29:08 +02003273/*! ZSTD_writeEpilogue() :
3274* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01003275* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02003276static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01003277{
Yann Colletc991cc12016-07-28 00:55:43 +02003278 BYTE* const ostart = (BYTE*)dst;
3279 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02003280 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01003281
Yann Collet009d6042017-05-19 10:17:59 -07003282 DEBUGLOG(5, "ZSTD_writeEpilogue");
Yann Collet87c18b22016-08-26 01:43:47 +02003283 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02003284
3285 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02003286 if (cctx->stage == ZSTDcs_init) {
Yann Collet1ad7c822017-05-22 17:06:04 -07003287 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->appliedParams, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02003288 if (ZSTD_isError(fhSize)) return fhSize;
3289 dstCapacity -= fhSize;
3290 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02003291 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01003292 }
3293
Yann Colletc991cc12016-07-28 00:55:43 +02003294 if (cctx->stage != ZSTDcs_ending) {
3295 /* write one last empty block, make it the "last" block */
3296 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
3297 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
3298 MEM_writeLE32(op, cBlockHeader24);
3299 op += ZSTD_blockHeaderSize;
3300 dstCapacity -= ZSTD_blockHeaderSize;
3301 }
3302
Yann Collet1ad7c822017-05-22 17:06:04 -07003303 if (cctx->appliedParams.fParams.checksumFlag) {
Yann Colletc991cc12016-07-28 00:55:43 +02003304 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
3305 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
3306 MEM_writeLE32(op, checksum);
3307 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02003308 }
Yann Collet2acb5d32015-10-29 16:49:43 +01003309
Yann Collet731ef162016-07-27 21:05:12 +02003310 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02003311 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01003312}
3313
Yann Colletfd416f12016-01-30 03:14:15 +01003314
Yann Collet62470b42016-07-28 15:29:08 +02003315size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
3316 void* dst, size_t dstCapacity,
3317 const void* src, size_t srcSize)
3318{
3319 size_t endResult;
Yann Collet009d6042017-05-19 10:17:59 -07003320 size_t const cSize = ZSTD_compressContinue_internal(cctx,
3321 dst, dstCapacity, src, srcSize,
3322 1 /* frame mode */, 1 /* last chunk */);
Yann Collet62470b42016-07-28 15:29:08 +02003323 if (ZSTD_isError(cSize)) return cSize;
3324 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
3325 if (ZSTD_isError(endResult)) return endResult;
Yann Collet1ad7c822017-05-22 17:06:04 -07003326 if (cctx->appliedParams.fParams.contentSizeFlag) { /* control src size */
Yann Collet2cf77552017-06-16 12:34:41 -07003327 DEBUGLOG(5, "end of frame : controlling src size");
Yann Colleta0ba8492017-06-16 13:29:17 -07003328 if (cctx->pledgedSrcSizePlusOne != cctx->consumedSrcSize+1) {
Yann Collet2cf77552017-06-16 12:34:41 -07003329 DEBUGLOG(5, "error : pledgedSrcSize = %u, while realSrcSize = %u",
Yann Colletaee916e2017-06-16 17:01:46 -07003330 (U32)cctx->pledgedSrcSizePlusOne-1, (U32)cctx->consumedSrcSize);
Yann Collet0be6fd32017-05-08 16:08:01 -07003331 return ERROR(srcSize_wrong);
Yann Collet9e73f2f2017-06-16 12:24:01 -07003332 } }
Yann Collet62470b42016-07-28 15:29:08 +02003333 return cSize + endResult;
3334}
3335
3336
Yann Collet19c10022016-07-28 01:25:46 +02003337static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01003338 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01003339 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01003340 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01003341 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01003342{
Yann Collet7bd1a292017-06-21 11:50:33 -07003343 CHECK_F( ZSTD_compressBegin_internal(cctx, dict, dictSize, ZSTD_dm_auto, NULL,
3344 params, srcSize, ZSTDb_not_buffered) );
Yann Collet62470b42016-07-28 15:29:08 +02003345 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01003346}
3347
Yann Collet21588e32016-03-30 16:50:44 +02003348size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
3349 void* dst, size_t dstCapacity,
3350 const void* src, size_t srcSize,
3351 const void* dict,size_t dictSize,
3352 ZSTD_parameters params)
3353{
Yann Colletcf409a72016-09-26 16:41:05 +02003354 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02003355 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
3356}
3357
Yann Colletc17e0202017-04-20 12:50:02 -07003358size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
3359 const void* dict, size_t dictSize, int compressionLevel)
Yann Collet31683c02015-12-18 01:26:48 +01003360{
Yann Collet407a11f2016-11-03 15:52:01 -07003361 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02003362 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02003363 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01003364}
3365
Yann Colletd1b26842016-03-15 01:24:33 +01003366size_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 +01003367{
Yann Collet21588e32016-03-30 16:50:44 +02003368 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01003369}
3370
Yann Colletd1b26842016-03-15 01:24:33 +01003371size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01003372{
Yann Collet44fe9912015-10-29 22:02:40 +01003373 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01003374 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01003375 memset(&ctxBody, 0, sizeof(ctxBody));
Yann Colletae728a42017-05-30 17:11:39 -07003376 ctxBody.customMem = ZSTD_defaultCMem;
Yann Colletd1b26842016-03-15 01:24:33 +01003377 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Colletae728a42017-05-30 17:11:39 -07003378 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 +01003379 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01003380}
Yann Colletfdcad6d2015-12-17 23:50:15 +01003381
Yann Colletfd416f12016-01-30 03:14:15 +01003382
Yann Collet81e13ef2016-06-07 00:51:51 +02003383/* ===== Dictionary API ===== */
3384
Yann Collet09ae03a2017-06-26 16:47:32 -07003385/*! ZSTD_estimateCDictSize_advanced() :
Yann Colleta1d67042017-05-08 17:51:49 -07003386 * Estimate amount of memory that will be needed to create a dictionary with following arguments */
Yann Collet09ae03a2017-06-26 16:47:32 -07003387size_t ZSTD_estimateCDictSize_advanced(size_t dictSize, ZSTD_compressionParameters cParams, unsigned byReference)
Yann Colleta1d67042017-05-08 17:51:49 -07003388{
Yann Collet7bd1a292017-06-21 11:50:33 -07003389 DEBUGLOG(5, "sizeof(ZSTD_CDict) : %u", (U32)sizeof(ZSTD_CDict));
Yann Collet31af8292017-06-26 15:52:39 -07003390 DEBUGLOG(5, "CCtx estimate : %u", (U32)ZSTD_estimateCCtxSize_advanced(cParams));
3391 return sizeof(ZSTD_CDict) + ZSTD_estimateCCtxSize_advanced(cParams)
Yann Collet25989e32017-05-25 15:07:37 -07003392 + (byReference ? 0 : dictSize);
Yann Colleta1d67042017-05-08 17:51:49 -07003393}
3394
Yann Collet09ae03a2017-06-26 16:47:32 -07003395size_t ZSTD_estimateCDictSize(size_t dictSize, int compressionLevel)
3396{
3397 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
3398 return ZSTD_estimateCDictSize_advanced(dictSize, cParams, 0);
3399}
3400
Yann Colletd7c65892016-09-15 02:50:27 +02003401size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
3402{
3403 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Collet7bd1a292017-06-21 11:50:33 -07003404 DEBUGLOG(5, "sizeof(*cdict) : %u", (U32)sizeof(*cdict));
3405 DEBUGLOG(5, "ZSTD_sizeof_CCtx : %u", (U32)ZSTD_sizeof_CCtx(cdict->refContext));
Yann Colletaca113f2016-12-23 22:25:03 +01003406 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02003407}
3408
Yann Collet1c3ab0c2017-04-27 12:57:11 -07003409static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_frameParameters fParams)
3410{
3411 ZSTD_parameters params;
3412 params.cParams = cParams;
3413 params.fParams = fParams;
3414 return params;
3415}
3416
Yann Colletcdf7e822017-05-25 18:05:49 -07003417static size_t ZSTD_initCDict_internal(
3418 ZSTD_CDict* cdict,
Yann Collet7bd1a292017-06-21 11:50:33 -07003419 const void* dictBuffer, size_t dictSize,
3420 unsigned byReference, ZSTD_dictMode_e dictMode,
Yann Colletcdf7e822017-05-25 18:05:49 -07003421 ZSTD_compressionParameters cParams)
3422{
Yann Collet204b6b72017-06-21 15:13:00 -07003423 DEBUGLOG(5, "ZSTD_initCDict_internal, mode %u", (U32)dictMode);
Yann Colletcdf7e822017-05-25 18:05:49 -07003424 if ((byReference) || (!dictBuffer) || (!dictSize)) {
3425 cdict->dictBuffer = NULL;
3426 cdict->dictContent = dictBuffer;
3427 } else {
3428 void* const internalBuffer = ZSTD_malloc(dictSize, cdict->refContext->customMem);
Yann Colletcdf7e822017-05-25 18:05:49 -07003429 cdict->dictBuffer = internalBuffer;
3430 cdict->dictContent = internalBuffer;
Yann Colletc3bce242017-06-20 16:09:11 -07003431 if (!internalBuffer) return ERROR(memory_allocation);
3432 memcpy(internalBuffer, dictBuffer, dictSize);
Yann Colletcdf7e822017-05-25 18:05:49 -07003433 }
3434 cdict->dictContentSize = dictSize;
3435
3436 { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */,
3437 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */
3438 ZSTD_parameters const params = ZSTD_makeParams(cParams, fParams);
Yann Collet7bd1a292017-06-21 11:50:33 -07003439 CHECK_F( ZSTD_compressBegin_internal(cdict->refContext,
3440 cdict->dictContent, dictSize, dictMode,
3441 NULL,
3442 params, ZSTD_CONTENTSIZE_UNKNOWN,
3443 ZSTDb_not_buffered) );
Yann Colletcdf7e822017-05-25 18:05:49 -07003444 }
3445
3446 return 0;
3447}
3448
Yann Collet7bd1a292017-06-21 11:50:33 -07003449ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize,
3450 unsigned byReference, ZSTD_dictMode_e dictMode,
Yann Collet31533ba2017-04-27 00:29:04 -07003451 ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02003452{
Yann Collet204b6b72017-06-21 15:13:00 -07003453 DEBUGLOG(5, "ZSTD_createCDict_advanced, mode %u", (U32)dictMode);
Yann Colletae728a42017-05-30 17:11:39 -07003454 if (!customMem.customAlloc ^ !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02003455
Yann Collet466f92e2017-06-20 16:25:29 -07003456 { ZSTD_CDict* const cdict = (ZSTD_CDict*)ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02003457 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
3458
Yann Collet1f57c2e2016-12-21 16:20:11 +01003459 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07003460 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01003461 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02003462 return NULL;
3463 }
Yann Colletcdf7e822017-05-25 18:05:49 -07003464 cdict->refContext = cctx;
Yann Collet81e13ef2016-06-07 00:51:51 +02003465
Yann Colletcdf7e822017-05-25 18:05:49 -07003466 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
Yann Collet7bd1a292017-06-21 11:50:33 -07003467 dictBuffer, dictSize,
3468 byReference, dictMode,
Yann Colletcdf7e822017-05-25 18:05:49 -07003469 cParams) )) {
3470 ZSTD_freeCDict(cdict);
3471 return NULL;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07003472 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01003473
Yann Collet81e13ef2016-06-07 00:51:51 +02003474 return cdict;
3475 }
3476}
3477
3478ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
3479{
Yann Collet31533ba2017-04-27 00:29:04 -07003480 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
Yann Collet7bd1a292017-06-21 11:50:33 -07003481 return ZSTD_createCDict_advanced(dict, dictSize,
3482 0 /* byReference */, ZSTD_dm_auto,
3483 cParams, ZSTD_defaultCMem);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003484}
3485
3486ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
3487{
Yann Collet31533ba2017-04-27 00:29:04 -07003488 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
Yann Collet7bd1a292017-06-21 11:50:33 -07003489 return ZSTD_createCDict_advanced(dict, dictSize,
3490 1 /* byReference */, ZSTD_dm_auto,
3491 cParams, ZSTD_defaultCMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02003492}
3493
3494size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
3495{
Yann Collet23b6e052016-08-28 21:05:43 -07003496 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02003497 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07003498 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01003499 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003500 ZSTD_free(cdict, cMem);
3501 return 0;
3502 }
Yann Collet81e13ef2016-06-07 00:51:51 +02003503}
3504
Yann Colletcdf7e822017-05-25 18:05:49 -07003505/*! ZSTD_initStaticCDict_advanced() :
3506 * Generate a digested dictionary in provided memory area.
3507 * workspace: The memory area to emplace the dictionary into.
3508 * Provided pointer must 8-bytes aligned.
3509 * It must outlive dictionary usage.
3510 * workspaceSize: Use ZSTD_estimateCDictSize()
3511 * to determine how large workspace must be.
3512 * cParams : use ZSTD_getCParams() to transform a compression level
3513 * into its relevants cParams.
3514 * @return : pointer to ZSTD_CDict*, or NULL if error (size too small)
3515 * Note : there is no corresponding "free" function.
3516 * Since workspace was allocated externally, it must be freed externally.
3517 */
3518ZSTD_CDict* ZSTD_initStaticCDict(void* workspace, size_t workspaceSize,
Yann Collet7bd1a292017-06-21 11:50:33 -07003519 const void* dict, size_t dictSize,
3520 unsigned byReference, ZSTD_dictMode_e dictMode,
Yann Colletcdf7e822017-05-25 18:05:49 -07003521 ZSTD_compressionParameters cParams)
3522{
Yann Collet31af8292017-06-26 15:52:39 -07003523 size_t const cctxSize = ZSTD_estimateCCtxSize_advanced(cParams);
Yann Colletcdf7e822017-05-25 18:05:49 -07003524 size_t const neededSize = sizeof(ZSTD_CDict) + (byReference ? 0 : dictSize)
3525 + cctxSize;
3526 ZSTD_CDict* const cdict = (ZSTD_CDict*) workspace;
3527 void* ptr;
Yann Collet2cf77552017-06-16 12:34:41 -07003528 DEBUGLOG(5, "(size_t)workspace & 7 : %u", (U32)(size_t)workspace & 7);
Yann Colletcdf7e822017-05-25 18:05:49 -07003529 if ((size_t)workspace & 7) return NULL; /* 8-aligned */
Yann Collet2cf77552017-06-16 12:34:41 -07003530 DEBUGLOG(5, "(workspaceSize < neededSize) : (%u < %u) => %u",
Yann Colletcdf7e822017-05-25 18:05:49 -07003531 (U32)workspaceSize, (U32)neededSize, (U32)(workspaceSize < neededSize));
3532 if (workspaceSize < neededSize) return NULL;
3533
3534 if (!byReference) {
3535 memcpy(cdict+1, dict, dictSize);
3536 dict = cdict+1;
3537 ptr = (char*)workspace + sizeof(ZSTD_CDict) + dictSize;
3538 } else {
3539 ptr = cdict+1;
3540 }
3541 cdict->refContext = ZSTD_initStaticCCtx(ptr, cctxSize);
3542
3543 if (ZSTD_isError( ZSTD_initCDict_internal(cdict,
Yann Collet7bd1a292017-06-21 11:50:33 -07003544 dict, dictSize,
3545 1 /* byReference */, dictMode,
3546 cParams) ))
Yann Colletcdf7e822017-05-25 18:05:49 -07003547 return NULL;
3548
3549 return cdict;
3550}
3551
Yann Collet8c910d22017-06-03 01:15:02 -07003552ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
Yann Collet95162342016-10-25 16:19:52 -07003553 return ZSTD_getParamsFromCCtx(cdict->refContext);
3554}
3555
Yann Collet715b9aa2017-04-18 13:55:53 -07003556/* ZSTD_compressBegin_usingCDict_advanced() :
Yann Collet4f818182017-04-17 17:57:35 -07003557 * cdict must be != NULL */
Yann Collet715b9aa2017-04-18 13:55:53 -07003558size_t ZSTD_compressBegin_usingCDict_advanced(
Yann Collet4f818182017-04-17 17:57:35 -07003559 ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
3560 ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003561{
Yann Collet5ac72b42017-05-23 11:18:24 -07003562 if (cdict==NULL) return ERROR(dictionary_wrong);
Yann Collet18803372017-05-22 18:21:51 -07003563 { ZSTD_parameters params = cdict->refContext->appliedParams;
Yann Collet4f818182017-04-17 17:57:35 -07003564 params.fParams = fParams;
Yann Collet18803372017-05-22 18:21:51 -07003565 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced");
Yann Collet7bd1a292017-06-21 11:50:33 -07003566 return ZSTD_compressBegin_internal(cctx,
3567 NULL, 0, ZSTD_dm_auto,
3568 cdict,
3569 params, pledgedSrcSize,
3570 ZSTDb_not_buffered);
Sean Purcell2db72492017-02-09 10:50:43 -08003571 }
Yann Collet4cb21292016-09-15 14:54:07 +02003572}
3573
Yann Collet4f818182017-04-17 17:57:35 -07003574/* ZSTD_compressBegin_usingCDict() :
3575 * pledgedSrcSize=0 means "unknown"
3576 * if pledgedSrcSize>0, it will enable contentSizeFlag */
Yann Collet768df122017-04-26 15:42:10 -07003577size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
Yann Collet4f818182017-04-17 17:57:35 -07003578{
Yann Collet768df122017-04-26 15:42:10 -07003579 ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Collet009d6042017-05-19 10:17:59 -07003580 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u", !fParams.noDictIDFlag);
Yann Collet768df122017-04-26 15:42:10 -07003581 return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0);
Yann Collet4f818182017-04-17 17:57:35 -07003582}
3583
Yann Colletf4bd8572017-04-27 11:31:55 -07003584size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
3585 void* dst, size_t dstCapacity,
3586 const void* src, size_t srcSize,
3587 const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
3588{
3589 CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */
3590 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02003591}
3592
Yann Collet07639052016-08-03 01:57:57 +02003593/*! ZSTD_compress_usingCDict() :
Yann Collet4f818182017-04-17 17:57:35 -07003594 * Compression using a digested Dictionary.
3595 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
3596 * Note that compression parameters are decided at CDict creation time
3597 * while frame parameters are hardcoded */
Yann Collet4cb21292016-09-15 14:54:07 +02003598size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
3599 void* dst, size_t dstCapacity,
3600 const void* src, size_t srcSize,
3601 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02003602{
Yann Collet4f818182017-04-17 17:57:35 -07003603 ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Colletf4bd8572017-04-27 11:31:55 -07003604 return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
Yann Collet81e13ef2016-06-07 00:51:51 +02003605}
3606
3607
3608
Yann Collet104e5b02016-08-12 13:04:27 +02003609/* ******************************************************************
3610* Streaming
3611********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003612
Yann Collet5a0c8e22016-08-12 01:20:36 +02003613ZSTD_CStream* ZSTD_createCStream(void)
3614{
Yann Colletae728a42017-05-30 17:11:39 -07003615 return ZSTD_createCStream_advanced(ZSTD_defaultCMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003616}
3617
Yann Colletdde10b22017-06-26 17:44:26 -07003618ZSTD_CStream* ZSTD_initStaticCStream(void *workspace, size_t workspaceSize)
3619{
3620 return ZSTD_initStaticCCtx(workspace, workspaceSize);
3621}
3622
Yann Collet5a0c8e22016-08-12 01:20:36 +02003623ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
Yann Colletae728a42017-05-30 17:11:39 -07003624{ /* CStream and CCtx are now same object */
Yann Collet6fb2f242017-05-10 11:06:06 -07003625 return ZSTD_createCCtx_advanced(customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003626}
3627
3628size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
3629{
Yann Collet78553662017-05-08 17:15:00 -07003630 return ZSTD_freeCCtx(zcs); /* same object */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003631}
3632
Yann Collet5a0c8e22016-08-12 01:20:36 +02003633
3634
Yann Collet104e5b02016-08-12 13:04:27 +02003635/*====== Initialization ======*/
3636
Yann Colletfa3671e2017-05-19 10:51:30 -07003637size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_MAX; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003638
Yann Colletc17e0202017-04-20 12:50:02 -07003639size_t ZSTD_CStreamOutSize(void)
3640{
Yann Colletfa3671e2017-05-19 10:51:30 -07003641 return ZSTD_compressBound(ZSTD_BLOCKSIZE_MAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
Yann Colletc17e0202017-04-20 12:50:02 -07003642}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003643
Yann Collet1ad7c822017-05-22 17:06:04 -07003644static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs,
Yann Collet2e427422017-06-27 17:09:12 -07003645 const void* dict, size_t dictSize, ZSTD_dictMode_e dictMode,
3646 const ZSTD_CDict* cdict,
Yann Colletb7372932017-06-27 15:49:12 -07003647 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003648{
Yann Colleta3d99262017-06-29 14:44:49 -07003649 DEBUGLOG(4, "ZSTD_resetCStream_internal");
Yann Colletb7372932017-06-27 15:49:12 -07003650 /* params are supposed to be fully validated at this point */
3651 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
3652 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
Yann Colletee5b7252016-10-27 14:20:55 -07003653
Yann Collet7bd1a292017-06-21 11:50:33 -07003654 CHECK_F( ZSTD_compressBegin_internal(zcs,
Yann Collet2e427422017-06-27 17:09:12 -07003655 dict, dictSize, dictMode,
Yann Colletb7372932017-06-27 15:49:12 -07003656 cdict,
Yann Collet7bd1a292017-06-21 11:50:33 -07003657 params, pledgedSrcSize,
3658 ZSTDb_buffered) );
Yann Collet4cb21292016-09-15 14:54:07 +02003659
3660 zcs->inToCompress = 0;
3661 zcs->inBuffPos = 0;
3662 zcs->inBuffTarget = zcs->blockSize;
3663 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -07003664 zcs->streamStage = zcss_load;
Yann Collet4cb21292016-09-15 14:54:07 +02003665 zcs->frameEnded = 0;
3666 return 0; /* ready to go */
3667}
3668
Sean Purcell2db72492017-02-09 10:50:43 -08003669size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
3670{
Yann Collet1ad7c822017-05-22 17:06:04 -07003671 ZSTD_parameters params = zcs->requestedParams;
Yann Collet0be6fd32017-05-08 16:08:01 -07003672 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
Yann Colletb0739bc2017-05-22 17:45:15 -07003673 DEBUGLOG(5, "ZSTD_resetCStream");
Yann Collet009d6042017-05-19 10:17:59 -07003674 if (zcs->compressionLevel != ZSTD_CLEVEL_CUSTOM) {
3675 params.cParams = ZSTD_getCParams(zcs->compressionLevel, pledgedSrcSize, 0 /* dictSize */);
3676 }
Yann Collet2e427422017-06-27 17:09:12 -07003677 return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->dictMode, zcs->cdict, params, pledgedSrcSize);
Sean Purcell2db72492017-02-09 10:50:43 -08003678}
Sean Purcell2db72492017-02-09 10:50:43 -08003679
Yann Collet204b6b72017-06-21 15:13:00 -07003680/*! ZSTD_initCStream_internal() :
Yann Colletb7372932017-06-27 15:49:12 -07003681 * Note : not static, but hidden (not exposed). Used by zstdmt_compress.c
Yann Collet204b6b72017-06-21 15:13:00 -07003682 * Assumption 1 : params are valid
3683 * Assumption 2 : either dict, or cdict, is defined, not both */
Yann Collet8c910d22017-06-03 01:15:02 -07003684size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
3685 const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
3686 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003687{
Yann Collet204b6b72017-06-21 15:13:00 -07003688 DEBUGLOG(5, "ZSTD_initCStream_internal");
Yann Collet4b987ad2017-04-10 17:50:44 -07003689 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet8c910d22017-06-03 01:15:02 -07003690 assert(!((dict) && (cdict))); /* either dict or cdict, not both */
Yann Collete88034f2017-04-10 22:24:02 -07003691
Yann Collete88034f2017-04-10 22:24:02 -07003692 if (dict && dictSize >= 8) {
Yann Collet204b6b72017-06-21 15:13:00 -07003693 DEBUGLOG(5, "loading dictionary of size %u", (U32)dictSize);
Yann Colletc7fe2622017-05-23 13:16:00 -07003694 if (zcs->staticSize) { /* static CCtx : never uses malloc */
3695 /* incompatible with internal cdict creation */
3696 return ERROR(memory_allocation);
Yann Collet02d37aa2017-04-05 14:53:51 -07003697 }
Yann Collete88034f2017-04-10 22:24:02 -07003698 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet7bd1a292017-06-21 11:50:33 -07003699 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize,
Yann Collet2e427422017-06-27 17:09:12 -07003700 zcs->dictContentByRef, zcs->dictMode,
Yann Collet204b6b72017-06-21 15:13:00 -07003701 params.cParams, zcs->customMem);
Yann Collete88034f2017-04-10 22:24:02 -07003702 zcs->cdict = zcs->cdictLocal;
Yann Collet466f92e2017-06-20 16:25:29 -07003703 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
Yann Collet8c910d22017-06-03 01:15:02 -07003704 } else {
3705 if (cdict) {
3706 ZSTD_parameters const cdictParams = ZSTD_getParamsFromCDict(cdict);
3707 params.cParams = cdictParams.cParams; /* cParams are enforced from cdict */
3708 }
Yann Collet466f92e2017-06-20 16:25:29 -07003709 ZSTD_freeCDict(zcs->cdictLocal);
3710 zcs->cdictLocal = NULL;
Yann Collet8c910d22017-06-03 01:15:02 -07003711 zcs->cdict = cdict;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003712 }
Sean Purcell57d423c2017-01-17 11:04:08 -08003713
Yann Collet8c910d22017-06-03 01:15:02 -07003714 zcs->requestedParams = params;
3715 zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Collet2e427422017-06-27 17:09:12 -07003716 return ZSTD_resetCStream_internal(zcs, NULL, 0, zcs->dictMode, zcs->cdict, params, pledgedSrcSize);
Yann Colletee5b7252016-10-27 14:20:55 -07003717}
3718
3719/* ZSTD_initCStream_usingCDict_advanced() :
Yann Collet5a0c8e22016-08-12 01:20:36 +02003720 * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
Yann Collet8c910d22017-06-03 01:15:02 -07003721size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs,
3722 const ZSTD_CDict* cdict,
3723 ZSTD_frameParameters fParams,
3724 unsigned long long pledgedSrcSize)
3725{ /* cannot handle NULL cdict (does not know what to do) */
3726 if (!cdict) return ERROR(dictionary_wrong);
Sean Purcell2db72492017-02-09 10:50:43 -08003727 { ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003728 params.fParams = fParams;
Yann Collet8c910d22017-06-03 01:15:02 -07003729 return ZSTD_initCStream_internal(zcs,
3730 NULL, 0, cdict,
3731 params, pledgedSrcSize);
Yann Collete88034f2017-04-10 22:24:02 -07003732 }
3733}
3734
3735/* note : cdict must outlive compression session */
3736size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3737{
Yann Collet8c910d22017-06-03 01:15:02 -07003738 ZSTD_frameParameters const fParams = { 0 /* contentSize */, 0 /* checksum */, 0 /* hideDictID */ };
3739 return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, fParams, 0); /* note : will check that cdict != NULL */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003740}
3741
Yann Collet95162342016-10-25 16:19:52 -07003742size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
3743 const void* dict, size_t dictSize,
3744 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3745{
Yann Collet4b987ad2017-04-10 17:50:44 -07003746 CHECK_F( ZSTD_checkCParams(params.cParams) );
Yann Collet1ad7c822017-05-22 17:06:04 -07003747 zcs->requestedParams = params;
3748 zcs->compressionLevel = ZSTD_CLEVEL_CUSTOM;
Yann Collet8c910d22017-06-03 01:15:02 -07003749 return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, pledgedSrcSize);
Yann Collet95162342016-10-25 16:19:52 -07003750}
3751
Yann Collet5a0c8e22016-08-12 01:20:36 +02003752size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3753{
3754 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet1ad7c822017-05-22 17:06:04 -07003755 zcs->compressionLevel = compressionLevel;
Yann Collet8c910d22017-06-03 01:15:02 -07003756 return ZSTD_initCStream_internal(zcs, dict, dictSize, NULL, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003757}
3758
Yann Collete795c8a2016-12-13 16:39:36 +01003759size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3760{
Yann Colletd564faa2016-12-18 21:39:15 +01003761 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
Yann Collete88034f2017-04-10 22:24:02 -07003762 params.fParams.contentSizeFlag = (pledgedSrcSize>0);
Yann Collet8c910d22017-06-03 01:15:02 -07003763 return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, params, pledgedSrcSize);
Yann Collete795c8a2016-12-13 16:39:36 +01003764}
3765
Yann Collet5a0c8e22016-08-12 01:20:36 +02003766size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3767{
Yann Collete88034f2017-04-10 22:24:02 -07003768 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0);
Yann Collet8c910d22017-06-03 01:15:02 -07003769 return ZSTD_initCStream_internal(zcs, NULL, 0, NULL, params, 0);
Yann Colletcb327632016-08-23 00:30:31 +02003770}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003771
Yann Collet104e5b02016-08-12 13:04:27 +02003772/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003773
Yann Collet01b15492017-05-30 18:10:26 -07003774MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity,
3775 const void* src, size_t srcSize)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003776{
3777 size_t const length = MIN(dstCapacity, srcSize);
Yann Collet18ab5af2017-05-31 09:59:22 -07003778 if (length) memcpy(dst, src, length);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003779 return length;
3780}
3781
Yann Colleta3d99262017-06-29 14:44:49 -07003782/** ZSTD_compressStream_generic():
3783 * internal function for all *compressStream*() variants and *compress_generic()
3784 * @return : hint size for next input */
Yann Colletd5c046c2017-06-30 14:51:01 -07003785size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3786 ZSTD_outBuffer* output,
3787 ZSTD_inBuffer* input,
3788 ZSTD_EndDirective const flushMode)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003789{
Yann Collet01b15492017-05-30 18:10:26 -07003790 const char* const istart = (const char*)input->src;
3791 const char* const iend = istart + input->size;
3792 const char* ip = istart + input->pos;
3793 char* const ostart = (char*)output->dst;
3794 char* const oend = ostart + output->size;
3795 char* op = ostart + output->pos;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003796 U32 someMoreWork = 1;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003797
Yann Collet58e8d792017-06-02 18:20:48 -07003798 /* check expectations */
Yann Collet2cb97742017-07-04 12:39:26 -07003799 DEBUGLOG(5, "ZSTD_compressStream_generic, flush=%u", (U32)flushMode);
Yann Collet6d4fef32017-05-17 18:36:15 -07003800 assert(zcs->inBuff != NULL);
Yann Colletecb0f462017-06-21 17:25:01 -07003801 assert(zcs->inBuffSize>0);
Yann Collet6d4fef32017-05-17 18:36:15 -07003802 assert(zcs->outBuff!= NULL);
Yann Colletecb0f462017-06-21 17:25:01 -07003803 assert(zcs->outBuffSize>0);
Yann Collet58e8d792017-06-02 18:20:48 -07003804 assert(output->pos <= output->size);
3805 assert(input->pos <= input->size);
Yann Collet009d6042017-05-19 10:17:59 -07003806
Yann Collet5a0c8e22016-08-12 01:20:36 +02003807 while (someMoreWork) {
Yann Collet0be6fd32017-05-08 16:08:01 -07003808 switch(zcs->streamStage)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003809 {
Yann Collet1ad7c822017-05-22 17:06:04 -07003810 case zcss_init:
3811 /* call ZSTD_initCStream() first ! */
3812 return ERROR(init_missing);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003813
3814 case zcss_load:
Yann Colleta3d99262017-06-29 14:44:49 -07003815 if ( (flushMode == ZSTD_e_end)
Yann Collet2084b042017-07-03 15:52:19 -07003816 && ((size_t)(oend-op) >= ZSTD_compressBound(iend-ip)) /* enough dstCapacity */
Yann Colleta3d99262017-06-29 14:44:49 -07003817 && (zcs->inBuffPos == 0) ) {
3818 /* shortcut to compression pass directly into output buffer */
3819 size_t const cSize = ZSTD_compressEnd(zcs,
3820 op, oend-op, ip, iend-ip);
3821 DEBUGLOG(4, "ZSTD_compressEnd : %u", (U32)cSize);
3822 if (ZSTD_isError(cSize)) return cSize;
3823 ip = iend;
3824 op += cSize;
3825 zcs->frameEnded = 1;
3826 ZSTD_startNewCompression(zcs);
3827 someMoreWork = 0; break;
Yann Collet2084b042017-07-03 15:52:19 -07003828 }
3829 /* complete loading into inBuffer */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003830 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
Yann Collet06589fe2017-05-31 10:03:20 -07003831 size_t const loaded = ZSTD_limitCopy(
3832 zcs->inBuff + zcs->inBuffPos, toLoad,
3833 ip, iend-ip);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003834 zcs->inBuffPos += loaded;
3835 ip += loaded;
Yann Collet009d6042017-05-19 10:17:59 -07003836 if ( (flushMode == ZSTD_e_continue)
3837 && (zcs->inBuffPos < zcs->inBuffTarget) ) {
3838 /* not enough input to fill full block : stop here */
3839 someMoreWork = 0; break;
3840 }
3841 if ( (flushMode == ZSTD_e_flush)
3842 && (zcs->inBuffPos == zcs->inToCompress) ) {
3843 /* empty */
3844 someMoreWork = 0; break;
Yann Collet559ee822017-06-16 11:58:21 -07003845 }
3846 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003847 /* compress current block (note : this stage cannot be stopped in the middle) */
Yann Collet009d6042017-05-19 10:17:59 -07003848 DEBUGLOG(5, "stream compression stage (flushMode==%u)", flushMode);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003849 { void* cDst;
3850 size_t cSize;
3851 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3852 size_t oSize = oend-op;
Yann Collet009d6042017-05-19 10:17:59 -07003853 unsigned const lastBlock = (flushMode == ZSTD_e_end) && (ip==iend);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003854 if (oSize >= ZSTD_compressBound(iSize))
Yann Collet559ee822017-06-16 11:58:21 -07003855 cDst = op; /* compress into output buffer, to skip flush stage */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003856 else
3857 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
Yann Collet009d6042017-05-19 10:17:59 -07003858 cSize = lastBlock ?
3859 ZSTD_compressEnd(zcs, cDst, oSize,
3860 zcs->inBuff + zcs->inToCompress, iSize) :
3861 ZSTD_compressContinue(zcs, cDst, oSize,
3862 zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003863 if (ZSTD_isError(cSize)) return cSize;
Yann Collet009d6042017-05-19 10:17:59 -07003864 zcs->frameEnded = lastBlock;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003865 /* prepare next block */
3866 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3867 if (zcs->inBuffTarget > zcs->inBuffSize)
Yann Collet009d6042017-05-19 10:17:59 -07003868 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize;
Yann Collet8b21ec42017-05-19 19:46:15 -07003869 DEBUGLOG(5, "inBuffTarget:%u / inBuffSize:%u",
3870 (U32)zcs->inBuffTarget, (U32)zcs->inBuffSize);
3871 if (!lastBlock)
3872 assert(zcs->inBuffTarget <= zcs->inBuffSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003873 zcs->inToCompress = zcs->inBuffPos;
Yann Collet009d6042017-05-19 10:17:59 -07003874 if (cDst == op) { /* no need to flush */
3875 op += cSize;
3876 if (zcs->frameEnded) {
Yann Collet559ee822017-06-16 11:58:21 -07003877 DEBUGLOG(5, "Frame completed directly in outBuffer");
Yann Collet009d6042017-05-19 10:17:59 -07003878 someMoreWork = 0;
Yann Colletb26728c2017-06-16 14:00:46 -07003879 ZSTD_startNewCompression(zcs);
Yann Collet009d6042017-05-19 10:17:59 -07003880 }
3881 break;
3882 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003883 zcs->outBuffContentSize = cSize;
3884 zcs->outBuffFlushedSize = 0;
Yann Collet009d6042017-05-19 10:17:59 -07003885 zcs->streamStage = zcss_flush; /* pass-through to flush stage */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003886 }
Jos Collin7cd7a752017-05-11 13:17:20 +05303887 /* fall-through */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003888 case zcss_flush:
Yann Collet009d6042017-05-19 10:17:59 -07003889 DEBUGLOG(5, "flush stage");
Yann Collet5a0c8e22016-08-12 01:20:36 +02003890 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
Yann Collet01b15492017-05-30 18:10:26 -07003891 size_t const flushed = ZSTD_limitCopy(op, oend-op,
3892 zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
Yann Collet2cb97742017-07-04 12:39:26 -07003893 DEBUGLOG(5, "toFlush: %u into %u ==> flushed: %u",
3894 (U32)toFlush, (U32)(oend-op), (U32)flushed);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003895 op += flushed;
3896 zcs->outBuffFlushedSize += flushed;
Yann Collet01b15492017-05-30 18:10:26 -07003897 if (toFlush!=flushed) {
Yann Collet2cb97742017-07-04 12:39:26 -07003898 /* flush not fully completed, presumably because dst is too small */
3899 assert(op==oend);
Yann Collet01b15492017-05-30 18:10:26 -07003900 someMoreWork = 0;
3901 break;
3902 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003903 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet009d6042017-05-19 10:17:59 -07003904 if (zcs->frameEnded) {
Yann Collet559ee822017-06-16 11:58:21 -07003905 DEBUGLOG(5, "Frame completed on flush");
Yann Collet009d6042017-05-19 10:17:59 -07003906 someMoreWork = 0;
Yann Colletb26728c2017-06-16 14:00:46 -07003907 ZSTD_startNewCompression(zcs);
Yann Collet009d6042017-05-19 10:17:59 -07003908 break;
3909 }
Yann Collet0be6fd32017-05-08 16:08:01 -07003910 zcs->streamStage = zcss_load;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003911 break;
3912 }
3913
Yann Colletcd2892f2017-06-01 09:44:54 -07003914 default: /* impossible */
3915 assert(0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003916 }
3917 }
3918
Yann Collet01b15492017-05-30 18:10:26 -07003919 input->pos = ip - istart;
3920 output->pos = op - ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003921 if (zcs->frameEnded) return 0;
3922 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3923 if (hintInSize==0) hintInSize = zcs->blockSize;
3924 return hintInSize;
3925 }
3926}
3927
Yann Collet53e17fb2016-08-17 01:39:22 +02003928size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003929{
Yann Collet01b15492017-05-30 18:10:26 -07003930 /* check conditions */
3931 if (output->pos > output->size) return ERROR(GENERIC);
3932 if (input->pos > input->size) return ERROR(GENERIC);
3933
3934 return ZSTD_compressStream_generic(zcs, output, input, ZSTD_e_continue);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003935}
3936
Yann Colletf35e2de2017-06-05 18:32:48 -07003937/*! ZSTDMT_initCStream_internal() :
3938 * Private use only. Init streaming operation.
3939 * expects params to be valid.
3940 * must receive dict, or cdict, or none, but not both.
3941 * @return : 0, or an error code */
3942size_t ZSTDMT_initCStream_internal(ZSTDMT_CCtx* zcs,
3943 const void* dict, size_t dictSize, const ZSTD_CDict* cdict,
3944 ZSTD_parameters params, unsigned long long pledgedSrcSize);
3945
3946
Yann Colletdeee6e52017-05-30 17:42:00 -07003947size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
3948 ZSTD_outBuffer* output,
3949 ZSTD_inBuffer* input,
3950 ZSTD_EndDirective endOp)
Yann Collet6d4fef32017-05-17 18:36:15 -07003951{
3952 /* check conditions */
Yann Colletdeee6e52017-05-30 17:42:00 -07003953 if (output->pos > output->size) return ERROR(GENERIC);
3954 if (input->pos > input->size) return ERROR(GENERIC);
Yann Collet6d4fef32017-05-17 18:36:15 -07003955 assert(cctx!=NULL);
Yann Collet01b15492017-05-30 18:10:26 -07003956
Yann Colleta3d99262017-06-29 14:44:49 -07003957 /* transparent initialization stage */
Yann Collet6d4fef32017-05-17 18:36:15 -07003958 if (cctx->streamStage == zcss_init) {
Yann Collet33a66392017-06-28 11:09:43 -07003959 const void* const prefix = cctx->prefix;
3960 size_t const prefixSize = cctx->prefixSize;
Yann Collet1ad7c822017-05-22 17:06:04 -07003961 ZSTD_parameters params = cctx->requestedParams;
Yann Collet6d4fef32017-05-17 18:36:15 -07003962 if (cctx->compressionLevel != ZSTD_CLEVEL_CUSTOM)
3963 params.cParams = ZSTD_getCParams(cctx->compressionLevel,
Yann Collet33a66392017-06-28 11:09:43 -07003964 cctx->pledgedSrcSizePlusOne-1, 0 /*dictSize*/);
3965 cctx->prefix = NULL; cctx->prefixSize = 0; /* single usage */
3966 assert(prefix==NULL || cctx->cdict==NULL); /* only one can be set */
Yann Colletf129fd32017-06-11 18:46:09 -07003967
3968#ifdef ZSTD_MULTITHREAD
Yann Colletf35e2de2017-06-05 18:32:48 -07003969 if (cctx->nbThreads > 1) {
Yann Collet33a66392017-06-28 11:09:43 -07003970 DEBUGLOG(4, "call ZSTDMT_initCStream_internal as nbThreads=%u", cctx->nbThreads);
3971 CHECK_F( ZSTDMT_initCStream_internal(cctx->mtctx, prefix, prefixSize, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
Yann Collet23aace92017-06-11 18:32:36 -07003972 cctx->streamStage = zcss_load;
Yann Colletf129fd32017-06-11 18:46:09 -07003973 } else
3974#endif
3975 {
Yann Collet2e427422017-06-27 17:09:12 -07003976 CHECK_F( ZSTD_resetCStream_internal(cctx, prefix, prefixSize, cctx->dictMode, cctx->cdict, params, cctx->pledgedSrcSizePlusOne-1) );
Yann Colletf35e2de2017-06-05 18:32:48 -07003977 } }
3978
Yann Colleta3d99262017-06-29 14:44:49 -07003979 /* compression stage */
Yann Colletf129fd32017-06-11 18:46:09 -07003980#ifdef ZSTD_MULTITHREAD
Yann Colletf35e2de2017-06-05 18:32:48 -07003981 if (cctx->nbThreads > 1) {
Yann Collet23aace92017-06-11 18:32:36 -07003982 size_t const flushMin = ZSTDMT_compressStream_generic(cctx->mtctx, output, input, endOp);
Yann Collet33a66392017-06-28 11:09:43 -07003983 DEBUGLOG(5, "ZSTDMT_compressStream_generic : %u", (U32)flushMin);
Yann Colletb26728c2017-06-16 14:00:46 -07003984 if ( ZSTD_isError(flushMin)
3985 || (endOp == ZSTD_e_end && flushMin == 0) ) { /* compression completed */
3986 ZSTD_startNewCompression(cctx);
Yann Collet9e73f2f2017-06-16 12:24:01 -07003987 }
Yann Collet23aace92017-06-11 18:32:36 -07003988 return flushMin;
Yann Collet6d4fef32017-05-17 18:36:15 -07003989 }
Yann Colletf129fd32017-06-11 18:46:09 -07003990#endif
Yann Collet6d4fef32017-05-17 18:36:15 -07003991
Yann Collet01b15492017-05-30 18:10:26 -07003992 CHECK_F( ZSTD_compressStream_generic(cctx, output, input, endOp) );
Yann Collet559ee822017-06-16 11:58:21 -07003993 DEBUGLOG(5, "completed ZSTD_compress_generic");
Yann Colletdeee6e52017-05-30 17:42:00 -07003994 return cctx->outBuffContentSize - cctx->outBuffFlushedSize; /* remaining to flush */
Yann Collet6d4fef32017-05-17 18:36:15 -07003995}
3996
Yann Colletdeee6e52017-05-30 17:42:00 -07003997size_t ZSTD_compress_generic_simpleArgs (
3998 ZSTD_CCtx* cctx,
3999 void* dst, size_t dstCapacity, size_t* dstPos,
4000 const void* src, size_t srcSize, size_t* srcPos,
4001 ZSTD_EndDirective endOp)
Yann Collet6d4fef32017-05-17 18:36:15 -07004002{
Yann Colletdeee6e52017-05-30 17:42:00 -07004003 ZSTD_outBuffer output = { dst, dstCapacity, *dstPos };
4004 ZSTD_inBuffer input = { src, srcSize, *srcPos };
Yann Collet01b15492017-05-30 18:10:26 -07004005 /* ZSTD_compress_generic() will check validity of dstPos and srcPos */
Yann Collet58e8d792017-06-02 18:20:48 -07004006 size_t const cErr = ZSTD_compress_generic(cctx, &output, &input, endOp);
Yann Colletdeee6e52017-05-30 17:42:00 -07004007 *dstPos = output.pos;
4008 *srcPos = input.pos;
Yann Collet58e8d792017-06-02 18:20:48 -07004009 return cErr;
Yann Collet5a0c8e22016-08-12 01:20:36 +02004010}
4011
4012
Yann Collet104e5b02016-08-12 13:04:27 +02004013/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02004014
4015/*! ZSTD_flushStream() :
4016* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02004017size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02004018{
Yann Collet18ab5af2017-05-31 09:59:22 -07004019 ZSTD_inBuffer input = { NULL, 0, 0 };
Yann Collet01b15492017-05-30 18:10:26 -07004020 if (output->pos > output->size) return ERROR(GENERIC);
4021 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_flush) );
4022 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
Yann Collet5a0c8e22016-08-12 01:20:36 +02004023}
4024
4025
Yann Collet53e17fb2016-08-17 01:39:22 +02004026size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02004027{
Yann Collet18ab5af2017-05-31 09:59:22 -07004028 ZSTD_inBuffer input = { NULL, 0, 0 };
Yann Collet01b15492017-05-30 18:10:26 -07004029 if (output->pos > output->size) return ERROR(GENERIC);
4030 CHECK_F( ZSTD_compressStream_generic(zcs, output, &input, ZSTD_e_end) );
Yann Collet2cb97742017-07-04 12:39:26 -07004031 { size_t const lastBlockSize = zcs->frameEnded ? 0 : ZSTD_BLOCKHEADERSIZE;
4032 size_t const checksumSize = zcs->frameEnded ? 0 : zcs->appliedParams.fParams.checksumFlag * 4;
4033 size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize + lastBlockSize + checksumSize;
4034 DEBUGLOG(5, "ZSTD_endStream : remaining to flush : %u",
4035 (unsigned)toFlush);
4036 return toFlush;
4037 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02004038}
4039
4040
Yann Collet70e8c382016-02-10 13:37:52 +01004041/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01004042
inikep2c5eeea2016-04-15 13:44:46 +02004043#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02004044int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01004045
Yann Collet3b719252016-03-30 19:48:05 +02004046static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletadbe74a2017-06-28 13:22:37 -07004047{ /* "default" - guarantees a monotonically increasing memory budget */
Yann Collet793c6492016-04-09 20:32:00 +02004048 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02004049 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02004050 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
4051 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Colletadbe74a2017-06-28 13:22:37 -07004052 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3 */
4053 { 20, 17, 18, 1, 5, 16, ZSTD_dfast }, /* level 4 */
4054 { 20, 17, 18, 2, 5, 16, ZSTD_greedy }, /* level 5 */
4055 { 21, 17, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
4056 { 21, 18, 19, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02004057 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Colletadbe74a2017-06-28 13:22:37 -07004058 { 21, 19, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
Yann Collet3c242e72016-07-13 14:56:24 +02004059 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
4060 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
4061 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
4062 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
4063 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
Yann Colletadbe74a2017-06-28 13:22:37 -07004064 { 22, 21, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
Yann Collet3c242e72016-07-13 14:56:24 +02004065 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Colletadbe74a2017-06-28 13:22:37 -07004066 { 23, 22, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
Yann Collet29297c62017-04-27 17:44:01 -07004067 { 23, 22, 22, 5, 4, 32, ZSTD_btopt }, /* level 18 */
Yann Collete19a9ef2016-08-26 20:02:49 +02004068 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Nick Terrell374f8682017-05-10 17:48:42 -07004069 { 25, 25, 23, 7, 3, 64, ZSTD_btultra }, /* level 20 */
Yann Colletadbe74a2017-06-28 13:22:37 -07004070 { 26, 26, 24, 7, 3,256, ZSTD_btultra }, /* level 21 */
Nick Terrell374f8682017-05-10 17:48:42 -07004071 { 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01004072},
4073{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02004074 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02004075 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02004076 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02004077 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
4078 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
4079 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
4080 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
4081 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
4082 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
4083 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
4084 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
4085 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
4086 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
4087 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
4088 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02004089 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02004090 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
4091 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
4092 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02004093 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
4094 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07004095 { 18, 19, 18, 11, 3,512, ZSTD_btultra }, /* level 20.*/
4096 { 18, 19, 18, 12, 3,512, ZSTD_btultra }, /* level 21.*/
4097 { 18, 19, 18, 13, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01004098},
4099{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02004100 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02004101 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
4102 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
4103 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
4104 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
4105 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
4106 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
4107 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
4108 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
4109 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
4110 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
4111 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
4112 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
4113 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
4114 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02004115 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
4116 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
4117 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
4118 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
4119 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
4120 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07004121 { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/
4122 { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/
4123 { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01004124},
4125{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02004126 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02004127 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02004128 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02004129 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
4130 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
4131 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
4132 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
4133 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
4134 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
4135 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
4136 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02004137 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
4138 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
4139 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
4140 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
4141 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
4142 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
4143 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
4144 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
4145 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
4146 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07004147 { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/
4148 { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/
4149 { 14, 15, 15, 10, 3,256, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01004150},
4151};
4152
Yann Collet03746622017-06-28 20:17:22 -07004153#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
Yann Collet81353512017-06-28 15:34:56 -07004154/* This function just controls
4155 * the monotonic memory budget increase of ZSTD_defaultCParameters[0].
Yann Collet2cb97742017-07-04 12:39:26 -07004156 * Run once, on first ZSTD_getCParams() usage, if ZSTD_DEBUG is enabled
Yann Collet81353512017-06-28 15:34:56 -07004157 */
4158MEM_STATIC void ZSTD_check_compressionLevel_monotonicIncrease_memoryBudget(void)
4159{
Yann Collet03746622017-06-28 20:17:22 -07004160 int level;
4161 for (level=1; level<ZSTD_maxCLevel(); level++) {
4162 ZSTD_compressionParameters const c1 = ZSTD_defaultCParameters[0][level];
4163 ZSTD_compressionParameters const c2 = ZSTD_defaultCParameters[0][level+1];
Yann Collet03746622017-06-28 20:17:22 -07004164 assert(c1.windowLog <= c2.windowLog);
4165# define ZSTD_TABLECOST(h,c) ((1<<(h)) + (1<<(c)))
4166 assert(ZSTD_TABLECOST(c1.hashLog, c1.chainLog) <= ZSTD_TABLECOST(c2.hashLog, c2.chainLog));
Yann Collet81353512017-06-28 15:34:56 -07004167 }
Yann Collet81353512017-06-28 15:34:56 -07004168}
Yann Collet03746622017-06-28 20:17:22 -07004169#endif
Yann Collet81353512017-06-28 15:34:56 -07004170
Yann Collet236d94f2016-05-18 12:06:33 +02004171/*! ZSTD_getCParams() :
4172* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
4173* Size values are optional, provide 0 if not known or unused */
Yann Collet009d6042017-05-19 10:17:59 -07004174ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01004175{
Yann Collet009d6042017-05-19 10:17:59 -07004176 size_t const addedSize = srcSizeHint ? 0 : 500;
4177 U64 const rSize = srcSizeHint+dictSize ? srcSizeHint+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02004178 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet81353512017-06-28 15:34:56 -07004179
4180#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
4181 static int g_monotonicTest = 1;
4182 if (g_monotonicTest) {
4183 ZSTD_check_compressionLevel_monotonicIncrease_memoryBudget();
4184 g_monotonicTest=0;
4185 }
4186#endif
4187
Yann Collet6d4fef32017-05-17 18:36:15 -07004188 if (compressionLevel <= 0) compressionLevel = ZSTD_CLEVEL_DEFAULT; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01004189 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collete51d51b2017-06-20 17:44:55 -07004190 { ZSTD_compressionParameters const cp = ZSTD_defaultCParameters[tableID][compressionLevel];
4191 return ZSTD_adjustCParams_internal(cp, srcSizeHint, dictSize); }
Yann Colletfd416f12016-01-30 03:14:15 +01004192}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02004193
4194/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02004195* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02004196* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet009d6042017-05-19 10:17:59 -07004197ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSizeHint, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02004198 ZSTD_parameters params;
Yann Collet009d6042017-05-19 10:17:59 -07004199 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSizeHint, dictSize);
Yann Collet3d2cd7f2016-06-27 15:12:26 +02004200 memset(&params, 0, sizeof(params));
4201 params.cParams = cParams;
4202 return params;
4203}