blob: d5de46a49b7e09251bef1449b1252ab5c062990c [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 Colletae7aa062016-02-03 02:46:46 +010012* Dependencies
Yann Colletf3eca252015-10-22 15:31:46 +010013***************************************/
Yann Colletd3b7f8d2016-06-04 19:47:02 +020014#include <string.h> /* memset */
Yann Collet14983e72015-11-11 21:38:21 +010015#include "mem.h"
Yann Collet5a0c8e22016-08-12 01:20:36 +020016#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
Yann Colletd0e2cd12016-06-05 00:58:01 +020017#include "fse.h"
Yann Collet130fe112016-06-05 00:42:28 +020018#define HUF_STATIC_LINKING_ONLY
19#include "huf.h"
Yann Colletd3b7f8d2016-06-04 19:47:02 +020020#include "zstd_internal.h" /* includes zstd.h */
Yann Colletf3eca252015-10-22 15:31:46 +010021
22
Yann Collet7d360282016-02-12 00:07:30 +010023/*-*************************************
Yann Collet31533ba2017-04-27 00:29:04 -070024* Debug
25***************************************/
26#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=1)
27# include <assert.h>
28#else
29# define assert(condition) ((void)0)
30#endif
31
32#define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; }
33
34#if defined(ZSTD_DEBUG) && (ZSTD_DEBUG>=2)
35# include <stdio.h>
36 static unsigned g_debugLevel = ZSTD_DEBUG;
37# define DEBUGLOG(l, ...) if (l<=g_debugLevel) { fprintf(stderr, __FILE__ ": "); fprintf(stderr, __VA_ARGS__); fprintf(stderr, " \n"); }
38#else
39# define DEBUGLOG(l, ...) {} /* disabled */
40#endif
41
42
43/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010044* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010045***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010046static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Collet731ef162016-07-27 21:05:12 +020047#define HASH_READ_SIZE 8
48typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
Yann Colletf3eca252015-10-22 15:31:46 +010049
Yann Collet71ddeb62017-04-20 22:54:54 -070050/* entropy tables always have same size */
51static size_t const hufCTable_size = HUF_CTABLE_SIZE(255);
Yann Collete42afbc2017-04-26 11:39:35 -070052static size_t const litlengthCTable_size = FSE_CTABLE_SIZE(LLFSELog, MaxLL);
53static size_t const offcodeCTable_size = FSE_CTABLE_SIZE(OffFSELog, MaxOff);
54static size_t const matchlengthCTable_size = FSE_CTABLE_SIZE(MLFSELog, MaxML);
Yann Collet72712032017-04-20 23:21:19 -070055static size_t const entropyScratchSpace_size = HUF_WORKSPACE_SIZE;
Yann Colleta34a39c2017-04-20 18:17:58 -070056
Yann Colletf3eca252015-10-22 15:31:46 +010057
Yann Collet7d360282016-02-12 00:07:30 +010058/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010059* Helper functions
60***************************************/
Yann Collet3f75d522017-03-31 17:11:38 -070061size_t ZSTD_compressBound(size_t srcSize) {
Yann Collet30c76982017-03-31 18:27:03 -070062 size_t const lowLimit = 256 KB;
63 size_t const margin = (srcSize < lowLimit) ? (lowLimit-srcSize) >> 12 : 0; /* from 64 to 0 */
Yann Collet3f75d522017-03-31 17:11:38 -070064 return srcSize + (srcSize >> 8) + margin;
65}
Yann Collet59d1f792016-01-23 19:28:41 +010066
67
Yann Collet7d360282016-02-12 00:07:30 +010068/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010069* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010070***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010071static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
72{
Yann Collet14983e72015-11-11 21:38:21 +010073 ssPtr->lit = ssPtr->litStart;
Yann Colletc0ce4f12016-07-30 00:55:13 +020074 ssPtr->sequences = ssPtr->sequencesStart;
Yann Collet5d393572016-04-07 17:19:00 +020075 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010076}
77
78
Yann Collet7d360282016-02-12 00:07:30 +010079/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010080* Context memory management
81***************************************/
Yann Collet0be6fd32017-05-08 16:08:01 -070082typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
83
Yann Colletaca113f2016-12-23 22:25:03 +010084struct ZSTD_CCtx_s {
Yann Collet89db5e02015-11-13 11:27:46 +010085 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010086 const BYTE* base; /* All regular indexes relative to this position */
87 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010088 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010089 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010090 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010091 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +010092 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Colletbb002742017-01-25 16:25:38 -080093 U32 loadedDictEnd; /* index of end of dictionary */
94 U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
Yann Collet14312d82017-02-23 23:42:12 -080095 U32 forceRawDict; /* Force loading dictionary in "content-only" mode (no header analysis) */
Yann Collet731ef162016-07-27 21:05:12 +020096 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +020097 U32 rep[ZSTD_REP_NUM];
Yann Colletb459aad2017-01-19 17:33:37 -080098 U32 repToConfirm[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +020099 U32 dictID;
Yann Collet5be2dd22015-11-11 13:43:58 +0100100 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +0100101 void* workSpace;
102 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +0100103 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +0200104 U64 frameContentSize;
Yann Collet20d5e032017-04-11 18:34:02 -0700105 U64 consumedSrcSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +0200106 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +0200107 ZSTD_customMem customMem;
Yann Colletecd651b2016-01-07 15:35:18 +0100108
Yann Collet712def92015-10-29 18:41:45 +0100109 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +0100110 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +0100111 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +0200112 U32* chainTable;
Yann Collet71ddeb62017-04-20 22:54:54 -0700113 HUF_repeat hufCTable_repeatMode;
114 HUF_CElt* hufCTable;
115 U32 fseCTables_ready;
Yann Collet71aaa322017-04-20 23:03:38 -0700116 FSE_CTable* offcodeCTable;
117 FSE_CTable* matchlengthCTable;
118 FSE_CTable* litlengthCTable;
Yann Collete42afbc2017-04-26 11:39:35 -0700119 unsigned* entropyScratchSpace;
Yann Collet0be6fd32017-05-08 16:08:01 -0700120
121 /* streaming */
122 ZSTD_CDict* cdictLocal;
123 const ZSTD_CDict* cdict;
124 char* inBuff;
125 size_t inBuffSize;
126 size_t inToCompress;
127 size_t inBuffPos;
128 size_t inBuffTarget;
129 char* outBuff;
130 size_t outBuffSize;
131 size_t outBuffContentSize;
132 size_t outBuffFlushedSize;
133 ZSTD_cStreamStage streamStage;
134 U32 frameEnded;
135 U64 pledgedSrcSize;
Yann Colletf3eca252015-10-22 15:31:46 +0100136};
137
Yann Collet5be2dd22015-11-11 13:43:58 +0100138ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +0100139{
inikep3763c772016-06-03 13:28:20 +0200140 return ZSTD_createCCtx_advanced(defaultCustomMem);
inikep50e82c02016-05-23 15:49:09 +0200141}
142
143ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
144{
Yann Collet69c2cdb2016-07-14 16:52:45 +0200145 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +0200146
Yann Collet23b6e052016-08-28 21:05:43 -0700147 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
148 if (!customMem.customAlloc || !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200149
Yann Collet23b6e052016-08-28 21:05:43 -0700150 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200151 if (!cctx) return NULL;
152 memset(cctx, 0, sizeof(ZSTD_CCtx));
Yann Colletbb002742017-01-25 16:25:38 -0800153 cctx->customMem = customMem;
Yann Collet69c2cdb2016-07-14 16:52:45 +0200154 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100155}
156
Yann Collet5be2dd22015-11-11 13:43:58 +0100157size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100158{
inikep36403962016-06-03 16:36:50 +0200159 if (cctx==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -0700160 ZSTD_free(cctx->workSpace, cctx->customMem);
Yann Collet78553662017-05-08 17:15:00 -0700161 cctx->workSpace = NULL;
162 ZSTD_freeCDict(cctx->cdictLocal);
163 cctx->cdictLocal = NULL;
164 ZSTD_free(cctx->inBuff, cctx->customMem);
165 cctx->inBuff = NULL;
166 ZSTD_free(cctx->outBuff, cctx->customMem);
167 cctx->outBuff = NULL;
Yann Collet23b6e052016-08-28 21:05:43 -0700168 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100169 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100170}
171
Yann Collet70e3b312016-08-23 01:18:06 +0200172size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200173{
Yann Colletd7c65892016-09-15 02:50:27 +0200174 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet791d7442017-05-08 16:17:30 -0700175 return sizeof(*cctx) + cctx->workSpaceSize
176 + ZSTD_sizeof_CDict(cctx->cdictLocal)
177 + cctx->outBuffSize + cctx->inBuffSize;
Yann Collet3ae543c2016-07-11 03:12:17 +0200178}
179
Yann Colletbb002742017-01-25 16:25:38 -0800180size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
181{
182 switch(param)
183 {
Yann Collet06e76972017-01-25 16:39:03 -0800184 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
Yann Collet14312d82017-02-23 23:42:12 -0800185 case ZSTD_p_forceRawDict : cctx->forceRawDict = value>0; return 0;
Yann Colletbb002742017-01-25 16:25:38 -0800186 default: return ERROR(parameter_unknown);
187 }
188}
189
Yann Colletb44be742016-03-26 20:52:14 +0100190const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100191{
Yann Colletb44be742016-03-26 20:52:14 +0100192 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100193}
194
Yann Collet95162342016-10-25 16:19:52 -0700195static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx)
196{
197 return cctx->params;
198}
199
Yann Collet59d70632015-11-04 12:05:27 +0100200
Yann Collet21588e32016-03-30 16:50:44 +0200201/** ZSTD_checkParams() :
202 ensure param values remain within authorized range.
203 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200204size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200205{
Yann Colletac8bace2016-09-07 14:54:23 +0200206# define CLAMPCHECK(val,min,max) { if ((val<min) | (val>max)) return ERROR(compressionParameter_unsupported); }
Yann Collet15354142016-04-04 04:22:53 +0200207 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200208 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200209 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
210 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Collet2e2e78d2017-03-29 16:02:47 -0700211 CLAMPCHECK(cParams.searchLength, ZSTD_SEARCHLENGTH_MIN, ZSTD_SEARCHLENGTH_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200212 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800213 if ((U32)(cParams.strategy) > (U32)ZSTD_btultra) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200214 return 0;
215}
216
217
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100218/** ZSTD_cycleLog() :
219 * condition for correct operation : hashLog > 1 */
220static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
221{
222 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
223 return hashLog - btScale;
224}
225
Yann Collet70d13012016-06-01 18:45:34 +0200226/** ZSTD_adjustCParams() :
Yann Colletcf409a72016-09-26 16:41:05 +0200227 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200228 mostly downsizing to reduce memory consumption and initialization.
229 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
230 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200231 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200232ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100233{
Yann Collet70d13012016-06-01 18:45:34 +0200234 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100235
Yann Collet70e45772016-03-19 18:08:32 +0100236 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200237 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
238 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200239 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200240 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200241 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200242 } }
Yann Collet70d13012016-06-01 18:45:34 +0200243 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100244 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
245 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
246 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100247
Yann Collet70d13012016-06-01 18:45:34 +0200248 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200249
250 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100251}
252
253
Yann Collet88472382016-07-14 17:05:38 +0200254size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100255{
Yann Collet731ef162016-07-27 21:05:12 +0200256 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
257 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
258 size_t const maxNbSeq = blockSize / divider;
259 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200260
Yann Collet731ef162016-07-27 21:05:12 +0200261 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
262 size_t const hSize = ((size_t)1) << cParams.hashLog;
263 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
264 size_t const h3Size = ((size_t)1) << hashLog3;
Yann Collet71ddeb62017-04-20 22:54:54 -0700265 size_t const entropySpace = hufCTable_size + litlengthCTable_size
Yann Colleta4086452017-04-20 23:09:39 -0700266 + offcodeCTable_size + matchlengthCTable_size
Yann Collet72712032017-04-20 23:21:19 -0700267 + entropyScratchSpace_size;
Yann Collet731ef162016-07-27 21:05:12 +0200268 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200269
Yann Colletfc514592017-05-08 17:07:59 -0700270 size_t const optBudget = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
Yann Collet3ae543c2016-07-11 03:12:17 +0200271 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
Nick Terrell5f2c7212017-05-10 16:49:58 -0700272 size_t const optSpace = ((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btultra)) ? optBudget : 0;
Yann Colletfc514592017-05-08 17:07:59 -0700273 size_t const neededSpace = entropySpace + tableSpace + tokenSpace + optSpace;
Yann Collet3ae543c2016-07-11 03:12:17 +0200274
275 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100276}
277
Yann Colleta7737f62016-09-06 09:44:59 +0200278
279static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2)
280{
281 return (param1.cParams.hashLog == param2.cParams.hashLog)
282 & (param1.cParams.chainLog == param2.cParams.chainLog)
Yann Collet0be6fd32017-05-08 16:08:01 -0700283 & (param1.cParams.strategy == param2.cParams.strategy) /* opt parser space */
284 & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3)); /* hashlog3 space */
Yann Colleta7737f62016-09-06 09:44:59 +0200285}
286
287/*! ZSTD_continueCCtx() :
288 reuse CCtx without reset (note : requires no dictionary) */
289static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
290{
291 U32 const end = (U32)(cctx->nextSrc - cctx->base);
292 cctx->params = params;
293 cctx->frameContentSize = frameContentSize;
Yann Collet20d5e032017-04-11 18:34:02 -0700294 cctx->consumedSrcSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200295 cctx->lowLimit = end;
296 cctx->dictLimit = end;
297 cctx->nextToUpdate = end+1;
298 cctx->stage = ZSTDcs_init;
299 cctx->dictID = 0;
300 cctx->loadedDictEnd = 0;
301 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200302 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
303 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200304 return 0;
305}
306
307typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e;
308
Yann Collet30fb4992017-04-18 14:08:50 -0700309/*! ZSTD_resetCCtx_internal() :
Sean Purcell3437bf22017-03-01 16:10:26 -0800310 note : `params` must be validated */
Yann Collet30fb4992017-04-18 14:08:50 -0700311static size_t ZSTD_resetCCtx_internal (ZSTD_CCtx* zc,
Yann Colletea2ecdc2016-07-14 22:43:12 +0200312 ZSTD_parameters params, U64 frameContentSize,
Yann Collet4cb21292016-09-15 14:54:07 +0200313 ZSTD_compResetPolicy_e const crp)
Yann Colleta7737f62016-09-06 09:44:59 +0200314{
Yann Collet0be6fd32017-05-08 16:08:01 -0700315 DEBUGLOG(5, "ZSTD_resetCCtx_internal \n");
316
Yann Collet4cb21292016-09-15 14:54:07 +0200317 if (crp == ZSTDcrp_continue)
Nick Terrella4197772017-03-01 17:51:56 -0800318 if (ZSTD_equivalentParams(params, zc->params)) {
Yann Collet0be6fd32017-05-08 16:08:01 -0700319 DEBUGLOG(5, "ZSTD_equivalentParams()==1 \n");
Yann Collet71ddeb62017-04-20 22:54:54 -0700320 zc->fseCTables_ready = 0;
321 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200322 return ZSTD_continueCCtx(zc, params, frameContentSize);
Nick Terrella4197772017-03-01 17:51:56 -0800323 }
inikep87d4f3d2016-03-02 15:56:24 +0100324
Yann Colleta7737f62016-09-06 09:44:59 +0200325 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
326 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
327 size_t const maxNbSeq = blockSize / divider;
328 size_t const tokenSpace = blockSize + 11*maxNbSeq;
329 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
330 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
331 U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
332 size_t const h3Size = ((size_t)1) << hashLog3;
333 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
334 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100335
Yann Colleta7737f62016-09-06 09:44:59 +0200336 /* Check if workSpace is large enough, alloc a new one if needed */
Yann Collet71ddeb62017-04-20 22:54:54 -0700337 { size_t const entropySpace = hufCTable_size + litlengthCTable_size
Yann Colleta4086452017-04-20 23:09:39 -0700338 + offcodeCTable_size + matchlengthCTable_size
Yann Collet72712032017-04-20 23:21:19 -0700339 + entropyScratchSpace_size;
Yann Collet71ddeb62017-04-20 22:54:54 -0700340 size_t const optPotentialSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits)) * sizeof(U32)
Yann Collete6fa70a2017-04-20 17:28:31 -0700341 + (ZSTD_OPT_NUM+1) * (sizeof(ZSTD_match_t)+sizeof(ZSTD_optimal_t));
Nick Terrell5f2c7212017-05-10 16:49:58 -0700342 size_t const optSpace = ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) ? optPotentialSpace : 0;
Yann Collet71ddeb62017-04-20 22:54:54 -0700343 size_t const neededSpace = entropySpace + optSpace + tableSpace + tokenSpace;
Yann Colleta7737f62016-09-06 09:44:59 +0200344 if (zc->workSpaceSize < neededSpace) {
Yann Collet0be6fd32017-05-08 16:08:01 -0700345 DEBUGLOG(5, "Need to update workSpaceSize from %uK to %uK \n",
346 (unsigned)zc->workSpaceSize>>10, (unsigned)neededSpace>>10);
Yann Collet0181fef2017-04-06 01:25:26 -0700347 zc->workSpaceSize = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200348 ZSTD_free(zc->workSpace, zc->customMem);
349 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
350 if (zc->workSpace == NULL) return ERROR(memory_allocation);
351 zc->workSpaceSize = neededSpace;
Yann Collet7bb60b12017-04-20 17:38:56 -0700352 ptr = zc->workSpace;
353
354 /* entropy space */
Yann Collet71ddeb62017-04-20 22:54:54 -0700355 zc->hufCTable = (HUF_CElt*)ptr;
356 ptr = (char*)zc->hufCTable + hufCTable_size; /* note : HUF_CElt* is incomplete type, size is estimated via macro */
Yann Collet71aaa322017-04-20 23:03:38 -0700357 zc->offcodeCTable = (FSE_CTable*) ptr;
358 ptr = (char*)ptr + offcodeCTable_size;
Yann Collet72712032017-04-20 23:21:19 -0700359 zc->matchlengthCTable = (FSE_CTable*) ptr;
Yann Collet71aaa322017-04-20 23:03:38 -0700360 ptr = (char*)ptr + matchlengthCTable_size;
Yann Collet72712032017-04-20 23:21:19 -0700361 zc->litlengthCTable = (FSE_CTable*) ptr;
362 ptr = (char*)ptr + litlengthCTable_size;
363 assert(((size_t)ptr & 3) == 0); /* ensure correct alignment */
Yann Collete42afbc2017-04-26 11:39:35 -0700364 zc->entropyScratchSpace = (unsigned*) ptr;
Yann Colleta7737f62016-09-06 09:44:59 +0200365 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100366
Yann Collete6fa70a2017-04-20 17:28:31 -0700367 /* init params */
368 zc->params = params;
369 zc->blockSize = blockSize;
Yann Collet0be6fd32017-05-08 16:08:01 -0700370 DEBUGLOG(5, "blockSize = %uK \n", (U32)blockSize>>10);
Yann Collete6fa70a2017-04-20 17:28:31 -0700371 zc->frameContentSize = frameContentSize;
372 zc->consumedSrcSize = 0;
Yann Collet70e8c382016-02-10 13:37:52 +0100373
Yann Collet083fcc82015-10-25 14:06:35 +0100374 XXH64_reset(&zc->xxhState, 0);
Yann Collete6fa70a2017-04-20 17:28:31 -0700375 zc->stage = ZSTDcs_init;
376 zc->dictID = 0;
377 zc->loadedDictEnd = 0;
Yann Collet71ddeb62017-04-20 22:54:54 -0700378 zc->fseCTables_ready = 0;
379 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta7737f62016-09-06 09:44:59 +0200380 zc->nextToUpdate = 1;
381 zc->nextSrc = NULL;
382 zc->base = NULL;
383 zc->dictBase = NULL;
384 zc->dictLimit = 0;
385 zc->lowLimit = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200386 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
Yann Collete6fa70a2017-04-20 17:28:31 -0700387 zc->hashLog3 = hashLog3;
388 zc->seqStore.litLengthSum = 0;
Yann Colleta7737f62016-09-06 09:44:59 +0200389
Yann Collet71aaa322017-04-20 23:03:38 -0700390 /* ensure entropy tables are close together at the beginning */
391 assert((void*)zc->hufCTable == zc->workSpace);
392 assert((char*)zc->offcodeCTable == (char*)zc->hufCTable + hufCTable_size);
393 assert((char*)zc->matchlengthCTable == (char*)zc->offcodeCTable + offcodeCTable_size);
394 assert((char*)zc->litlengthCTable == (char*)zc->matchlengthCTable + matchlengthCTable_size);
Yann Collete42afbc2017-04-26 11:39:35 -0700395 assert((char*)zc->entropyScratchSpace == (char*)zc->litlengthCTable + litlengthCTable_size);
396 ptr = (char*)zc->entropyScratchSpace + entropyScratchSpace_size;
Yann Collete6fa70a2017-04-20 17:28:31 -0700397
398 /* opt parser space */
Nick Terrelleeb31ee2017-03-09 11:44:25 -0800399 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btultra)) {
Yann Collet0be6fd32017-05-08 16:08:01 -0700400 DEBUGLOG(5, "reserving optimal parser space ");
Yann Collete6fa70a2017-04-20 17:28:31 -0700401 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
Yann Colleta7737f62016-09-06 09:44:59 +0200402 zc->seqStore.litFreq = (U32*)ptr;
403 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
404 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
405 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
406 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
407 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
408 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
409 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
410 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
Yann Colleta7737f62016-09-06 09:44:59 +0200411 }
Yann Collete6fa70a2017-04-20 17:28:31 -0700412
413 /* table Space */
414 if (crp!=ZSTDcrp_noMemset) memset(ptr, 0, tableSpace); /* reset tables only */
415 assert(((size_t)ptr & 3) == 0); /* ensure ptr is properly aligned */
416 zc->hashTable = (U32*)(ptr);
417 zc->chainTable = zc->hashTable + hSize;
418 zc->hashTable3 = zc->chainTable + chainSize;
419 ptr = zc->hashTable3 + h3Size;
420
421 /* sequences storage */
Yann Colleta7737f62016-09-06 09:44:59 +0200422 zc->seqStore.sequencesStart = (seqDef*)ptr;
423 ptr = zc->seqStore.sequencesStart + maxNbSeq;
424 zc->seqStore.llCode = (BYTE*) ptr;
425 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
426 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
427 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
428
Yann Colleta7737f62016-09-06 09:44:59 +0200429 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100430 }
Yann Colletf3eca252015-10-22 15:31:46 +0100431}
432
Yann Collet32dfae62017-01-19 10:32:55 -0800433/* ZSTD_invalidateRepCodes() :
434 * ensures next compression will not use repcodes from previous block.
435 * Note : only works with regular variant;
436 * do not use with extDict variant ! */
437void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
438 int i;
439 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0;
440}
Yann Collet083fcc82015-10-25 14:06:35 +0100441
Yann Collet7b51a292016-01-26 15:58:49 +0100442
Yann Colleta4cab802017-04-18 14:54:54 -0700443/*! ZSTD_copyCCtx_internal() :
444 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
445 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
446 * pledgedSrcSize=0 means "empty" if fParams.contentSizeFlag=1
447 * @return : 0, or an error code */
448size_t ZSTD_copyCCtx_internal(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx,
449 ZSTD_frameParameters fParams, unsigned long long pledgedSrcSize)
Yann Collet7b51a292016-01-26 15:58:49 +0100450{
Yann Collet0be6fd32017-05-08 16:08:01 -0700451 DEBUGLOG(5, "ZSTD_copyCCtx_internal \n");
Yann Collet7b51a292016-01-26 15:58:49 +0100452 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Sean Purcell2db72492017-02-09 10:50:43 -0800453
inikep28669512016-06-02 13:04:18 +0200454 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Sean Purcell2db72492017-02-09 10:50:43 -0800455 { ZSTD_parameters params = srcCCtx->params;
Yann Colleta4cab802017-04-18 14:54:54 -0700456 params.fParams = fParams;
Yann Collet31533ba2017-04-27 00:29:04 -0700457 DEBUGLOG(5, "ZSTD_resetCCtx_internal : dictIDFlag : %u \n", !fParams.noDictIDFlag);
Yann Collet30fb4992017-04-18 14:08:50 -0700458 ZSTD_resetCCtx_internal(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset);
Sean Purcell2db72492017-02-09 10:50:43 -0800459 }
Yann Collet7b51a292016-01-26 15:58:49 +0100460
461 /* copy tables */
Yann Collet731ef162016-07-27 21:05:12 +0200462 { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
Yann Collete6fa70a2017-04-20 17:28:31 -0700463 size_t const hSize = (size_t)1 << srcCCtx->params.cParams.hashLog;
Yann Collet731ef162016-07-27 21:05:12 +0200464 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
465 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collete6fa70a2017-04-20 17:28:31 -0700466 assert((U32*)dstCCtx->chainTable == (U32*)dstCCtx->hashTable + hSize); /* chainTable must follow hashTable */
467 assert((U32*)dstCCtx->hashTable3 == (U32*)dstCCtx->chainTable + chainSize);
468 memcpy(dstCCtx->hashTable, srcCCtx->hashTable, tableSpace); /* presumes all tables follow each other */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100469 }
Yann Collet7b51a292016-01-26 15:58:49 +0100470
Yann Colletc46fb922016-05-29 05:01:04 +0200471 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100472 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
473 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
474 dstCCtx->nextSrc = srcCCtx->nextSrc;
475 dstCCtx->base = srcCCtx->base;
476 dstCCtx->dictBase = srcCCtx->dictBase;
477 dstCCtx->dictLimit = srcCCtx->dictLimit;
478 dstCCtx->lowLimit = srcCCtx->lowLimit;
479 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200480 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100481
Yann Colletfb810d62016-01-28 00:18:06 +0100482 /* copy entropy tables */
Yann Collet71ddeb62017-04-20 22:54:54 -0700483 dstCCtx->fseCTables_ready = srcCCtx->fseCTables_ready;
484 if (srcCCtx->fseCTables_ready) {
Yann Colleta34a39c2017-04-20 18:17:58 -0700485 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, litlengthCTable_size);
486 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, matchlengthCTable_size);
487 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, offcodeCTable_size);
Yann Colletfb810d62016-01-28 00:18:06 +0100488 }
Yann Collet71ddeb62017-04-20 22:54:54 -0700489 dstCCtx->hufCTable_repeatMode = srcCCtx->hufCTable_repeatMode;
490 if (srcCCtx->hufCTable_repeatMode) {
491 memcpy(dstCCtx->hufCTable, srcCCtx->hufCTable, hufCTable_size);
Nick Terrella4197772017-03-01 17:51:56 -0800492 }
Yann Collet7b51a292016-01-26 15:58:49 +0100493
494 return 0;
495}
496
Yann Colleta4cab802017-04-18 14:54:54 -0700497/*! ZSTD_copyCCtx() :
498 * Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
499 * Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
500 * pledgedSrcSize==0 means "unknown".
501* @return : 0, or an error code */
502size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
503{
504 ZSTD_frameParameters fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
505 fParams.contentSizeFlag = pledgedSrcSize>0;
506
507 return ZSTD_copyCCtx_internal(dstCCtx, srcCCtx, fParams, pledgedSrcSize);
508}
509
Yann Collet7b51a292016-01-26 15:58:49 +0100510
Yann Colletecabfe32016-03-20 16:20:06 +0100511/*! ZSTD_reduceTable() :
Yann Colleta4cab802017-04-18 14:54:54 -0700512 * reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100513static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100514{
Yann Colletecabfe32016-03-20 16:20:06 +0100515 U32 u;
516 for (u=0 ; u < size ; u++) {
517 if (table[u] < reducerValue) table[u] = 0;
518 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100519 }
520}
521
Yann Colletecabfe32016-03-20 16:20:06 +0100522/*! ZSTD_reduceIndex() :
523* rescale all indexes to avoid future overflow (indexes are U32) */
524static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
525{
Yann Collet731ef162016-07-27 21:05:12 +0200526 { U32 const hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100527 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
528
Yann Collet731ef162016-07-27 21:05:12 +0200529 { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200530 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100531
Yann Collet731ef162016-07-27 21:05:12 +0200532 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100533 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
534}
535
Yann Collet89db5e02015-11-13 11:27:46 +0100536
Yann Collet863ec402016-01-28 17:56:33 +0100537/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100538* Block entropic compression
539*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100540
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200541/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100542
Yann Colletd1b26842016-03-15 01:24:33 +0100543size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100544{
Yann Colletd1b26842016-03-15 01:24:33 +0100545 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200546 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
547 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100548 return ZSTD_blockHeaderSize+srcSize;
549}
550
551
Yann Colletd1b26842016-03-15 01:24:33 +0100552static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100553{
554 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200555 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100556
Yann Colletd1b26842016-03-15 01:24:33 +0100557 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100558
Yann Collet59d1f792016-01-23 19:28:41 +0100559 switch(flSize)
560 {
561 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200562 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100563 break;
564 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200565 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100566 break;
567 default: /*note : should not be necessary : flSize is within {1,2,3} */
568 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200569 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100570 break;
571 }
572
573 memcpy(ostart + flSize, src, srcSize);
574 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100575}
576
Yann Colletd1b26842016-03-15 01:24:33 +0100577static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100578{
579 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200580 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100581
Yann Collet198e6aa2016-07-20 20:12:24 +0200582 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100583
584 switch(flSize)
585 {
586 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200587 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100588 break;
589 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200590 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100591 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100592 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100593 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200594 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100595 break;
596 }
597
598 ostart[flSize] = *(const BYTE*)src;
599 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100600}
601
Yann Collet59d1f792016-01-23 19:28:41 +0100602
Yann Colleta5c2c082016-03-20 01:09:18 +0100603static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100604
Yann Colletb923f652016-01-26 03:14:20 +0100605static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100606 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100607 const void* src, size_t srcSize)
608{
Yann Colleta910dc82016-03-18 12:37:45 +0100609 size_t const minGain = ZSTD_minGain(srcSize);
610 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200611 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100612 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200613 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100614 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100615
Yann Collet14983e72015-11-11 21:38:21 +0100616
Yann Colleta5c2c082016-03-20 01:09:18 +0100617 /* small ? don't even attempt compression (speed opt) */
618# define LITERAL_NOENTROPY 63
Yann Collet71ddeb62017-04-20 22:54:54 -0700619 { size_t const minLitSize = zc->hufCTable_repeatMode == HUF_repeat_valid ? 6 : LITERAL_NOENTROPY;
Yann Colleta5c2c082016-03-20 01:09:18 +0100620 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
621 }
622
623 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Collet71ddeb62017-04-20 22:54:54 -0700624 { HUF_repeat repeat = zc->hufCTable_repeatMode;
Nick Terrell54c4bab2017-03-03 12:30:24 -0800625 int const preferRepeat = zc->params.cParams.strategy < ZSTD_lazy ? srcSize <= 1024 : 0;
Nick Terrella4197772017-03-01 17:51:56 -0800626 if (repeat == HUF_repeat_valid && lhSize == 3) singleStream = 1;
Yann Collete348dad2017-04-20 11:14:13 -0700627 cLitSize = singleStream ? HUF_compress1X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Yann Collete42afbc2017-04-26 11:39:35 -0700628 zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat)
Yann Collete348dad2017-04-20 11:14:13 -0700629 : HUF_compress4X_repeat(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11,
Yann Collete42afbc2017-04-26 11:39:35 -0700630 zc->entropyScratchSpace, entropyScratchSpace_size, zc->hufCTable, &repeat, preferRepeat);
Nick Terrella4197772017-03-01 17:51:56 -0800631 if (repeat != HUF_repeat_none) { hType = set_repeat; } /* reused the existing table */
Yann Collet71ddeb62017-04-20 22:54:54 -0700632 else { zc->hufCTable_repeatMode = HUF_repeat_check; } /* now have a table to reuse */
Yann Colletb923f652016-01-26 03:14:20 +0100633 }
Yann Collet14983e72015-11-11 21:38:21 +0100634
Nick Terrella4197772017-03-01 17:51:56 -0800635 if ((cLitSize==0) | (cLitSize >= srcSize - minGain)) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700636 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100637 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800638 }
639 if (cLitSize==1) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700640 zc->hufCTable_repeatMode = HUF_repeat_none;
Yann Colleta910dc82016-03-18 12:37:45 +0100641 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Nick Terrella4197772017-03-01 17:51:56 -0800642 }
Yann Collet14983e72015-11-11 21:38:21 +0100643
644 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100645 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100646 {
Yann Collet59d1f792016-01-23 19:28:41 +0100647 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200648 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200649 MEM_writeLE24(ostart, lhc);
650 break;
651 }
Yann Collet59d1f792016-01-23 19:28:41 +0100652 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200653 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200654 MEM_writeLE32(ostart, lhc);
655 break;
656 }
Yann Colleta910dc82016-03-18 12:37:45 +0100657 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100658 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200659 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200660 MEM_writeLE32(ostart, lhc);
661 ostart[4] = (BYTE)(cLitSize >> 10);
662 break;
663 }
Yann Collet14983e72015-11-11 21:38:21 +0100664 }
Yann Colleta910dc82016-03-18 12:37:45 +0100665 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100666}
667
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200668static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
669 8, 9, 10, 11, 12, 13, 14, 15,
670 16, 16, 17, 17, 18, 18, 19, 19,
671 20, 20, 20, 20, 21, 21, 21, 21,
672 22, 22, 22, 22, 22, 22, 22, 22,
673 23, 23, 23, 23, 23, 23, 23, 23,
674 24, 24, 24, 24, 24, 24, 24, 24,
675 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100676
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200677static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
678 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
679 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
680 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
681 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
682 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
683 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
684 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200685
686
687void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100688{
Yann Colleted57d852016-07-29 21:22:17 +0200689 BYTE const LL_deltaCode = 19;
690 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200691 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200692 BYTE* const llCodeTable = seqStorePtr->llCode;
693 BYTE* const ofCodeTable = seqStorePtr->ofCode;
694 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200695 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200696 U32 u;
697 for (u=0; u<nbSeq; u++) {
698 U32 const llv = sequences[u].litLength;
699 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200700 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200701 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200702 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200703 }
Yann Colleted57d852016-07-29 21:22:17 +0200704 if (seqStorePtr->longLengthID==1)
705 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
706 if (seqStorePtr->longLengthID==2)
707 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100708}
709
Sean Purcell553f67e2017-03-02 15:15:31 -0800710MEM_STATIC size_t ZSTD_compressSequences (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100711 void* dst, size_t dstCapacity,
Sean Purcell553f67e2017-03-02 15:15:31 -0800712 size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100713{
Sean Purcell553f67e2017-03-02 15:15:31 -0800714 const int longOffsets = zc->params.cParams.windowLog > STREAM_ACCUMULATOR_MIN;
Yann Colletb923f652016-01-26 03:14:20 +0100715 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100716 U32 count[MaxSeq+1];
717 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100718 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
719 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
720 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100721 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200722 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200723 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
724 const BYTE* const llCodeTable = seqStorePtr->llCode;
725 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +0100726 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100727 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100728 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200729 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +0100730 BYTE* seqHead;
Yann Colletd79a9a02016-11-30 15:52:20 -0800731 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Collet14983e72015-11-11 21:38:21 +0100732
Yann Collet14983e72015-11-11 21:38:21 +0100733 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100734 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100735 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100736 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100737 if (ZSTD_isError(cSize)) return cSize;
738 op += cSize;
739 }
740
741 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100742 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100743 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
744 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
745 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100746 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100747
Yann Colletbe391432016-03-22 23:19:28 +0100748 /* seqHead : flags for FSE encoding type */
749 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100750
Yann Colletfb810d62016-01-28 00:18:06 +0100751#define MIN_SEQ_FOR_DYNAMIC_FSE 64
752#define MAX_SEQ_FOR_STATIC_FSE 1000
753
Yann Colletb44be742016-03-26 20:52:14 +0100754 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +0200755 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +0100756
Yann Collet14983e72015-11-11 21:38:21 +0100757 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100758 { U32 max = MaxLL;
Yann Collete42afbc2017-04-26 11:39:35 -0700759 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +0100760 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
761 *op++ = llCodeTable[0];
762 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200763 LLtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -0700764 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200765 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100766 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800767 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200768 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100769 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100770 size_t nbSeq_1 = nbSeq;
771 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
772 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
773 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100774 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -0700775 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +0100776 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800777 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200778 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100779 } }
Yann Collet14983e72015-11-11 21:38:21 +0100780
Yann Colletb44be742016-03-26 20:52:14 +0100781 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100782 { U32 max = MaxOff;
Yann Collete42afbc2017-04-26 11:39:35 -0700783 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +0100784 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100785 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100786 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200787 Offtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -0700788 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200789 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +0200790 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800791 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200792 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100793 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100794 size_t nbSeq_1 = nbSeq;
795 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100796 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100797 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100798 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -0700799 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletadd08d62016-03-23 01:32:41 +0100800 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800801 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200802 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100803 } }
804
Yann Collet14983e72015-11-11 21:38:21 +0100805 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100806 { U32 max = MaxML;
Yann Collete42afbc2017-04-26 11:39:35 -0700807 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->entropyScratchSpace);
Yann Colletfadda6c2016-03-22 12:14:26 +0100808 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100809 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100810 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200811 MLtype = set_rle;
Yann Collet71ddeb62017-04-20 22:54:54 -0700812 } else if ((zc->fseCTables_ready) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200813 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100814 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800815 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200816 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100817 } else {
818 size_t nbSeq_1 = nbSeq;
819 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
820 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
821 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
822 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
Yann Collet23776ce2017-03-23 17:59:50 -0700823 if (FSE_isError(NCountSize)) return NCountSize;
Yann Colletfadda6c2016-03-22 12:14:26 +0100824 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800825 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200826 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100827 } }
Yann Collet14983e72015-11-11 21:38:21 +0100828
Yann Colletbe391432016-03-22 23:19:28 +0100829 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Collet71ddeb62017-04-20 22:54:54 -0700830 zc->fseCTables_ready = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100831
832 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100833 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100834 FSE_CState_t stateMatchLength;
835 FSE_CState_t stateOffsetBits;
836 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100837
Yann Collet95d07d72016-09-06 16:38:51 +0200838 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100839
Yann Collet597847a2016-03-20 19:14:22 +0100840 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100841 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100842 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100843 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +0200844 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100845 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200846 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100847 if (MEM_32bits()) BIT_flushBits(&blockStream);
Sean Purcelld44703d2017-03-01 14:36:25 -0800848 if (longOffsets) {
849 U32 const ofBits = ofCodeTable[nbSeq-1];
850 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
851 if (extraBits) {
852 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, extraBits);
853 BIT_flushBits(&blockStream);
854 }
855 BIT_addBits(&blockStream, sequences[nbSeq-1].offset >> extraBits,
856 ofBits - extraBits);
857 } else {
858 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
859 }
Yann Collet597847a2016-03-20 19:14:22 +0100860 BIT_flushBits(&blockStream);
861
Yann Colletfadda6c2016-03-22 12:14:26 +0100862 { size_t n;
863 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +0200864 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200865 BYTE const ofCode = ofCodeTable[n];
866 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200867 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +0200868 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200869 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +0100870 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100871 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
872 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
873 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
874 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200875 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100876 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +0200877 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100878 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200879 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100880 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Sean Purcelld44703d2017-03-01 14:36:25 -0800881 if (longOffsets) {
882 int const extraBits = ofBits - MIN(ofBits, STREAM_ACCUMULATOR_MIN-1);
883 if (extraBits) {
884 BIT_addBits(&blockStream, sequences[n].offset, extraBits);
885 BIT_flushBits(&blockStream); /* (7)*/
886 }
887 BIT_addBits(&blockStream, sequences[n].offset >> extraBits,
888 ofBits - extraBits); /* 31 */
889 } else {
890 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
891 }
Yann Colletb9151402016-03-26 17:18:11 +0100892 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100893 } }
Yann Collet14983e72015-11-11 21:38:21 +0100894
895 FSE_flushCState(&blockStream, &stateMatchLength);
896 FSE_flushCState(&blockStream, &stateOffsetBits);
897 FSE_flushCState(&blockStream, &stateLitLength);
898
Yann Colletb9151402016-03-26 17:18:11 +0100899 { size_t const streamSize = BIT_closeCStream(&blockStream);
900 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
901 op += streamSize;
902 } }
Yann Collet14983e72015-11-11 21:38:21 +0100903
904 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100905_check_compressibility:
Nick Terrella4197772017-03-01 17:51:56 -0800906 { size_t const minGain = ZSTD_minGain(srcSize);
907 size_t const maxCSize = srcSize - minGain;
908 if ((size_t)(op-ostart) >= maxCSize) {
Yann Collet71ddeb62017-04-20 22:54:54 -0700909 zc->hufCTable_repeatMode = HUF_repeat_none;
Nick Terrella4197772017-03-01 17:51:56 -0800910 return 0;
911 } }
Yann Collet14983e72015-11-11 21:38:21 +0100912
Yann Collet4266c0a2016-06-14 01:49:25 +0200913 /* confirm repcodes */
Yann Colletb459aad2017-01-19 17:33:37 -0800914 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; }
Yann Collet4266c0a2016-06-14 01:49:25 +0200915
Yann Collet5054ee02015-11-23 13:34:21 +0100916 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100917}
918
Yann Colletbb002742017-01-25 16:25:38 -0800919#if 0 /* for debug */
920# define STORESEQ_DEBUG
921#include <stdio.h> /* fprintf */
922U32 g_startDebug = 0;
923const BYTE* g_start = NULL;
924#endif
925
Yann Collet95cd0c22016-03-08 18:24:21 +0100926/*! ZSTD_storeSeq() :
927 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
928 `offsetCode` : distance to match, or 0 == repCode.
929 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100930*/
Yann Colletd57dffb2016-07-03 01:48:26 +0200931MEM_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 +0100932{
Yann Colletbb002742017-01-25 16:25:38 -0800933#ifdef STORESEQ_DEBUG
934 if (g_startDebug) {
935 const U32 pos = (U32)((const BYTE*)literals - g_start);
936 if (g_start==NULL) g_start = (const BYTE*)literals;
937 if ((pos > 1895000) && (pos < 1895300))
Yann Collet31533ba2017-04-27 00:29:04 -0700938 DEBUGLOG(5, "Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
Yann Colletbb002742017-01-25 16:25:38 -0800939 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
940 }
Yann Collet14983e72015-11-11 21:38:21 +0100941#endif
Yann Collet14983e72015-11-11 21:38:21 +0100942 /* copy Literals */
943 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
944 seqStorePtr->lit += litLength;
945
946 /* literal Length */
Yann Collete6fa70a2017-04-20 17:28:31 -0700947 if (litLength>0xFFFF) {
948 seqStorePtr->longLengthID = 1;
949 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
950 }
Yann Colletc0ce4f12016-07-30 00:55:13 +0200951 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100952
953 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200954 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100955
956 /* match Length */
Yann Collete6fa70a2017-04-20 17:28:31 -0700957 if (matchCode>0xFFFF) {
958 seqStorePtr->longLengthID = 2;
959 seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
960 }
Yann Colletc0ce4f12016-07-30 00:55:13 +0200961 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +0200962
Yann Colletc0ce4f12016-07-30 00:55:13 +0200963 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +0100964}
965
966
Yann Collet7d360282016-02-12 00:07:30 +0100967/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100968* Match length counter
969***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100970static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100971{
Yann Collet863ec402016-01-28 17:56:33 +0100972 if (MEM_isLittleEndian()) {
973 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100974# if defined(_MSC_VER) && defined(_WIN64)
975 unsigned long r = 0;
976 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100977 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100978# elif defined(__GNUC__) && (__GNUC__ >= 3)
979 return (__builtin_ctzll((U64)val) >> 3);
980# else
Yann Collete348dad2017-04-20 11:14:13 -0700981 static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2,
982 0, 3, 1, 3, 1, 4, 2, 7,
983 0, 2, 3, 6, 1, 5, 3, 5,
984 1, 3, 4, 4, 2, 5, 6, 7,
985 7, 0, 1, 2, 3, 3, 4, 6,
986 2, 6, 5, 5, 3, 4, 5, 6,
987 7, 1, 2, 4, 6, 4, 4, 5,
988 7, 2, 6, 5, 7, 6, 7, 7 };
Yann Collet14983e72015-11-11 21:38:21 +0100989 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
990# endif
Yann Collet863ec402016-01-28 17:56:33 +0100991 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100992# if defined(_MSC_VER)
993 unsigned long r=0;
994 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100995 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100996# elif defined(__GNUC__) && (__GNUC__ >= 3)
997 return (__builtin_ctz((U32)val) >> 3);
998# else
Yann Collete348dad2017-04-20 11:14:13 -0700999 static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0,
1000 3, 2, 2, 1, 3, 2, 0, 1,
1001 3, 3, 1, 2, 2, 2, 2, 0,
1002 3, 1, 2, 0, 1, 0, 1, 1 };
Yann Collet14983e72015-11-11 21:38:21 +01001003 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
1004# endif
1005 }
Yann Collet863ec402016-01-28 17:56:33 +01001006 } else { /* Big Endian CPU */
1007 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +01001008# if defined(_MSC_VER) && defined(_WIN64)
1009 unsigned long r = 0;
1010 _BitScanReverse64( &r, val );
1011 return (unsigned)(r>>3);
1012# elif defined(__GNUC__) && (__GNUC__ >= 3)
1013 return (__builtin_clzll(val) >> 3);
1014# else
1015 unsigned r;
1016 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
1017 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
1018 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
1019 r += (!val);
1020 return r;
1021# endif
Yann Collet863ec402016-01-28 17:56:33 +01001022 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +01001023# if defined(_MSC_VER)
1024 unsigned long r = 0;
1025 _BitScanReverse( &r, (unsigned long)val );
1026 return (unsigned)(r>>3);
1027# elif defined(__GNUC__) && (__GNUC__ >= 3)
1028 return (__builtin_clz((U32)val) >> 3);
1029# else
1030 unsigned r;
1031 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
1032 r += (!val);
1033 return r;
1034# endif
Yann Collet863ec402016-01-28 17:56:33 +01001035 } }
Yann Collet14983e72015-11-11 21:38:21 +01001036}
1037
1038
Yann Colleta436a522016-06-20 23:34:04 +02001039static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +01001040{
1041 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +02001042 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +01001043
Yann Colleta436a522016-06-20 23:34:04 +02001044 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +02001045 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +01001046 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
1047 pIn += ZSTD_NbCommonBytes(diff);
1048 return (size_t)(pIn - pStart);
1049 }
Yann Collet14983e72015-11-11 21:38:21 +01001050 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
1051 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
1052 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
1053 return (size_t)(pIn - pStart);
1054}
1055
Yann Collet04b12d82016-02-11 06:23:24 +01001056/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +01001057* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +01001058* convention : on reaching mEnd, match count continue starting from iStart
1059*/
1060static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
1061{
Yann Collet7591a7f2016-05-20 11:44:43 +02001062 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +02001063 size_t const matchLength = ZSTD_count(ip, match, vEnd);
1064 if (match + matchLength != mEnd) return matchLength;
1065 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +01001066}
1067
Yann Collet14983e72015-11-11 21:38:21 +01001068
Yann Collet863ec402016-01-28 17:56:33 +01001069/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +01001070* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +01001071***************************************/
inikepcc52a972016-02-19 10:09:35 +01001072static const U32 prime3bytes = 506832829U;
1073static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Collete6fa70a2017-04-20 17:28:31 -07001074MEM_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 +01001075
Yann Collet4b100f42015-10-30 15:49:48 +01001076static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +01001077static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +01001078static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +01001079
Yann Collet4b100f42015-10-30 15:49:48 +01001080static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001081static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001082static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001083
1084static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001085static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001086static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +01001087
Yann Collet14983e72015-11-11 21:38:21 +01001088static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +01001089static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +01001090static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001091
Yann Collet45dc3562016-07-12 09:47:31 +02001092static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
1093static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
1094static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
1095
Yann Collet5be2dd22015-11-11 13:43:58 +01001096static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +01001097{
1098 switch(mls)
1099 {
1100 default:
Yann Collet5be2dd22015-11-11 13:43:58 +01001101 case 4: return ZSTD_hash4Ptr(p, hBits);
1102 case 5: return ZSTD_hash5Ptr(p, hBits);
1103 case 6: return ZSTD_hash6Ptr(p, hBits);
1104 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +02001105 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +01001106 }
1107}
Yann Collet2acb5d32015-10-29 16:49:43 +01001108
Yann Collet863ec402016-01-28 17:56:33 +01001109
Yann Collet2ce49232016-02-02 14:36:49 +01001110/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +01001111* Fast Scan
1112***************************************/
Yann Collet417890c2015-12-04 17:16:37 +01001113static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
1114{
1115 U32* const hashTable = zc->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001116 U32 const hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +01001117 const BYTE* const base = zc->base;
1118 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001119 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +01001120 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +01001121
Yann Colletfb810d62016-01-28 00:18:06 +01001122 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +01001123 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +01001124 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +01001125 }
1126}
1127
1128
Yann Collet1f44b3f2015-11-05 17:32:18 +01001129FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +02001130void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +02001131 const void* src, size_t srcSize,
1132 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001133{
Yann Collet4266c0a2016-06-14 01:49:25 +02001134 U32* const hashTable = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001135 U32 const hBits = cctx->params.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +02001136 seqStore_t* seqStorePtr = &(cctx->seqStore);
1137 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001138 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +01001139 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001140 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +02001141 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +02001142 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001143 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001144 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +02001145 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1146 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001147
Yann Collet1f44b3f2015-11-05 17:32:18 +01001148 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001149 ip += (ip==lowest);
1150 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +02001151 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1152 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +02001153 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001154
1155 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +02001156 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +02001157 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +02001158 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
1159 U32 const current = (U32)(ip-base);
1160 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +01001161 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +01001162 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001163
Yann Collet280f9a82016-08-08 00:44:00 +02001164 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +02001165 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +01001166 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001167 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1168 } else {
Yann Collet92d75662016-07-03 01:10:53 +02001169 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001170 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001171 ip += ((ip-anchor) >> g_searchStrength) + 1;
1172 continue;
1173 }
Yann Collet45dc3562016-07-12 09:47:31 +02001174 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001175 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001176 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001177 offset_2 = offset_1;
1178 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001179
Yann Colleta436a522016-06-20 23:34:04 +02001180 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001181 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001182
Yann Collet402fdcf2015-11-20 12:46:08 +01001183 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001184 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001185 anchor = ip;
1186
Yann Colletfb810d62016-01-28 00:18:06 +01001187 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001188 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001189 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 +01001190 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1191 /* check immediate repcode */
1192 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001193 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001194 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001195 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001196 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001197 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001198 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001199 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1200 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001201 anchor = ip;
1202 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001203 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001204
Yann Collet4266c0a2016-06-14 01:49:25 +02001205 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001206 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1207 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001208
Yann Collet70e45772016-03-19 18:08:32 +01001209 /* Last Literals */
1210 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001211 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1212 seqStorePtr->lit += lastLLSize;
1213 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001214}
1215
1216
Yann Collet82260dd2016-02-11 07:14:25 +01001217static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001218 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001219{
Yann Collet3b719252016-03-30 19:48:05 +02001220 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001221 switch(mls)
1222 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001223 default: /* includes case 3 */
Yann Collet1f44b3f2015-11-05 17:32:18 +01001224 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001225 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001226 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001227 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001228 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001229 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001230 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001231 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001232 }
1233}
Yann Colletf3eca252015-10-22 15:31:46 +01001234
Yann Colletf3eca252015-10-22 15:31:46 +01001235
Yann Collet82260dd2016-02-11 07:14:25 +01001236static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001237 const void* src, size_t srcSize,
1238 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001239{
1240 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001241 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001242 seqStore_t* seqStorePtr = &(ctx->seqStore);
1243 const BYTE* const base = ctx->base;
1244 const BYTE* const dictBase = ctx->dictBase;
1245 const BYTE* const istart = (const BYTE*)src;
1246 const BYTE* ip = istart;
1247 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001248 const U32 lowestIndex = ctx->lowLimit;
1249 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001250 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001251 const BYTE* const lowPrefixPtr = base + dictLimit;
1252 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001253 const BYTE* const iend = istart + srcSize;
1254 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001255 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001256
Yann Colleta436a522016-06-20 23:34:04 +02001257 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001258 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001259 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001260 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001261 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001262 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001263 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001264 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001265 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001266 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001267 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001268 hashTable[h] = current; /* update hash table */
1269
Yann Colleta436a522016-06-20 23:34:04 +02001270 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001271 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001272 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001273 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
Yann Collet743402c2015-11-20 12:03:53 +01001274 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001275 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001276 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001277 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001278 (MEM_read32(match) != MEM_read32(ip)) ) {
1279 ip += ((ip-anchor) >> g_searchStrength) + 1;
1280 continue;
1281 }
1282 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001283 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001284 U32 offset;
Yann Collete6fa70a2017-04-20 17:28:31 -07001285 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
Yann Colleta436a522016-06-20 23:34:04 +02001286 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001287 offset = current - matchIndex;
1288 offset_2 = offset_1;
1289 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001290 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001291 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001292
Yann Collet5054ee02015-11-23 13:34:21 +01001293 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001294 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001295 anchor = ip;
1296
Yann Colletfb810d62016-01-28 00:18:06 +01001297 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001298 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001299 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001300 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1301 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001302 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001303 U32 const current2 = (U32)(ip-base);
1304 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001305 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001306 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1307 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001308 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete6fa70a2017-04-20 17:28:31 -07001309 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet5054ee02015-11-23 13:34:21 +01001310 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001311 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001312 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001313 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001314 anchor = ip;
1315 continue;
1316 }
Yann Collet743402c2015-11-20 12:03:53 +01001317 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001318 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001319
Yann Collet4266c0a2016-06-14 01:49:25 +02001320 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001321 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001322
Yann Collet89db5e02015-11-13 11:27:46 +01001323 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001324 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001325 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1326 seqStorePtr->lit += lastLLSize;
1327 }
Yann Collet89db5e02015-11-13 11:27:46 +01001328}
1329
1330
Yann Collet82260dd2016-02-11 07:14:25 +01001331static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001332 const void* src, size_t srcSize)
1333{
Yann Collet731ef162016-07-27 21:05:12 +02001334 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001335 switch(mls)
1336 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001337 default: /* includes case 3 */
Yann Collet89db5e02015-11-13 11:27:46 +01001338 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001339 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001340 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001341 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001342 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001343 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001344 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001345 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001346 }
1347}
1348
1349
Yann Collet04b12d82016-02-11 06:23:24 +01001350/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001351* Double Fast
1352***************************************/
1353static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1354{
1355 U32* const hashLarge = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001356 U32 const hBitsL = cctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001357 U32* const hashSmall = cctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001358 U32 const hBitsS = cctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001359 const BYTE* const base = cctx->base;
1360 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001361 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001362 const size_t fastHashFillStep = 3;
1363
1364 while(ip <= iend) {
1365 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1366 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1367 ip += fastHashFillStep;
1368 }
1369}
1370
1371
1372FORCE_INLINE
1373void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1374 const void* src, size_t srcSize,
1375 const U32 mls)
1376{
1377 U32* const hashLong = cctx->hashTable;
1378 const U32 hBitsL = cctx->params.cParams.hashLog;
1379 U32* const hashSmall = cctx->chainTable;
1380 const U32 hBitsS = cctx->params.cParams.chainLog;
1381 seqStore_t* seqStorePtr = &(cctx->seqStore);
1382 const BYTE* const base = cctx->base;
1383 const BYTE* const istart = (const BYTE*)src;
1384 const BYTE* ip = istart;
1385 const BYTE* anchor = istart;
1386 const U32 lowestIndex = cctx->dictLimit;
1387 const BYTE* const lowest = base + lowestIndex;
1388 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001389 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001390 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1391 U32 offsetSaved = 0;
1392
1393 /* init */
1394 ip += (ip==lowest);
1395 { U32 const maxRep = (U32)(ip-lowest);
1396 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1397 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1398 }
1399
1400 /* Main Search Loop */
1401 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1402 size_t mLength;
1403 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1404 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1405 U32 const current = (U32)(ip-base);
1406 U32 const matchIndexL = hashLong[h2];
1407 U32 const matchIndexS = hashSmall[h];
1408 const BYTE* matchLong = base + matchIndexL;
1409 const BYTE* match = base + matchIndexS;
1410 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1411
Yann Colletc17e0202017-04-20 12:50:02 -07001412 assert(offset_1 <= current); /* supposed guaranteed by construction */
1413 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001414 /* favor repcode */
Yann Collet45dc3562016-07-12 09:47:31 +02001415 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1416 ip++;
1417 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1418 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001419 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001420 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1421 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001422 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001423 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1424 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Collete6fa70a2017-04-20 17:28:31 -07001425 size_t const hl3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1426 U32 const matchIndexL3 = hashLong[hl3];
1427 const BYTE* matchL3 = base + matchIndexL3;
1428 hashLong[hl3] = current + 1;
1429 if ( (matchIndexL3 > lowestIndex) && (MEM_read64(matchL3) == MEM_read64(ip+1)) ) {
1430 mLength = ZSTD_count(ip+9, matchL3+8, iend) + 8;
Yann Colletc54692f2016-08-24 01:10:42 +02001431 ip++;
Yann Collete6fa70a2017-04-20 17:28:31 -07001432 offset = (U32)(ip-matchL3);
1433 while (((ip>anchor) & (matchL3>lowest)) && (ip[-1] == matchL3[-1])) { ip--; matchL3--; mLength++; } /* catch up */
Yann Colletc54692f2016-08-24 01:10:42 +02001434 } else {
1435 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1436 offset = (U32)(ip-match);
1437 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1438 }
Yann Collet45dc3562016-07-12 09:47:31 +02001439 } else {
1440 ip += ((ip-anchor) >> g_searchStrength) + 1;
1441 continue;
1442 }
1443
1444 offset_2 = offset_1;
1445 offset_1 = offset;
1446
1447 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1448 }
1449
1450 /* match found */
1451 ip += mLength;
1452 anchor = ip;
1453
1454 if (ip <= ilimit) {
1455 /* Fill Table */
1456 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1457 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1458 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1459 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1460
1461 /* check immediate repcode */
1462 while ( (ip <= ilimit)
1463 && ( (offset_2>0)
1464 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1465 /* store sequence */
1466 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001467 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001468 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1469 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1470 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1471 ip += rLength;
1472 anchor = ip;
1473 continue; /* faster when present ... (?) */
1474 } } }
1475
1476 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001477 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1478 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet45dc3562016-07-12 09:47:31 +02001479
1480 /* Last Literals */
1481 { size_t const lastLLSize = iend - anchor;
1482 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1483 seqStorePtr->lit += lastLLSize;
1484 }
1485}
1486
1487
1488static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1489{
1490 const U32 mls = ctx->params.cParams.searchLength;
1491 switch(mls)
1492 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001493 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001494 case 4 :
1495 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1496 case 5 :
1497 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1498 case 6 :
1499 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1500 case 7 :
1501 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1502 }
1503}
1504
1505
1506static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1507 const void* src, size_t srcSize,
1508 const U32 mls)
1509{
1510 U32* const hashLong = ctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001511 U32 const hBitsL = ctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001512 U32* const hashSmall = ctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001513 U32 const hBitsS = ctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001514 seqStore_t* seqStorePtr = &(ctx->seqStore);
1515 const BYTE* const base = ctx->base;
1516 const BYTE* const dictBase = ctx->dictBase;
1517 const BYTE* const istart = (const BYTE*)src;
1518 const BYTE* ip = istart;
1519 const BYTE* anchor = istart;
1520 const U32 lowestIndex = ctx->lowLimit;
1521 const BYTE* const dictStart = dictBase + lowestIndex;
1522 const U32 dictLimit = ctx->dictLimit;
1523 const BYTE* const lowPrefixPtr = base + dictLimit;
1524 const BYTE* const dictEnd = dictBase + dictLimit;
1525 const BYTE* const iend = istart + srcSize;
1526 const BYTE* const ilimit = iend - 8;
1527 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1528
1529 /* Search Loop */
1530 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1531 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1532 const U32 matchIndex = hashSmall[hSmall];
1533 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1534 const BYTE* match = matchBase + matchIndex;
1535
1536 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1537 const U32 matchLongIndex = hashLong[hLong];
1538 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1539 const BYTE* matchLong = matchLongBase + matchLongIndex;
1540
1541 const U32 current = (U32)(ip-base);
1542 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1543 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1544 const BYTE* repMatch = repBase + repIndex;
1545 size_t mLength;
1546 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1547
1548 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1549 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1550 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1551 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1552 ip++;
1553 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1554 } else {
1555 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1556 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1557 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1558 U32 offset;
1559 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1560 offset = current - matchLongIndex;
1561 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1562 offset_2 = offset_1;
1563 offset_1 = offset;
1564 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001565
Yann Collet73d74a02016-07-12 13:03:48 +02001566 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001567 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1568 U32 const matchIndex3 = hashLong[h3];
1569 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1570 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001571 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001572 hashLong[h3] = current + 1;
1573 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1574 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1575 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1576 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1577 ip++;
1578 offset = current+1 - matchIndex3;
1579 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1580 } else {
1581 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1582 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1583 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1584 offset = current - matchIndex;
1585 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1586 }
Yann Collet45dc3562016-07-12 09:47:31 +02001587 offset_2 = offset_1;
1588 offset_1 = offset;
1589 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001590
Yann Collet45dc3562016-07-12 09:47:31 +02001591 } else {
1592 ip += ((ip-anchor) >> g_searchStrength) + 1;
1593 continue;
1594 } }
1595
1596 /* found a match : store it */
1597 ip += mLength;
1598 anchor = ip;
1599
1600 if (ip <= ilimit) {
1601 /* Fill Table */
Nick Terrellf35ef5c2017-03-09 12:51:33 -08001602 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1603 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
Yann Collet45dc3562016-07-12 09:47:31 +02001604 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1605 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1606 /* check immediate repcode */
1607 while (ip <= ilimit) {
1608 U32 const current2 = (U32)(ip-base);
1609 U32 const repIndex2 = current2 - offset_2;
1610 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1611 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1612 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1613 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07001614 size_t const repLength2 = ZSTD_count_2segments(ip+4, repMatch2+4, iend, repEnd2, lowPrefixPtr) + 4;
Yann Collet45dc3562016-07-12 09:47:31 +02001615 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1616 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1617 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1618 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1619 ip += repLength2;
1620 anchor = ip;
1621 continue;
1622 }
1623 break;
1624 } } }
1625
1626 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001627 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet45dc3562016-07-12 09:47:31 +02001628
1629 /* Last Literals */
1630 { size_t const lastLLSize = iend - anchor;
1631 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1632 seqStorePtr->lit += lastLLSize;
1633 }
1634}
1635
1636
1637static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1638 const void* src, size_t srcSize)
1639{
Yann Collet731ef162016-07-27 21:05:12 +02001640 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001641 switch(mls)
1642 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001643 default: /* includes case 3 */
Yann Collet45dc3562016-07-12 09:47:31 +02001644 case 4 :
1645 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1646 case 5 :
1647 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1648 case 6 :
1649 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1650 case 7 :
1651 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1652 }
1653}
1654
1655
1656/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001657* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001658***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001659/** ZSTD_insertBt1() : add one or multiple positions to tree.
1660* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001661* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001662static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1663 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001664{
Yann Collet731ef162016-07-27 21:05:12 +02001665 U32* const hashTable = zc->hashTable;
1666 U32 const hashLog = zc->params.cParams.hashLog;
1667 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1668 U32* const bt = zc->chainTable;
1669 U32 const btLog = zc->params.cParams.chainLog - 1;
1670 U32 const btMask = (1 << btLog) - 1;
1671 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001672 size_t commonLengthSmaller=0, commonLengthLarger=0;
1673 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001674 const BYTE* const dictBase = zc->dictBase;
1675 const U32 dictLimit = zc->dictLimit;
1676 const BYTE* const dictEnd = dictBase + dictLimit;
1677 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07001678 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001679 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001680 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001681 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001682 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001683 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001684 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001685 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001686 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001687#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001688 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1689 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1690 predictedSmall += (predictedSmall>0);
1691 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001692#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001693
Yann Collet6c3e2e72015-12-11 10:44:07 +01001694 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001695
Yann Colletfb810d62016-01-28 00:18:06 +01001696 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001697 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001698 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08001699
Yann Colletc0932082016-06-30 14:07:30 +02001700#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001701 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001702 if (matchIndex == predictedSmall) {
1703 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001704 *smallerPtr = matchIndex;
1705 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1706 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1707 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001708 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001709 continue;
1710 }
Yann Colletfb810d62016-01-28 00:18:06 +01001711 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001712 *largerPtr = matchIndex;
1713 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1714 largerPtr = nextPtr;
1715 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001716 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001717 continue;
1718 }
Yann Collet04b12d82016-02-11 06:23:24 +01001719#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001720 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001721 match = base + matchIndex;
1722 if (match[matchLength] == ip[matchLength])
1723 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001724 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001725 match = dictBase + matchIndex;
1726 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1727 if (matchIndex+matchLength >= dictLimit)
Nick Terrellf35ef5c2017-03-09 12:51:33 -08001728 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet1358f912016-01-01 07:29:39 +01001729 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001730
Yann Colletb8a6f682016-02-15 17:06:29 +01001731 if (matchLength > bestLength) {
1732 bestLength = matchLength;
1733 if (matchLength > matchEndIdx - matchIndex)
1734 matchEndIdx = matchIndex + (U32)matchLength;
1735 }
Yann Colletee3f4512015-12-29 22:26:09 +01001736
Yann Collet59d70632015-11-04 12:05:27 +01001737 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001738 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001739
Yann Colletfb810d62016-01-28 00:18:06 +01001740 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001741 /* match is smaller than current */
1742 *smallerPtr = matchIndex; /* update smaller idx */
1743 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001744 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001745 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001746 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001747 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001748 /* match is larger than current */
1749 *largerPtr = matchIndex;
1750 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001751 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001752 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001753 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001754 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001755
Yann Collet59d70632015-11-04 12:05:27 +01001756 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02001757 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01001758 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1759 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001760}
1761
1762
Yann Collet82260dd2016-02-11 07:14:25 +01001763static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001764 ZSTD_CCtx* zc,
1765 const BYTE* const ip, const BYTE* const iend,
1766 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001767 U32 nbCompares, const U32 mls,
1768 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001769{
Yann Collet731ef162016-07-27 21:05:12 +02001770 U32* const hashTable = zc->hashTable;
1771 U32 const hashLog = zc->params.cParams.hashLog;
1772 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1773 U32* const bt = zc->chainTable;
1774 U32 const btLog = zc->params.cParams.chainLog - 1;
1775 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001776 U32 matchIndex = hashTable[h];
1777 size_t commonLengthSmaller=0, commonLengthLarger=0;
1778 const BYTE* const base = zc->base;
1779 const BYTE* const dictBase = zc->dictBase;
1780 const U32 dictLimit = zc->dictLimit;
1781 const BYTE* const dictEnd = dictBase + dictLimit;
1782 const BYTE* const prefixStart = base + dictLimit;
1783 const U32 current = (U32)(ip-base);
1784 const U32 btLow = btMask >= current ? 0 : current - btMask;
1785 const U32 windowLow = zc->lowLimit;
1786 U32* smallerPtr = bt + 2*(current&btMask);
1787 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001788 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001789 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001790 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001791
Yann Collet6c3e2e72015-12-11 10:44:07 +01001792 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001793
Yann Colletfb810d62016-01-28 00:18:06 +01001794 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001795 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01001796 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1797 const BYTE* match;
1798
Yann Colletfb810d62016-01-28 00:18:06 +01001799 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001800 match = base + matchIndex;
1801 if (match[matchLength] == ip[matchLength])
1802 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001803 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001804 match = dictBase + matchIndex;
1805 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001806 if (matchIndex+matchLength >= dictLimit)
Nick Terrellf35ef5c2017-03-09 12:51:33 -08001807 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001808 }
1809
Yann Colletfb810d62016-01-28 00:18:06 +01001810 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001811 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001812 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02001813 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001814 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001815 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1816 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1817 }
1818
Yann Colletfb810d62016-01-28 00:18:06 +01001819 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001820 /* match is smaller than current */
1821 *smallerPtr = matchIndex; /* update smaller idx */
1822 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1823 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1824 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1825 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001826 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001827 /* match is larger than current */
1828 *largerPtr = matchIndex;
1829 commonLengthLarger = matchLength;
1830 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1831 largerPtr = nextPtr;
1832 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001833 } }
Yann Collet03526e12015-11-23 15:29:15 +01001834
1835 *smallerPtr = *largerPtr = 0;
1836
Yann Collet72e84cf2015-12-31 19:08:44 +01001837 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001838 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001839}
1840
Yann Collet2cc12cb2016-01-01 07:47:58 +01001841
Yann Colletb8a6f682016-02-15 17:06:29 +01001842static 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 +01001843{
1844 const BYTE* const base = zc->base;
1845 const U32 target = (U32)(ip - base);
1846 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001847
1848 while(idx < target)
1849 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001850}
1851
Yann Collet52447382016-03-20 16:00:00 +01001852/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001853static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001854 ZSTD_CCtx* zc,
1855 const BYTE* const ip, const BYTE* const iLimit,
1856 size_t* offsetPtr,
1857 const U32 maxNbAttempts, const U32 mls)
1858{
1859 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001860 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001861 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1862}
1863
1864
Yann Collet768c6bc2016-02-10 14:01:49 +01001865static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001866 ZSTD_CCtx* zc, /* Index table will be updated */
1867 const BYTE* ip, const BYTE* const iLimit,
1868 size_t* offsetPtr,
1869 const U32 maxNbAttempts, const U32 matchLengthSearch)
1870{
1871 switch(matchLengthSearch)
1872 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001873 default : /* includes case 3 */
Yann Collet2cc12cb2016-01-01 07:47:58 +01001874 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1875 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07001876 case 7 :
Yann Collet2cc12cb2016-01-01 07:47:58 +01001877 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1878 }
1879}
1880
1881
Yann Colletb8a6f682016-02-15 17:06:29 +01001882static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1883{
1884 const BYTE* const base = zc->base;
1885 const U32 target = (U32)(ip - base);
1886 U32 idx = zc->nextToUpdate;
1887
1888 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1889}
1890
inikep64d7bcb2016-04-07 19:14:09 +02001891
Yann Collet03526e12015-11-23 15:29:15 +01001892/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001893static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001894 ZSTD_CCtx* zc,
1895 const BYTE* const ip, const BYTE* const iLimit,
1896 size_t* offsetPtr,
1897 const U32 maxNbAttempts, const U32 mls)
1898{
Yann Colletee3f4512015-12-29 22:26:09 +01001899 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001900 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001901 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001902}
1903
1904
Yann Collet82260dd2016-02-11 07:14:25 +01001905static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001906 ZSTD_CCtx* zc, /* Index table will be updated */
1907 const BYTE* ip, const BYTE* const iLimit,
1908 size_t* offsetPtr,
1909 const U32 maxNbAttempts, const U32 matchLengthSearch)
1910{
1911 switch(matchLengthSearch)
1912 {
Yann Collet933ce4a2017-03-29 14:32:15 -07001913 default : /* includes case 3 */
Yann Collet03526e12015-11-23 15:29:15 +01001914 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1915 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
Yann Collet933ce4a2017-03-29 14:32:15 -07001916 case 7 :
Yann Collet03526e12015-11-23 15:29:15 +01001917 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1918 }
1919}
1920
1921
Yann Collet5106a762015-11-05 15:00:24 +01001922
Yann Collet731ef162016-07-27 21:05:12 +02001923/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02001924* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02001925***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02001926#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1927
1928/* Update chains up to ip (excluded)
Anders Oleson517577b2017-02-20 12:08:59 -08001929 Assumption : always within prefix (i.e. not within extDict) */
inikep64d7bcb2016-04-07 19:14:09 +02001930FORCE_INLINE
1931U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1932{
1933 U32* const hashTable = zc->hashTable;
1934 const U32 hashLog = zc->params.cParams.hashLog;
1935 U32* const chainTable = zc->chainTable;
1936 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1937 const BYTE* const base = zc->base;
1938 const U32 target = (U32)(ip - base);
1939 U32 idx = zc->nextToUpdate;
1940
Yann Collet22d76322016-06-21 08:01:51 +02001941 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001942 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1943 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1944 hashTable[h] = idx;
1945 idx++;
1946 }
1947
1948 zc->nextToUpdate = target;
1949 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1950}
1951
1952
Nick Terrell55fc1f92017-05-24 13:50:10 -07001953/* inlining is important to hardwire a hot branch (template emulation) */
1954FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001955size_t ZSTD_HcFindBestMatch_generic (
1956 ZSTD_CCtx* zc, /* Index table will be updated */
1957 const BYTE* const ip, const BYTE* const iLimit,
1958 size_t* offsetPtr,
1959 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1960{
1961 U32* const chainTable = zc->chainTable;
1962 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1963 const U32 chainMask = chainSize-1;
1964 const BYTE* const base = zc->base;
1965 const BYTE* const dictBase = zc->dictBase;
1966 const U32 dictLimit = zc->dictLimit;
1967 const BYTE* const prefixStart = base + dictLimit;
1968 const BYTE* const dictEnd = dictBase + dictLimit;
1969 const U32 lowLimit = zc->lowLimit;
1970 const U32 current = (U32)(ip-base);
1971 const U32 minChain = current > chainSize ? current - chainSize : 0;
1972 int nbAttempts=maxNbAttempts;
Yann Collete42afbc2017-04-26 11:39:35 -07001973 size_t ml=4-1;
inikep64d7bcb2016-04-07 19:14:09 +02001974
1975 /* HC4 match finder */
1976 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1977
Yann Collet22d76322016-06-21 08:01:51 +02001978 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02001979 const BYTE* match;
1980 size_t currentMl=0;
1981 if ((!extDict) || matchIndex >= dictLimit) {
1982 match = base + matchIndex;
1983 if (match[ml] == ip[ml]) /* potentially better */
1984 currentMl = ZSTD_count(ip, match, iLimit);
1985 } else {
1986 match = dictBase + matchIndex;
1987 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
Yann Collete42afbc2017-04-26 11:39:35 -07001988 currentMl = ZSTD_count_2segments(ip+4, match+4, iLimit, dictEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02001989 }
1990
1991 /* save best solution */
Yann Colletc17e0202017-04-20 12:50:02 -07001992 if (currentMl > ml) {
1993 ml = currentMl;
1994 *offsetPtr = current - matchIndex + ZSTD_REP_MOVE;
1995 if (ip+currentMl == iLimit) break; /* best possible, avoids read overflow on next attempt */
1996 }
inikep64d7bcb2016-04-07 19:14:09 +02001997
1998 if (matchIndex <= minChain) break;
1999 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
2000 }
2001
2002 return ml;
2003}
2004
2005
2006FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
2007 ZSTD_CCtx* zc,
2008 const BYTE* ip, const BYTE* const iLimit,
2009 size_t* offsetPtr,
2010 const U32 maxNbAttempts, const U32 matchLengthSearch)
2011{
2012 switch(matchLengthSearch)
2013 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002014 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02002015 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
2016 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
Yann Collet933ce4a2017-03-29 14:32:15 -07002017 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02002018 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
2019 }
2020}
2021
2022
2023FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
2024 ZSTD_CCtx* zc,
2025 const BYTE* ip, const BYTE* const iLimit,
2026 size_t* offsetPtr,
2027 const U32 maxNbAttempts, const U32 matchLengthSearch)
2028{
2029 switch(matchLengthSearch)
2030 {
Yann Collet933ce4a2017-03-29 14:32:15 -07002031 default : /* includes case 3 */
inikep64d7bcb2016-04-07 19:14:09 +02002032 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
2033 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
Yann Collet933ce4a2017-03-29 14:32:15 -07002034 case 7 :
inikep64d7bcb2016-04-07 19:14:09 +02002035 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
2036 }
2037}
2038
inikep64d7bcb2016-04-07 19:14:09 +02002039
Yann Collet287b7d92015-11-22 13:24:05 +01002040/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02002041* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02002042*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01002043FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002044void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
2045 const void* src, size_t srcSize,
2046 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01002047{
inikepfaa8d8a2016-04-05 19:01:10 +02002048 seqStore_t* seqStorePtr = &(ctx->seqStore);
2049 const BYTE* const istart = (const BYTE*)src;
2050 const BYTE* ip = istart;
2051 const BYTE* anchor = istart;
2052 const BYTE* const iend = istart + srcSize;
2053 const BYTE* const ilimit = iend - 8;
2054 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002055
Yann Collet793c6492016-04-09 20:32:00 +02002056 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
2057 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01002058
inikep64d7bcb2016-04-07 19:14:09 +02002059 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2060 size_t* offsetPtr,
2061 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02002062 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02002063 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02002064
inikepfaa8d8a2016-04-05 19:01:10 +02002065 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02002066 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02002067 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02002068 { U32 const maxRep = (U32)(ip-base);
2069 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
2070 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
2071 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01002072
inikepfaa8d8a2016-04-05 19:01:10 +02002073 /* Match Loop */
2074 while (ip < ilimit) {
2075 size_t matchLength=0;
2076 size_t offset=0;
2077 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01002078
inikepfaa8d8a2016-04-05 19:01:10 +02002079 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02002080 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02002081 /* repcode : we take it */
Yann Collete42afbc2017-04-26 11:39:35 -07002082 matchLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002083 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01002084 }
Yann Collet5be2dd22015-11-11 13:43:58 +01002085
inikepfaa8d8a2016-04-05 19:01:10 +02002086 /* first search (depth 0) */
2087 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002088 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002089 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002090 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002091 }
Yann Collet5106a762015-11-05 15:00:24 +01002092
Yann Collete42afbc2017-04-26 11:39:35 -07002093 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002094 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2095 continue;
2096 }
2097
inikep64d7bcb2016-04-07 19:14:09 +02002098 /* let's try to find a better solution */
2099 if (depth>=1)
2100 while (ip<ilimit) {
2101 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002102 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002103 size_t const mlRep = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002104 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002105 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002106 if ((mlRep >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002107 matchLength = mlRep, offset = 0, start = ip;
2108 }
2109 { size_t offset2=99999999;
2110 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002111 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2112 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002113 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002114 matchLength = ml2, offset = offset2, start = ip;
2115 continue; /* search a better one */
2116 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002117
inikep64d7bcb2016-04-07 19:14:09 +02002118 /* let's find an even better one */
2119 if ((depth==2) && (ip<ilimit)) {
2120 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02002121 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
Yann Collete42afbc2017-04-26 11:39:35 -07002122 size_t const ml2 = ZSTD_count(ip+4, ip+4-offset_1, iend) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002123 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002124 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002125 if ((ml2 >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002126 matchLength = ml2, offset = 0, start = ip;
2127 }
2128 { size_t offset2=99999999;
2129 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002130 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2131 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002132 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002133 matchLength = ml2, offset = offset2, start = ip;
2134 continue;
2135 } } }
2136 break; /* nothing found : store previous solution */
2137 }
2138
Nick Terrell55f9cd42017-06-19 15:12:28 -07002139 /* NOTE:
2140 * start[-offset+ZSTD_REP_MOVE-1] is undefined behavior.
2141 * (-offset+ZSTD_REP_MOVE-1) is unsigned, and is added to start, which
2142 * overflows the pointer, which is undefined behavior.
2143 */
inikep64d7bcb2016-04-07 19:14:09 +02002144 /* catch up */
2145 if (offset) {
Yann Colletc17e0202017-04-20 12:50:02 -07002146 while ( (start > anchor)
2147 && (start > base+offset-ZSTD_REP_MOVE)
Nick Terrell55f9cd42017-06-19 15:12:28 -07002148 && (start[-1] == (start-offset+ZSTD_REP_MOVE)[-1]) ) /* only search for offset within prefix */
inikep64d7bcb2016-04-07 19:14:09 +02002149 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02002150 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02002151 }
inikepfaa8d8a2016-04-05 19:01:10 +02002152 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002153_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002154 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002155 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002156 anchor = ip = start + matchLength;
2157 }
Yann Collet48537162016-04-07 15:24:29 +02002158
inikepfaa8d8a2016-04-05 19:01:10 +02002159 /* check immediate repcode */
2160 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02002161 && ((offset_2>0)
2162 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02002163 /* store sequence */
Yann Collete42afbc2017-04-26 11:39:35 -07002164 matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet9634f672016-07-03 01:23:58 +02002165 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02002166 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2167 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002168 anchor = ip;
2169 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02002170 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002171
Yann Collet4266c0a2016-06-14 01:49:25 +02002172 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002173 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
2174 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02002175
inikepfaa8d8a2016-04-05 19:01:10 +02002176 /* Last Literals */
2177 { size_t const lastLLSize = iend - anchor;
2178 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2179 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002180 }
Yann Collet5106a762015-11-05 15:00:24 +01002181}
2182
Yann Collet5be2dd22015-11-11 13:43:58 +01002183
inikep64d7bcb2016-04-07 19:14:09 +02002184static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2185{
2186 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2187}
2188
2189static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2190{
2191 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2192}
2193
2194static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2195{
2196 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2197}
2198
2199static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2200{
2201 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2202}
2203
2204
inikepfaa8d8a2016-04-05 19:01:10 +02002205FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002206void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2207 const void* src, size_t srcSize,
2208 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002209{
inikepfaa8d8a2016-04-05 19:01:10 +02002210 seqStore_t* seqStorePtr = &(ctx->seqStore);
2211 const BYTE* const istart = (const BYTE*)src;
2212 const BYTE* ip = istart;
2213 const BYTE* anchor = istart;
2214 const BYTE* const iend = istart + srcSize;
2215 const BYTE* const ilimit = iend - 8;
2216 const BYTE* const base = ctx->base;
2217 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002218 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002219 const BYTE* const prefixStart = base + dictLimit;
2220 const BYTE* const dictBase = ctx->dictBase;
2221 const BYTE* const dictEnd = dictBase + dictLimit;
2222 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2223
2224 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2225 const U32 mls = ctx->params.cParams.searchLength;
2226
inikep64d7bcb2016-04-07 19:14:09 +02002227 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2228 size_t* offsetPtr,
2229 U32 maxNbAttempts, U32 matchLengthSearch);
2230 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2231
Yann Collet302ff032016-07-03 01:28:16 +02002232 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002233
Yann Collet302ff032016-07-03 01:28:16 +02002234 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002235 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002236 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002237
2238 /* Match Loop */
2239 while (ip < ilimit) {
2240 size_t matchLength=0;
2241 size_t offset=0;
2242 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002243 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002244
2245 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002246 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002247 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2248 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002249 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002250 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002251 /* repcode detected we should take it */
2252 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002253 matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002254 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002255 } }
2256
2257 /* first search (depth 0) */
2258 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002259 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002260 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002261 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002262 }
2263
Yann Collete42afbc2017-04-26 11:39:35 -07002264 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002265 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2266 continue;
2267 }
2268
inikep64d7bcb2016-04-07 19:14:09 +02002269 /* let's try to find a better solution */
2270 if (depth>=1)
2271 while (ip<ilimit) {
2272 ip ++;
2273 current++;
2274 /* check repCode */
2275 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002276 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002277 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2278 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002279 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002280 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2281 /* repcode detected */
2282 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002283 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002284 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002285 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002286 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002287 matchLength = repLength, offset = 0, start = ip;
2288 } }
2289
2290 /* search match, depth 1 */
2291 { size_t offset2=99999999;
2292 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002293 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2294 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002295 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002296 matchLength = ml2, offset = offset2, start = ip;
2297 continue; /* search a better one */
2298 } }
2299
2300 /* let's find an even better one */
2301 if ((depth==2) && (ip<ilimit)) {
2302 ip ++;
2303 current++;
2304 /* check repCode */
2305 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002306 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002307 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2308 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002309 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002310 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2311 /* repcode detected */
2312 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002313 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Colletc17e0202017-04-20 12:50:02 -07002314 int const gain2 = (int)(repLength * 4);
2315 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002316 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002317 matchLength = repLength, offset = 0, start = ip;
2318 } }
2319
2320 /* search match, depth 2 */
2321 { size_t offset2=99999999;
2322 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002323 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2324 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002325 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002326 matchLength = ml2, offset = offset2, start = ip;
2327 continue;
2328 } } }
2329 break; /* nothing found : store previous solution */
2330 }
2331
inikepfaa8d8a2016-04-05 19:01:10 +02002332 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002333 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002334 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002335 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2336 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002337 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002338 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002339 }
inikepfaa8d8a2016-04-05 19:01:10 +02002340
inikepfaa8d8a2016-04-05 19:01:10 +02002341 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002342_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002343 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002344 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002345 anchor = ip = start + matchLength;
2346 }
2347
2348 /* check immediate repcode */
2349 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002350 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002351 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2352 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002353 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002354 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2355 /* repcode detected we should take it */
2356 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002357 matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Collet302ff032016-07-03 01:28:16 +02002358 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002359 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2360 ip += matchLength;
2361 anchor = ip;
2362 continue; /* faster when present ... (?) */
2363 }
2364 break;
2365 } }
2366
Yann Collet4266c0a2016-06-14 01:49:25 +02002367 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002368 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002369
inikepfaa8d8a2016-04-05 19:01:10 +02002370 /* Last Literals */
2371 { size_t const lastLLSize = iend - anchor;
2372 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2373 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002374 }
2375}
2376
2377
Yann Collet59d1f792016-01-23 19:28:41 +01002378void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002379{
inikep64d7bcb2016-04-07 19:14:09 +02002380 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002381}
2382
Yann Collet59d1f792016-01-23 19:28:41 +01002383static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002384{
Yann Colleta1249dc2016-01-25 04:22:03 +01002385 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002386}
Yann Collet9a24e592015-11-22 02:53:43 +01002387
Yann Collet59d1f792016-01-23 19:28:41 +01002388static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002389{
Yann Colleta1249dc2016-01-25 04:22:03 +01002390 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002391}
2392
Yann Collet59d1f792016-01-23 19:28:41 +01002393static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002394{
Yann Colleta1249dc2016-01-25 04:22:03 +01002395 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002396}
2397
inikepef519412016-04-21 11:08:43 +02002398
inikepef519412016-04-21 11:08:43 +02002399/* The optimal parser */
2400#include "zstd_opt.h"
2401
2402static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2403{
Yann Colletd4f4e582016-06-27 01:31:35 +02002404#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002405 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2406#else
2407 (void)ctx; (void)src; (void)srcSize;
2408 return;
2409#endif
2410}
2411
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002412static void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002413{
2414#ifdef ZSTD_OPT_H_91842398743
2415 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002416#else
2417 (void)ctx; (void)src; (void)srcSize;
2418 return;
2419#endif
inikepef519412016-04-21 11:08:43 +02002420}
2421
inikepd3b8d7a2016-02-22 10:06:17 +01002422static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002423{
Yann Colletd4f4e582016-06-27 01:31:35 +02002424#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002425 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2426#else
2427 (void)ctx; (void)src; (void)srcSize;
2428 return;
2429#endif
2430}
2431
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002432static void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002433{
2434#ifdef ZSTD_OPT_H_91842398743
2435 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002436#else
2437 (void)ctx; (void)src; (void)srcSize;
2438 return;
2439#endif
inikepe2bfe242016-01-31 11:25:48 +01002440}
2441
Yann Collet7a231792015-11-21 15:27:35 +01002442
Yann Collet59d1f792016-01-23 19:28:41 +01002443typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002444
Yann Colletb923f652016-01-26 03:14:20 +01002445static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002446{
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002447 static const ZSTD_blockCompressor blockCompressor[2][8] = {
Yann Colletc17e0202017-04-20 12:50:02 -07002448 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy,
2449 ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002450 ZSTD_compressBlock_btopt, ZSTD_compressBlock_btultra },
Yann Colletc17e0202017-04-20 12:50:02 -07002451 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict,
2452 ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002453 ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01002454 };
2455
2456 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002457}
2458
2459
Yann Colletd1b26842016-03-15 01:24:33 +01002460static 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 +01002461{
Yann Collet19cab462016-06-17 12:54:52 +02002462 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002463 const BYTE* const base = zc->base;
2464 const BYTE* const istart = (const BYTE*)src;
2465 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002466 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 +02002467 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002468 if (current > zc->nextToUpdate + 384)
Yann Colletc17e0202017-04-20 12:50:02 -07002469 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 +01002470 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002471 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002472}
2473
2474
Yann Colletc991cc12016-07-28 00:55:43 +02002475/*! ZSTD_compress_generic() :
2476* Compress a chunk of data into one or multiple blocks.
2477* All blocks will be terminated, all input will be consumed.
2478* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2479* Frame is supposed already started (header already produced)
2480* @return : compressed size, or an error code
2481*/
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002482static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2483 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002484 const void* src, size_t srcSize,
2485 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002486{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002487 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002488 size_t remaining = srcSize;
2489 const BYTE* ip = (const BYTE*)src;
2490 BYTE* const ostart = (BYTE*)dst;
2491 BYTE* op = ostart;
Yann Colletd4180ca2016-07-27 21:21:36 +02002492 U32 const maxDist = 1 << cctx->params.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002493
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002494 if (cctx->params.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002495 XXH64_update(&cctx->xxhState, src, srcSize);
2496
Yann Collet2ce49232016-02-02 14:36:49 +01002497 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002498 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002499 size_t cSize;
2500
Yann Colletc17e0202017-04-20 12:50:02 -07002501 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
2502 return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01002503 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002504
Yann Collet346efcc2016-08-02 14:26:00 +02002505 /* preemptive overflow correction */
Sean Purcell881abe42017-03-07 16:52:23 -08002506 if (cctx->lowLimit > (3U<<29)) {
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002507 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002508 U32 const current = (U32)(ip - cctx->base);
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002509 U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002510 U32 const correction = current - newCurrent;
2511 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002512 ZSTD_reduceIndex(cctx, correction);
2513 cctx->base += correction;
2514 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002515 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002516 cctx->dictLimit -= correction;
2517 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2518 else cctx->nextToUpdate -= correction;
2519 }
2520
Yann Collet06e76972017-01-25 16:39:03 -08002521 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002522 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002523 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2524 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2525 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002526 }
Yann Collet89db5e02015-11-13 11:27:46 +01002527
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002528 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002529 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002530
Yann Collet2ce49232016-02-02 14:36:49 +01002531 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002532 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2533 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2534 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2535 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2536 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002537 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002538 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002539 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002540 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002541 }
2542
2543 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002544 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002545 ip += blockSize;
2546 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002547 }
2548
Yann Collet62470b42016-07-28 15:29:08 +02002549 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002550 return op-ostart;
2551}
2552
2553
Yann Collet6236eba2016-04-12 15:52:33 +02002554static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002555 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002556{ BYTE* const op = (BYTE*)dst;
Yann Collet31533ba2017-04-27 00:29:04 -07002557 U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2558 U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002559 U32 const checksumFlag = params.fParams.checksumFlag>0;
2560 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002561 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002562 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2563 U32 const fcsCode = params.fParams.contentSizeFlag ?
Nick Terrell55fc1f92017-05-24 13:50:10 -07002564 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002565 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002566 size_t pos;
2567
2568 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet0be6fd32017-05-08 16:08:01 -07002569 DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u \n",
2570 !params.fParams.noDictIDFlag, dictID, dictIDSizeCode);
Yann Collet6236eba2016-04-12 15:52:33 +02002571
2572 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002573 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002574 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002575 switch(dictIDSizeCode)
2576 {
2577 default: /* impossible */
2578 case 0 : break;
2579 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002580 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002581 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2582 }
Yann Collet673f0d72016-06-06 00:26:38 +02002583 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002584 {
2585 default: /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002586 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002587 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2588 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002589 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002590 }
Yann Colletc46fb922016-05-29 05:01:04 +02002591 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002592}
2593
2594
Yann Collet346efcc2016-08-02 14:26:00 +02002595static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002596 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002597 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002598 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002599{
Yann Collet2acb5d32015-10-29 16:49:43 +01002600 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002601 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002602
Yann Collet346efcc2016-08-02 14:26:00 +02002603 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002604
Yann Collet346efcc2016-08-02 14:26:00 +02002605 if (frame && (cctx->stage==ZSTDcs_init)) {
2606 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002607 if (ZSTD_isError(fhSize)) return fhSize;
2608 dstCapacity -= fhSize;
2609 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002610 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002611 }
Yann Colletf3eca252015-10-22 15:31:46 +01002612
Yann Collet417890c2015-12-04 17:16:37 +01002613 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002614 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002615 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002616 ptrdiff_t const delta = cctx->nextSrc - ip;
2617 cctx->lowLimit = cctx->dictLimit;
2618 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2619 cctx->dictBase = cctx->base;
2620 cctx->base -= delta;
2621 cctx->nextToUpdate = cctx->dictLimit;
2622 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002623 }
2624
Yann Collet346efcc2016-08-02 14:26:00 +02002625 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2626 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2627 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2628 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2629 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002630 }
2631
Yann Collet346efcc2016-08-02 14:26:00 +02002632 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002633
Yann Collet5eb749e2017-01-11 18:21:25 +01002634 if (srcSize) {
2635 size_t const cSize = frame ?
Yann Collet346efcc2016-08-02 14:26:00 +02002636 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2637 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002638 if (ZSTD_isError(cSize)) return cSize;
Yann Collet20d5e032017-04-11 18:34:02 -07002639 cctx->consumedSrcSize += srcSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002640 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01002641 } else
2642 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002643}
2644
Yann Colletbf42c8e2016-01-09 01:08:23 +01002645
Yann Collet5b567392016-07-28 01:17:22 +02002646size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002647 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002648 const void* src, size_t srcSize)
2649{
Yann Collet20d5e032017-04-11 18:34:02 -07002650 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
Yann Collet5b567392016-07-28 01:17:22 +02002651}
2652
2653
Yann Colletcf05b9d2016-07-18 16:52:10 +02002654size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002655{
Yann Colletcf05b9d2016-07-18 16:52:10 +02002656 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
2657}
2658
2659size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2660{
2661 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002662 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07002663 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002664}
2665
Yann Collet16a0b102017-03-24 12:46:46 -07002666/*! ZSTD_loadDictionaryContent() :
2667 * @return : 0, or an error code
2668 */
Yann Colletb923f652016-01-26 03:14:20 +01002669static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002670{
2671 const BYTE* const ip = (const BYTE*) src;
2672 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002673
Yann Collet417890c2015-12-04 17:16:37 +01002674 /* input becomes current prefix */
2675 zc->lowLimit = zc->dictLimit;
2676 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2677 zc->dictBase = zc->base;
2678 zc->base += ip - zc->nextSrc;
2679 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08002680 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002681
2682 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002683 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002684
Yann Collet3b719252016-03-30 19:48:05 +02002685 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002686 {
2687 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002688 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002689 break;
2690
Yann Collet45dc3562016-07-12 09:47:31 +02002691 case ZSTD_dfast:
2692 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2693 break;
2694
Yann Collet417890c2015-12-04 17:16:37 +01002695 case ZSTD_greedy:
2696 case ZSTD_lazy:
2697 case ZSTD_lazy2:
Yann Collet16a0b102017-03-24 12:46:46 -07002698 if (srcSize >= HASH_READ_SIZE)
2699 ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002700 break;
2701
2702 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002703 case ZSTD_btopt:
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002704 case ZSTD_btultra:
Yann Collet16a0b102017-03-24 12:46:46 -07002705 if (srcSize >= HASH_READ_SIZE)
2706 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002707 break;
2708
2709 default:
2710 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2711 }
2712
Nick Terrellecf90ca2017-02-13 18:27:34 -08002713 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002714 return 0;
2715}
2716
2717
Nick Terrellf9c9af32016-10-19 17:22:08 -07002718/* Dictionaries that assign zero probability to symbols that show up causes problems
2719 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2720 that we may encounter during compression.
2721 NOTE: This behavior is not standard and could be improved in the future. */
2722static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2723 U32 s;
2724 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
2725 for (s = 0; s <= maxSymbolValue; ++s) {
2726 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
2727 }
2728 return 0;
2729}
2730
2731
Yann Colletb923f652016-01-26 03:14:20 +01002732/* Dictionary format :
Yann Colletbea78e82017-03-22 18:09:11 -07002733 * See :
2734 * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
2735 */
Yann Collet16a0b102017-03-24 12:46:46 -07002736/*! ZSTD_loadZstdDictionary() :
2737 * @return : 0, or an error code
2738 * assumptions : magic number supposed already checked
2739 * dictSize supposed > 8
Yann Colletbea78e82017-03-22 18:09:11 -07002740 */
Yann Collet16a0b102017-03-24 12:46:46 -07002741static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002742{
Yann Collet52a06222016-06-15 13:53:34 +02002743 const BYTE* dictPtr = (const BYTE*)dict;
2744 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07002745 short offcodeNCount[MaxOff+1];
2746 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08002747 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01002748
Yann Colletbea78e82017-03-22 18:09:11 -07002749 dictPtr += 4; /* skip magic number */
2750 cctx->dictID = cctx->params.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
2751 dictPtr += 4;
2752
Yann Collet71ddeb62017-04-20 22:54:54 -07002753 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufCTable, 255, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002754 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002755 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002756 }
Yann Colletfb810d62016-01-28 00:18:06 +01002757
Nick Terrellf9c9af32016-10-19 17:22:08 -07002758 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02002759 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002760 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002761 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002762 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Colletc17e0202017-04-20 12:50:02 -07002763 CHECK_E( FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)),
2764 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002765 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002766 }
Yann Colletfb810d62016-01-28 00:18:06 +01002767
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002768 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002769 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002770 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002771 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002772 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002773 /* Every match length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07002774 CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
2775 CHECK_E( FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)),
2776 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002777 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002778 }
Yann Colletfb810d62016-01-28 00:18:06 +01002779
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002780 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002781 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002782 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002783 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002784 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002785 /* Every literal length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07002786 CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
2787 CHECK_E( FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)),
2788 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002789 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002790 }
Yann Colletfb810d62016-01-28 00:18:06 +01002791
Yann Collet52a06222016-06-15 13:53:34 +02002792 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07002793 cctx->rep[0] = MEM_readLE32(dictPtr+0);
2794 cctx->rep[1] = MEM_readLE32(dictPtr+4);
2795 cctx->rep[2] = MEM_readLE32(dictPtr+8);
Yann Collet52a06222016-06-15 13:53:34 +02002796 dictPtr += 12;
2797
Yann Colletbea78e82017-03-22 18:09:11 -07002798 { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
2799 U32 offcodeMax = MaxOff;
2800 if (dictContentSize <= ((U32)-1) - 128 KB) {
2801 U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
2802 offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
Nick Terrellb2c39a22016-10-24 14:11:27 -07002803 }
Yann Colletbea78e82017-03-22 18:09:11 -07002804 /* All offset values <= dictContentSize + 128 KB must be representable */
Nick Terrellf9c9af32016-10-19 17:22:08 -07002805 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
Yann Colletbea78e82017-03-22 18:09:11 -07002806 /* All repCodes must be <= dictContentSize and != 0*/
2807 { U32 u;
2808 for (u=0; u<3; u++) {
2809 if (cctx->rep[u] == 0) return ERROR(dictionary_corrupted);
2810 if (cctx->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07002811 } }
Nick Terrellf9c9af32016-10-19 17:22:08 -07002812
Yann Collet71ddeb62017-04-20 22:54:54 -07002813 cctx->fseCTables_ready = 1;
2814 cctx->hufCTable_repeatMode = HUF_repeat_valid;
Yann Collet16a0b102017-03-24 12:46:46 -07002815 return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
2816 }
Yann Colletb923f652016-01-26 03:14:20 +01002817}
2818
Yann Colletd1b26842016-03-15 01:24:33 +01002819/** ZSTD_compress_insertDictionary() :
2820* @return : 0, or an error code */
Yann Collet16a0b102017-03-24 12:46:46 -07002821static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002822{
Yann Colletc46fb922016-05-29 05:01:04 +02002823 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002824
Yann Collet14312d82017-02-23 23:42:12 -08002825 /* dict as pure content */
Yann Collet16a0b102017-03-24 12:46:46 -07002826 if ((MEM_readLE32(dict) != ZSTD_DICT_MAGIC) || (cctx->forceRawDict))
2827 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002828
Yann Colletbea78e82017-03-22 18:09:11 -07002829 /* dict as zstd dictionary */
Yann Collet16a0b102017-03-24 12:46:46 -07002830 return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002831}
2832
Yann Collet27caf2a2016-04-01 15:48:48 +02002833/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002834* @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02002835static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01002836 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002837 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002838{
Yann Colleta7737f62016-09-06 09:44:59 +02002839 ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
Yann Colletab9162e2017-04-11 10:46:20 -07002840 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet30fb4992017-04-18 14:08:50 -07002841 CHECK_F(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, crp));
Yann Colleta7737f62016-09-06 09:44:59 +02002842 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002843}
2844
2845
Yann Collet27caf2a2016-04-01 15:48:48 +02002846/*! ZSTD_compressBegin_advanced() :
2847* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002848size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002849 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02002850 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02002851{
2852 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02002853 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet81e13ef2016-06-07 00:51:51 +02002854 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002855}
2856
2857
Yann Collet81e13ef2016-06-07 00:51:51 +02002858size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002859{
Yann Collet6c6e1752016-06-27 15:28:45 +02002860 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002861 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002862}
Yann Collet083fcc82015-10-25 14:06:35 +01002863
inikep19bd48f2016-04-04 12:10:00 +02002864
Yann Colletb05c4822017-01-12 02:01:28 +01002865size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002866{
Yann Colletb05c4822017-01-12 02:01:28 +01002867 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002868}
2869
2870
Yann Collet62470b42016-07-28 15:29:08 +02002871/*! ZSTD_writeEpilogue() :
2872* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01002873* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02002874static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002875{
Yann Colletc991cc12016-07-28 00:55:43 +02002876 BYTE* const ostart = (BYTE*)dst;
2877 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02002878 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002879
Yann Collet0be6fd32017-05-08 16:08:01 -07002880 DEBUGLOG(5, "ZSTD_writeEpilogue \n");
Yann Collet87c18b22016-08-26 01:43:47 +02002881 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02002882
2883 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02002884 if (cctx->stage == ZSTDcs_init) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002885 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002886 if (ZSTD_isError(fhSize)) return fhSize;
2887 dstCapacity -= fhSize;
2888 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02002889 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002890 }
2891
Yann Colletc991cc12016-07-28 00:55:43 +02002892 if (cctx->stage != ZSTDcs_ending) {
2893 /* write one last empty block, make it the "last" block */
2894 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2895 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2896 MEM_writeLE32(op, cBlockHeader24);
2897 op += ZSTD_blockHeaderSize;
2898 dstCapacity -= ZSTD_blockHeaderSize;
2899 }
2900
2901 if (cctx->params.fParams.checksumFlag) {
2902 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2903 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2904 MEM_writeLE32(op, checksum);
2905 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002906 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002907
Yann Collet731ef162016-07-27 21:05:12 +02002908 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02002909 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01002910}
2911
Yann Colletfd416f12016-01-30 03:14:15 +01002912
Yann Collet62470b42016-07-28 15:29:08 +02002913size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2914 void* dst, size_t dstCapacity,
2915 const void* src, size_t srcSize)
2916{
2917 size_t endResult;
Yann Collet0be6fd32017-05-08 16:08:01 -07002918 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize,
2919 1 /* frame mode */, 1 /* last chunk */);
Yann Collet62470b42016-07-28 15:29:08 +02002920 if (ZSTD_isError(cSize)) return cSize;
2921 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2922 if (ZSTD_isError(endResult)) return endResult;
Yann Collet20d5e032017-04-11 18:34:02 -07002923 if (cctx->params.fParams.contentSizeFlag) { /* control src size */
Yann Collet0be6fd32017-05-08 16:08:01 -07002924 if (cctx->frameContentSize != cctx->consumedSrcSize)
2925 return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07002926 }
Yann Collet62470b42016-07-28 15:29:08 +02002927 return cSize + endResult;
2928}
2929
2930
Yann Collet19c10022016-07-28 01:25:46 +02002931static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002932 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002933 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002934 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002935 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002936{
Yann Collet3e21ec52016-09-06 15:36:19 +02002937 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize));
Yann Collet62470b42016-07-28 15:29:08 +02002938 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002939}
2940
Yann Collet21588e32016-03-30 16:50:44 +02002941size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2942 void* dst, size_t dstCapacity,
2943 const void* src, size_t srcSize,
2944 const void* dict,size_t dictSize,
2945 ZSTD_parameters params)
2946{
Yann Colletcf409a72016-09-26 16:41:05 +02002947 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02002948 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2949}
2950
Yann Colletc17e0202017-04-20 12:50:02 -07002951size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
2952 const void* dict, size_t dictSize, int compressionLevel)
Yann Collet31683c02015-12-18 01:26:48 +01002953{
Yann Collet407a11f2016-11-03 15:52:01 -07002954 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02002955 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002956 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002957}
2958
Yann Colletd1b26842016-03-15 01:24:33 +01002959size_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 +01002960{
Yann Collet21588e32016-03-30 16:50:44 +02002961 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002962}
2963
Yann Colletd1b26842016-03-15 01:24:33 +01002964size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002965{
Yann Collet44fe9912015-10-29 22:02:40 +01002966 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002967 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002968 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002969 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002970 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Collet23b6e052016-08-28 21:05:43 -07002971 ZSTD_free(ctxBody.workSpace, defaultCustomMem); /* can't free ctxBody itself, as it's on stack; free only heap content */
Yann Collet44fe9912015-10-29 22:02:40 +01002972 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002973}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002974
Yann Colletfd416f12016-01-30 03:14:15 +01002975
Yann Collet81e13ef2016-06-07 00:51:51 +02002976/* ===== Dictionary API ===== */
2977
2978struct ZSTD_CDict_s {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002979 void* dictBuffer;
2980 const void* dictContent;
Yann Collet81e13ef2016-06-07 00:51:51 +02002981 size_t dictContentSize;
2982 ZSTD_CCtx* refContext;
David Lamda9d3b72016-08-29 09:03:12 -07002983}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
Yann Collet81e13ef2016-06-07 00:51:51 +02002984
Yann Colleta1d67042017-05-08 17:51:49 -07002985/*! ZSTD_estimateCDictSize() :
2986 * Estimate amount of memory that will be needed to create a dictionary with following arguments */
2987size_t ZSTD_estimateCDictSize(ZSTD_compressionParameters cParams, size_t dictSize)
2988{
2989 cParams = ZSTD_adjustCParams(cParams, 0, dictSize);
Yann Colletfa8dadb2017-05-08 18:24:16 -07002990 return sizeof(ZSTD_CDict) + dictSize + ZSTD_estimateCCtxSize(cParams);
Yann Colleta1d67042017-05-08 17:51:49 -07002991}
2992
Yann Colletd7c65892016-09-15 02:50:27 +02002993size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2994{
2995 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Colletaca113f2016-12-23 22:25:03 +01002996 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02002997}
2998
Yann Collet1c3ab0c2017-04-27 12:57:11 -07002999static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_frameParameters fParams)
3000{
3001 ZSTD_parameters params;
3002 params.cParams = cParams;
3003 params.fParams = fParams;
3004 return params;
3005}
3006
Yann Collet1f57c2e2016-12-21 16:20:11 +01003007ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
Yann Collet31533ba2017-04-27 00:29:04 -07003008 ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02003009{
Yann Collet23b6e052016-08-28 21:05:43 -07003010 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
3011 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02003012
Yann Collet23b6e052016-08-28 21:05:43 -07003013 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02003014 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
3015
Yann Collet1f57c2e2016-12-21 16:20:11 +01003016 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07003017 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01003018 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02003019 return NULL;
3020 }
3021
Yann Collet1f57c2e2016-12-21 16:20:11 +01003022 if ((byReference) || (!dictBuffer) || (!dictSize)) {
3023 cdict->dictBuffer = NULL;
3024 cdict->dictContent = dictBuffer;
Yann Collet1f57c2e2016-12-21 16:20:11 +01003025 } else {
3026 void* const internalBuffer = ZSTD_malloc(dictSize, customMem);
Yann Collet4e5eea62016-12-21 16:44:35 +01003027 if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; }
Yann Collet1f57c2e2016-12-21 16:20:11 +01003028 memcpy(internalBuffer, dictBuffer, dictSize);
3029 cdict->dictBuffer = internalBuffer;
3030 cdict->dictContent = internalBuffer;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07003031 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01003032
Yann Collet31533ba2017-04-27 00:29:04 -07003033 { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */
Yann Collet1c3ab0c2017-04-27 12:57:11 -07003034 ZSTD_parameters const params = ZSTD_makeParams(cParams, fParams);
Yann Collet31533ba2017-04-27 00:29:04 -07003035 size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
Yann Collet81e13ef2016-06-07 00:51:51 +02003036 if (ZSTD_isError(errorCode)) {
Yann Collet1f57c2e2016-12-21 16:20:11 +01003037 ZSTD_free(cdict->dictBuffer, customMem);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003038 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01003039 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02003040 return NULL;
3041 } }
3042
Yann Collet81e13ef2016-06-07 00:51:51 +02003043 cdict->refContext = cctx;
Yann Collet1f57c2e2016-12-21 16:20:11 +01003044 cdict->dictContentSize = dictSize;
Yann Collet81e13ef2016-06-07 00:51:51 +02003045 return cdict;
3046 }
3047}
3048
3049ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
3050{
3051 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet31533ba2017-04-27 00:29:04 -07003052 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
3053 return ZSTD_createCDict_advanced(dict, dictSize, 0, cParams, allocator);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003054}
3055
3056ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
3057{
3058 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet31533ba2017-04-27 00:29:04 -07003059 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
3060 return ZSTD_createCDict_advanced(dict, dictSize, 1, cParams, allocator);
Yann Collet81e13ef2016-06-07 00:51:51 +02003061}
3062
3063size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
3064{
Yann Collet23b6e052016-08-28 21:05:43 -07003065 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02003066 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07003067 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01003068 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003069 ZSTD_free(cdict, cMem);
3070 return 0;
3071 }
Yann Collet81e13ef2016-06-07 00:51:51 +02003072}
3073
Yann Collet95162342016-10-25 16:19:52 -07003074static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
3075 return ZSTD_getParamsFromCCtx(cdict->refContext);
3076}
3077
Yann Collet715b9aa2017-04-18 13:55:53 -07003078/* ZSTD_compressBegin_usingCDict_advanced() :
Yann Collet4f818182017-04-17 17:57:35 -07003079 * cdict must be != NULL */
Yann Collet715b9aa2017-04-18 13:55:53 -07003080size_t ZSTD_compressBegin_usingCDict_advanced(
Yann Collet4f818182017-04-17 17:57:35 -07003081 ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
3082 ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003083{
Yann Collet7cf78f12017-04-04 12:38:14 -07003084 if (cdict==NULL) return ERROR(GENERIC); /* does not support NULL cdict */
Yann Collet31533ba2017-04-27 00:29:04 -07003085 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced : dictIDFlag == %u \n", !fParams.noDictIDFlag);
Yann Collet4f818182017-04-17 17:57:35 -07003086 if (cdict->dictContentSize)
Yann Colleta4cab802017-04-18 14:54:54 -07003087 CHECK_F( ZSTD_copyCCtx_internal(cctx, cdict->refContext, fParams, pledgedSrcSize) )
Sean Purcell2db72492017-02-09 10:50:43 -08003088 else {
3089 ZSTD_parameters params = cdict->refContext->params;
Yann Collet4f818182017-04-17 17:57:35 -07003090 params.fParams = fParams;
Yann Colletab9162e2017-04-11 10:46:20 -07003091 CHECK_F(ZSTD_compressBegin_internal(cctx, NULL, 0, params, pledgedSrcSize));
Sean Purcell2db72492017-02-09 10:50:43 -08003092 }
Yann Collet4cb21292016-09-15 14:54:07 +02003093 return 0;
3094}
3095
Yann Collet4f818182017-04-17 17:57:35 -07003096/* ZSTD_compressBegin_usingCDict() :
3097 * pledgedSrcSize=0 means "unknown"
3098 * if pledgedSrcSize>0, it will enable contentSizeFlag */
Yann Collet768df122017-04-26 15:42:10 -07003099size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
Yann Collet4f818182017-04-17 17:57:35 -07003100{
Yann Collet768df122017-04-26 15:42:10 -07003101 ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Collet31533ba2017-04-27 00:29:04 -07003102 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u \n", !fParams.noDictIDFlag);
Yann Collet768df122017-04-26 15:42:10 -07003103 return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0);
Yann Collet4f818182017-04-17 17:57:35 -07003104}
3105
Yann Colletf4bd8572017-04-27 11:31:55 -07003106size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
3107 void* dst, size_t dstCapacity,
3108 const void* src, size_t srcSize,
3109 const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
3110{
3111 CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */
3112 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02003113}
3114
Yann Collet07639052016-08-03 01:57:57 +02003115/*! ZSTD_compress_usingCDict() :
Yann Collet4f818182017-04-17 17:57:35 -07003116 * Compression using a digested Dictionary.
3117 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
3118 * Note that compression parameters are decided at CDict creation time
3119 * while frame parameters are hardcoded */
Yann Collet4cb21292016-09-15 14:54:07 +02003120size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
3121 void* dst, size_t dstCapacity,
3122 const void* src, size_t srcSize,
3123 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02003124{
Yann Collet4f818182017-04-17 17:57:35 -07003125 ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Colletf4bd8572017-04-27 11:31:55 -07003126 return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
Yann Collet81e13ef2016-06-07 00:51:51 +02003127}
3128
3129
3130
Yann Collet104e5b02016-08-12 13:04:27 +02003131/* ******************************************************************
3132* Streaming
3133********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003134
Yann Collet5a0c8e22016-08-12 01:20:36 +02003135ZSTD_CStream* ZSTD_createCStream(void)
3136{
3137 return ZSTD_createCStream_advanced(defaultCustomMem);
3138}
3139
3140ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
3141{
Yann Collet6fb2f242017-05-10 11:06:06 -07003142 /* CStream and CCtx are now same object */
3143 return ZSTD_createCCtx_advanced(customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003144}
3145
3146size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
3147{
Yann Collet78553662017-05-08 17:15:00 -07003148 return ZSTD_freeCCtx(zcs); /* same object */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003149}
3150
Yann Colletfa8dadb2017-05-08 18:24:16 -07003151size_t ZSTD_estimateCStreamSize(ZSTD_compressionParameters cParams)
3152{
3153 size_t const CCtxSize = ZSTD_estimateCCtxSize(cParams);
3154 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
3155 size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
3156 size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
3157 size_t const streamingSize = inBuffSize + outBuffSize;
3158
Yann Collet669346f2017-05-10 11:08:00 -07003159 return CCtxSize + streamingSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003160}
3161
3162
Yann Collet104e5b02016-08-12 13:04:27 +02003163/*====== Initialization ======*/
3164
3165size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003166
Yann Colletc17e0202017-04-20 12:50:02 -07003167size_t ZSTD_CStreamOutSize(void)
3168{
3169 return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
3170}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003171
Yann Collet0be6fd32017-05-08 16:08:01 -07003172static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003173{
Yann Colletd564faa2016-12-18 21:39:15 +01003174 if (zcs->inBuffSize==0) return ERROR(stage_wrong); /* zcs has not been init at least once => can't reset */
Yann Colletee5b7252016-10-27 14:20:55 -07003175
Yann Collet31533ba2017-04-27 00:29:04 -07003176 DEBUGLOG(5, "ZSTD_resetCStream_internal : dictIDFlag == %u \n", !zcs->params.fParams.noDictIDFlag);
3177
Yann Collet0be6fd32017-05-08 16:08:01 -07003178 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict_advanced(zcs, zcs->cdict, params.fParams, pledgedSrcSize))
3179 else CHECK_F(ZSTD_compressBegin_internal(zcs, NULL, 0, params, pledgedSrcSize));
Yann Collet4cb21292016-09-15 14:54:07 +02003180
3181 zcs->inToCompress = 0;
3182 zcs->inBuffPos = 0;
3183 zcs->inBuffTarget = zcs->blockSize;
3184 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -07003185 zcs->streamStage = zcss_load;
Yann Collet4cb21292016-09-15 14:54:07 +02003186 zcs->frameEnded = 0;
Yann Collete795c8a2016-12-13 16:39:36 +01003187 zcs->pledgedSrcSize = pledgedSrcSize;
Yann Collet4cb21292016-09-15 14:54:07 +02003188 return 0; /* ready to go */
3189}
3190
Sean Purcell2db72492017-02-09 10:50:43 -08003191size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
3192{
3193
Yann Collet0be6fd32017-05-08 16:08:01 -07003194 ZSTD_parameters params = zcs->params;
3195 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
Yann Collet31533ba2017-04-27 00:29:04 -07003196 DEBUGLOG(5, "ZSTD_resetCStream : dictIDFlag == %u \n", !zcs->params.fParams.noDictIDFlag);
Yann Collet0be6fd32017-05-08 16:08:01 -07003197 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Sean Purcell2db72492017-02-09 10:50:43 -08003198}
Sean Purcell2db72492017-02-09 10:50:43 -08003199
Yann Collet4b987ad2017-04-10 17:50:44 -07003200/* ZSTD_initCStream_internal() :
Yann Collete88034f2017-04-10 22:24:02 -07003201 * params are supposed validated at this stage
3202 * and zcs->cdict is supposed to be correct */
3203static size_t ZSTD_initCStream_stage2(ZSTD_CStream* zcs,
3204 const ZSTD_parameters params,
3205 unsigned long long pledgedSrcSize)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003206{
Yann Collet4b987ad2017-04-10 17:50:44 -07003207 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Colletfc514592017-05-08 17:07:59 -07003208 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
Yann Collete88034f2017-04-10 22:24:02 -07003209
Yann Collet5a0c8e22016-08-12 01:20:36 +02003210 /* allocate buffers */
Yann Colletfc514592017-05-08 17:07:59 -07003211 { size_t const neededInBuffSize = ((size_t)1 << params.cParams.windowLog) + zcs->blockSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003212 if (zcs->inBuffSize < neededInBuffSize) {
Yann Collet02d37aa2017-04-05 14:53:51 -07003213 zcs->inBuffSize = 0;
Yann Colletcf409a72016-09-26 16:41:05 +02003214 ZSTD_free(zcs->inBuff, zcs->customMem);
Yann Colletfc514592017-05-08 17:07:59 -07003215 zcs->inBuff = (char*)ZSTD_malloc(neededInBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003216 if (zcs->inBuff == NULL) return ERROR(memory_allocation);
Yann Collet02d37aa2017-04-05 14:53:51 -07003217 zcs->inBuffSize = neededInBuffSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003218 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003219 }
3220 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
Yann Collet02d37aa2017-04-05 14:53:51 -07003221 size_t const outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
3222 zcs->outBuffSize = 0;
Yann Colletcf409a72016-09-26 16:41:05 +02003223 ZSTD_free(zcs->outBuff, zcs->customMem);
Yann Colletfc514592017-05-08 17:07:59 -07003224 zcs->outBuff = (char*)ZSTD_malloc(outBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003225 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
Yann Collet02d37aa2017-04-05 14:53:51 -07003226 zcs->outBuffSize = outBuffSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003227 }
3228
Yann Collet31533ba2017-04-27 00:29:04 -07003229 DEBUGLOG(5, "ZSTD_initCStream_stage2 : dictIDFlag == %u \n", !params.fParams.noDictIDFlag);
Yann Collet0be6fd32017-05-08 16:08:01 -07003230 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003231}
3232
Yann Collet77bf59e2017-04-27 11:43:04 -07003233/* ZSTD_initCStream_usingCDict_advanced() :
3234 * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
3235size_t ZSTD_initCStream_usingCDict_advanced(ZSTD_CStream* zcs, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize, ZSTD_frameParameters fParams)
Yann Collete88034f2017-04-10 22:24:02 -07003236{
3237 if (!cdict) return ERROR(GENERIC); /* cannot handle NULL cdict (does not know what to do) */
Yann Collet4ee6b152017-04-11 11:59:44 -07003238 { ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict);
Yann Collet77bf59e2017-04-27 11:43:04 -07003239 params.fParams = fParams;
Yann Collete88034f2017-04-10 22:24:02 -07003240 zcs->cdict = cdict;
Yann Collet77bf59e2017-04-27 11:43:04 -07003241 return ZSTD_initCStream_stage2(zcs, params, pledgedSrcSize);
Yann Collete88034f2017-04-10 22:24:02 -07003242 }
3243}
3244
Yann Collete88034f2017-04-10 22:24:02 -07003245/* note : cdict must outlive compression session */
3246size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3247{
Yann Collet77bf59e2017-04-27 11:43:04 -07003248 ZSTD_frameParameters const fParams = { 0 /* content */, 0 /* checksum */, 0 /* noDictID */ };
3249 return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, 0, fParams);
Yann Collete88034f2017-04-10 22:24:02 -07003250}
3251
3252static size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
3253 const void* dict, size_t dictSize,
3254 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3255{
3256 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
3257 zcs->cdict = NULL;
3258
3259 if (dict && dictSize >= 8) {
3260 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet31533ba2017-04-27 00:29:04 -07003261 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0 /* copy */, params.cParams, zcs->customMem);
Yann Collete88034f2017-04-10 22:24:02 -07003262 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
3263 zcs->cdict = zcs->cdictLocal;
3264 }
3265
Yann Collet31533ba2017-04-27 00:29:04 -07003266 DEBUGLOG(5, "ZSTD_initCStream_internal : dictIDFlag == %u \n", !params.fParams.noDictIDFlag);
Yann Collete88034f2017-04-10 22:24:02 -07003267 return ZSTD_initCStream_stage2(zcs, params, pledgedSrcSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003268}
3269
Yann Collet95162342016-10-25 16:19:52 -07003270size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
3271 const void* dict, size_t dictSize,
3272 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3273{
Yann Collet4b987ad2017-04-10 17:50:44 -07003274 CHECK_F( ZSTD_checkCParams(params.cParams) );
Yann Collet0be6fd32017-05-08 16:08:01 -07003275 DEBUGLOG(5, "ZSTD_initCStream_advanced : pledgedSrcSize == %u \n", (U32)pledgedSrcSize);
3276 DEBUGLOG(5, "wlog %u \n", params.cParams.windowLog);
Yann Collet4b987ad2017-04-10 17:50:44 -07003277 return ZSTD_initCStream_internal(zcs, dict, dictSize, params, pledgedSrcSize);
Yann Collet95162342016-10-25 16:19:52 -07003278}
3279
Yann Collet5a0c8e22016-08-12 01:20:36 +02003280size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3281{
3282 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet4b987ad2017-04-10 17:50:44 -07003283 return ZSTD_initCStream_internal(zcs, dict, dictSize, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003284}
3285
Yann Collete795c8a2016-12-13 16:39:36 +01003286size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3287{
Yann Colletd564faa2016-12-18 21:39:15 +01003288 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
Yann Collete88034f2017-04-10 22:24:02 -07003289 params.fParams.contentSizeFlag = (pledgedSrcSize>0);
Yann Collet4b987ad2017-04-10 17:50:44 -07003290 return ZSTD_initCStream_internal(zcs, NULL, 0, params, pledgedSrcSize);
Yann Collete795c8a2016-12-13 16:39:36 +01003291}
3292
Yann Collet5a0c8e22016-08-12 01:20:36 +02003293size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3294{
Yann Collete88034f2017-04-10 22:24:02 -07003295 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0);
3296 return ZSTD_initCStream_internal(zcs, NULL, 0, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003297}
3298
Yann Collet70e3b312016-08-23 01:18:06 +02003299size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
Yann Colletcb327632016-08-23 00:30:31 +02003300{
Yann Collet791d7442017-05-08 16:17:30 -07003301 return ZSTD_sizeof_CCtx(zcs); /* same object */
Yann Colletcb327632016-08-23 00:30:31 +02003302}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003303
Yann Collet104e5b02016-08-12 13:04:27 +02003304/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003305
3306typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
3307
3308MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
3309{
3310 size_t const length = MIN(dstCapacity, srcSize);
3311 memcpy(dst, src, length);
3312 return length;
3313}
3314
3315static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3316 void* dst, size_t* dstCapacityPtr,
3317 const void* src, size_t* srcSizePtr,
3318 ZSTD_flush_e const flush)
3319{
3320 U32 someMoreWork = 1;
3321 const char* const istart = (const char*)src;
3322 const char* const iend = istart + *srcSizePtr;
3323 const char* ip = istart;
3324 char* const ostart = (char*)dst;
3325 char* const oend = ostart + *dstCapacityPtr;
3326 char* op = ostart;
3327
Yann Collet0be6fd32017-05-08 16:08:01 -07003328 DEBUGLOG(5, "ZSTD_compressStream_generic \n");
Yann Collet5a0c8e22016-08-12 01:20:36 +02003329 while (someMoreWork) {
Yann Collet0be6fd32017-05-08 16:08:01 -07003330 switch(zcs->streamStage)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003331 {
3332 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
3333
3334 case zcss_load:
3335 /* complete inBuffer */
3336 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3337 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
Yann Collet0be6fd32017-05-08 16:08:01 -07003338 DEBUGLOG(5, "loading %u/%u \n", (U32)loaded, (U32)toLoad);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003339 zcs->inBuffPos += loaded;
3340 ip += loaded;
3341 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
3342 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
3343 } }
3344 /* compress current block (note : this stage cannot be stopped in the middle) */
Yann Collet0be6fd32017-05-08 16:08:01 -07003345 DEBUGLOG(5, "stream compression stage (flush==%u)\n", flush);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003346 { void* cDst;
3347 size_t cSize;
3348 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3349 size_t oSize = oend-op;
3350 if (oSize >= ZSTD_compressBound(iSize))
3351 cDst = op; /* compress directly into output buffer (avoid flush stage) */
3352 else
3353 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
3354 cSize = (flush == zsf_end) ?
Yann Collet0be6fd32017-05-08 16:08:01 -07003355 ZSTD_compressEnd(zcs, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
3356 ZSTD_compressContinue(zcs, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003357 if (ZSTD_isError(cSize)) return cSize;
Yann Collet0be6fd32017-05-08 16:08:01 -07003358 DEBUGLOG(5, "cSize = %u \n", (U32)cSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003359 if (flush == zsf_end) zcs->frameEnded = 1;
3360 /* prepare next block */
3361 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3362 if (zcs->inBuffTarget > zcs->inBuffSize)
Yann Collet0be6fd32017-05-08 16:08:01 -07003363 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffTarget == blockSize <= inBuffSize */
3364 assert(zcs->inBuffTarget <= zcs->inBuffSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003365 zcs->inToCompress = zcs->inBuffPos;
3366 if (cDst == op) { op += cSize; break; } /* no need to flush */
3367 zcs->outBuffContentSize = cSize;
3368 zcs->outBuffFlushedSize = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -07003369 zcs->streamStage = zcss_flush; /* pass-through to flush stage */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003370 }
Jos Collin7cd7a752017-05-11 13:17:20 +05303371 /* fall-through */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003372 case zcss_flush:
Yann Collet0be6fd32017-05-08 16:08:01 -07003373 DEBUGLOG(5, "flush stage \n");
Yann Collet5a0c8e22016-08-12 01:20:36 +02003374 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3375 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
Yann Collet0be6fd32017-05-08 16:08:01 -07003376 DEBUGLOG(5, "toFlush: %u ; flushed: %u \n", (U32)toFlush, (U32)flushed);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003377 op += flushed;
3378 zcs->outBuffFlushedSize += flushed;
3379 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
3380 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -07003381 zcs->streamStage = zcss_load;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003382 break;
3383 }
3384
3385 case zcss_final:
3386 someMoreWork = 0; /* do nothing */
3387 break;
3388
3389 default:
3390 return ERROR(GENERIC); /* impossible */
3391 }
3392 }
3393
3394 *srcSizePtr = ip - istart;
3395 *dstCapacityPtr = op - ostart;
3396 if (zcs->frameEnded) return 0;
3397 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3398 if (hintInSize==0) hintInSize = zcs->blockSize;
3399 return hintInSize;
3400 }
3401}
3402
Yann Collet53e17fb2016-08-17 01:39:22 +02003403size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003404{
Yann Collet53e17fb2016-08-17 01:39:22 +02003405 size_t sizeRead = input->size - input->pos;
3406 size_t sizeWritten = output->size - output->pos;
3407 size_t const result = ZSTD_compressStream_generic(zcs,
3408 (char*)(output->dst) + output->pos, &sizeWritten,
3409 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
3410 input->pos += sizeRead;
3411 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003412 return result;
3413}
3414
3415
Yann Collet104e5b02016-08-12 13:04:27 +02003416/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003417
3418/*! ZSTD_flushStream() :
3419* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003420size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003421{
3422 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003423 size_t sizeWritten = output->size - output->pos;
Yann Colletc4119022016-08-17 01:50:54 +02003424 size_t const result = ZSTD_compressStream_generic(zcs,
Yann Collet95d07d72016-09-06 16:38:51 +02003425 (char*)(output->dst) + output->pos, &sizeWritten,
3426 &srcSize, &srcSize, /* use a valid src address instead of NULL */
Yann Colletc4119022016-08-17 01:50:54 +02003427 zsf_flush);
Yann Collet53e17fb2016-08-17 01:39:22 +02003428 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003429 if (ZSTD_isError(result)) return result;
3430 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3431}
3432
3433
Yann Collet53e17fb2016-08-17 01:39:22 +02003434size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003435{
Yann Collet53e17fb2016-08-17 01:39:22 +02003436 BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
3437 BYTE* const oend = (BYTE*)(output->dst) + output->size;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003438 BYTE* op = ostart;
3439
Yann Collet0be6fd32017-05-08 16:08:01 -07003440 DEBUGLOG(5, "ZSTD_endStream (dstCapacity : %u) \n", (U32)(oend-op));
3441 if (zcs->streamStage != zcss_final) {
Yann Collet5a0c8e22016-08-12 01:20:36 +02003442 /* flush whatever remains */
3443 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003444 size_t sizeWritten = output->size - output->pos;
Yann Colletc17e0202017-04-20 12:50:02 -07003445 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten,
3446 &srcSize /* use a valid src address instead of NULL */, &srcSize, zsf_end);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003447 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3448 op += sizeWritten;
3449 if (remainingToFlush) {
Yann Collet53e17fb2016-08-17 01:39:22 +02003450 output->pos += sizeWritten;
Yann Collet0be6fd32017-05-08 16:08:01 -07003451 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */
3452 + ((zcs->params.fParams.checksumFlag > 0) * 4) /* optional 32-bits checksum */;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003453 }
3454 /* create epilogue */
Yann Collet0be6fd32017-05-08 16:08:01 -07003455 zcs->streamStage = zcss_final;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003456 zcs->outBuffContentSize = !notEnded ? 0 :
Yann Colletc17e0202017-04-20 12:50:02 -07003457 /* write epilogue, including final empty block, into outBuff */
Yann Collet0be6fd32017-05-08 16:08:01 -07003458 ZSTD_compressEnd(zcs, zcs->outBuff, zcs->outBuffSize, NULL, 0);
Yann Collet88009a82017-04-12 00:51:24 -07003459 if (ZSTD_isError(zcs->outBuffContentSize)) return zcs->outBuffContentSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003460 }
3461
3462 /* flush epilogue */
3463 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3464 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3465 op += flushed;
3466 zcs->outBuffFlushedSize += flushed;
Yann Collet53e17fb2016-08-17 01:39:22 +02003467 output->pos += op-ostart;
Yann Collet0be6fd32017-05-08 16:08:01 -07003468 if (toFlush==flushed) zcs->streamStage = zcss_init; /* end reached */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003469 return toFlush - flushed;
3470 }
3471}
3472
3473
3474
Yann Collet70e8c382016-02-10 13:37:52 +01003475/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003476
Yann Collet236d94f2016-05-18 12:06:33 +02003477#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02003478#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003479int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003480
Yann Collet3b719252016-03-30 19:48:05 +02003481static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003482{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003483 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003484 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003485 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3486 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003487 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3488 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003489 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3490 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3491 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003492 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003493 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3494 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3495 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3496 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3497 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3498 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3499 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3500 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003501 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
Yann Collet29297c62017-04-27 17:44:01 -07003502 { 23, 22, 22, 5, 4, 32, ZSTD_btopt }, /* level 18 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003503 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Nick Terrell374f8682017-05-10 17:48:42 -07003504 { 25, 25, 23, 7, 3, 64, ZSTD_btultra }, /* level 20 */
3505 { 26, 26, 23, 7, 3,256, ZSTD_btultra }, /* level 21 */
3506 { 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003507},
3508{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003509 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003510 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003511 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003512 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3513 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3514 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3515 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3516 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3517 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3518 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3519 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3520 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3521 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3522 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3523 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003524 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003525 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3526 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3527 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003528 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3529 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003530 { 18, 19, 18, 11, 3,512, ZSTD_btultra }, /* level 20.*/
3531 { 18, 19, 18, 12, 3,512, ZSTD_btultra }, /* level 21.*/
3532 { 18, 19, 18, 13, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003533},
3534{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003535 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003536 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3537 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3538 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3539 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3540 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3541 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3542 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3543 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3544 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3545 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3546 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3547 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3548 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3549 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003550 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3551 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3552 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3553 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3554 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3555 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003556 { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/
3557 { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/
3558 { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003559},
3560{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003561 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003562 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003563 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003564 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3565 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3566 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3567 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3568 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3569 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3570 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3571 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003572 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3573 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3574 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3575 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3576 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3577 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3578 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3579 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3580 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3581 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003582 { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/
3583 { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/
3584 { 14, 15, 15, 10, 3,256, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003585},
3586};
3587
Yann Collet236d94f2016-05-18 12:06:33 +02003588/*! ZSTD_getCParams() :
3589* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3590* Size values are optional, provide 0 if not known or unused */
Yann Collet52c04fe2016-07-07 11:53:18 +02003591ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003592{
Yann Collet15354142016-04-04 04:22:53 +02003593 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02003594 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02003595 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003596 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02003597 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003598 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003599 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003600 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3601 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003602 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003603 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3604 }
Yann Collet70d13012016-06-01 18:45:34 +02003605 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003606 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003607}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003608
3609/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003610* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003611* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet52c04fe2016-07-07 11:53:18 +02003612ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003613 ZSTD_parameters params;
3614 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3615 memset(&params, 0, sizeof(params));
3616 params.cParams = cParams;
3617 return params;
3618}