blob: 3ba1748f07e23012eab3498ea225f19af1f5544c [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
2139 /* catch up */
2140 if (offset) {
Yann Colletc17e0202017-04-20 12:50:02 -07002141 while ( (start > anchor)
2142 && (start > base+offset-ZSTD_REP_MOVE)
2143 && (start[-1] == start[-1-offset+ZSTD_REP_MOVE]) ) /* only search for offset within prefix */
inikep64d7bcb2016-04-07 19:14:09 +02002144 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02002145 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02002146 }
2147
inikepfaa8d8a2016-04-05 19:01:10 +02002148 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002149_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002150 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002151 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002152 anchor = ip = start + matchLength;
2153 }
Yann Collet48537162016-04-07 15:24:29 +02002154
inikepfaa8d8a2016-04-05 19:01:10 +02002155 /* check immediate repcode */
2156 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02002157 && ((offset_2>0)
2158 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02002159 /* store sequence */
Yann Collete42afbc2017-04-26 11:39:35 -07002160 matchLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet9634f672016-07-03 01:23:58 +02002161 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02002162 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2163 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02002164 anchor = ip;
2165 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02002166 } }
inikepfaa8d8a2016-04-05 19:01:10 +02002167
Yann Collet4266c0a2016-06-14 01:49:25 +02002168 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002169 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
2170 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02002171
inikepfaa8d8a2016-04-05 19:01:10 +02002172 /* Last Literals */
2173 { size_t const lastLLSize = iend - anchor;
2174 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2175 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002176 }
Yann Collet5106a762015-11-05 15:00:24 +01002177}
2178
Yann Collet5be2dd22015-11-11 13:43:58 +01002179
inikep64d7bcb2016-04-07 19:14:09 +02002180static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2181{
2182 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2183}
2184
2185static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2186{
2187 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2188}
2189
2190static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2191{
2192 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2193}
2194
2195static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2196{
2197 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2198}
2199
2200
inikepfaa8d8a2016-04-05 19:01:10 +02002201FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002202void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2203 const void* src, size_t srcSize,
2204 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002205{
inikepfaa8d8a2016-04-05 19:01:10 +02002206 seqStore_t* seqStorePtr = &(ctx->seqStore);
2207 const BYTE* const istart = (const BYTE*)src;
2208 const BYTE* ip = istart;
2209 const BYTE* anchor = istart;
2210 const BYTE* const iend = istart + srcSize;
2211 const BYTE* const ilimit = iend - 8;
2212 const BYTE* const base = ctx->base;
2213 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002214 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002215 const BYTE* const prefixStart = base + dictLimit;
2216 const BYTE* const dictBase = ctx->dictBase;
2217 const BYTE* const dictEnd = dictBase + dictLimit;
2218 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2219
2220 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2221 const U32 mls = ctx->params.cParams.searchLength;
2222
inikep64d7bcb2016-04-07 19:14:09 +02002223 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2224 size_t* offsetPtr,
2225 U32 maxNbAttempts, U32 matchLengthSearch);
2226 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2227
Yann Collet302ff032016-07-03 01:28:16 +02002228 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002229
Yann Collet302ff032016-07-03 01:28:16 +02002230 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002231 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002232 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002233
2234 /* Match Loop */
2235 while (ip < ilimit) {
2236 size_t matchLength=0;
2237 size_t offset=0;
2238 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002239 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002240
2241 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002242 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002243 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2244 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002245 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002246 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002247 /* repcode detected we should take it */
2248 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002249 matchLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002250 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002251 } }
2252
2253 /* first search (depth 0) */
2254 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002255 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002256 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002257 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002258 }
2259
Yann Collete42afbc2017-04-26 11:39:35 -07002260 if (matchLength < 4) {
inikepfaa8d8a2016-04-05 19:01:10 +02002261 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2262 continue;
2263 }
2264
inikep64d7bcb2016-04-07 19:14:09 +02002265 /* let's try to find a better solution */
2266 if (depth>=1)
2267 while (ip<ilimit) {
2268 ip ++;
2269 current++;
2270 /* check repCode */
2271 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002272 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002273 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2274 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002275 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002276 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2277 /* repcode detected */
2278 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002279 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
inikep64d7bcb2016-04-07 19:14:09 +02002280 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002281 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002282 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002283 matchLength = repLength, offset = 0, start = ip;
2284 } }
2285
2286 /* search match, depth 1 */
2287 { size_t offset2=99999999;
2288 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002289 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2290 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
Yann Collete42afbc2017-04-26 11:39:35 -07002291 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002292 matchLength = ml2, offset = offset2, start = ip;
2293 continue; /* search a better one */
2294 } }
2295
2296 /* let's find an even better one */
2297 if ((depth==2) && (ip<ilimit)) {
2298 ip ++;
2299 current++;
2300 /* check repCode */
2301 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002302 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002303 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2304 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002305 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002306 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2307 /* repcode detected */
2308 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002309 size_t const repLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Colletc17e0202017-04-20 12:50:02 -07002310 int const gain2 = (int)(repLength * 4);
2311 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
Yann Collete42afbc2017-04-26 11:39:35 -07002312 if ((repLength >= 4) && (gain2 > gain1))
inikep64d7bcb2016-04-07 19:14:09 +02002313 matchLength = repLength, offset = 0, start = ip;
2314 } }
2315
2316 /* search match, depth 2 */
2317 { size_t offset2=99999999;
2318 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002319 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2320 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
Yann Collete42afbc2017-04-26 11:39:35 -07002321 if ((ml2 >= 4) && (gain2 > gain1)) {
inikep64d7bcb2016-04-07 19:14:09 +02002322 matchLength = ml2, offset = offset2, start = ip;
2323 continue;
2324 } } }
2325 break; /* nothing found : store previous solution */
2326 }
2327
inikepfaa8d8a2016-04-05 19:01:10 +02002328 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002329 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002330 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002331 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2332 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002333 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002334 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002335 }
inikepfaa8d8a2016-04-05 19:01:10 +02002336
inikepfaa8d8a2016-04-05 19:01:10 +02002337 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002338_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002339 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002340 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002341 anchor = ip = start + matchLength;
2342 }
2343
2344 /* check immediate repcode */
2345 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002346 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002347 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2348 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002349 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002350 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2351 /* repcode detected we should take it */
2352 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Collete42afbc2017-04-26 11:39:35 -07002353 matchLength = ZSTD_count_2segments(ip+4, repMatch+4, iend, repEnd, prefixStart) + 4;
Yann Collet302ff032016-07-03 01:28:16 +02002354 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002355 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2356 ip += matchLength;
2357 anchor = ip;
2358 continue; /* faster when present ... (?) */
2359 }
2360 break;
2361 } }
2362
Yann Collet4266c0a2016-06-14 01:49:25 +02002363 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002364 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002365
inikepfaa8d8a2016-04-05 19:01:10 +02002366 /* Last Literals */
2367 { size_t const lastLLSize = iend - anchor;
2368 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2369 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002370 }
2371}
2372
2373
Yann Collet59d1f792016-01-23 19:28:41 +01002374void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002375{
inikep64d7bcb2016-04-07 19:14:09 +02002376 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002377}
2378
Yann Collet59d1f792016-01-23 19:28:41 +01002379static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002380{
Yann Colleta1249dc2016-01-25 04:22:03 +01002381 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002382}
Yann Collet9a24e592015-11-22 02:53:43 +01002383
Yann Collet59d1f792016-01-23 19:28:41 +01002384static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002385{
Yann Colleta1249dc2016-01-25 04:22:03 +01002386 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002387}
2388
Yann Collet59d1f792016-01-23 19:28:41 +01002389static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002390{
Yann Colleta1249dc2016-01-25 04:22:03 +01002391 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002392}
2393
inikepef519412016-04-21 11:08:43 +02002394
inikepef519412016-04-21 11:08:43 +02002395/* The optimal parser */
2396#include "zstd_opt.h"
2397
2398static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2399{
Yann Colletd4f4e582016-06-27 01:31:35 +02002400#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002401 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2402#else
2403 (void)ctx; (void)src; (void)srcSize;
2404 return;
2405#endif
2406}
2407
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002408static void ZSTD_compressBlock_btultra(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002409{
2410#ifdef ZSTD_OPT_H_91842398743
2411 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002412#else
2413 (void)ctx; (void)src; (void)srcSize;
2414 return;
2415#endif
inikepef519412016-04-21 11:08:43 +02002416}
2417
inikepd3b8d7a2016-02-22 10:06:17 +01002418static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002419{
Yann Colletd4f4e582016-06-27 01:31:35 +02002420#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002421 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2422#else
2423 (void)ctx; (void)src; (void)srcSize;
2424 return;
2425#endif
2426}
2427
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002428static void ZSTD_compressBlock_btultra_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002429{
2430#ifdef ZSTD_OPT_H_91842398743
2431 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002432#else
2433 (void)ctx; (void)src; (void)srcSize;
2434 return;
2435#endif
inikepe2bfe242016-01-31 11:25:48 +01002436}
2437
Yann Collet7a231792015-11-21 15:27:35 +01002438
Yann Collet59d1f792016-01-23 19:28:41 +01002439typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002440
Yann Colletb923f652016-01-26 03:14:20 +01002441static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002442{
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002443 static const ZSTD_blockCompressor blockCompressor[2][8] = {
Yann Colletc17e0202017-04-20 12:50:02 -07002444 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy,
2445 ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002446 ZSTD_compressBlock_btopt, ZSTD_compressBlock_btultra },
Yann Colletc17e0202017-04-20 12:50:02 -07002447 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict,
2448 ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict,
Nick Terrell5f2c7212017-05-10 16:49:58 -07002449 ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btultra_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01002450 };
2451
2452 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002453}
2454
2455
Yann Colletd1b26842016-03-15 01:24:33 +01002456static 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 +01002457{
Yann Collet19cab462016-06-17 12:54:52 +02002458 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002459 const BYTE* const base = zc->base;
2460 const BYTE* const istart = (const BYTE*)src;
2461 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002462 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 +02002463 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002464 if (current > zc->nextToUpdate + 384)
Yann Colletc17e0202017-04-20 12:50:02 -07002465 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 +01002466 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002467 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002468}
2469
2470
Yann Colletc991cc12016-07-28 00:55:43 +02002471/*! ZSTD_compress_generic() :
2472* Compress a chunk of data into one or multiple blocks.
2473* All blocks will be terminated, all input will be consumed.
2474* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2475* Frame is supposed already started (header already produced)
2476* @return : compressed size, or an error code
2477*/
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002478static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2479 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002480 const void* src, size_t srcSize,
2481 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002482{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002483 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002484 size_t remaining = srcSize;
2485 const BYTE* ip = (const BYTE*)src;
2486 BYTE* const ostart = (BYTE*)dst;
2487 BYTE* op = ostart;
Yann Colletd4180ca2016-07-27 21:21:36 +02002488 U32 const maxDist = 1 << cctx->params.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002489
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002490 if (cctx->params.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002491 XXH64_update(&cctx->xxhState, src, srcSize);
2492
Yann Collet2ce49232016-02-02 14:36:49 +01002493 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002494 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002495 size_t cSize;
2496
Yann Colletc17e0202017-04-20 12:50:02 -07002497 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE)
2498 return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01002499 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002500
Yann Collet346efcc2016-08-02 14:26:00 +02002501 /* preemptive overflow correction */
Sean Purcell881abe42017-03-07 16:52:23 -08002502 if (cctx->lowLimit > (3U<<29)) {
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002503 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002504 U32 const current = (U32)(ip - cctx->base);
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002505 U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002506 U32 const correction = current - newCurrent;
2507 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002508 ZSTD_reduceIndex(cctx, correction);
2509 cctx->base += correction;
2510 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002511 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002512 cctx->dictLimit -= correction;
2513 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2514 else cctx->nextToUpdate -= correction;
2515 }
2516
Yann Collet06e76972017-01-25 16:39:03 -08002517 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002518 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002519 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2520 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2521 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002522 }
Yann Collet89db5e02015-11-13 11:27:46 +01002523
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002524 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002525 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002526
Yann Collet2ce49232016-02-02 14:36:49 +01002527 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002528 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2529 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2530 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2531 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2532 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002533 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002534 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002535 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002536 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002537 }
2538
2539 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002540 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002541 ip += blockSize;
2542 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002543 }
2544
Yann Collet62470b42016-07-28 15:29:08 +02002545 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002546 return op-ostart;
2547}
2548
2549
Yann Collet6236eba2016-04-12 15:52:33 +02002550static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002551 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002552{ BYTE* const op = (BYTE*)dst;
Yann Collet31533ba2017-04-27 00:29:04 -07002553 U32 const dictIDSizeCodeLength = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2554 U32 const dictIDSizeCode = params.fParams.noDictIDFlag ? 0 : dictIDSizeCodeLength; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002555 U32 const checksumFlag = params.fParams.checksumFlag>0;
2556 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002557 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002558 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2559 U32 const fcsCode = params.fParams.contentSizeFlag ?
Nick Terrell55fc1f92017-05-24 13:50:10 -07002560 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : 0; /* 0-3 */
Yann Collet731ef162016-07-27 21:05:12 +02002561 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002562 size_t pos;
2563
2564 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet0be6fd32017-05-08 16:08:01 -07002565 DEBUGLOG(5, "ZSTD_writeFrameHeader : dictIDFlag : %u ; dictID : %u ; dictIDSizeCode : %u \n",
2566 !params.fParams.noDictIDFlag, dictID, dictIDSizeCode);
Yann Collet6236eba2016-04-12 15:52:33 +02002567
2568 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002569 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002570 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002571 switch(dictIDSizeCode)
2572 {
2573 default: /* impossible */
2574 case 0 : break;
2575 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002576 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002577 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2578 }
Yann Collet673f0d72016-06-06 00:26:38 +02002579 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002580 {
2581 default: /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002582 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002583 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2584 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002585 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002586 }
Yann Colletc46fb922016-05-29 05:01:04 +02002587 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002588}
2589
2590
Yann Collet346efcc2016-08-02 14:26:00 +02002591static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002592 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002593 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002594 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002595{
Yann Collet2acb5d32015-10-29 16:49:43 +01002596 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002597 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002598
Yann Collet346efcc2016-08-02 14:26:00 +02002599 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002600
Yann Collet346efcc2016-08-02 14:26:00 +02002601 if (frame && (cctx->stage==ZSTDcs_init)) {
2602 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002603 if (ZSTD_isError(fhSize)) return fhSize;
2604 dstCapacity -= fhSize;
2605 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002606 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002607 }
Yann Colletf3eca252015-10-22 15:31:46 +01002608
Yann Collet417890c2015-12-04 17:16:37 +01002609 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002610 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002611 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002612 ptrdiff_t const delta = cctx->nextSrc - ip;
2613 cctx->lowLimit = cctx->dictLimit;
2614 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2615 cctx->dictBase = cctx->base;
2616 cctx->base -= delta;
2617 cctx->nextToUpdate = cctx->dictLimit;
2618 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002619 }
2620
Yann Collet346efcc2016-08-02 14:26:00 +02002621 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2622 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2623 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2624 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2625 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002626 }
2627
Yann Collet346efcc2016-08-02 14:26:00 +02002628 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002629
Yann Collet5eb749e2017-01-11 18:21:25 +01002630 if (srcSize) {
2631 size_t const cSize = frame ?
Yann Collet346efcc2016-08-02 14:26:00 +02002632 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2633 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002634 if (ZSTD_isError(cSize)) return cSize;
Yann Collet20d5e032017-04-11 18:34:02 -07002635 cctx->consumedSrcSize += srcSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002636 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01002637 } else
2638 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002639}
2640
Yann Colletbf42c8e2016-01-09 01:08:23 +01002641
Yann Collet5b567392016-07-28 01:17:22 +02002642size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002643 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002644 const void* src, size_t srcSize)
2645{
Yann Collet20d5e032017-04-11 18:34:02 -07002646 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1 /* frame mode */, 0 /* last chunk */);
Yann Collet5b567392016-07-28 01:17:22 +02002647}
2648
2649
Yann Colletcf05b9d2016-07-18 16:52:10 +02002650size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002651{
Yann Colletcf05b9d2016-07-18 16:52:10 +02002652 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
2653}
2654
2655size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2656{
2657 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002658 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07002659 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0 /* frame mode */, 0 /* last chunk */);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002660}
2661
Yann Collet16a0b102017-03-24 12:46:46 -07002662/*! ZSTD_loadDictionaryContent() :
2663 * @return : 0, or an error code
2664 */
Yann Colletb923f652016-01-26 03:14:20 +01002665static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002666{
2667 const BYTE* const ip = (const BYTE*) src;
2668 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002669
Yann Collet417890c2015-12-04 17:16:37 +01002670 /* input becomes current prefix */
2671 zc->lowLimit = zc->dictLimit;
2672 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2673 zc->dictBase = zc->base;
2674 zc->base += ip - zc->nextSrc;
2675 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08002676 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002677
2678 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002679 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002680
Yann Collet3b719252016-03-30 19:48:05 +02002681 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002682 {
2683 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002684 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002685 break;
2686
Yann Collet45dc3562016-07-12 09:47:31 +02002687 case ZSTD_dfast:
2688 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2689 break;
2690
Yann Collet417890c2015-12-04 17:16:37 +01002691 case ZSTD_greedy:
2692 case ZSTD_lazy:
2693 case ZSTD_lazy2:
Yann Collet16a0b102017-03-24 12:46:46 -07002694 if (srcSize >= HASH_READ_SIZE)
2695 ZSTD_insertAndFindFirstIndex(zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002696 break;
2697
2698 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002699 case ZSTD_btopt:
Nick Terrelleeb31ee2017-03-09 11:44:25 -08002700 case ZSTD_btultra:
Yann Collet16a0b102017-03-24 12:46:46 -07002701 if (srcSize >= HASH_READ_SIZE)
2702 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002703 break;
2704
2705 default:
2706 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2707 }
2708
Nick Terrellecf90ca2017-02-13 18:27:34 -08002709 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002710 return 0;
2711}
2712
2713
Nick Terrellf9c9af32016-10-19 17:22:08 -07002714/* Dictionaries that assign zero probability to symbols that show up causes problems
2715 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2716 that we may encounter during compression.
2717 NOTE: This behavior is not standard and could be improved in the future. */
2718static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2719 U32 s;
2720 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
2721 for (s = 0; s <= maxSymbolValue; ++s) {
2722 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
2723 }
2724 return 0;
2725}
2726
2727
Yann Colletb923f652016-01-26 03:14:20 +01002728/* Dictionary format :
Yann Colletbea78e82017-03-22 18:09:11 -07002729 * See :
2730 * https://github.com/facebook/zstd/blob/master/doc/zstd_compression_format.md#dictionary-format
2731 */
Yann Collet16a0b102017-03-24 12:46:46 -07002732/*! ZSTD_loadZstdDictionary() :
2733 * @return : 0, or an error code
2734 * assumptions : magic number supposed already checked
2735 * dictSize supposed > 8
Yann Colletbea78e82017-03-22 18:09:11 -07002736 */
Yann Collet16a0b102017-03-24 12:46:46 -07002737static size_t ZSTD_loadZstdDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002738{
Yann Collet52a06222016-06-15 13:53:34 +02002739 const BYTE* dictPtr = (const BYTE*)dict;
2740 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07002741 short offcodeNCount[MaxOff+1];
2742 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08002743 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01002744
Yann Colletbea78e82017-03-22 18:09:11 -07002745 dictPtr += 4; /* skip magic number */
2746 cctx->dictID = cctx->params.fParams.noDictIDFlag ? 0 : MEM_readLE32(dictPtr);
2747 dictPtr += 4;
2748
Yann Collet71ddeb62017-04-20 22:54:54 -07002749 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufCTable, 255, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002750 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002751 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002752 }
Yann Colletfb810d62016-01-28 00:18:06 +01002753
Nick Terrellf9c9af32016-10-19 17:22:08 -07002754 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02002755 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002756 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002757 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002758 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Colletc17e0202017-04-20 12:50:02 -07002759 CHECK_E( FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)),
2760 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002761 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002762 }
Yann Colletfb810d62016-01-28 00:18:06 +01002763
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002764 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002765 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002766 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002767 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002768 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002769 /* Every match length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07002770 CHECK_F( ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
2771 CHECK_E( FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)),
2772 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002773 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002774 }
Yann Colletfb810d62016-01-28 00:18:06 +01002775
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002776 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002777 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002778 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002779 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002780 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002781 /* Every literal length code must have non-zero probability */
Yann Colletc17e0202017-04-20 12:50:02 -07002782 CHECK_F( ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
2783 CHECK_E( FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)),
2784 dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002785 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002786 }
Yann Colletfb810d62016-01-28 00:18:06 +01002787
Yann Collet52a06222016-06-15 13:53:34 +02002788 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07002789 cctx->rep[0] = MEM_readLE32(dictPtr+0);
2790 cctx->rep[1] = MEM_readLE32(dictPtr+4);
2791 cctx->rep[2] = MEM_readLE32(dictPtr+8);
Yann Collet52a06222016-06-15 13:53:34 +02002792 dictPtr += 12;
2793
Yann Colletbea78e82017-03-22 18:09:11 -07002794 { size_t const dictContentSize = (size_t)(dictEnd - dictPtr);
2795 U32 offcodeMax = MaxOff;
2796 if (dictContentSize <= ((U32)-1) - 128 KB) {
2797 U32 const maxOffset = (U32)dictContentSize + 128 KB; /* The maximum offset that must be supported */
2798 offcodeMax = ZSTD_highbit32(maxOffset); /* Calculate minimum offset code required to represent maxOffset */
Nick Terrellb2c39a22016-10-24 14:11:27 -07002799 }
Yann Colletbea78e82017-03-22 18:09:11 -07002800 /* All offset values <= dictContentSize + 128 KB must be representable */
Nick Terrellf9c9af32016-10-19 17:22:08 -07002801 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
Yann Colletbea78e82017-03-22 18:09:11 -07002802 /* All repCodes must be <= dictContentSize and != 0*/
2803 { U32 u;
2804 for (u=0; u<3; u++) {
2805 if (cctx->rep[u] == 0) return ERROR(dictionary_corrupted);
2806 if (cctx->rep[u] > dictContentSize) return ERROR(dictionary_corrupted);
Yann Collet16a0b102017-03-24 12:46:46 -07002807 } }
Nick Terrellf9c9af32016-10-19 17:22:08 -07002808
Yann Collet71ddeb62017-04-20 22:54:54 -07002809 cctx->fseCTables_ready = 1;
2810 cctx->hufCTable_repeatMode = HUF_repeat_valid;
Yann Collet16a0b102017-03-24 12:46:46 -07002811 return ZSTD_loadDictionaryContent(cctx, dictPtr, dictContentSize);
2812 }
Yann Colletb923f652016-01-26 03:14:20 +01002813}
2814
Yann Colletd1b26842016-03-15 01:24:33 +01002815/** ZSTD_compress_insertDictionary() :
2816* @return : 0, or an error code */
Yann Collet16a0b102017-03-24 12:46:46 -07002817static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002818{
Yann Colletc46fb922016-05-29 05:01:04 +02002819 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002820
Yann Collet14312d82017-02-23 23:42:12 -08002821 /* dict as pure content */
Yann Collet16a0b102017-03-24 12:46:46 -07002822 if ((MEM_readLE32(dict) != ZSTD_DICT_MAGIC) || (cctx->forceRawDict))
2823 return ZSTD_loadDictionaryContent(cctx, dict, dictSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002824
Yann Colletbea78e82017-03-22 18:09:11 -07002825 /* dict as zstd dictionary */
Yann Collet16a0b102017-03-24 12:46:46 -07002826 return ZSTD_loadZstdDictionary(cctx, dict, dictSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002827}
2828
Yann Collet27caf2a2016-04-01 15:48:48 +02002829/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002830* @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02002831static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01002832 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002833 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002834{
Yann Colleta7737f62016-09-06 09:44:59 +02002835 ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
Yann Colletab9162e2017-04-11 10:46:20 -07002836 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Collet30fb4992017-04-18 14:08:50 -07002837 CHECK_F(ZSTD_resetCCtx_internal(cctx, params, pledgedSrcSize, crp));
Yann Colleta7737f62016-09-06 09:44:59 +02002838 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002839}
2840
2841
Yann Collet27caf2a2016-04-01 15:48:48 +02002842/*! ZSTD_compressBegin_advanced() :
2843* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002844size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002845 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02002846 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02002847{
2848 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02002849 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet81e13ef2016-06-07 00:51:51 +02002850 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002851}
2852
2853
Yann Collet81e13ef2016-06-07 00:51:51 +02002854size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002855{
Yann Collet6c6e1752016-06-27 15:28:45 +02002856 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002857 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002858}
Yann Collet083fcc82015-10-25 14:06:35 +01002859
inikep19bd48f2016-04-04 12:10:00 +02002860
Yann Colletb05c4822017-01-12 02:01:28 +01002861size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002862{
Yann Colletb05c4822017-01-12 02:01:28 +01002863 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002864}
2865
2866
Yann Collet62470b42016-07-28 15:29:08 +02002867/*! ZSTD_writeEpilogue() :
2868* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01002869* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02002870static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002871{
Yann Colletc991cc12016-07-28 00:55:43 +02002872 BYTE* const ostart = (BYTE*)dst;
2873 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02002874 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002875
Yann Collet0be6fd32017-05-08 16:08:01 -07002876 DEBUGLOG(5, "ZSTD_writeEpilogue \n");
Yann Collet87c18b22016-08-26 01:43:47 +02002877 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02002878
2879 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02002880 if (cctx->stage == ZSTDcs_init) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002881 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002882 if (ZSTD_isError(fhSize)) return fhSize;
2883 dstCapacity -= fhSize;
2884 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02002885 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002886 }
2887
Yann Colletc991cc12016-07-28 00:55:43 +02002888 if (cctx->stage != ZSTDcs_ending) {
2889 /* write one last empty block, make it the "last" block */
2890 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2891 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2892 MEM_writeLE32(op, cBlockHeader24);
2893 op += ZSTD_blockHeaderSize;
2894 dstCapacity -= ZSTD_blockHeaderSize;
2895 }
2896
2897 if (cctx->params.fParams.checksumFlag) {
2898 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2899 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2900 MEM_writeLE32(op, checksum);
2901 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002902 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002903
Yann Collet731ef162016-07-27 21:05:12 +02002904 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02002905 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01002906}
2907
Yann Colletfd416f12016-01-30 03:14:15 +01002908
Yann Collet62470b42016-07-28 15:29:08 +02002909size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2910 void* dst, size_t dstCapacity,
2911 const void* src, size_t srcSize)
2912{
2913 size_t endResult;
Yann Collet0be6fd32017-05-08 16:08:01 -07002914 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize,
2915 1 /* frame mode */, 1 /* last chunk */);
Yann Collet62470b42016-07-28 15:29:08 +02002916 if (ZSTD_isError(cSize)) return cSize;
2917 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2918 if (ZSTD_isError(endResult)) return endResult;
Yann Collet20d5e032017-04-11 18:34:02 -07002919 if (cctx->params.fParams.contentSizeFlag) { /* control src size */
Yann Collet0be6fd32017-05-08 16:08:01 -07002920 if (cctx->frameContentSize != cctx->consumedSrcSize)
2921 return ERROR(srcSize_wrong);
Yann Collet20d5e032017-04-11 18:34:02 -07002922 }
Yann Collet62470b42016-07-28 15:29:08 +02002923 return cSize + endResult;
2924}
2925
2926
Yann Collet19c10022016-07-28 01:25:46 +02002927static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002928 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002929 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002930 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002931 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002932{
Yann Collet3e21ec52016-09-06 15:36:19 +02002933 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize));
Yann Collet62470b42016-07-28 15:29:08 +02002934 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002935}
2936
Yann Collet21588e32016-03-30 16:50:44 +02002937size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2938 void* dst, size_t dstCapacity,
2939 const void* src, size_t srcSize,
2940 const void* dict,size_t dictSize,
2941 ZSTD_parameters params)
2942{
Yann Colletcf409a72016-09-26 16:41:05 +02002943 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02002944 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2945}
2946
Yann Colletc17e0202017-04-20 12:50:02 -07002947size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize,
2948 const void* dict, size_t dictSize, int compressionLevel)
Yann Collet31683c02015-12-18 01:26:48 +01002949{
Yann Collet407a11f2016-11-03 15:52:01 -07002950 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02002951 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002952 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002953}
2954
Yann Colletd1b26842016-03-15 01:24:33 +01002955size_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 +01002956{
Yann Collet21588e32016-03-30 16:50:44 +02002957 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002958}
2959
Yann Colletd1b26842016-03-15 01:24:33 +01002960size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002961{
Yann Collet44fe9912015-10-29 22:02:40 +01002962 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002963 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002964 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002965 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002966 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Collet23b6e052016-08-28 21:05:43 -07002967 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 +01002968 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002969}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002970
Yann Colletfd416f12016-01-30 03:14:15 +01002971
Yann Collet81e13ef2016-06-07 00:51:51 +02002972/* ===== Dictionary API ===== */
2973
2974struct ZSTD_CDict_s {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002975 void* dictBuffer;
2976 const void* dictContent;
Yann Collet81e13ef2016-06-07 00:51:51 +02002977 size_t dictContentSize;
2978 ZSTD_CCtx* refContext;
David Lamda9d3b72016-08-29 09:03:12 -07002979}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
Yann Collet81e13ef2016-06-07 00:51:51 +02002980
Yann Colleta1d67042017-05-08 17:51:49 -07002981/*! ZSTD_estimateCDictSize() :
2982 * Estimate amount of memory that will be needed to create a dictionary with following arguments */
2983size_t ZSTD_estimateCDictSize(ZSTD_compressionParameters cParams, size_t dictSize)
2984{
2985 cParams = ZSTD_adjustCParams(cParams, 0, dictSize);
Yann Colletfa8dadb2017-05-08 18:24:16 -07002986 return sizeof(ZSTD_CDict) + dictSize + ZSTD_estimateCCtxSize(cParams);
Yann Colleta1d67042017-05-08 17:51:49 -07002987}
2988
Yann Colletd7c65892016-09-15 02:50:27 +02002989size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2990{
2991 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Colletaca113f2016-12-23 22:25:03 +01002992 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02002993}
2994
Yann Collet1c3ab0c2017-04-27 12:57:11 -07002995static ZSTD_parameters ZSTD_makeParams(ZSTD_compressionParameters cParams, ZSTD_frameParameters fParams)
2996{
2997 ZSTD_parameters params;
2998 params.cParams = cParams;
2999 params.fParams = fParams;
3000 return params;
3001}
3002
Yann Collet1f57c2e2016-12-21 16:20:11 +01003003ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
Yann Collet31533ba2017-04-27 00:29:04 -07003004 ZSTD_compressionParameters cParams, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02003005{
Yann Collet23b6e052016-08-28 21:05:43 -07003006 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
3007 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02003008
Yann Collet23b6e052016-08-28 21:05:43 -07003009 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02003010 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
3011
Yann Collet1f57c2e2016-12-21 16:20:11 +01003012 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07003013 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01003014 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02003015 return NULL;
3016 }
3017
Yann Collet1f57c2e2016-12-21 16:20:11 +01003018 if ((byReference) || (!dictBuffer) || (!dictSize)) {
3019 cdict->dictBuffer = NULL;
3020 cdict->dictContent = dictBuffer;
Yann Collet1f57c2e2016-12-21 16:20:11 +01003021 } else {
3022 void* const internalBuffer = ZSTD_malloc(dictSize, customMem);
Yann Collet4e5eea62016-12-21 16:44:35 +01003023 if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; }
Yann Collet1f57c2e2016-12-21 16:20:11 +01003024 memcpy(internalBuffer, dictBuffer, dictSize);
3025 cdict->dictBuffer = internalBuffer;
3026 cdict->dictContent = internalBuffer;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07003027 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01003028
Yann Collet31533ba2017-04-27 00:29:04 -07003029 { ZSTD_frameParameters const fParams = { 0 /* contentSizeFlag */, 0 /* checksumFlag */, 0 /* noDictIDFlag */ }; /* dummy */
Yann Collet1c3ab0c2017-04-27 12:57:11 -07003030 ZSTD_parameters const params = ZSTD_makeParams(cParams, fParams);
Yann Collet31533ba2017-04-27 00:29:04 -07003031 size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
Yann Collet81e13ef2016-06-07 00:51:51 +02003032 if (ZSTD_isError(errorCode)) {
Yann Collet1f57c2e2016-12-21 16:20:11 +01003033 ZSTD_free(cdict->dictBuffer, customMem);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003034 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01003035 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02003036 return NULL;
3037 } }
3038
Yann Collet81e13ef2016-06-07 00:51:51 +02003039 cdict->refContext = cctx;
Yann Collet1f57c2e2016-12-21 16:20:11 +01003040 cdict->dictContentSize = dictSize;
Yann Collet81e13ef2016-06-07 00:51:51 +02003041 return cdict;
3042 }
3043}
3044
3045ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
3046{
3047 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet31533ba2017-04-27 00:29:04 -07003048 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
3049 return ZSTD_createCDict_advanced(dict, dictSize, 0, cParams, allocator);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003050}
3051
3052ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
3053{
3054 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet31533ba2017-04-27 00:29:04 -07003055 ZSTD_compressionParameters cParams = ZSTD_getCParams(compressionLevel, 0, dictSize);
3056 return ZSTD_createCDict_advanced(dict, dictSize, 1, cParams, allocator);
Yann Collet81e13ef2016-06-07 00:51:51 +02003057}
3058
3059size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
3060{
Yann Collet23b6e052016-08-28 21:05:43 -07003061 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02003062 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07003063 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01003064 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07003065 ZSTD_free(cdict, cMem);
3066 return 0;
3067 }
Yann Collet81e13ef2016-06-07 00:51:51 +02003068}
3069
Yann Collet95162342016-10-25 16:19:52 -07003070static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
3071 return ZSTD_getParamsFromCCtx(cdict->refContext);
3072}
3073
Yann Collet715b9aa2017-04-18 13:55:53 -07003074/* ZSTD_compressBegin_usingCDict_advanced() :
Yann Collet4f818182017-04-17 17:57:35 -07003075 * cdict must be != NULL */
Yann Collet715b9aa2017-04-18 13:55:53 -07003076size_t ZSTD_compressBegin_usingCDict_advanced(
Yann Collet4f818182017-04-17 17:57:35 -07003077 ZSTD_CCtx* const cctx, const ZSTD_CDict* const cdict,
3078 ZSTD_frameParameters const fParams, unsigned long long const pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003079{
Yann Collet7cf78f12017-04-04 12:38:14 -07003080 if (cdict==NULL) return ERROR(GENERIC); /* does not support NULL cdict */
Yann Collet31533ba2017-04-27 00:29:04 -07003081 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict_advanced : dictIDFlag == %u \n", !fParams.noDictIDFlag);
Yann Collet4f818182017-04-17 17:57:35 -07003082 if (cdict->dictContentSize)
Yann Colleta4cab802017-04-18 14:54:54 -07003083 CHECK_F( ZSTD_copyCCtx_internal(cctx, cdict->refContext, fParams, pledgedSrcSize) )
Sean Purcell2db72492017-02-09 10:50:43 -08003084 else {
3085 ZSTD_parameters params = cdict->refContext->params;
Yann Collet4f818182017-04-17 17:57:35 -07003086 params.fParams = fParams;
Yann Colletab9162e2017-04-11 10:46:20 -07003087 CHECK_F(ZSTD_compressBegin_internal(cctx, NULL, 0, params, pledgedSrcSize));
Sean Purcell2db72492017-02-09 10:50:43 -08003088 }
Yann Collet4cb21292016-09-15 14:54:07 +02003089 return 0;
3090}
3091
Yann Collet4f818182017-04-17 17:57:35 -07003092/* ZSTD_compressBegin_usingCDict() :
3093 * pledgedSrcSize=0 means "unknown"
3094 * if pledgedSrcSize>0, it will enable contentSizeFlag */
Yann Collet768df122017-04-26 15:42:10 -07003095size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict)
Yann Collet4f818182017-04-17 17:57:35 -07003096{
Yann Collet768df122017-04-26 15:42:10 -07003097 ZSTD_frameParameters const fParams = { 0 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Collet31533ba2017-04-27 00:29:04 -07003098 DEBUGLOG(5, "ZSTD_compressBegin_usingCDict : dictIDFlag == %u \n", !fParams.noDictIDFlag);
Yann Collet768df122017-04-26 15:42:10 -07003099 return ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, 0);
Yann Collet4f818182017-04-17 17:57:35 -07003100}
3101
Yann Colletf4bd8572017-04-27 11:31:55 -07003102size_t ZSTD_compress_usingCDict_advanced(ZSTD_CCtx* cctx,
3103 void* dst, size_t dstCapacity,
3104 const void* src, size_t srcSize,
3105 const ZSTD_CDict* cdict, ZSTD_frameParameters fParams)
3106{
3107 CHECK_F (ZSTD_compressBegin_usingCDict_advanced(cctx, cdict, fParams, srcSize)); /* will check if cdict != NULL */
3108 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02003109}
3110
Yann Collet07639052016-08-03 01:57:57 +02003111/*! ZSTD_compress_usingCDict() :
Yann Collet4f818182017-04-17 17:57:35 -07003112 * Compression using a digested Dictionary.
3113 * Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
3114 * Note that compression parameters are decided at CDict creation time
3115 * while frame parameters are hardcoded */
Yann Collet4cb21292016-09-15 14:54:07 +02003116size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
3117 void* dst, size_t dstCapacity,
3118 const void* src, size_t srcSize,
3119 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02003120{
Yann Collet4f818182017-04-17 17:57:35 -07003121 ZSTD_frameParameters const fParams = { 1 /*content*/, 0 /*checksum*/, 0 /*noDictID*/ };
Yann Colletf4bd8572017-04-27 11:31:55 -07003122 return ZSTD_compress_usingCDict_advanced(cctx, dst, dstCapacity, src, srcSize, cdict, fParams);
Yann Collet81e13ef2016-06-07 00:51:51 +02003123}
3124
3125
3126
Yann Collet104e5b02016-08-12 13:04:27 +02003127/* ******************************************************************
3128* Streaming
3129********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003130
Yann Collet5a0c8e22016-08-12 01:20:36 +02003131ZSTD_CStream* ZSTD_createCStream(void)
3132{
3133 return ZSTD_createCStream_advanced(defaultCustomMem);
3134}
3135
3136ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
3137{
Yann Collet6fb2f242017-05-10 11:06:06 -07003138 /* CStream and CCtx are now same object */
3139 return ZSTD_createCCtx_advanced(customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003140}
3141
3142size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
3143{
Yann Collet78553662017-05-08 17:15:00 -07003144 return ZSTD_freeCCtx(zcs); /* same object */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003145}
3146
Yann Colletfa8dadb2017-05-08 18:24:16 -07003147size_t ZSTD_estimateCStreamSize(ZSTD_compressionParameters cParams)
3148{
3149 size_t const CCtxSize = ZSTD_estimateCCtxSize(cParams);
3150 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
3151 size_t const inBuffSize = ((size_t)1 << cParams.windowLog) + blockSize;
3152 size_t const outBuffSize = ZSTD_compressBound(blockSize) + 1;
3153 size_t const streamingSize = inBuffSize + outBuffSize;
3154
Yann Collet669346f2017-05-10 11:08:00 -07003155 return CCtxSize + streamingSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003156}
3157
3158
Yann Collet104e5b02016-08-12 13:04:27 +02003159/*====== Initialization ======*/
3160
3161size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003162
Yann Colletc17e0202017-04-20 12:50:02 -07003163size_t ZSTD_CStreamOutSize(void)
3164{
3165 return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ;
3166}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003167
Yann Collet0be6fd32017-05-08 16:08:01 -07003168static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02003169{
Yann Colletd564faa2016-12-18 21:39:15 +01003170 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 -07003171
Yann Collet31533ba2017-04-27 00:29:04 -07003172 DEBUGLOG(5, "ZSTD_resetCStream_internal : dictIDFlag == %u \n", !zcs->params.fParams.noDictIDFlag);
3173
Yann Collet0be6fd32017-05-08 16:08:01 -07003174 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict_advanced(zcs, zcs->cdict, params.fParams, pledgedSrcSize))
3175 else CHECK_F(ZSTD_compressBegin_internal(zcs, NULL, 0, params, pledgedSrcSize));
Yann Collet4cb21292016-09-15 14:54:07 +02003176
3177 zcs->inToCompress = 0;
3178 zcs->inBuffPos = 0;
3179 zcs->inBuffTarget = zcs->blockSize;
3180 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -07003181 zcs->streamStage = zcss_load;
Yann Collet4cb21292016-09-15 14:54:07 +02003182 zcs->frameEnded = 0;
Yann Collete795c8a2016-12-13 16:39:36 +01003183 zcs->pledgedSrcSize = pledgedSrcSize;
Yann Collet4cb21292016-09-15 14:54:07 +02003184 return 0; /* ready to go */
3185}
3186
Sean Purcell2db72492017-02-09 10:50:43 -08003187size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
3188{
3189
Yann Collet0be6fd32017-05-08 16:08:01 -07003190 ZSTD_parameters params = zcs->params;
3191 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
Yann Collet31533ba2017-04-27 00:29:04 -07003192 DEBUGLOG(5, "ZSTD_resetCStream : dictIDFlag == %u \n", !zcs->params.fParams.noDictIDFlag);
Yann Collet0be6fd32017-05-08 16:08:01 -07003193 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Sean Purcell2db72492017-02-09 10:50:43 -08003194}
Sean Purcell2db72492017-02-09 10:50:43 -08003195
Yann Collet4b987ad2017-04-10 17:50:44 -07003196/* ZSTD_initCStream_internal() :
Yann Collete88034f2017-04-10 22:24:02 -07003197 * params are supposed validated at this stage
3198 * and zcs->cdict is supposed to be correct */
3199static size_t ZSTD_initCStream_stage2(ZSTD_CStream* zcs,
3200 const ZSTD_parameters params,
3201 unsigned long long pledgedSrcSize)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003202{
Yann Collet4b987ad2017-04-10 17:50:44 -07003203 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
Yann Colletfc514592017-05-08 17:07:59 -07003204 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
Yann Collete88034f2017-04-10 22:24:02 -07003205
Yann Collet5a0c8e22016-08-12 01:20:36 +02003206 /* allocate buffers */
Yann Colletfc514592017-05-08 17:07:59 -07003207 { size_t const neededInBuffSize = ((size_t)1 << params.cParams.windowLog) + zcs->blockSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003208 if (zcs->inBuffSize < neededInBuffSize) {
Yann Collet02d37aa2017-04-05 14:53:51 -07003209 zcs->inBuffSize = 0;
Yann Colletcf409a72016-09-26 16:41:05 +02003210 ZSTD_free(zcs->inBuff, zcs->customMem);
Yann Colletfc514592017-05-08 17:07:59 -07003211 zcs->inBuff = (char*)ZSTD_malloc(neededInBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003212 if (zcs->inBuff == NULL) return ERROR(memory_allocation);
Yann Collet02d37aa2017-04-05 14:53:51 -07003213 zcs->inBuffSize = neededInBuffSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003214 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02003215 }
3216 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
Yann Collet02d37aa2017-04-05 14:53:51 -07003217 size_t const outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
3218 zcs->outBuffSize = 0;
Yann Colletcf409a72016-09-26 16:41:05 +02003219 ZSTD_free(zcs->outBuff, zcs->customMem);
Yann Colletfc514592017-05-08 17:07:59 -07003220 zcs->outBuff = (char*)ZSTD_malloc(outBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003221 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
Yann Collet02d37aa2017-04-05 14:53:51 -07003222 zcs->outBuffSize = outBuffSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003223 }
3224
Yann Collet31533ba2017-04-27 00:29:04 -07003225 DEBUGLOG(5, "ZSTD_initCStream_stage2 : dictIDFlag == %u \n", !params.fParams.noDictIDFlag);
Yann Collet0be6fd32017-05-08 16:08:01 -07003226 return ZSTD_resetCStream_internal(zcs, params, pledgedSrcSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003227}
3228
Yann Collet77bf59e2017-04-27 11:43:04 -07003229/* ZSTD_initCStream_usingCDict_advanced() :
3230 * same as ZSTD_initCStream_usingCDict(), with control over frame parameters */
3231size_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 -07003232{
3233 if (!cdict) return ERROR(GENERIC); /* cannot handle NULL cdict (does not know what to do) */
Yann Collet4ee6b152017-04-11 11:59:44 -07003234 { ZSTD_parameters params = ZSTD_getParamsFromCDict(cdict);
Yann Collet77bf59e2017-04-27 11:43:04 -07003235 params.fParams = fParams;
Yann Collete88034f2017-04-10 22:24:02 -07003236 zcs->cdict = cdict;
Yann Collet77bf59e2017-04-27 11:43:04 -07003237 return ZSTD_initCStream_stage2(zcs, params, pledgedSrcSize);
Yann Collete88034f2017-04-10 22:24:02 -07003238 }
3239}
3240
Yann Collete88034f2017-04-10 22:24:02 -07003241/* note : cdict must outlive compression session */
3242size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3243{
Yann Collet77bf59e2017-04-27 11:43:04 -07003244 ZSTD_frameParameters const fParams = { 0 /* content */, 0 /* checksum */, 0 /* noDictID */ };
3245 return ZSTD_initCStream_usingCDict_advanced(zcs, cdict, 0, fParams);
Yann Collete88034f2017-04-10 22:24:02 -07003246}
3247
3248static size_t ZSTD_initCStream_internal(ZSTD_CStream* zcs,
3249 const void* dict, size_t dictSize,
3250 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3251{
3252 assert(!ZSTD_isError(ZSTD_checkCParams(params.cParams)));
3253 zcs->cdict = NULL;
3254
3255 if (dict && dictSize >= 8) {
3256 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet31533ba2017-04-27 00:29:04 -07003257 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0 /* copy */, params.cParams, zcs->customMem);
Yann Collete88034f2017-04-10 22:24:02 -07003258 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
3259 zcs->cdict = zcs->cdictLocal;
3260 }
3261
Yann Collet31533ba2017-04-27 00:29:04 -07003262 DEBUGLOG(5, "ZSTD_initCStream_internal : dictIDFlag == %u \n", !params.fParams.noDictIDFlag);
Yann Collete88034f2017-04-10 22:24:02 -07003263 return ZSTD_initCStream_stage2(zcs, params, pledgedSrcSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003264}
3265
Yann Collet95162342016-10-25 16:19:52 -07003266size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
3267 const void* dict, size_t dictSize,
3268 ZSTD_parameters params, unsigned long long pledgedSrcSize)
3269{
Yann Collet4b987ad2017-04-10 17:50:44 -07003270 CHECK_F( ZSTD_checkCParams(params.cParams) );
Yann Collet0be6fd32017-05-08 16:08:01 -07003271 DEBUGLOG(5, "ZSTD_initCStream_advanced : pledgedSrcSize == %u \n", (U32)pledgedSrcSize);
3272 DEBUGLOG(5, "wlog %u \n", params.cParams.windowLog);
Yann Collet4b987ad2017-04-10 17:50:44 -07003273 return ZSTD_initCStream_internal(zcs, dict, dictSize, params, pledgedSrcSize);
Yann Collet95162342016-10-25 16:19:52 -07003274}
3275
Yann Collet5a0c8e22016-08-12 01:20:36 +02003276size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3277{
3278 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet4b987ad2017-04-10 17:50:44 -07003279 return ZSTD_initCStream_internal(zcs, dict, dictSize, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003280}
3281
Yann Collete795c8a2016-12-13 16:39:36 +01003282size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3283{
Yann Colletd564faa2016-12-18 21:39:15 +01003284 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
Yann Collete88034f2017-04-10 22:24:02 -07003285 params.fParams.contentSizeFlag = (pledgedSrcSize>0);
Yann Collet4b987ad2017-04-10 17:50:44 -07003286 return ZSTD_initCStream_internal(zcs, NULL, 0, params, pledgedSrcSize);
Yann Collete795c8a2016-12-13 16:39:36 +01003287}
3288
Yann Collet5a0c8e22016-08-12 01:20:36 +02003289size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3290{
Yann Collete88034f2017-04-10 22:24:02 -07003291 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, 0);
3292 return ZSTD_initCStream_internal(zcs, NULL, 0, params, 0);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003293}
3294
Yann Collet70e3b312016-08-23 01:18:06 +02003295size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
Yann Colletcb327632016-08-23 00:30:31 +02003296{
Yann Collet791d7442017-05-08 16:17:30 -07003297 return ZSTD_sizeof_CCtx(zcs); /* same object */
Yann Colletcb327632016-08-23 00:30:31 +02003298}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003299
Yann Collet104e5b02016-08-12 13:04:27 +02003300/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003301
3302typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
3303
3304MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
3305{
3306 size_t const length = MIN(dstCapacity, srcSize);
3307 memcpy(dst, src, length);
3308 return length;
3309}
3310
3311static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3312 void* dst, size_t* dstCapacityPtr,
3313 const void* src, size_t* srcSizePtr,
3314 ZSTD_flush_e const flush)
3315{
3316 U32 someMoreWork = 1;
3317 const char* const istart = (const char*)src;
3318 const char* const iend = istart + *srcSizePtr;
3319 const char* ip = istart;
3320 char* const ostart = (char*)dst;
3321 char* const oend = ostart + *dstCapacityPtr;
3322 char* op = ostart;
3323
Yann Collet0be6fd32017-05-08 16:08:01 -07003324 DEBUGLOG(5, "ZSTD_compressStream_generic \n");
Yann Collet5a0c8e22016-08-12 01:20:36 +02003325 while (someMoreWork) {
Yann Collet0be6fd32017-05-08 16:08:01 -07003326 switch(zcs->streamStage)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003327 {
3328 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
3329
3330 case zcss_load:
3331 /* complete inBuffer */
3332 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3333 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
Yann Collet0be6fd32017-05-08 16:08:01 -07003334 DEBUGLOG(5, "loading %u/%u \n", (U32)loaded, (U32)toLoad);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003335 zcs->inBuffPos += loaded;
3336 ip += loaded;
3337 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
3338 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
3339 } }
3340 /* compress current block (note : this stage cannot be stopped in the middle) */
Yann Collet0be6fd32017-05-08 16:08:01 -07003341 DEBUGLOG(5, "stream compression stage (flush==%u)\n", flush);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003342 { void* cDst;
3343 size_t cSize;
3344 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3345 size_t oSize = oend-op;
3346 if (oSize >= ZSTD_compressBound(iSize))
3347 cDst = op; /* compress directly into output buffer (avoid flush stage) */
3348 else
3349 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
3350 cSize = (flush == zsf_end) ?
Yann Collet0be6fd32017-05-08 16:08:01 -07003351 ZSTD_compressEnd(zcs, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
3352 ZSTD_compressContinue(zcs, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003353 if (ZSTD_isError(cSize)) return cSize;
Yann Collet0be6fd32017-05-08 16:08:01 -07003354 DEBUGLOG(5, "cSize = %u \n", (U32)cSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003355 if (flush == zsf_end) zcs->frameEnded = 1;
3356 /* prepare next block */
3357 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3358 if (zcs->inBuffTarget > zcs->inBuffSize)
Yann Collet0be6fd32017-05-08 16:08:01 -07003359 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffTarget == blockSize <= inBuffSize */
3360 assert(zcs->inBuffTarget <= zcs->inBuffSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003361 zcs->inToCompress = zcs->inBuffPos;
3362 if (cDst == op) { op += cSize; break; } /* no need to flush */
3363 zcs->outBuffContentSize = cSize;
3364 zcs->outBuffFlushedSize = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -07003365 zcs->streamStage = zcss_flush; /* pass-through to flush stage */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003366 }
Jos Collin7cd7a752017-05-11 13:17:20 +05303367 /* fall-through */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003368 case zcss_flush:
Yann Collet0be6fd32017-05-08 16:08:01 -07003369 DEBUGLOG(5, "flush stage \n");
Yann Collet5a0c8e22016-08-12 01:20:36 +02003370 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3371 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
Yann Collet0be6fd32017-05-08 16:08:01 -07003372 DEBUGLOG(5, "toFlush: %u ; flushed: %u \n", (U32)toFlush, (U32)flushed);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003373 op += flushed;
3374 zcs->outBuffFlushedSize += flushed;
3375 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
3376 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
Yann Collet0be6fd32017-05-08 16:08:01 -07003377 zcs->streamStage = zcss_load;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003378 break;
3379 }
3380
3381 case zcss_final:
3382 someMoreWork = 0; /* do nothing */
3383 break;
3384
3385 default:
3386 return ERROR(GENERIC); /* impossible */
3387 }
3388 }
3389
3390 *srcSizePtr = ip - istart;
3391 *dstCapacityPtr = op - ostart;
3392 if (zcs->frameEnded) return 0;
3393 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3394 if (hintInSize==0) hintInSize = zcs->blockSize;
3395 return hintInSize;
3396 }
3397}
3398
Yann Collet53e17fb2016-08-17 01:39:22 +02003399size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003400{
Yann Collet53e17fb2016-08-17 01:39:22 +02003401 size_t sizeRead = input->size - input->pos;
3402 size_t sizeWritten = output->size - output->pos;
3403 size_t const result = ZSTD_compressStream_generic(zcs,
3404 (char*)(output->dst) + output->pos, &sizeWritten,
3405 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
3406 input->pos += sizeRead;
3407 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003408 return result;
3409}
3410
3411
Yann Collet104e5b02016-08-12 13:04:27 +02003412/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003413
3414/*! ZSTD_flushStream() :
3415* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003416size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003417{
3418 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003419 size_t sizeWritten = output->size - output->pos;
Yann Colletc4119022016-08-17 01:50:54 +02003420 size_t const result = ZSTD_compressStream_generic(zcs,
Yann Collet95d07d72016-09-06 16:38:51 +02003421 (char*)(output->dst) + output->pos, &sizeWritten,
3422 &srcSize, &srcSize, /* use a valid src address instead of NULL */
Yann Colletc4119022016-08-17 01:50:54 +02003423 zsf_flush);
Yann Collet53e17fb2016-08-17 01:39:22 +02003424 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003425 if (ZSTD_isError(result)) return result;
3426 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3427}
3428
3429
Yann Collet53e17fb2016-08-17 01:39:22 +02003430size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003431{
Yann Collet53e17fb2016-08-17 01:39:22 +02003432 BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
3433 BYTE* const oend = (BYTE*)(output->dst) + output->size;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003434 BYTE* op = ostart;
3435
Yann Collet0be6fd32017-05-08 16:08:01 -07003436 DEBUGLOG(5, "ZSTD_endStream (dstCapacity : %u) \n", (U32)(oend-op));
3437 if (zcs->streamStage != zcss_final) {
Yann Collet5a0c8e22016-08-12 01:20:36 +02003438 /* flush whatever remains */
3439 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003440 size_t sizeWritten = output->size - output->pos;
Yann Colletc17e0202017-04-20 12:50:02 -07003441 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten,
3442 &srcSize /* use a valid src address instead of NULL */, &srcSize, zsf_end);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003443 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3444 op += sizeWritten;
3445 if (remainingToFlush) {
Yann Collet53e17fb2016-08-17 01:39:22 +02003446 output->pos += sizeWritten;
Yann Collet0be6fd32017-05-08 16:08:01 -07003447 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */
3448 + ((zcs->params.fParams.checksumFlag > 0) * 4) /* optional 32-bits checksum */;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003449 }
3450 /* create epilogue */
Yann Collet0be6fd32017-05-08 16:08:01 -07003451 zcs->streamStage = zcss_final;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003452 zcs->outBuffContentSize = !notEnded ? 0 :
Yann Colletc17e0202017-04-20 12:50:02 -07003453 /* write epilogue, including final empty block, into outBuff */
Yann Collet0be6fd32017-05-08 16:08:01 -07003454 ZSTD_compressEnd(zcs, zcs->outBuff, zcs->outBuffSize, NULL, 0);
Yann Collet88009a82017-04-12 00:51:24 -07003455 if (ZSTD_isError(zcs->outBuffContentSize)) return zcs->outBuffContentSize;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003456 }
3457
3458 /* flush epilogue */
3459 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3460 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3461 op += flushed;
3462 zcs->outBuffFlushedSize += flushed;
Yann Collet53e17fb2016-08-17 01:39:22 +02003463 output->pos += op-ostart;
Yann Collet0be6fd32017-05-08 16:08:01 -07003464 if (toFlush==flushed) zcs->streamStage = zcss_init; /* end reached */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003465 return toFlush - flushed;
3466 }
3467}
3468
3469
3470
Yann Collet70e8c382016-02-10 13:37:52 +01003471/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003472
Yann Collet236d94f2016-05-18 12:06:33 +02003473#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02003474#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003475int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003476
Yann Collet3b719252016-03-30 19:48:05 +02003477static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003478{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003479 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003480 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003481 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3482 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003483 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3484 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003485 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3486 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3487 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003488 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003489 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3490 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3491 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3492 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3493 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3494 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3495 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3496 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003497 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
Yann Collet29297c62017-04-27 17:44:01 -07003498 { 23, 22, 22, 5, 4, 32, ZSTD_btopt }, /* level 18 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003499 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Nick Terrell374f8682017-05-10 17:48:42 -07003500 { 25, 25, 23, 7, 3, 64, ZSTD_btultra }, /* level 20 */
3501 { 26, 26, 23, 7, 3,256, ZSTD_btultra }, /* level 21 */
3502 { 27, 27, 25, 9, 3,512, ZSTD_btultra }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003503},
3504{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003505 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003506 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003507 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003508 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3509 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3510 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3511 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3512 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3513 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3514 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3515 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3516 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3517 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3518 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3519 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003520 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003521 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3522 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3523 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003524 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3525 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003526 { 18, 19, 18, 11, 3,512, ZSTD_btultra }, /* level 20.*/
3527 { 18, 19, 18, 12, 3,512, ZSTD_btultra }, /* level 21.*/
3528 { 18, 19, 18, 13, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003529},
3530{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003531 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003532 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3533 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3534 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3535 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3536 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3537 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3538 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3539 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3540 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3541 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3542 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3543 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3544 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3545 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003546 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3547 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3548 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3549 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3550 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3551 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003552 { 17, 18, 17, 9, 3,256, ZSTD_btultra }, /* level 20.*/
3553 { 17, 18, 17, 10, 3,256, ZSTD_btultra }, /* level 21.*/
3554 { 17, 18, 17, 11, 3,512, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003555},
3556{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003557 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003558 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003559 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003560 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3561 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3562 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3563 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3564 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3565 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3566 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3567 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003568 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3569 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3570 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3571 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3572 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3573 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3574 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3575 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3576 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3577 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Nick Terrell374f8682017-05-10 17:48:42 -07003578 { 14, 15, 15, 8, 3,256, ZSTD_btultra }, /* level 20.*/
3579 { 14, 15, 15, 9, 3,256, ZSTD_btultra }, /* level 21.*/
3580 { 14, 15, 15, 10, 3,256, ZSTD_btultra }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003581},
3582};
3583
Yann Collet236d94f2016-05-18 12:06:33 +02003584/*! ZSTD_getCParams() :
3585* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3586* Size values are optional, provide 0 if not known or unused */
Yann Collet52c04fe2016-07-07 11:53:18 +02003587ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003588{
Yann Collet15354142016-04-04 04:22:53 +02003589 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02003590 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02003591 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003592 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02003593 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003594 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003595 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003596 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3597 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003598 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003599 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3600 }
Yann Collet70d13012016-06-01 18:45:34 +02003601 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003602 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003603}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003604
3605/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003606* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003607* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet52c04fe2016-07-07 11:53:18 +02003608ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003609 ZSTD_parameters params;
3610 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3611 memset(&params, 0, sizeof(params));
3612 params.cParams = cParams;
3613 return params;
3614}