blob: ec758db00c37450781fecb79dd4af2efa43390ed [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 Colletf2a3b6e2016-05-31 18:13:56 +020016#define XXH_STATIC_LINKING_ONLY /* XXH64_state_t */
Yann Collet7ae67bb2016-09-06 06:28:05 +020017#include "xxhash.h" /* XXH_reset, update, digest */
Yann Collet5a0c8e22016-08-12 01:20:36 +020018#define FSE_STATIC_LINKING_ONLY /* FSE_encodeSymbol */
Yann Colletd0e2cd12016-06-05 00:58:01 +020019#include "fse.h"
Yann Collet130fe112016-06-05 00:42:28 +020020#define HUF_STATIC_LINKING_ONLY
21#include "huf.h"
Yann Colletd3b7f8d2016-06-04 19:47:02 +020022#include "zstd_internal.h" /* includes zstd.h */
Yann Colletf3eca252015-10-22 15:31:46 +010023
24
Yann Collet7d360282016-02-12 00:07:30 +010025/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010026* Constants
Yann Colletf3eca252015-10-22 15:31:46 +010027***************************************/
Yann Colletbb604482016-03-19 15:18:42 +010028static const U32 g_searchStrength = 8; /* control skip over incompressible data */
Yann Collet731ef162016-07-27 21:05:12 +020029#define HASH_READ_SIZE 8
30typedef enum { ZSTDcs_created=0, ZSTDcs_init, ZSTDcs_ongoing, ZSTDcs_ending } ZSTD_compressionStage_e;
Yann Colletf3eca252015-10-22 15:31:46 +010031
Yann Colletf3eca252015-10-22 15:31:46 +010032
Yann Collet7d360282016-02-12 00:07:30 +010033/*-*************************************
Yann Collet59d1f792016-01-23 19:28:41 +010034* Helper functions
35***************************************/
Yann Colletc261f712016-12-12 00:25:07 +010036#define ZSTD_STATIC_ASSERT(c) { enum { ZSTD_static_assert = 1/(int)(!!(c)) }; }
Yann Collet59d1f792016-01-23 19:28:41 +010037size_t ZSTD_compressBound(size_t srcSize) { return FSE_compressBound(srcSize) + 12; }
38
39
Yann Collet7d360282016-02-12 00:07:30 +010040/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010041* Sequence storage
Yann Colletf3eca252015-10-22 15:31:46 +010042***************************************/
Yann Collet14983e72015-11-11 21:38:21 +010043static void ZSTD_resetSeqStore(seqStore_t* ssPtr)
44{
Yann Collet14983e72015-11-11 21:38:21 +010045 ssPtr->lit = ssPtr->litStart;
Yann Colletc0ce4f12016-07-30 00:55:13 +020046 ssPtr->sequences = ssPtr->sequencesStart;
Yann Collet5d393572016-04-07 17:19:00 +020047 ssPtr->longLengthID = 0;
Yann Collet14983e72015-11-11 21:38:21 +010048}
49
50
Yann Collet7d360282016-02-12 00:07:30 +010051/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +010052* Context memory management
53***************************************/
Yann Colletaca113f2016-12-23 22:25:03 +010054struct ZSTD_CCtx_s {
Yann Collet89db5e02015-11-13 11:27:46 +010055 const BYTE* nextSrc; /* next block here to continue on current prefix */
Yann Colleteeb8ba12015-10-22 16:55:40 +010056 const BYTE* base; /* All regular indexes relative to this position */
57 const BYTE* dictBase; /* extDict indexes relative to this position */
Yann Colletf3eca252015-10-22 15:31:46 +010058 U32 dictLimit; /* below that point, need extDict */
Yann Colleteeb8ba12015-10-22 16:55:40 +010059 U32 lowLimit; /* below that point, no more data */
Yann Colletf3eca252015-10-22 15:31:46 +010060 U32 nextToUpdate; /* index from which to continue dictionary update */
inikepcc52a972016-02-19 10:09:35 +010061 U32 nextToUpdate3; /* index from which to continue dictionary update */
inikep7adceef2016-03-23 15:53:38 +010062 U32 hashLog3; /* dispatch table : larger == faster, more memory */
Yann Colletbb002742017-01-25 16:25:38 -080063 U32 loadedDictEnd; /* index of end of dictionary */
64 U32 forceWindow; /* force back-references to respect limit of 1<<wLog, even for dictionary */
Yann Collet14312d82017-02-23 23:42:12 -080065 U32 forceRawDict; /* Force loading dictionary in "content-only" mode (no header analysis) */
Yann Collet731ef162016-07-27 21:05:12 +020066 ZSTD_compressionStage_e stage;
Yann Collet4266c0a2016-06-14 01:49:25 +020067 U32 rep[ZSTD_REP_NUM];
Yann Colletb459aad2017-01-19 17:33:37 -080068 U32 repToConfirm[ZSTD_REP_NUM];
Yann Colletc46fb922016-05-29 05:01:04 +020069 U32 dictID;
Yann Collet5be2dd22015-11-11 13:43:58 +010070 ZSTD_parameters params;
Yann Collet712def92015-10-29 18:41:45 +010071 void* workSpace;
72 size_t workSpaceSize;
Yann Collet120230b2015-12-02 14:00:45 +010073 size_t blockSize;
Yann Collet673f0d72016-06-06 00:26:38 +020074 U64 frameContentSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +020075 XXH64_state_t xxhState;
inikep28669512016-06-02 13:04:18 +020076 ZSTD_customMem customMem;
Yann Colletecd651b2016-01-07 15:35:18 +010077
Yann Collet712def92015-10-29 18:41:45 +010078 seqStore_t seqStore; /* sequences storage ptrs */
Yann Collet083fcc82015-10-25 14:06:35 +010079 U32* hashTable;
inikepcc52a972016-02-19 10:09:35 +010080 U32* hashTable3;
Yann Collet8a57b922016-04-04 13:49:18 +020081 U32* chainTable;
Yann Colletb923f652016-01-26 03:14:20 +010082 HUF_CElt* hufTable;
Yann Colletfb810d62016-01-28 00:18:06 +010083 U32 flagStaticTables;
Yann Collet731ef162016-07-27 21:05:12 +020084 FSE_CTable offcodeCTable [FSE_CTABLE_SIZE_U32(OffFSELog, MaxOff)];
85 FSE_CTable matchlengthCTable[FSE_CTABLE_SIZE_U32(MLFSELog, MaxML)];
86 FSE_CTable litlengthCTable [FSE_CTABLE_SIZE_U32(LLFSELog, MaxLL)];
Yann Collete928f7e2016-12-01 16:13:35 -080087 unsigned tmpCounters[1024];
Yann Colletf3eca252015-10-22 15:31:46 +010088};
89
Yann Collet5be2dd22015-11-11 13:43:58 +010090ZSTD_CCtx* ZSTD_createCCtx(void)
Yann Colletf3eca252015-10-22 15:31:46 +010091{
inikep3763c772016-06-03 13:28:20 +020092 return ZSTD_createCCtx_advanced(defaultCustomMem);
inikep50e82c02016-05-23 15:49:09 +020093}
94
95ZSTD_CCtx* ZSTD_createCCtx_advanced(ZSTD_customMem customMem)
96{
Yann Collet69c2cdb2016-07-14 16:52:45 +020097 ZSTD_CCtx* cctx;
inikep50e82c02016-05-23 15:49:09 +020098
Yann Collet23b6e052016-08-28 21:05:43 -070099 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
100 if (!customMem.customAlloc || !customMem.customFree) return NULL;
inikep107e2432016-05-23 16:24:52 +0200101
Yann Collet23b6e052016-08-28 21:05:43 -0700102 cctx = (ZSTD_CCtx*) ZSTD_malloc(sizeof(ZSTD_CCtx), customMem);
Yann Collet69c2cdb2016-07-14 16:52:45 +0200103 if (!cctx) return NULL;
104 memset(cctx, 0, sizeof(ZSTD_CCtx));
Yann Colletbb002742017-01-25 16:25:38 -0800105 cctx->customMem = customMem;
Yann Collet69c2cdb2016-07-14 16:52:45 +0200106 return cctx;
Yann Colletf3eca252015-10-22 15:31:46 +0100107}
108
Yann Collet5be2dd22015-11-11 13:43:58 +0100109size_t ZSTD_freeCCtx(ZSTD_CCtx* cctx)
Yann Colletf3eca252015-10-22 15:31:46 +0100110{
inikep36403962016-06-03 16:36:50 +0200111 if (cctx==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -0700112 ZSTD_free(cctx->workSpace, cctx->customMem);
113 ZSTD_free(cctx, cctx->customMem);
Yann Collet982ffc72016-02-05 02:33:10 +0100114 return 0; /* reserved as a potential error code in the future */
Yann Collet083fcc82015-10-25 14:06:35 +0100115}
116
Yann Collet70e3b312016-08-23 01:18:06 +0200117size_t ZSTD_sizeof_CCtx(const ZSTD_CCtx* cctx)
Yann Collet3ae543c2016-07-11 03:12:17 +0200118{
Yann Colletd7c65892016-09-15 02:50:27 +0200119 if (cctx==NULL) return 0; /* support sizeof on NULL */
Yann Collet3ae543c2016-07-11 03:12:17 +0200120 return sizeof(*cctx) + cctx->workSpaceSize;
121}
122
Yann Colletbb002742017-01-25 16:25:38 -0800123size_t ZSTD_setCCtxParameter(ZSTD_CCtx* cctx, ZSTD_CCtxParameter param, unsigned value)
124{
125 switch(param)
126 {
Yann Collet06e76972017-01-25 16:39:03 -0800127 case ZSTD_p_forceWindow : cctx->forceWindow = value>0; cctx->loadedDictEnd = 0; return 0;
Yann Collet14312d82017-02-23 23:42:12 -0800128 case ZSTD_p_forceRawDict : cctx->forceRawDict = value>0; return 0;
Yann Colletbb002742017-01-25 16:25:38 -0800129 default: return ERROR(parameter_unknown);
130 }
131}
132
Yann Colletb44be742016-03-26 20:52:14 +0100133const seqStore_t* ZSTD_getSeqStore(const ZSTD_CCtx* ctx) /* hidden interface */
Yann Collet7d360282016-02-12 00:07:30 +0100134{
Yann Colletb44be742016-03-26 20:52:14 +0100135 return &(ctx->seqStore);
Yann Collet7d360282016-02-12 00:07:30 +0100136}
137
Yann Collet95162342016-10-25 16:19:52 -0700138static ZSTD_parameters ZSTD_getParamsFromCCtx(const ZSTD_CCtx* cctx)
139{
140 return cctx->params;
141}
142
Yann Collet59d70632015-11-04 12:05:27 +0100143
Yann Collet21588e32016-03-30 16:50:44 +0200144/** ZSTD_checkParams() :
145 ensure param values remain within authorized range.
146 @return : 0, or an error code if one value is beyond authorized range */
Yann Collet3b719252016-03-30 19:48:05 +0200147size_t ZSTD_checkCParams(ZSTD_compressionParameters cParams)
Yann Collet21588e32016-03-30 16:50:44 +0200148{
Yann Colletac8bace2016-09-07 14:54:23 +0200149# define CLAMPCHECK(val,min,max) { if ((val<min) | (val>max)) return ERROR(compressionParameter_unsupported); }
Yann Collet15354142016-04-04 04:22:53 +0200150 CLAMPCHECK(cParams.windowLog, ZSTD_WINDOWLOG_MIN, ZSTD_WINDOWLOG_MAX);
Yann Collet8a57b922016-04-04 13:49:18 +0200151 CLAMPCHECK(cParams.chainLog, ZSTD_CHAINLOG_MIN, ZSTD_CHAINLOG_MAX);
Yann Collet3b719252016-03-30 19:48:05 +0200152 CLAMPCHECK(cParams.hashLog, ZSTD_HASHLOG_MIN, ZSTD_HASHLOG_MAX);
153 CLAMPCHECK(cParams.searchLog, ZSTD_SEARCHLOG_MIN, ZSTD_SEARCHLOG_MAX);
Yann Colletedbcd9f2016-09-06 14:30:57 +0200154 { U32 const searchLengthMin = ((cParams.strategy == ZSTD_fast) | (cParams.strategy == ZSTD_greedy)) ? ZSTD_SEARCHLENGTH_MIN+1 : ZSTD_SEARCHLENGTH_MIN;
Yann Collet3b719252016-03-30 19:48:05 +0200155 U32 const searchLengthMax = (cParams.strategy == ZSTD_fast) ? ZSTD_SEARCHLENGTH_MAX : ZSTD_SEARCHLENGTH_MAX-1;
156 CLAMPCHECK(cParams.searchLength, searchLengthMin, searchLengthMax); }
157 CLAMPCHECK(cParams.targetLength, ZSTD_TARGETLENGTH_MIN, ZSTD_TARGETLENGTH_MAX);
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200158 if ((U32)(cParams.strategy) > (U32)ZSTD_btopt2) return ERROR(compressionParameter_unsupported);
Yann Collet21588e32016-03-30 16:50:44 +0200159 return 0;
160}
161
162
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100163/** ZSTD_cycleLog() :
164 * condition for correct operation : hashLog > 1 */
165static U32 ZSTD_cycleLog(U32 hashLog, ZSTD_strategy strat)
166{
167 U32 const btScale = ((U32)strat >= (U32)ZSTD_btlazy2);
168 return hashLog - btScale;
169}
170
Yann Collet70d13012016-06-01 18:45:34 +0200171/** ZSTD_adjustCParams() :
Yann Colletcf409a72016-09-26 16:41:05 +0200172 optimize `cPar` for a given input (`srcSize` and `dictSize`).
Yann Collet21588e32016-03-30 16:50:44 +0200173 mostly downsizing to reduce memory consumption and initialization.
174 Both `srcSize` and `dictSize` are optional (use 0 if unknown),
175 but if both are 0, no optimization can be done.
Yann Collet70d13012016-06-01 18:45:34 +0200176 Note : cPar is considered validated at this stage. Use ZSTD_checkParams() to ensure that. */
Yann Collet52c04fe2016-07-07 11:53:18 +0200177ZSTD_compressionParameters ZSTD_adjustCParams(ZSTD_compressionParameters cPar, unsigned long long srcSize, size_t dictSize)
Yann Collet59d70632015-11-04 12:05:27 +0100178{
Yann Collet70d13012016-06-01 18:45:34 +0200179 if (srcSize+dictSize == 0) return cPar; /* no size information available : no adjustment */
Yann Collet59d70632015-11-04 12:05:27 +0100180
Yann Collet70e45772016-03-19 18:08:32 +0100181 /* resize params, to use less memory when necessary */
Yann Colletdd6466a2016-03-30 20:06:26 +0200182 { U32 const minSrcSize = (srcSize==0) ? 500 : 0;
183 U64 const rSize = srcSize + dictSize + minSrcSize;
Yann Colletb59bf962016-04-04 14:53:16 +0200184 if (rSize < ((U64)1<<ZSTD_WINDOWLOG_MAX)) {
Yann Colletcf409a72016-09-26 16:41:05 +0200185 U32 const srcLog = MAX(ZSTD_HASHLOG_MIN, ZSTD_highbit32((U32)(rSize)-1) + 1);
Yann Collet70d13012016-06-01 18:45:34 +0200186 if (cPar.windowLog > srcLog) cPar.windowLog = srcLog;
Yann Collet21588e32016-03-30 16:50:44 +0200187 } }
Yann Collet70d13012016-06-01 18:45:34 +0200188 if (cPar.hashLog > cPar.windowLog) cPar.hashLog = cPar.windowLog;
Yann Colletc3a5c4b2016-12-12 00:47:30 +0100189 { U32 const cycleLog = ZSTD_cycleLog(cPar.chainLog, cPar.strategy);
190 if (cycleLog > cPar.windowLog) cPar.chainLog -= (cycleLog - cPar.windowLog);
191 }
Yann Colletc6eea2b2016-03-19 17:18:00 +0100192
Yann Collet70d13012016-06-01 18:45:34 +0200193 if (cPar.windowLog < ZSTD_WINDOWLOG_ABSOLUTEMIN) cPar.windowLog = ZSTD_WINDOWLOG_ABSOLUTEMIN; /* required for frame header */
Yann Collet70d13012016-06-01 18:45:34 +0200194
195 return cPar;
Yann Collet59d70632015-11-04 12:05:27 +0100196}
197
198
Yann Collet88472382016-07-14 17:05:38 +0200199size_t ZSTD_estimateCCtxSize(ZSTD_compressionParameters cParams)
Yann Collete74215e2016-03-19 16:09:09 +0100200{
Yann Collet731ef162016-07-27 21:05:12 +0200201 size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << cParams.windowLog);
202 U32 const divider = (cParams.searchLength==3) ? 3 : 4;
203 size_t const maxNbSeq = blockSize / divider;
204 size_t const tokenSpace = blockSize + 11*maxNbSeq;
Yann Collet3ae543c2016-07-11 03:12:17 +0200205
Yann Collet731ef162016-07-27 21:05:12 +0200206 size_t const chainSize = (cParams.strategy == ZSTD_fast) ? 0 : (1 << cParams.chainLog);
207 size_t const hSize = ((size_t)1) << cParams.hashLog;
208 U32 const hashLog3 = (cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, cParams.windowLog);
209 size_t const h3Size = ((size_t)1) << hashLog3;
210 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Collet3ae543c2016-07-11 03:12:17 +0200211
212 size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
213 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
214 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200215 + (((cParams.strategy == ZSTD_btopt) || (cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Collet3ae543c2016-07-11 03:12:17 +0200216
217 return sizeof(ZSTD_CCtx) + neededSpace;
Yann Collet2e91dde2016-03-08 12:22:11 +0100218}
219
Yann Colleta7737f62016-09-06 09:44:59 +0200220
221static U32 ZSTD_equivalentParams(ZSTD_parameters param1, ZSTD_parameters param2)
222{
223 return (param1.cParams.hashLog == param2.cParams.hashLog)
224 & (param1.cParams.chainLog == param2.cParams.chainLog)
Yann Colletedbcd9f2016-09-06 14:30:57 +0200225 & (param1.cParams.strategy == param2.cParams.strategy)
226 & ((param1.cParams.searchLength==3) == (param2.cParams.searchLength==3));
Yann Colleta7737f62016-09-06 09:44:59 +0200227}
228
229/*! ZSTD_continueCCtx() :
230 reuse CCtx without reset (note : requires no dictionary) */
231static size_t ZSTD_continueCCtx(ZSTD_CCtx* cctx, ZSTD_parameters params, U64 frameContentSize)
232{
233 U32 const end = (U32)(cctx->nextSrc - cctx->base);
234 cctx->params = params;
235 cctx->frameContentSize = frameContentSize;
236 cctx->lowLimit = end;
237 cctx->dictLimit = end;
238 cctx->nextToUpdate = end+1;
239 cctx->stage = ZSTDcs_init;
240 cctx->dictID = 0;
241 cctx->loadedDictEnd = 0;
242 { int i; for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = repStartValue[i]; }
Yann Colletb6249222016-09-06 09:54:22 +0200243 cctx->seqStore.litLengthSum = 0; /* force reset of btopt stats */
244 XXH64_reset(&cctx->xxhState, 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200245 return 0;
246}
247
248typedef enum { ZSTDcrp_continue, ZSTDcrp_noMemset, ZSTDcrp_fullReset } ZSTD_compResetPolicy_e;
249
Yann Collet27caf2a2016-04-01 15:48:48 +0200250/*! ZSTD_resetCCtx_advanced() :
Yann Colletdccd6b62017-02-27 15:57:50 -0800251 note : @params must be validated */
Yann Collet5be2dd22015-11-11 13:43:58 +0100252static size_t ZSTD_resetCCtx_advanced (ZSTD_CCtx* zc,
Yann Colletea2ecdc2016-07-14 22:43:12 +0200253 ZSTD_parameters params, U64 frameContentSize,
Yann Collet4cb21292016-09-15 14:54:07 +0200254 ZSTD_compResetPolicy_e const crp)
Yann Colleta7737f62016-09-06 09:44:59 +0200255{
Yann Collet4cb21292016-09-15 14:54:07 +0200256 if (crp == ZSTDcrp_continue)
Yann Colleta7737f62016-09-06 09:44:59 +0200257 if (ZSTD_equivalentParams(params, zc->params))
258 return ZSTD_continueCCtx(zc, params, frameContentSize);
inikep87d4f3d2016-03-02 15:56:24 +0100259
Yann Colleta7737f62016-09-06 09:44:59 +0200260 { size_t const blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, (size_t)1 << params.cParams.windowLog);
261 U32 const divider = (params.cParams.searchLength==3) ? 3 : 4;
262 size_t const maxNbSeq = blockSize / divider;
263 size_t const tokenSpace = blockSize + 11*maxNbSeq;
264 size_t const chainSize = (params.cParams.strategy == ZSTD_fast) ? 0 : (1 << params.cParams.chainLog);
265 size_t const hSize = ((size_t)1) << params.cParams.hashLog;
266 U32 const hashLog3 = (params.cParams.searchLength>3) ? 0 : MIN(ZSTD_HASHLOG3_MAX, params.cParams.windowLog);
267 size_t const h3Size = ((size_t)1) << hashLog3;
268 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
269 void* ptr;
Yann Collete74215e2016-03-19 16:09:09 +0100270
Yann Colleta7737f62016-09-06 09:44:59 +0200271 /* Check if workSpace is large enough, alloc a new one if needed */
272 { size_t const optSpace = ((MaxML+1) + (MaxLL+1) + (MaxOff+1) + (1<<Litbits))*sizeof(U32)
273 + (ZSTD_OPT_NUM+1)*(sizeof(ZSTD_match_t) + sizeof(ZSTD_optimal_t));
274 size_t const neededSpace = tableSpace + (256*sizeof(U32)) /* huffTable */ + tokenSpace
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200275 + (((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) ? optSpace : 0);
Yann Colleta7737f62016-09-06 09:44:59 +0200276 if (zc->workSpaceSize < neededSpace) {
277 ZSTD_free(zc->workSpace, zc->customMem);
278 zc->workSpace = ZSTD_malloc(neededSpace, zc->customMem);
279 if (zc->workSpace == NULL) return ERROR(memory_allocation);
280 zc->workSpaceSize = neededSpace;
281 } }
Yann Collet083fcc82015-10-25 14:06:35 +0100282
Yann Colleta7737f62016-09-06 09:44:59 +0200283 if (crp!=ZSTDcrp_noMemset) memset(zc->workSpace, 0, tableSpace); /* reset tables only */
284 XXH64_reset(&zc->xxhState, 0);
285 zc->hashLog3 = hashLog3;
286 zc->hashTable = (U32*)(zc->workSpace);
287 zc->chainTable = zc->hashTable + hSize;
288 zc->hashTable3 = zc->chainTable + chainSize;
289 ptr = zc->hashTable3 + h3Size;
290 zc->hufTable = (HUF_CElt*)ptr;
291 zc->flagStaticTables = 0;
292 ptr = ((U32*)ptr) + 256; /* note : HUF_CElt* is incomplete type, size is simulated using U32 */
Yann Collet70e8c382016-02-10 13:37:52 +0100293
Yann Colleta7737f62016-09-06 09:44:59 +0200294 zc->nextToUpdate = 1;
295 zc->nextSrc = NULL;
296 zc->base = NULL;
297 zc->dictBase = NULL;
298 zc->dictLimit = 0;
299 zc->lowLimit = 0;
300 zc->params = params;
301 zc->blockSize = blockSize;
302 zc->frameContentSize = frameContentSize;
303 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = repStartValue[i]; }
304
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +0200305 if ((params.cParams.strategy == ZSTD_btopt) || (params.cParams.strategy == ZSTD_btopt2)) {
Yann Colleta7737f62016-09-06 09:44:59 +0200306 zc->seqStore.litFreq = (U32*)ptr;
307 zc->seqStore.litLengthFreq = zc->seqStore.litFreq + (1<<Litbits);
308 zc->seqStore.matchLengthFreq = zc->seqStore.litLengthFreq + (MaxLL+1);
309 zc->seqStore.offCodeFreq = zc->seqStore.matchLengthFreq + (MaxML+1);
310 ptr = zc->seqStore.offCodeFreq + (MaxOff+1);
311 zc->seqStore.matchTable = (ZSTD_match_t*)ptr;
312 ptr = zc->seqStore.matchTable + ZSTD_OPT_NUM+1;
313 zc->seqStore.priceTable = (ZSTD_optimal_t*)ptr;
314 ptr = zc->seqStore.priceTable + ZSTD_OPT_NUM+1;
315 zc->seqStore.litLengthSum = 0;
316 }
317 zc->seqStore.sequencesStart = (seqDef*)ptr;
318 ptr = zc->seqStore.sequencesStart + maxNbSeq;
319 zc->seqStore.llCode = (BYTE*) ptr;
320 zc->seqStore.mlCode = zc->seqStore.llCode + maxNbSeq;
321 zc->seqStore.ofCode = zc->seqStore.mlCode + maxNbSeq;
322 zc->seqStore.litStart = zc->seqStore.ofCode + maxNbSeq;
323
324 zc->stage = ZSTDcs_init;
325 zc->dictID = 0;
326 zc->loadedDictEnd = 0;
327
328 return 0;
Yann Collet72d706a2016-03-23 20:44:12 +0100329 }
Yann Colletf3eca252015-10-22 15:31:46 +0100330}
331
Yann Collet32dfae62017-01-19 10:32:55 -0800332/* ZSTD_invalidateRepCodes() :
333 * ensures next compression will not use repcodes from previous block.
334 * Note : only works with regular variant;
335 * do not use with extDict variant ! */
336void ZSTD_invalidateRepCodes(ZSTD_CCtx* cctx) {
337 int i;
338 for (i=0; i<ZSTD_REP_NUM; i++) cctx->rep[i] = 0;
339}
Yann Collet083fcc82015-10-25 14:06:35 +0100340
Yann Collet370b08e2016-03-08 00:03:59 +0100341/*! ZSTD_copyCCtx() :
342* Duplicate an existing context `srcCCtx` into another one `dstCCtx`.
Yann Collet731ef162016-07-27 21:05:12 +0200343* Only works during stage ZSTDcs_init (i.e. after creation, but before first call to ZSTD_compressContinue()).
Yann Collet7b51a292016-01-26 15:58:49 +0100344* @return : 0, or an error code */
Yann Collet97b378a2016-09-21 17:20:19 +0200345size_t ZSTD_copyCCtx(ZSTD_CCtx* dstCCtx, const ZSTD_CCtx* srcCCtx, unsigned long long pledgedSrcSize)
Yann Collet7b51a292016-01-26 15:58:49 +0100346{
Yann Collet731ef162016-07-27 21:05:12 +0200347 if (srcCCtx->stage!=ZSTDcs_init) return ERROR(stage_wrong);
Yann Collet7b51a292016-01-26 15:58:49 +0100348
Sean Purcell2db72492017-02-09 10:50:43 -0800349
inikep28669512016-06-02 13:04:18 +0200350 memcpy(&dstCCtx->customMem, &srcCCtx->customMem, sizeof(ZSTD_customMem));
Sean Purcell2db72492017-02-09 10:50:43 -0800351 { ZSTD_parameters params = srcCCtx->params;
352 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
353 ZSTD_resetCCtx_advanced(dstCCtx, params, pledgedSrcSize, ZSTDcrp_noMemset);
354 }
Yann Collet7b51a292016-01-26 15:58:49 +0100355
356 /* copy tables */
Yann Collet731ef162016-07-27 21:05:12 +0200357 { size_t const chainSize = (srcCCtx->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << srcCCtx->params.cParams.chainLog);
358 size_t const hSize = ((size_t)1) << srcCCtx->params.cParams.hashLog;
359 size_t const h3Size = (size_t)1 << srcCCtx->hashLog3;
360 size_t const tableSpace = (chainSize + hSize + h3Size) * sizeof(U32);
Yann Colletc6eea2b2016-03-19 17:18:00 +0100361 memcpy(dstCCtx->workSpace, srcCCtx->workSpace, tableSpace);
362 }
Yann Collet7b51a292016-01-26 15:58:49 +0100363
Yann Colletc46fb922016-05-29 05:01:04 +0200364 /* copy dictionary offsets */
Yann Colletc6eea2b2016-03-19 17:18:00 +0100365 dstCCtx->nextToUpdate = srcCCtx->nextToUpdate;
366 dstCCtx->nextToUpdate3= srcCCtx->nextToUpdate3;
367 dstCCtx->nextSrc = srcCCtx->nextSrc;
368 dstCCtx->base = srcCCtx->base;
369 dstCCtx->dictBase = srcCCtx->dictBase;
370 dstCCtx->dictLimit = srcCCtx->dictLimit;
371 dstCCtx->lowLimit = srcCCtx->lowLimit;
372 dstCCtx->loadedDictEnd= srcCCtx->loadedDictEnd;
Yann Colletc46fb922016-05-29 05:01:04 +0200373 dstCCtx->dictID = srcCCtx->dictID;
Yann Collet7b51a292016-01-26 15:58:49 +0100374
Yann Colletfb810d62016-01-28 00:18:06 +0100375 /* copy entropy tables */
376 dstCCtx->flagStaticTables = srcCCtx->flagStaticTables;
Yann Collet863ec402016-01-28 17:56:33 +0100377 if (srcCCtx->flagStaticTables) {
Yann Collet7b51a292016-01-26 15:58:49 +0100378 memcpy(dstCCtx->hufTable, srcCCtx->hufTable, 256*4);
Yann Colletfb810d62016-01-28 00:18:06 +0100379 memcpy(dstCCtx->litlengthCTable, srcCCtx->litlengthCTable, sizeof(dstCCtx->litlengthCTable));
380 memcpy(dstCCtx->matchlengthCTable, srcCCtx->matchlengthCTable, sizeof(dstCCtx->matchlengthCTable));
381 memcpy(dstCCtx->offcodeCTable, srcCCtx->offcodeCTable, sizeof(dstCCtx->offcodeCTable));
382 }
Yann Collet7b51a292016-01-26 15:58:49 +0100383
384 return 0;
385}
386
387
Yann Colletecabfe32016-03-20 16:20:06 +0100388/*! ZSTD_reduceTable() :
Yann Colletd64f4352016-03-21 00:07:42 +0100389* reduce table indexes by `reducerValue` */
Yann Colletecabfe32016-03-20 16:20:06 +0100390static void ZSTD_reduceTable (U32* const table, U32 const size, U32 const reducerValue)
Yann Collet89db5e02015-11-13 11:27:46 +0100391{
Yann Colletecabfe32016-03-20 16:20:06 +0100392 U32 u;
393 for (u=0 ; u < size ; u++) {
394 if (table[u] < reducerValue) table[u] = 0;
395 else table[u] -= reducerValue;
Yann Collet89db5e02015-11-13 11:27:46 +0100396 }
397}
398
Yann Colletecabfe32016-03-20 16:20:06 +0100399/*! ZSTD_reduceIndex() :
400* rescale all indexes to avoid future overflow (indexes are U32) */
401static void ZSTD_reduceIndex (ZSTD_CCtx* zc, const U32 reducerValue)
402{
Yann Collet731ef162016-07-27 21:05:12 +0200403 { U32 const hSize = 1 << zc->params.cParams.hashLog;
Yann Colletecabfe32016-03-20 16:20:06 +0100404 ZSTD_reduceTable(zc->hashTable, hSize, reducerValue); }
405
Yann Collet731ef162016-07-27 21:05:12 +0200406 { U32 const chainSize = (zc->params.cParams.strategy == ZSTD_fast) ? 0 : (1 << zc->params.cParams.chainLog);
Yann Collet8a57b922016-04-04 13:49:18 +0200407 ZSTD_reduceTable(zc->chainTable, chainSize, reducerValue); }
Yann Colletecabfe32016-03-20 16:20:06 +0100408
Yann Collet731ef162016-07-27 21:05:12 +0200409 { U32 const h3Size = (zc->hashLog3) ? 1 << zc->hashLog3 : 0;
Yann Colletecabfe32016-03-20 16:20:06 +0100410 ZSTD_reduceTable(zc->hashTable3, h3Size, reducerValue); }
411}
412
Yann Collet89db5e02015-11-13 11:27:46 +0100413
Yann Collet863ec402016-01-28 17:56:33 +0100414/*-*******************************************************
Yann Collet14983e72015-11-11 21:38:21 +0100415* Block entropic compression
416*********************************************************/
Yann Collet14983e72015-11-11 21:38:21 +0100417
Przemyslaw Skibinski3ee94a72016-10-24 15:58:07 +0200418/* See doc/zstd_compression_format.md for detailed format description */
Yann Collet14983e72015-11-11 21:38:21 +0100419
Yann Colletd1b26842016-03-15 01:24:33 +0100420size_t ZSTD_noCompressBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100421{
Yann Colletd1b26842016-03-15 01:24:33 +0100422 if (srcSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet6fa05a22016-07-20 14:58:49 +0200423 memcpy((BYTE*)dst + ZSTD_blockHeaderSize, src, srcSize);
424 MEM_writeLE24(dst, (U32)(srcSize << 2) + (U32)bt_raw);
Yann Collet14983e72015-11-11 21:38:21 +0100425 return ZSTD_blockHeaderSize+srcSize;
426}
427
428
Yann Colletd1b26842016-03-15 01:24:33 +0100429static size_t ZSTD_noCompressLiterals (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100430{
431 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200432 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100433
Yann Colletd1b26842016-03-15 01:24:33 +0100434 if (srcSize + flSize > dstCapacity) return ERROR(dstSize_tooSmall);
Yann Collet14983e72015-11-11 21:38:21 +0100435
Yann Collet59d1f792016-01-23 19:28:41 +0100436 switch(flSize)
437 {
438 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200439 ostart[0] = (BYTE)((U32)set_basic + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100440 break;
441 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200442 MEM_writeLE16(ostart, (U16)((U32)set_basic + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100443 break;
444 default: /*note : should not be necessary : flSize is within {1,2,3} */
445 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200446 MEM_writeLE32(ostart, (U32)((U32)set_basic + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100447 break;
448 }
449
450 memcpy(ostart + flSize, src, srcSize);
451 return srcSize + flSize;
Yann Collet14983e72015-11-11 21:38:21 +0100452}
453
Yann Colletd1b26842016-03-15 01:24:33 +0100454static size_t ZSTD_compressRleLiteralsBlock (void* dst, size_t dstCapacity, const void* src, size_t srcSize)
Yann Collet14983e72015-11-11 21:38:21 +0100455{
456 BYTE* const ostart = (BYTE* const)dst;
Yann Collet731ef162016-07-27 21:05:12 +0200457 U32 const flSize = 1 + (srcSize>31) + (srcSize>4095);
Yann Collet14983e72015-11-11 21:38:21 +0100458
Yann Collet198e6aa2016-07-20 20:12:24 +0200459 (void)dstCapacity; /* dstCapacity already guaranteed to be >=4, hence large enough */
Yann Collet59d1f792016-01-23 19:28:41 +0100460
461 switch(flSize)
462 {
463 case 1: /* 2 - 1 - 5 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200464 ostart[0] = (BYTE)((U32)set_rle + (srcSize<<3));
Yann Collet59d1f792016-01-23 19:28:41 +0100465 break;
466 case 2: /* 2 - 2 - 12 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200467 MEM_writeLE16(ostart, (U16)((U32)set_rle + (1<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100468 break;
Yann Colleta910dc82016-03-18 12:37:45 +0100469 default: /*note : should not be necessary : flSize is necessarily within {1,2,3} */
Yann Collet59d1f792016-01-23 19:28:41 +0100470 case 3: /* 2 - 2 - 20 */
Yann Colletf8e7b532016-07-23 16:31:49 +0200471 MEM_writeLE32(ostart, (U32)((U32)set_rle + (3<<2) + (srcSize<<4)));
Yann Collet59d1f792016-01-23 19:28:41 +0100472 break;
473 }
474
475 ostart[flSize] = *(const BYTE*)src;
476 return flSize+1;
Yann Collet14983e72015-11-11 21:38:21 +0100477}
478
Yann Collet59d1f792016-01-23 19:28:41 +0100479
Yann Colleta5c2c082016-03-20 01:09:18 +0100480static size_t ZSTD_minGain(size_t srcSize) { return (srcSize >> 6) + 2; }
Yann Collet14983e72015-11-11 21:38:21 +0100481
Yann Colletb923f652016-01-26 03:14:20 +0100482static size_t ZSTD_compressLiterals (ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100483 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100484 const void* src, size_t srcSize)
485{
Yann Colleta910dc82016-03-18 12:37:45 +0100486 size_t const minGain = ZSTD_minGain(srcSize);
487 size_t const lhSize = 3 + (srcSize >= 1 KB) + (srcSize >= 16 KB);
Yann Collet731ef162016-07-27 21:05:12 +0200488 BYTE* const ostart = (BYTE*)dst;
Yann Colletafe07092016-01-25 04:10:46 +0100489 U32 singleStream = srcSize < 256;
Yann Colletf8e7b532016-07-23 16:31:49 +0200490 symbolEncodingType_e hType = set_compressed;
Yann Colleta910dc82016-03-18 12:37:45 +0100491 size_t cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100492
Yann Collet14983e72015-11-11 21:38:21 +0100493
Yann Colleta5c2c082016-03-20 01:09:18 +0100494 /* small ? don't even attempt compression (speed opt) */
495# define LITERAL_NOENTROPY 63
496 { size_t const minLitSize = zc->flagStaticTables ? 6 : LITERAL_NOENTROPY;
497 if (srcSize <= minLitSize) return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
498 }
499
500 if (dstCapacity < lhSize+1) return ERROR(dstSize_tooSmall); /* not enough space for compression */
Yann Colletfb810d62016-01-28 00:18:06 +0100501 if (zc->flagStaticTables && (lhSize==3)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200502 hType = set_repeat;
Yann Colletb923f652016-01-26 03:14:20 +0100503 singleStream = 1;
Yann Colleta910dc82016-03-18 12:37:45 +0100504 cLitSize = HUF_compress1X_usingCTable(ostart+lhSize, dstCapacity-lhSize, src, srcSize, zc->hufTable);
Yann Colletfb810d62016-01-28 00:18:06 +0100505 } else {
Yann Colleta0d742b2016-12-01 17:47:30 -0800506 cLitSize = singleStream ? HUF_compress1X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters))
507 : HUF_compress4X_wksp(ostart+lhSize, dstCapacity-lhSize, src, srcSize, 255, 11, zc->tmpCounters, sizeof(zc->tmpCounters));
Yann Colletb923f652016-01-26 03:14:20 +0100508 }
Yann Collet14983e72015-11-11 21:38:21 +0100509
Yann Collet98c88842016-07-15 16:12:38 +0200510 if ((cLitSize==0) | (cLitSize >= srcSize - minGain))
Yann Colleta910dc82016-03-18 12:37:45 +0100511 return ZSTD_noCompressLiterals(dst, dstCapacity, src, srcSize);
512 if (cLitSize==1)
513 return ZSTD_compressRleLiteralsBlock(dst, dstCapacity, src, srcSize);
Yann Collet14983e72015-11-11 21:38:21 +0100514
515 /* Build header */
Yann Collet59d1f792016-01-23 19:28:41 +0100516 switch(lhSize)
Yann Collet14983e72015-11-11 21:38:21 +0100517 {
Yann Collet59d1f792016-01-23 19:28:41 +0100518 case 3: /* 2 - 2 - 10 - 10 */
Yann Colletc2e1a682016-07-22 17:30:52 +0200519 { U32 const lhc = hType + ((!singleStream) << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<14);
Yann Collet198e6aa2016-07-20 20:12:24 +0200520 MEM_writeLE24(ostart, lhc);
521 break;
522 }
Yann Collet59d1f792016-01-23 19:28:41 +0100523 case 4: /* 2 - 2 - 14 - 14 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200524 { U32 const lhc = hType + (2 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<18);
Yann Collet198e6aa2016-07-20 20:12:24 +0200525 MEM_writeLE32(ostart, lhc);
526 break;
527 }
Yann Colleta910dc82016-03-18 12:37:45 +0100528 default: /* should not be necessary, lhSize is only {3,4,5} */
Yann Collet59d1f792016-01-23 19:28:41 +0100529 case 5: /* 2 - 2 - 18 - 18 */
Yann Collet32faf6c2016-07-22 04:45:06 +0200530 { U32 const lhc = hType + (3 << 2) + ((U32)srcSize<<4) + ((U32)cLitSize<<22);
Yann Collet198e6aa2016-07-20 20:12:24 +0200531 MEM_writeLE32(ostart, lhc);
532 ostart[4] = (BYTE)(cLitSize >> 10);
533 break;
534 }
Yann Collet14983e72015-11-11 21:38:21 +0100535 }
Yann Colleta910dc82016-03-18 12:37:45 +0100536 return lhSize+cLitSize;
Yann Collet14983e72015-11-11 21:38:21 +0100537}
538
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200539static const BYTE LL_Code[64] = { 0, 1, 2, 3, 4, 5, 6, 7,
540 8, 9, 10, 11, 12, 13, 14, 15,
541 16, 16, 17, 17, 18, 18, 19, 19,
542 20, 20, 20, 20, 21, 21, 21, 21,
543 22, 22, 22, 22, 22, 22, 22, 22,
544 23, 23, 23, 23, 23, 23, 23, 23,
545 24, 24, 24, 24, 24, 24, 24, 24,
546 24, 24, 24, 24, 24, 24, 24, 24 };
Yann Collet14983e72015-11-11 21:38:21 +0100547
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200548static const BYTE ML_Code[128] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
549 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
550 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 36, 36, 37, 37, 37, 37,
551 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39,
552 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
553 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
554 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
555 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42 };
Yann Colleted57d852016-07-29 21:22:17 +0200556
557
558void ZSTD_seqToCodes(const seqStore_t* seqStorePtr)
Yann Colletb44be742016-03-26 20:52:14 +0100559{
Yann Colleted57d852016-07-29 21:22:17 +0200560 BYTE const LL_deltaCode = 19;
561 BYTE const ML_deltaCode = 36;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200562 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200563 BYTE* const llCodeTable = seqStorePtr->llCode;
564 BYTE* const ofCodeTable = seqStorePtr->ofCode;
565 BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200566 U32 const nbSeq = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart);
Yann Colleted57d852016-07-29 21:22:17 +0200567 U32 u;
568 for (u=0; u<nbSeq; u++) {
569 U32 const llv = sequences[u].litLength;
570 U32 const mlv = sequences[u].matchLength;
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200571 llCodeTable[u] = (llv> 63) ? (BYTE)ZSTD_highbit32(llv) + LL_deltaCode : LL_Code[llv];
Yann Colleted57d852016-07-29 21:22:17 +0200572 ofCodeTable[u] = (BYTE)ZSTD_highbit32(sequences[u].offset);
Yann Collet3b2bd1d2016-07-30 13:21:41 +0200573 mlCodeTable[u] = (mlv>127) ? (BYTE)ZSTD_highbit32(mlv) + ML_deltaCode : ML_Code[mlv];
Yann Collet5d393572016-04-07 17:19:00 +0200574 }
Yann Colleted57d852016-07-29 21:22:17 +0200575 if (seqStorePtr->longLengthID==1)
576 llCodeTable[seqStorePtr->longLengthPos] = MaxLL;
577 if (seqStorePtr->longLengthID==2)
578 mlCodeTable[seqStorePtr->longLengthPos] = MaxML;
Yann Colletb44be742016-03-26 20:52:14 +0100579}
580
581
Yann Colletb923f652016-01-26 03:14:20 +0100582size_t ZSTD_compressSequences(ZSTD_CCtx* zc,
Yann Colletd1b26842016-03-15 01:24:33 +0100583 void* dst, size_t dstCapacity,
Yann Collet14983e72015-11-11 21:38:21 +0100584 size_t srcSize)
585{
Yann Colletb923f652016-01-26 03:14:20 +0100586 const seqStore_t* seqStorePtr = &(zc->seqStore);
Yann Collet14983e72015-11-11 21:38:21 +0100587 U32 count[MaxSeq+1];
588 S16 norm[MaxSeq+1];
Yann Colletfb810d62016-01-28 00:18:06 +0100589 FSE_CTable* CTable_LitLength = zc->litlengthCTable;
590 FSE_CTable* CTable_OffsetBits = zc->offcodeCTable;
591 FSE_CTable* CTable_MatchLength = zc->matchlengthCTable;
Yann Collet14983e72015-11-11 21:38:21 +0100592 U32 LLtype, Offtype, MLtype; /* compressed, raw or rle */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200593 const seqDef* const sequences = seqStorePtr->sequencesStart;
Yann Colleted57d852016-07-29 21:22:17 +0200594 const BYTE* const ofCodeTable = seqStorePtr->ofCode;
595 const BYTE* const llCodeTable = seqStorePtr->llCode;
596 const BYTE* const mlCodeTable = seqStorePtr->mlCode;
Yann Collet5054ee02015-11-23 13:34:21 +0100597 BYTE* const ostart = (BYTE*)dst;
Yann Colletd1b26842016-03-15 01:24:33 +0100598 BYTE* const oend = ostart + dstCapacity;
Yann Colleta910dc82016-03-18 12:37:45 +0100599 BYTE* op = ostart;
Yann Colletc0ce4f12016-07-30 00:55:13 +0200600 size_t const nbSeq = seqStorePtr->sequences - seqStorePtr->sequencesStart;
Yann Collet14983e72015-11-11 21:38:21 +0100601 BYTE* seqHead;
Yann Colletd79a9a02016-11-30 15:52:20 -0800602 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Collet14983e72015-11-11 21:38:21 +0100603
Yann Collet14983e72015-11-11 21:38:21 +0100604 /* Compress literals */
Yann Colleta5c2c082016-03-20 01:09:18 +0100605 { const BYTE* const literals = seqStorePtr->litStart;
Yann Colleta910dc82016-03-18 12:37:45 +0100606 size_t const litSize = seqStorePtr->lit - literals;
Yann Colleta5c2c082016-03-20 01:09:18 +0100607 size_t const cSize = ZSTD_compressLiterals(zc, op, dstCapacity, literals, litSize);
Yann Collet14983e72015-11-11 21:38:21 +0100608 if (ZSTD_isError(cSize)) return cSize;
609 op += cSize;
610 }
611
612 /* Sequences Header */
Yann Collet7cbe79a2016-03-23 22:31:57 +0100613 if ((oend-op) < 3 /*max nbSeq Size*/ + 1 /*seqHead */) return ERROR(dstSize_tooSmall);
Yann Colletd409db62016-03-04 14:45:31 +0100614 if (nbSeq < 0x7F) *op++ = (BYTE)nbSeq;
615 else if (nbSeq < LONGNBSEQ) op[0] = (BYTE)((nbSeq>>8) + 0x80), op[1] = (BYTE)nbSeq, op+=2;
616 else op[0]=0xFF, MEM_writeLE16(op+1, (U16)(nbSeq - LONGNBSEQ)), op+=3;
Yann Collete93d6ce2016-01-31 00:58:06 +0100617 if (nbSeq==0) goto _check_compressibility;
Yann Collet14983e72015-11-11 21:38:21 +0100618
Yann Colletbe391432016-03-22 23:19:28 +0100619 /* seqHead : flags for FSE encoding type */
620 seqHead = op++;
Yann Collet14983e72015-11-11 21:38:21 +0100621
Yann Colletfb810d62016-01-28 00:18:06 +0100622#define MIN_SEQ_FOR_DYNAMIC_FSE 64
623#define MAX_SEQ_FOR_STATIC_FSE 1000
624
Yann Colletb44be742016-03-26 20:52:14 +0100625 /* convert length/distances into codes */
Yann Colleted57d852016-07-29 21:22:17 +0200626 ZSTD_seqToCodes(seqStorePtr);
Yann Collet597847a2016-03-20 19:14:22 +0100627
Yann Collet14983e72015-11-11 21:38:21 +0100628 /* CTable for Literal Lengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100629 { U32 max = MaxLL;
Yann Collete928f7e2016-12-01 16:13:35 -0800630 size_t const mostFrequent = FSE_countFast_wksp(count, &max, llCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100631 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
632 *op++ = llCodeTable[0];
633 FSE_buildCTable_rle(CTable_LitLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200634 LLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100635 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200636 LLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100637 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (LL_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800638 FSE_buildCTable_wksp(CTable_LitLength, LL_defaultNorm, MaxLL, LL_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200639 LLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100640 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100641 size_t nbSeq_1 = nbSeq;
642 const U32 tableLog = FSE_optimalTableLog(LLFSELog, nbSeq, max);
643 if (count[llCodeTable[nbSeq-1]]>1) { count[llCodeTable[nbSeq-1]]--; nbSeq_1--; }
644 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100645 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
646 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
647 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800648 FSE_buildCTable_wksp(CTable_LitLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200649 LLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100650 } }
Yann Collet14983e72015-11-11 21:38:21 +0100651
Yann Colletb44be742016-03-26 20:52:14 +0100652 /* CTable for Offsets */
Yann Colletfadda6c2016-03-22 12:14:26 +0100653 { U32 max = MaxOff;
Yann Collete928f7e2016-12-01 16:13:35 -0800654 size_t const mostFrequent = FSE_countFast_wksp(count, &max, ofCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100655 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet7cbe79a2016-03-23 22:31:57 +0100656 *op++ = ofCodeTable[0];
Yann Colletfadda6c2016-03-22 12:14:26 +0100657 FSE_buildCTable_rle(CTable_OffsetBits, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200658 Offtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100659 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200660 Offtype = set_repeat;
Yann Collet48537162016-04-07 15:24:29 +0200661 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (OF_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800662 FSE_buildCTable_wksp(CTable_OffsetBits, OF_defaultNorm, MaxOff, OF_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200663 Offtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100664 } else {
Yann Colletfadda6c2016-03-22 12:14:26 +0100665 size_t nbSeq_1 = nbSeq;
666 const U32 tableLog = FSE_optimalTableLog(OffFSELog, nbSeq, max);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100667 if (count[ofCodeTable[nbSeq-1]]>1) { count[ofCodeTable[nbSeq-1]]--; nbSeq_1--; }
Yann Colletfadda6c2016-03-22 12:14:26 +0100668 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
Yann Colletadd08d62016-03-23 01:32:41 +0100669 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
670 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
671 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800672 FSE_buildCTable_wksp(CTable_OffsetBits, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200673 Offtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100674 } }
675
Yann Collet14983e72015-11-11 21:38:21 +0100676 /* CTable for MatchLengths */
Yann Colletfadda6c2016-03-22 12:14:26 +0100677 { U32 max = MaxML;
Yann Collete928f7e2016-12-01 16:13:35 -0800678 size_t const mostFrequent = FSE_countFast_wksp(count, &max, mlCodeTable, nbSeq, zc->tmpCounters);
Yann Colletfadda6c2016-03-22 12:14:26 +0100679 if ((mostFrequent == nbSeq) && (nbSeq > 2)) {
Yann Collet72d706a2016-03-23 20:44:12 +0100680 *op++ = *mlCodeTable;
Yann Colletfadda6c2016-03-22 12:14:26 +0100681 FSE_buildCTable_rle(CTable_MatchLength, (BYTE)max);
Yann Colletf8e7b532016-07-23 16:31:49 +0200682 MLtype = set_rle;
Yann Colletfadda6c2016-03-22 12:14:26 +0100683 } else if ((zc->flagStaticTables) && (nbSeq < MAX_SEQ_FOR_STATIC_FSE)) {
Yann Colletf8e7b532016-07-23 16:31:49 +0200684 MLtype = set_repeat;
Yann Colletfadda6c2016-03-22 12:14:26 +0100685 } else if ((nbSeq < MIN_SEQ_FOR_DYNAMIC_FSE) || (mostFrequent < (nbSeq >> (ML_defaultNormLog-1)))) {
Yann Colletd79a9a02016-11-30 15:52:20 -0800686 FSE_buildCTable_wksp(CTable_MatchLength, ML_defaultNorm, MaxML, ML_defaultNormLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200687 MLtype = set_basic;
Yann Colletfadda6c2016-03-22 12:14:26 +0100688 } else {
689 size_t nbSeq_1 = nbSeq;
690 const U32 tableLog = FSE_optimalTableLog(MLFSELog, nbSeq, max);
691 if (count[mlCodeTable[nbSeq-1]]>1) { count[mlCodeTable[nbSeq-1]]--; nbSeq_1--; }
692 FSE_normalizeCount(norm, tableLog, count, nbSeq_1, max);
693 { size_t const NCountSize = FSE_writeNCount(op, oend-op, norm, max, tableLog); /* overflow protected */
694 if (FSE_isError(NCountSize)) return ERROR(GENERIC);
695 op += NCountSize; }
Yann Colletd79a9a02016-11-30 15:52:20 -0800696 FSE_buildCTable_wksp(CTable_MatchLength, norm, max, tableLog, scratchBuffer, sizeof(scratchBuffer));
Yann Colletf8e7b532016-07-23 16:31:49 +0200697 MLtype = set_compressed;
Yann Colletfadda6c2016-03-22 12:14:26 +0100698 } }
Yann Collet14983e72015-11-11 21:38:21 +0100699
Yann Colletbe391432016-03-22 23:19:28 +0100700 *seqHead = (BYTE)((LLtype<<6) + (Offtype<<4) + (MLtype<<2));
Yann Colletfb810d62016-01-28 00:18:06 +0100701 zc->flagStaticTables = 0;
Yann Collet14983e72015-11-11 21:38:21 +0100702
703 /* Encoding Sequences */
Yann Collet70e45772016-03-19 18:08:32 +0100704 { BIT_CStream_t blockStream;
Yann Colleta910dc82016-03-18 12:37:45 +0100705 FSE_CState_t stateMatchLength;
706 FSE_CState_t stateOffsetBits;
707 FSE_CState_t stateLitLength;
Yann Collet14983e72015-11-11 21:38:21 +0100708
Yann Collet95d07d72016-09-06 16:38:51 +0200709 CHECK_E(BIT_initCStream(&blockStream, op, oend-op), dstSize_tooSmall); /* not enough space remaining */
Yann Collet14983e72015-11-11 21:38:21 +0100710
Yann Collet597847a2016-03-20 19:14:22 +0100711 /* first symbols */
Yann Colletfadda6c2016-03-22 12:14:26 +0100712 FSE_initCState2(&stateMatchLength, CTable_MatchLength, mlCodeTable[nbSeq-1]);
Yann Collet7cbe79a2016-03-23 22:31:57 +0100713 FSE_initCState2(&stateOffsetBits, CTable_OffsetBits, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100714 FSE_initCState2(&stateLitLength, CTable_LitLength, llCodeTable[nbSeq-1]);
Yann Colleted57d852016-07-29 21:22:17 +0200715 BIT_addBits(&blockStream, sequences[nbSeq-1].litLength, LL_bits[llCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100716 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200717 BIT_addBits(&blockStream, sequences[nbSeq-1].matchLength, ML_bits[mlCodeTable[nbSeq-1]]);
Yann Colletb9151402016-03-26 17:18:11 +0100718 if (MEM_32bits()) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200719 BIT_addBits(&blockStream, sequences[nbSeq-1].offset, ofCodeTable[nbSeq-1]);
Yann Collet597847a2016-03-20 19:14:22 +0100720 BIT_flushBits(&blockStream);
721
Yann Colletfadda6c2016-03-22 12:14:26 +0100722 { size_t n;
723 for (n=nbSeq-2 ; n<nbSeq ; n--) { /* intentional underflow */
Yann Collet3c6b8082016-07-30 03:20:47 +0200724 BYTE const llCode = llCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200725 BYTE const ofCode = ofCodeTable[n];
726 BYTE const mlCode = mlCodeTable[n];
Yann Collet731ef162016-07-27 21:05:12 +0200727 U32 const llBits = LL_bits[llCode];
Yann Collet731ef162016-07-27 21:05:12 +0200728 U32 const ofBits = ofCode; /* 32b*/ /* 64b*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200729 U32 const mlBits = ML_bits[mlCode];
Yann Colletfadda6c2016-03-22 12:14:26 +0100730 /* (7)*/ /* (7)*/
Yann Colletb9151402016-03-26 17:18:11 +0100731 FSE_encodeSymbol(&blockStream, &stateOffsetBits, ofCode); /* 15 */ /* 15 */
732 FSE_encodeSymbol(&blockStream, &stateMatchLength, mlCode); /* 24 */ /* 24 */
733 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
734 FSE_encodeSymbol(&blockStream, &stateLitLength, llCode); /* 16 */ /* 33 */
Yann Collet582933f2016-04-11 16:25:56 +0200735 if (MEM_32bits() || (ofBits+mlBits+llBits >= 64-7-(LLFSELog+MLFSELog+OffFSELog)))
Yann Colletb9151402016-03-26 17:18:11 +0100736 BIT_flushBits(&blockStream); /* (7)*/
Yann Colleted57d852016-07-29 21:22:17 +0200737 BIT_addBits(&blockStream, sequences[n].litLength, llBits);
Yann Colletb9151402016-03-26 17:18:11 +0100738 if (MEM_32bits() && ((llBits+mlBits)>24)) BIT_flushBits(&blockStream);
Yann Colleted57d852016-07-29 21:22:17 +0200739 BIT_addBits(&blockStream, sequences[n].matchLength, mlBits);
Yann Colletb9151402016-03-26 17:18:11 +0100740 if (MEM_32bits()) BIT_flushBits(&blockStream); /* (7)*/
Yann Collet3c6b8082016-07-30 03:20:47 +0200741 BIT_addBits(&blockStream, sequences[n].offset, ofBits); /* 31 */
Yann Colletb9151402016-03-26 17:18:11 +0100742 BIT_flushBits(&blockStream); /* (7)*/
Yann Colletfadda6c2016-03-22 12:14:26 +0100743 } }
Yann Collet14983e72015-11-11 21:38:21 +0100744
745 FSE_flushCState(&blockStream, &stateMatchLength);
746 FSE_flushCState(&blockStream, &stateOffsetBits);
747 FSE_flushCState(&blockStream, &stateLitLength);
748
Yann Colletb9151402016-03-26 17:18:11 +0100749 { size_t const streamSize = BIT_closeCStream(&blockStream);
750 if (streamSize==0) return ERROR(dstSize_tooSmall); /* not enough space */
751 op += streamSize;
752 } }
Yann Collet14983e72015-11-11 21:38:21 +0100753
754 /* check compressibility */
Yann Collete93d6ce2016-01-31 00:58:06 +0100755_check_compressibility:
Yann Colletfadda6c2016-03-22 12:14:26 +0100756 { size_t const minGain = ZSTD_minGain(srcSize);
757 size_t const maxCSize = srcSize - minGain;
758 if ((size_t)(op-ostart) >= maxCSize) return 0; }
Yann Collet14983e72015-11-11 21:38:21 +0100759
Yann Collet4266c0a2016-06-14 01:49:25 +0200760 /* confirm repcodes */
Yann Colletb459aad2017-01-19 17:33:37 -0800761 { int i; for (i=0; i<ZSTD_REP_NUM; i++) zc->rep[i] = zc->repToConfirm[i]; }
Yann Collet4266c0a2016-06-14 01:49:25 +0200762
Yann Collet5054ee02015-11-23 13:34:21 +0100763 return op - ostart;
Yann Collet14983e72015-11-11 21:38:21 +0100764}
765
766
Yann Colletbb002742017-01-25 16:25:38 -0800767#if 0 /* for debug */
768# define STORESEQ_DEBUG
769#include <stdio.h> /* fprintf */
770U32 g_startDebug = 0;
771const BYTE* g_start = NULL;
772#endif
773
Yann Collet95cd0c22016-03-08 18:24:21 +0100774/*! ZSTD_storeSeq() :
775 Store a sequence (literal length, literals, offset code and match length code) into seqStore_t.
776 `offsetCode` : distance to match, or 0 == repCode.
777 `matchCode` : matchLength - MINMATCH
Yann Collet14983e72015-11-11 21:38:21 +0100778*/
Yann Colletd57dffb2016-07-03 01:48:26 +0200779MEM_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 +0100780{
Yann Colletbb002742017-01-25 16:25:38 -0800781#ifdef STORESEQ_DEBUG
782 if (g_startDebug) {
783 const U32 pos = (U32)((const BYTE*)literals - g_start);
784 if (g_start==NULL) g_start = (const BYTE*)literals;
785 if ((pos > 1895000) && (pos < 1895300))
786 fprintf(stderr, "Cpos %6u :%5u literals & match %3u bytes at distance %6u \n",
787 pos, (U32)litLength, (U32)matchCode+MINMATCH, (U32)offsetCode);
788 }
Yann Collet14983e72015-11-11 21:38:21 +0100789#endif
Yann Collet14983e72015-11-11 21:38:21 +0100790 /* copy Literals */
791 ZSTD_wildcopy(seqStorePtr->lit, literals, litLength);
792 seqStorePtr->lit += litLength;
793
794 /* literal Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200795 if (litLength>0xFFFF) { seqStorePtr->longLengthID = 1; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
796 seqStorePtr->sequences[0].litLength = (U16)litLength;
Yann Collet14983e72015-11-11 21:38:21 +0100797
798 /* match offset */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200799 seqStorePtr->sequences[0].offset = offsetCode + 1;
Yann Collet14983e72015-11-11 21:38:21 +0100800
801 /* match Length */
Yann Colletc0ce4f12016-07-30 00:55:13 +0200802 if (matchCode>0xFFFF) { seqStorePtr->longLengthID = 2; seqStorePtr->longLengthPos = (U32)(seqStorePtr->sequences - seqStorePtr->sequencesStart); }
803 seqStorePtr->sequences[0].matchLength = (U16)matchCode;
Yann Colleted57d852016-07-29 21:22:17 +0200804
Yann Colletc0ce4f12016-07-30 00:55:13 +0200805 seqStorePtr->sequences++;
Yann Collet14983e72015-11-11 21:38:21 +0100806}
807
808
Yann Collet7d360282016-02-12 00:07:30 +0100809/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100810* Match length counter
811***************************************/
Yann Collet5054ee02015-11-23 13:34:21 +0100812static unsigned ZSTD_NbCommonBytes (register size_t val)
Yann Collet14983e72015-11-11 21:38:21 +0100813{
Yann Collet863ec402016-01-28 17:56:33 +0100814 if (MEM_isLittleEndian()) {
815 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100816# if defined(_MSC_VER) && defined(_WIN64)
817 unsigned long r = 0;
818 _BitScanForward64( &r, (U64)val );
Yann Colletd6080882015-12-09 09:05:22 +0100819 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100820# elif defined(__GNUC__) && (__GNUC__ >= 3)
821 return (__builtin_ctzll((U64)val) >> 3);
822# else
823 static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
824 return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
825# endif
Yann Collet863ec402016-01-28 17:56:33 +0100826 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100827# if defined(_MSC_VER)
828 unsigned long r=0;
829 _BitScanForward( &r, (U32)val );
Yann Colletd6080882015-12-09 09:05:22 +0100830 return (unsigned)(r>>3);
Yann Collet14983e72015-11-11 21:38:21 +0100831# elif defined(__GNUC__) && (__GNUC__ >= 3)
832 return (__builtin_ctz((U32)val) >> 3);
833# else
834 static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
835 return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
836# endif
837 }
Yann Collet863ec402016-01-28 17:56:33 +0100838 } else { /* Big Endian CPU */
839 if (MEM_64bits()) {
Yann Collet14983e72015-11-11 21:38:21 +0100840# if defined(_MSC_VER) && defined(_WIN64)
841 unsigned long r = 0;
842 _BitScanReverse64( &r, val );
843 return (unsigned)(r>>3);
844# elif defined(__GNUC__) && (__GNUC__ >= 3)
845 return (__builtin_clzll(val) >> 3);
846# else
847 unsigned r;
848 const unsigned n32 = sizeof(size_t)*4; /* calculate this way due to compiler complaining in 32-bits mode */
849 if (!(val>>n32)) { r=4; } else { r=0; val>>=n32; }
850 if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
851 r += (!val);
852 return r;
853# endif
Yann Collet863ec402016-01-28 17:56:33 +0100854 } else { /* 32 bits */
Yann Collet14983e72015-11-11 21:38:21 +0100855# if defined(_MSC_VER)
856 unsigned long r = 0;
857 _BitScanReverse( &r, (unsigned long)val );
858 return (unsigned)(r>>3);
859# elif defined(__GNUC__) && (__GNUC__ >= 3)
860 return (__builtin_clz((U32)val) >> 3);
861# else
862 unsigned r;
863 if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
864 r += (!val);
865 return r;
866# endif
Yann Collet863ec402016-01-28 17:56:33 +0100867 } }
Yann Collet14983e72015-11-11 21:38:21 +0100868}
869
870
Yann Colleta436a522016-06-20 23:34:04 +0200871static size_t ZSTD_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* const pInLimit)
Yann Collet14983e72015-11-11 21:38:21 +0100872{
873 const BYTE* const pStart = pIn;
Yann Colleta436a522016-06-20 23:34:04 +0200874 const BYTE* const pInLoopLimit = pInLimit - (sizeof(size_t)-1);
Yann Collet14983e72015-11-11 21:38:21 +0100875
Yann Colleta436a522016-06-20 23:34:04 +0200876 while (pIn < pInLoopLimit) {
Yann Collet7591a7f2016-05-20 11:44:43 +0200877 size_t const diff = MEM_readST(pMatch) ^ MEM_readST(pIn);
Yann Collet14983e72015-11-11 21:38:21 +0100878 if (!diff) { pIn+=sizeof(size_t); pMatch+=sizeof(size_t); continue; }
879 pIn += ZSTD_NbCommonBytes(diff);
880 return (size_t)(pIn - pStart);
881 }
Yann Collet14983e72015-11-11 21:38:21 +0100882 if (MEM_64bits()) if ((pIn<(pInLimit-3)) && (MEM_read32(pMatch) == MEM_read32(pIn))) { pIn+=4; pMatch+=4; }
883 if ((pIn<(pInLimit-1)) && (MEM_read16(pMatch) == MEM_read16(pIn))) { pIn+=2; pMatch+=2; }
884 if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;
885 return (size_t)(pIn - pStart);
886}
887
Yann Collet04b12d82016-02-11 06:23:24 +0100888/** ZSTD_count_2segments() :
Yann Collet7d360282016-02-12 00:07:30 +0100889* can count match length with `ip` & `match` in 2 different segments.
Yann Collet5054ee02015-11-23 13:34:21 +0100890* convention : on reaching mEnd, match count continue starting from iStart
891*/
892static size_t ZSTD_count_2segments(const BYTE* ip, const BYTE* match, const BYTE* iEnd, const BYTE* mEnd, const BYTE* iStart)
893{
Yann Collet7591a7f2016-05-20 11:44:43 +0200894 const BYTE* const vEnd = MIN( ip + (mEnd - match), iEnd);
Yann Collet731ef162016-07-27 21:05:12 +0200895 size_t const matchLength = ZSTD_count(ip, match, vEnd);
896 if (match + matchLength != mEnd) return matchLength;
897 return matchLength + ZSTD_count(ip+matchLength, iStart, iEnd);
Yann Collet5054ee02015-11-23 13:34:21 +0100898}
899
Yann Collet14983e72015-11-11 21:38:21 +0100900
Yann Collet863ec402016-01-28 17:56:33 +0100901/*-*************************************
Yann Collet14983e72015-11-11 21:38:21 +0100902* Hashes
Yann Colletf3eca252015-10-22 15:31:46 +0100903***************************************/
inikepcc52a972016-02-19 10:09:35 +0100904static const U32 prime3bytes = 506832829U;
905static U32 ZSTD_hash3(U32 u, U32 h) { return ((u << (32-24)) * prime3bytes) >> (32-h) ; }
Yann Colletd4f4e582016-06-27 01:31:35 +0200906MEM_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 +0100907
Yann Collet4b100f42015-10-30 15:49:48 +0100908static const U32 prime4bytes = 2654435761U;
Yann Collet863ec402016-01-28 17:56:33 +0100909static U32 ZSTD_hash4(U32 u, U32 h) { return (u * prime4bytes) >> (32-h) ; }
Yann Collet5be2dd22015-11-11 13:43:58 +0100910static size_t ZSTD_hash4Ptr(const void* ptr, U32 h) { return ZSTD_hash4(MEM_read32(ptr), h); }
Yann Collet2acb5d32015-10-29 16:49:43 +0100911
Yann Collet4b100f42015-10-30 15:49:48 +0100912static const U64 prime5bytes = 889523592379ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100913static size_t ZSTD_hash5(U64 u, U32 h) { return (size_t)(((u << (64-40)) * prime5bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100914static size_t ZSTD_hash5Ptr(const void* p, U32 h) { return ZSTD_hash5(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100915
916static const U64 prime6bytes = 227718039650203ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100917static size_t ZSTD_hash6(U64 u, U32 h) { return (size_t)(((u << (64-48)) * prime6bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100918static size_t ZSTD_hash6Ptr(const void* p, U32 h) { return ZSTD_hash6(MEM_readLE64(p), h); }
Yann Collet4b100f42015-10-30 15:49:48 +0100919
Yann Collet14983e72015-11-11 21:38:21 +0100920static const U64 prime7bytes = 58295818150454627ULL;
Yann Collet863ec402016-01-28 17:56:33 +0100921static size_t ZSTD_hash7(U64 u, U32 h) { return (size_t)(((u << (64-56)) * prime7bytes) >> (64-h)) ; }
Yann Collet4f0a3932016-02-07 04:00:27 +0100922static size_t ZSTD_hash7Ptr(const void* p, U32 h) { return ZSTD_hash7(MEM_readLE64(p), h); }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100923
Yann Collet45dc3562016-07-12 09:47:31 +0200924static const U64 prime8bytes = 0xCF1BBCDCB7A56463ULL;
925static size_t ZSTD_hash8(U64 u, U32 h) { return (size_t)(((u) * prime8bytes) >> (64-h)) ; }
926static size_t ZSTD_hash8Ptr(const void* p, U32 h) { return ZSTD_hash8(MEM_readLE64(p), h); }
927
Yann Collet5be2dd22015-11-11 13:43:58 +0100928static size_t ZSTD_hashPtr(const void* p, U32 hBits, U32 mls)
Yann Collet4b100f42015-10-30 15:49:48 +0100929{
930 switch(mls)
931 {
932 default:
Yann Collet5be2dd22015-11-11 13:43:58 +0100933 case 4: return ZSTD_hash4Ptr(p, hBits);
934 case 5: return ZSTD_hash5Ptr(p, hBits);
935 case 6: return ZSTD_hash6Ptr(p, hBits);
936 case 7: return ZSTD_hash7Ptr(p, hBits);
Yann Collet45dc3562016-07-12 09:47:31 +0200937 case 8: return ZSTD_hash8Ptr(p, hBits);
Yann Collet4b100f42015-10-30 15:49:48 +0100938 }
939}
Yann Collet2acb5d32015-10-29 16:49:43 +0100940
Yann Collet863ec402016-01-28 17:56:33 +0100941
Yann Collet2ce49232016-02-02 14:36:49 +0100942/*-*************************************
Yann Collet1f44b3f2015-11-05 17:32:18 +0100943* Fast Scan
944***************************************/
Yann Collet417890c2015-12-04 17:16:37 +0100945static void ZSTD_fillHashTable (ZSTD_CCtx* zc, const void* end, const U32 mls)
946{
947 U32* const hashTable = zc->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200948 U32 const hBits = zc->params.cParams.hashLog;
Yann Collet417890c2015-12-04 17:16:37 +0100949 const BYTE* const base = zc->base;
950 const BYTE* ip = base + zc->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +0200951 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet37f3d1b2016-03-19 15:11:42 +0100952 const size_t fastHashFillStep = 3;
Yann Collet417890c2015-12-04 17:16:37 +0100953
Yann Colletfb810d62016-01-28 00:18:06 +0100954 while(ip <= iend) {
Yann Collet417890c2015-12-04 17:16:37 +0100955 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip - base);
Yann Collet37f3d1b2016-03-19 15:11:42 +0100956 ip += fastHashFillStep;
Yann Collet417890c2015-12-04 17:16:37 +0100957 }
958}
959
960
Yann Collet1f44b3f2015-11-05 17:32:18 +0100961FORCE_INLINE
Yann Collet4266c0a2016-06-14 01:49:25 +0200962void ZSTD_compressBlock_fast_generic(ZSTD_CCtx* cctx,
Yann Collet280f9a82016-08-08 00:44:00 +0200963 const void* src, size_t srcSize,
964 const U32 mls)
Yann Collet1f44b3f2015-11-05 17:32:18 +0100965{
Yann Collet4266c0a2016-06-14 01:49:25 +0200966 U32* const hashTable = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +0200967 U32 const hBits = cctx->params.cParams.hashLog;
Yann Collet4266c0a2016-06-14 01:49:25 +0200968 seqStore_t* seqStorePtr = &(cctx->seqStore);
969 const BYTE* const base = cctx->base;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100970 const BYTE* const istart = (const BYTE*)src;
Yann Collet805a52a2015-11-06 10:52:17 +0100971 const BYTE* ip = istart;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100972 const BYTE* anchor = istart;
Yann Collet731ef162016-07-27 21:05:12 +0200973 const U32 lowestIndex = cctx->dictLimit;
Yann Collet4266c0a2016-06-14 01:49:25 +0200974 const BYTE* const lowest = base + lowestIndex;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100975 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +0200976 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet92d75662016-07-03 01:10:53 +0200977 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
978 U32 offsetSaved = 0;
Yann Collet1f44b3f2015-11-05 17:32:18 +0100979
Yann Collet1f44b3f2015-11-05 17:32:18 +0100980 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +0200981 ip += (ip==lowest);
982 { U32 const maxRep = (U32)(ip-lowest);
Yann Collet92d75662016-07-03 01:10:53 +0200983 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
984 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
Yann Collet4266c0a2016-06-14 01:49:25 +0200985 }
Yann Collet1f44b3f2015-11-05 17:32:18 +0100986
987 /* Main Search Loop */
Yann Collet4266c0a2016-06-14 01:49:25 +0200988 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
Yann Colleta436a522016-06-20 23:34:04 +0200989 size_t mLength;
Yann Collet43dfe012016-06-13 21:43:06 +0200990 size_t const h = ZSTD_hashPtr(ip, hBits, mls);
991 U32 const current = (U32)(ip-base);
992 U32 const matchIndex = hashTable[h];
Yann Colletd94efbf2015-12-29 14:29:08 +0100993 const BYTE* match = base + matchIndex;
Yann Collet96ffa422016-01-02 01:16:28 +0100994 hashTable[h] = current; /* update hash table */
Yann Collet1f44b3f2015-11-05 17:32:18 +0100995
Yann Collet280f9a82016-08-08 00:44:00 +0200996 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) {
Yann Collet45dc3562016-07-12 09:47:31 +0200997 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
Yann Collet402fdcf2015-11-20 12:46:08 +0100998 ip++;
Yann Colleta436a522016-06-20 23:34:04 +0200999 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1000 } else {
Yann Collet92d75662016-07-03 01:10:53 +02001001 U32 offset;
Yann Colleta436a522016-06-20 23:34:04 +02001002 if ( (matchIndex <= lowestIndex) || (MEM_read32(match) != MEM_read32(ip)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001003 ip += ((ip-anchor) >> g_searchStrength) + 1;
1004 continue;
1005 }
Yann Collet45dc3562016-07-12 09:47:31 +02001006 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001007 offset = (U32)(ip-match);
Yann Colleta436a522016-06-20 23:34:04 +02001008 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001009 offset_2 = offset_1;
1010 offset_1 = offset;
inikep59453082016-03-16 15:35:14 +01001011
Yann Colleta436a522016-06-20 23:34:04 +02001012 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Collet402fdcf2015-11-20 12:46:08 +01001013 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001014
Yann Collet402fdcf2015-11-20 12:46:08 +01001015 /* match found */
Yann Colleta436a522016-06-20 23:34:04 +02001016 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001017 anchor = ip;
1018
Yann Colletfb810d62016-01-28 00:18:06 +01001019 if (ip <= ilimit) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001020 /* Fill Table */
Yann Colletecd651b2016-01-07 15:35:18 +01001021 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 +01001022 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1023 /* check immediate repcode */
1024 while ( (ip <= ilimit)
Yann Collet4266c0a2016-06-14 01:49:25 +02001025 && ( (offset_2>0)
Yann Collet43dfe012016-06-13 21:43:06 +02001026 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001027 /* store sequence */
Yann Collet45dc3562016-07-12 09:47:31 +02001028 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Collet92d75662016-07-03 01:10:53 +02001029 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001030 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001031 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1032 ip += rLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001033 anchor = ip;
1034 continue; /* faster when present ... (?) */
Yann Colletfb810d62016-01-28 00:18:06 +01001035 } } }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001036
Yann Collet4266c0a2016-06-14 01:49:25 +02001037 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001038 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1039 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet4266c0a2016-06-14 01:49:25 +02001040
Yann Collet70e45772016-03-19 18:08:32 +01001041 /* Last Literals */
1042 { size_t const lastLLSize = iend - anchor;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001043 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1044 seqStorePtr->lit += lastLLSize;
1045 }
Yann Collet1f44b3f2015-11-05 17:32:18 +01001046}
1047
1048
Yann Collet82260dd2016-02-11 07:14:25 +01001049static void ZSTD_compressBlock_fast(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001050 const void* src, size_t srcSize)
Yann Collet1f44b3f2015-11-05 17:32:18 +01001051{
Yann Collet3b719252016-03-30 19:48:05 +02001052 const U32 mls = ctx->params.cParams.searchLength;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001053 switch(mls)
1054 {
1055 default:
1056 case 4 :
Yann Collet59d1f792016-01-23 19:28:41 +01001057 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 4); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001058 case 5 :
Yann Collet59d1f792016-01-23 19:28:41 +01001059 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 5); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001060 case 6 :
Yann Collet59d1f792016-01-23 19:28:41 +01001061 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 6); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001062 case 7 :
Yann Collet59d1f792016-01-23 19:28:41 +01001063 ZSTD_compressBlock_fast_generic(ctx, src, srcSize, 7); return;
Yann Collet1f44b3f2015-11-05 17:32:18 +01001064 }
1065}
Yann Colletf3eca252015-10-22 15:31:46 +01001066
Yann Colletf3eca252015-10-22 15:31:46 +01001067
Yann Collet82260dd2016-02-11 07:14:25 +01001068static void ZSTD_compressBlock_fast_extDict_generic(ZSTD_CCtx* ctx,
Yann Collet59d1f792016-01-23 19:28:41 +01001069 const void* src, size_t srcSize,
1070 const U32 mls)
Yann Collet89db5e02015-11-13 11:27:46 +01001071{
1072 U32* hashTable = ctx->hashTable;
Yann Collet3b719252016-03-30 19:48:05 +02001073 const U32 hBits = ctx->params.cParams.hashLog;
Yann Collet89db5e02015-11-13 11:27:46 +01001074 seqStore_t* seqStorePtr = &(ctx->seqStore);
1075 const BYTE* const base = ctx->base;
1076 const BYTE* const dictBase = ctx->dictBase;
1077 const BYTE* const istart = (const BYTE*)src;
1078 const BYTE* ip = istart;
1079 const BYTE* anchor = istart;
Yann Collet43dfe012016-06-13 21:43:06 +02001080 const U32 lowestIndex = ctx->lowLimit;
1081 const BYTE* const dictStart = dictBase + lowestIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001082 const U32 dictLimit = ctx->dictLimit;
Yann Collet743402c2015-11-20 12:03:53 +01001083 const BYTE* const lowPrefixPtr = base + dictLimit;
1084 const BYTE* const dictEnd = dictBase + dictLimit;
Yann Collet89db5e02015-11-13 11:27:46 +01001085 const BYTE* const iend = istart + srcSize;
1086 const BYTE* const ilimit = iend - 8;
Yann Collet4266c0a2016-06-14 01:49:25 +02001087 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
Yann Collet89db5e02015-11-13 11:27:46 +01001088
Yann Colleta436a522016-06-20 23:34:04 +02001089 /* Search Loop */
Yann Colletfb810d62016-01-28 00:18:06 +01001090 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
Yann Collet89db5e02015-11-13 11:27:46 +01001091 const size_t h = ZSTD_hashPtr(ip, hBits, mls);
Yann Collet743402c2015-11-20 12:03:53 +01001092 const U32 matchIndex = hashTable[h];
Yann Collet89db5e02015-11-13 11:27:46 +01001093 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
Yann Collet6bcdeac2015-11-26 11:43:00 +01001094 const BYTE* match = matchBase + matchIndex;
Yann Collet89db5e02015-11-13 11:27:46 +01001095 const U32 current = (U32)(ip-base);
Yann Colleta436a522016-06-20 23:34:04 +02001096 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
Yann Collet402fdcf2015-11-20 12:46:08 +01001097 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
Yann Collet89db5e02015-11-13 11:27:46 +01001098 const BYTE* repMatch = repBase + repIndex;
Yann Colleta436a522016-06-20 23:34:04 +02001099 size_t mLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001100 hashTable[h] = current; /* update hash table */
1101
Yann Colleta436a522016-06-20 23:34:04 +02001102 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
Yann Collet4266c0a2016-06-14 01:49:25 +02001103 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
Yann Collet402fdcf2015-11-20 12:46:08 +01001104 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
Yann Colleta436a522016-06-20 23:34:04 +02001105 mLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repMatchEnd, lowPrefixPtr) + EQUAL_READ32;
Yann Collet743402c2015-11-20 12:03:53 +01001106 ip++;
Yann Colleta436a522016-06-20 23:34:04 +02001107 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001108 } else {
Yann Collet43dfe012016-06-13 21:43:06 +02001109 if ( (matchIndex < lowestIndex) ||
Yann Collet52447382016-03-20 16:00:00 +01001110 (MEM_read32(match) != MEM_read32(ip)) ) {
1111 ip += ((ip-anchor) >> g_searchStrength) + 1;
1112 continue;
1113 }
1114 { const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
Yann Collet5054ee02015-11-23 13:34:21 +01001115 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
Yann Colleta436a522016-06-20 23:34:04 +02001116 U32 offset;
1117 mLength = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iend, matchEnd, lowPrefixPtr) + EQUAL_READ32;
1118 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
Yann Collet402fdcf2015-11-20 12:46:08 +01001119 offset = current - matchIndex;
1120 offset_2 = offset_1;
1121 offset_1 = offset;
Yann Colleta436a522016-06-20 23:34:04 +02001122 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletfb810d62016-01-28 00:18:06 +01001123 } }
Yann Collet89db5e02015-11-13 11:27:46 +01001124
Yann Collet5054ee02015-11-23 13:34:21 +01001125 /* found a match : store it */
Yann Colleta436a522016-06-20 23:34:04 +02001126 ip += mLength;
Yann Collet402fdcf2015-11-20 12:46:08 +01001127 anchor = ip;
1128
Yann Colletfb810d62016-01-28 00:18:06 +01001129 if (ip <= ilimit) {
Yann Collet6bcdeac2015-11-26 11:43:00 +01001130 /* Fill Table */
Yann Collet3e21ec52016-09-06 15:36:19 +02001131 hashTable[ZSTD_hashPtr(base+current+2, hBits, mls)] = current+2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001132 hashTable[ZSTD_hashPtr(ip-2, hBits, mls)] = (U32)(ip-2-base);
1133 /* check immediate repcode */
Yann Colletfb810d62016-01-28 00:18:06 +01001134 while (ip <= ilimit) {
Yann Collet27caf2a2016-04-01 15:48:48 +02001135 U32 const current2 = (U32)(ip-base);
1136 U32 const repIndex2 = current2 - offset_2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001137 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001138 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1139 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
Yann Collet5054ee02015-11-23 13:34:21 +01001140 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02001141 size_t repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
Yann Collet5054ee02015-11-23 13:34:21 +01001142 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
inikep7bc19b62016-04-06 09:46:01 +02001143 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
Yann Collet5054ee02015-11-23 13:34:21 +01001144 hashTable[ZSTD_hashPtr(ip, hBits, mls)] = current2;
inikep7bc19b62016-04-06 09:46:01 +02001145 ip += repLength2;
Yann Collet402fdcf2015-11-20 12:46:08 +01001146 anchor = ip;
1147 continue;
1148 }
Yann Collet743402c2015-11-20 12:03:53 +01001149 break;
Yann Colletfb810d62016-01-28 00:18:06 +01001150 } } }
Yann Collet89db5e02015-11-13 11:27:46 +01001151
Yann Collet4266c0a2016-06-14 01:49:25 +02001152 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001153 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02001154
Yann Collet89db5e02015-11-13 11:27:46 +01001155 /* Last Literals */
Yann Collet70e45772016-03-19 18:08:32 +01001156 { size_t const lastLLSize = iend - anchor;
Yann Collet89db5e02015-11-13 11:27:46 +01001157 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1158 seqStorePtr->lit += lastLLSize;
1159 }
Yann Collet89db5e02015-11-13 11:27:46 +01001160}
1161
1162
Yann Collet82260dd2016-02-11 07:14:25 +01001163static void ZSTD_compressBlock_fast_extDict(ZSTD_CCtx* ctx,
Yann Collet89db5e02015-11-13 11:27:46 +01001164 const void* src, size_t srcSize)
1165{
Yann Collet731ef162016-07-27 21:05:12 +02001166 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet89db5e02015-11-13 11:27:46 +01001167 switch(mls)
1168 {
1169 default:
1170 case 4 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001171 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 4); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001172 case 5 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001173 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 5); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001174 case 6 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001175 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 6); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001176 case 7 :
Yann Colleta1249dc2016-01-25 04:22:03 +01001177 ZSTD_compressBlock_fast_extDict_generic(ctx, src, srcSize, 7); return;
Yann Collet89db5e02015-11-13 11:27:46 +01001178 }
1179}
1180
1181
Yann Collet04b12d82016-02-11 06:23:24 +01001182/*-*************************************
Yann Collet45dc3562016-07-12 09:47:31 +02001183* Double Fast
1184***************************************/
1185static void ZSTD_fillDoubleHashTable (ZSTD_CCtx* cctx, const void* end, const U32 mls)
1186{
1187 U32* const hashLarge = cctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001188 U32 const hBitsL = cctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001189 U32* const hashSmall = cctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001190 U32 const hBitsS = cctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001191 const BYTE* const base = cctx->base;
1192 const BYTE* ip = base + cctx->nextToUpdate;
Yann Collet731ef162016-07-27 21:05:12 +02001193 const BYTE* const iend = ((const BYTE*)end) - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001194 const size_t fastHashFillStep = 3;
1195
1196 while(ip <= iend) {
1197 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip - base);
1198 hashLarge[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip - base);
1199 ip += fastHashFillStep;
1200 }
1201}
1202
1203
1204FORCE_INLINE
1205void ZSTD_compressBlock_doubleFast_generic(ZSTD_CCtx* cctx,
1206 const void* src, size_t srcSize,
1207 const U32 mls)
1208{
1209 U32* const hashLong = cctx->hashTable;
1210 const U32 hBitsL = cctx->params.cParams.hashLog;
1211 U32* const hashSmall = cctx->chainTable;
1212 const U32 hBitsS = cctx->params.cParams.chainLog;
1213 seqStore_t* seqStorePtr = &(cctx->seqStore);
1214 const BYTE* const base = cctx->base;
1215 const BYTE* const istart = (const BYTE*)src;
1216 const BYTE* ip = istart;
1217 const BYTE* anchor = istart;
1218 const U32 lowestIndex = cctx->dictLimit;
1219 const BYTE* const lowest = base + lowestIndex;
1220 const BYTE* const iend = istart + srcSize;
Yann Collet731ef162016-07-27 21:05:12 +02001221 const BYTE* const ilimit = iend - HASH_READ_SIZE;
Yann Collet45dc3562016-07-12 09:47:31 +02001222 U32 offset_1=cctx->rep[0], offset_2=cctx->rep[1];
1223 U32 offsetSaved = 0;
1224
1225 /* init */
1226 ip += (ip==lowest);
1227 { U32 const maxRep = (U32)(ip-lowest);
1228 if (offset_2 > maxRep) offsetSaved = offset_2, offset_2 = 0;
1229 if (offset_1 > maxRep) offsetSaved = offset_1, offset_1 = 0;
1230 }
1231
1232 /* Main Search Loop */
1233 while (ip < ilimit) { /* < instead of <=, because repcode check at (ip+1) */
1234 size_t mLength;
1235 size_t const h2 = ZSTD_hashPtr(ip, hBitsL, 8);
1236 size_t const h = ZSTD_hashPtr(ip, hBitsS, mls);
1237 U32 const current = (U32)(ip-base);
1238 U32 const matchIndexL = hashLong[h2];
1239 U32 const matchIndexS = hashSmall[h];
1240 const BYTE* matchLong = base + matchIndexL;
1241 const BYTE* match = base + matchIndexS;
1242 hashLong[h2] = hashSmall[h] = current; /* update hash tables */
1243
1244 if ((offset_1 > 0) & (MEM_read32(ip+1-offset_1) == MEM_read32(ip+1))) { /* note : by construction, offset_1 <= current */
1245 mLength = ZSTD_count(ip+1+4, ip+1+4-offset_1, iend) + 4;
1246 ip++;
1247 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1248 } else {
Yann Colleteed20812016-07-12 15:11:40 +02001249 U32 offset;
Yann Collet45dc3562016-07-12 09:47:31 +02001250 if ( (matchIndexL > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip)) ) {
1251 mLength = ZSTD_count(ip+8, matchLong+8, iend) + 8;
Yann Colleteed20812016-07-12 15:11:40 +02001252 offset = (U32)(ip-matchLong);
Yann Collet45dc3562016-07-12 09:47:31 +02001253 while (((ip>anchor) & (matchLong>lowest)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1254 } else if ( (matchIndexS > lowestIndex) && (MEM_read32(match) == MEM_read32(ip)) ) {
Yann Colletc54692f2016-08-24 01:10:42 +02001255 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1256 U32 const matchIndex3 = hashLong[h3];
1257 const BYTE* match3 = base + matchIndex3;
1258 hashLong[h3] = current + 1;
1259 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1260 mLength = ZSTD_count(ip+9, match3+8, iend) + 8;
1261 ip++;
1262 offset = (U32)(ip-match3);
1263 while (((ip>anchor) & (match3>lowest)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1264 } else {
1265 mLength = ZSTD_count(ip+4, match+4, iend) + 4;
1266 offset = (U32)(ip-match);
1267 while (((ip>anchor) & (match>lowest)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1268 }
Yann Collet45dc3562016-07-12 09:47:31 +02001269 } else {
1270 ip += ((ip-anchor) >> g_searchStrength) + 1;
1271 continue;
1272 }
1273
1274 offset_2 = offset_1;
1275 offset_1 = offset;
1276
1277 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
1278 }
1279
1280 /* match found */
1281 ip += mLength;
1282 anchor = ip;
1283
1284 if (ip <= ilimit) {
1285 /* Fill Table */
1286 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] =
1287 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2; /* here because current+2 could be > iend-8 */
1288 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] =
1289 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1290
1291 /* check immediate repcode */
1292 while ( (ip <= ilimit)
1293 && ( (offset_2>0)
1294 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
1295 /* store sequence */
1296 size_t const rLength = ZSTD_count(ip+4, ip+4-offset_2, iend) + 4;
Yann Colleteed20812016-07-12 15:11:40 +02001297 { U32 const tmpOff = offset_2; offset_2 = offset_1; offset_1 = tmpOff; } /* swap offset_2 <=> offset_1 */
Yann Collet45dc3562016-07-12 09:47:31 +02001298 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = (U32)(ip-base);
1299 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = (U32)(ip-base);
1300 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, rLength-MINMATCH);
1301 ip += rLength;
1302 anchor = ip;
1303 continue; /* faster when present ... (?) */
1304 } } }
1305
1306 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001307 cctx->repToConfirm[0] = offset_1 ? offset_1 : offsetSaved;
1308 cctx->repToConfirm[1] = offset_2 ? offset_2 : offsetSaved;
Yann Collet45dc3562016-07-12 09:47:31 +02001309
1310 /* Last Literals */
1311 { size_t const lastLLSize = iend - anchor;
1312 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1313 seqStorePtr->lit += lastLLSize;
1314 }
1315}
1316
1317
1318static void ZSTD_compressBlock_doubleFast(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
1319{
1320 const U32 mls = ctx->params.cParams.searchLength;
1321 switch(mls)
1322 {
1323 default:
1324 case 4 :
1325 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 4); return;
1326 case 5 :
1327 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 5); return;
1328 case 6 :
1329 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 6); return;
1330 case 7 :
1331 ZSTD_compressBlock_doubleFast_generic(ctx, src, srcSize, 7); return;
1332 }
1333}
1334
1335
1336static void ZSTD_compressBlock_doubleFast_extDict_generic(ZSTD_CCtx* ctx,
1337 const void* src, size_t srcSize,
1338 const U32 mls)
1339{
1340 U32* const hashLong = ctx->hashTable;
Yann Collet731ef162016-07-27 21:05:12 +02001341 U32 const hBitsL = ctx->params.cParams.hashLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001342 U32* const hashSmall = ctx->chainTable;
Yann Collet731ef162016-07-27 21:05:12 +02001343 U32 const hBitsS = ctx->params.cParams.chainLog;
Yann Collet45dc3562016-07-12 09:47:31 +02001344 seqStore_t* seqStorePtr = &(ctx->seqStore);
1345 const BYTE* const base = ctx->base;
1346 const BYTE* const dictBase = ctx->dictBase;
1347 const BYTE* const istart = (const BYTE*)src;
1348 const BYTE* ip = istart;
1349 const BYTE* anchor = istart;
1350 const U32 lowestIndex = ctx->lowLimit;
1351 const BYTE* const dictStart = dictBase + lowestIndex;
1352 const U32 dictLimit = ctx->dictLimit;
1353 const BYTE* const lowPrefixPtr = base + dictLimit;
1354 const BYTE* const dictEnd = dictBase + dictLimit;
1355 const BYTE* const iend = istart + srcSize;
1356 const BYTE* const ilimit = iend - 8;
1357 U32 offset_1=ctx->rep[0], offset_2=ctx->rep[1];
1358
1359 /* Search Loop */
1360 while (ip < ilimit) { /* < instead of <=, because (ip+1) */
1361 const size_t hSmall = ZSTD_hashPtr(ip, hBitsS, mls);
1362 const U32 matchIndex = hashSmall[hSmall];
1363 const BYTE* matchBase = matchIndex < dictLimit ? dictBase : base;
1364 const BYTE* match = matchBase + matchIndex;
1365
1366 const size_t hLong = ZSTD_hashPtr(ip, hBitsL, 8);
1367 const U32 matchLongIndex = hashLong[hLong];
1368 const BYTE* matchLongBase = matchLongIndex < dictLimit ? dictBase : base;
1369 const BYTE* matchLong = matchLongBase + matchLongIndex;
1370
1371 const U32 current = (U32)(ip-base);
1372 const U32 repIndex = current + 1 - offset_1; /* offset_1 expected <= current +1 */
1373 const BYTE* repBase = repIndex < dictLimit ? dictBase : base;
1374 const BYTE* repMatch = repBase + repIndex;
1375 size_t mLength;
1376 hashSmall[hSmall] = hashLong[hLong] = current; /* update hash table */
1377
1378 if ( (((U32)((dictLimit-1) - repIndex) >= 3) /* intentional underflow */ & (repIndex > lowestIndex))
1379 && (MEM_read32(repMatch) == MEM_read32(ip+1)) ) {
1380 const BYTE* repMatchEnd = repIndex < dictLimit ? dictEnd : iend;
1381 mLength = ZSTD_count_2segments(ip+1+4, repMatch+4, iend, repMatchEnd, lowPrefixPtr) + 4;
1382 ip++;
1383 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, 0, mLength-MINMATCH);
1384 } else {
1385 if ((matchLongIndex > lowestIndex) && (MEM_read64(matchLong) == MEM_read64(ip))) {
1386 const BYTE* matchEnd = matchLongIndex < dictLimit ? dictEnd : iend;
1387 const BYTE* lowMatchPtr = matchLongIndex < dictLimit ? dictStart : lowPrefixPtr;
1388 U32 offset;
1389 mLength = ZSTD_count_2segments(ip+8, matchLong+8, iend, matchEnd, lowPrefixPtr) + 8;
1390 offset = current - matchLongIndex;
1391 while (((ip>anchor) & (matchLong>lowMatchPtr)) && (ip[-1] == matchLong[-1])) { ip--; matchLong--; mLength++; } /* catch up */
1392 offset_2 = offset_1;
1393 offset_1 = offset;
1394 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001395
Yann Collet73d74a02016-07-12 13:03:48 +02001396 } else if ((matchIndex > lowestIndex) && (MEM_read32(match) == MEM_read32(ip))) {
Yann Colletc54692f2016-08-24 01:10:42 +02001397 size_t const h3 = ZSTD_hashPtr(ip+1, hBitsL, 8);
1398 U32 const matchIndex3 = hashLong[h3];
1399 const BYTE* const match3Base = matchIndex3 < dictLimit ? dictBase : base;
1400 const BYTE* match3 = match3Base + matchIndex3;
Yann Collet45dc3562016-07-12 09:47:31 +02001401 U32 offset;
Yann Colletc54692f2016-08-24 01:10:42 +02001402 hashLong[h3] = current + 1;
1403 if ( (matchIndex3 > lowestIndex) && (MEM_read64(match3) == MEM_read64(ip+1)) ) {
1404 const BYTE* matchEnd = matchIndex3 < dictLimit ? dictEnd : iend;
1405 const BYTE* lowMatchPtr = matchIndex3 < dictLimit ? dictStart : lowPrefixPtr;
1406 mLength = ZSTD_count_2segments(ip+9, match3+8, iend, matchEnd, lowPrefixPtr) + 8;
1407 ip++;
1408 offset = current+1 - matchIndex3;
1409 while (((ip>anchor) & (match3>lowMatchPtr)) && (ip[-1] == match3[-1])) { ip--; match3--; mLength++; } /* catch up */
1410 } else {
1411 const BYTE* matchEnd = matchIndex < dictLimit ? dictEnd : iend;
1412 const BYTE* lowMatchPtr = matchIndex < dictLimit ? dictStart : lowPrefixPtr;
1413 mLength = ZSTD_count_2segments(ip+4, match+4, iend, matchEnd, lowPrefixPtr) + 4;
1414 offset = current - matchIndex;
1415 while (((ip>anchor) & (match>lowMatchPtr)) && (ip[-1] == match[-1])) { ip--; match--; mLength++; } /* catch up */
1416 }
Yann Collet45dc3562016-07-12 09:47:31 +02001417 offset_2 = offset_1;
1418 offset_1 = offset;
1419 ZSTD_storeSeq(seqStorePtr, ip-anchor, anchor, offset + ZSTD_REP_MOVE, mLength-MINMATCH);
Yann Colletc54692f2016-08-24 01:10:42 +02001420
Yann Collet45dc3562016-07-12 09:47:31 +02001421 } else {
1422 ip += ((ip-anchor) >> g_searchStrength) + 1;
1423 continue;
1424 } }
1425
1426 /* found a match : store it */
1427 ip += mLength;
1428 anchor = ip;
1429
1430 if (ip <= ilimit) {
1431 /* Fill Table */
1432 hashSmall[ZSTD_hashPtr(base+current+2, hBitsS, mls)] = current+2;
1433 hashLong[ZSTD_hashPtr(base+current+2, hBitsL, 8)] = current+2;
1434 hashSmall[ZSTD_hashPtr(ip-2, hBitsS, mls)] = (U32)(ip-2-base);
1435 hashLong[ZSTD_hashPtr(ip-2, hBitsL, 8)] = (U32)(ip-2-base);
1436 /* check immediate repcode */
1437 while (ip <= ilimit) {
1438 U32 const current2 = (U32)(ip-base);
1439 U32 const repIndex2 = current2 - offset_2;
1440 const BYTE* repMatch2 = repIndex2 < dictLimit ? dictBase + repIndex2 : base + repIndex2;
1441 if ( (((U32)((dictLimit-1) - repIndex2) >= 3) & (repIndex2 > lowestIndex)) /* intentional overflow */
1442 && (MEM_read32(repMatch2) == MEM_read32(ip)) ) {
1443 const BYTE* const repEnd2 = repIndex2 < dictLimit ? dictEnd : iend;
1444 size_t const repLength2 = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch2+EQUAL_READ32, iend, repEnd2, lowPrefixPtr) + EQUAL_READ32;
1445 U32 tmpOffset = offset_2; offset_2 = offset_1; offset_1 = tmpOffset; /* swap offset_2 <=> offset_1 */
1446 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, repLength2-MINMATCH);
1447 hashSmall[ZSTD_hashPtr(ip, hBitsS, mls)] = current2;
1448 hashLong[ZSTD_hashPtr(ip, hBitsL, 8)] = current2;
1449 ip += repLength2;
1450 anchor = ip;
1451 continue;
1452 }
1453 break;
1454 } } }
1455
1456 /* save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001457 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet45dc3562016-07-12 09:47:31 +02001458
1459 /* Last Literals */
1460 { size_t const lastLLSize = iend - anchor;
1461 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1462 seqStorePtr->lit += lastLLSize;
1463 }
1464}
1465
1466
1467static void ZSTD_compressBlock_doubleFast_extDict(ZSTD_CCtx* ctx,
1468 const void* src, size_t srcSize)
1469{
Yann Collet731ef162016-07-27 21:05:12 +02001470 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet45dc3562016-07-12 09:47:31 +02001471 switch(mls)
1472 {
1473 default:
1474 case 4 :
1475 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 4); return;
1476 case 5 :
1477 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 5); return;
1478 case 6 :
1479 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 6); return;
1480 case 7 :
1481 ZSTD_compressBlock_doubleFast_extDict_generic(ctx, src, srcSize, 7); return;
1482 }
1483}
1484
1485
1486/*-*************************************
Yann Collet96b9f0b2015-11-04 03:52:54 +01001487* Binary Tree search
Yann Colletf3eca252015-10-22 15:31:46 +01001488***************************************/
Yann Collet04b12d82016-02-11 06:23:24 +01001489/** ZSTD_insertBt1() : add one or multiple positions to tree.
1490* ip : assumed <= iend-8 .
Yann Collet06eade52015-11-23 14:23:47 +01001491* @return : nb of positions added */
Yann Collet1358f912016-01-01 07:29:39 +01001492static U32 ZSTD_insertBt1(ZSTD_CCtx* zc, const BYTE* const ip, const U32 mls, const BYTE* const iend, U32 nbCompares,
1493 U32 extDict)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001494{
Yann Collet731ef162016-07-27 21:05:12 +02001495 U32* const hashTable = zc->hashTable;
1496 U32 const hashLog = zc->params.cParams.hashLog;
1497 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1498 U32* const bt = zc->chainTable;
1499 U32 const btLog = zc->params.cParams.chainLog - 1;
1500 U32 const btMask = (1 << btLog) - 1;
1501 U32 matchIndex = hashTable[h];
Yann Collet96b9f0b2015-11-04 03:52:54 +01001502 size_t commonLengthSmaller=0, commonLengthLarger=0;
1503 const BYTE* const base = zc->base;
Yann Collet1358f912016-01-01 07:29:39 +01001504 const BYTE* const dictBase = zc->dictBase;
1505 const U32 dictLimit = zc->dictLimit;
1506 const BYTE* const dictEnd = dictBase + dictLimit;
1507 const BYTE* const prefixStart = base + dictLimit;
Yann Collet2b361cf2016-10-14 16:03:34 -07001508 const BYTE* match;
Yann Collet6c3e2e72015-12-11 10:44:07 +01001509 const U32 current = (U32)(ip-base);
Yann Collete9eba602015-11-08 15:08:03 +01001510 const U32 btLow = btMask >= current ? 0 : current - btMask;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001511 U32* smallerPtr = bt + 2*(current&btMask);
Yann Colleta87278a2016-01-17 00:12:55 +01001512 U32* largerPtr = smallerPtr + 1;
Yann Collet59d70632015-11-04 12:05:27 +01001513 U32 dummy32; /* to be nullified at the end */
Yann Collet731ef162016-07-27 21:05:12 +02001514 U32 const windowLow = zc->lowLimit;
Yann Collet72e84cf2015-12-31 19:08:44 +01001515 U32 matchEndIdx = current+8;
Yann Colletb8a6f682016-02-15 17:06:29 +01001516 size_t bestLength = 8;
Yann Colletc0932082016-06-30 14:07:30 +02001517#ifdef ZSTD_C_PREDICT
Yann Collet7beaa052016-01-21 11:57:45 +01001518 U32 predictedSmall = *(bt + 2*((current-1)&btMask) + 0);
1519 U32 predictedLarge = *(bt + 2*((current-1)&btMask) + 1);
1520 predictedSmall += (predictedSmall>0);
1521 predictedLarge += (predictedLarge>0);
Yann Colletc0932082016-06-30 14:07:30 +02001522#endif /* ZSTD_C_PREDICT */
Yann Colletf48e35c2015-11-07 01:13:31 +01001523
Yann Collet6c3e2e72015-12-11 10:44:07 +01001524 hashTable[h] = current; /* Update Hash Table */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001525
Yann Colletfb810d62016-01-28 00:18:06 +01001526 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001527 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet96b9f0b2015-11-04 03:52:54 +01001528 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
Yann Collet25f46dc2016-11-29 16:59:27 -08001529
Yann Colletc0932082016-06-30 14:07:30 +02001530#ifdef ZSTD_C_PREDICT /* note : can create issues when hlog small <= 11 */
Yann Collet70e8c382016-02-10 13:37:52 +01001531 const U32* predictPtr = bt + 2*((matchIndex-1) & btMask); /* written this way, as bt is a roll buffer */
Yann Colletfb810d62016-01-28 00:18:06 +01001532 if (matchIndex == predictedSmall) {
1533 /* no need to check length, result known */
Yann Colleta87278a2016-01-17 00:12:55 +01001534 *smallerPtr = matchIndex;
1535 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1536 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1537 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Collet7beaa052016-01-21 11:57:45 +01001538 predictedSmall = predictPtr[1] + (predictPtr[1]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001539 continue;
1540 }
Yann Colletfb810d62016-01-28 00:18:06 +01001541 if (matchIndex == predictedLarge) {
Yann Colleta87278a2016-01-17 00:12:55 +01001542 *largerPtr = matchIndex;
1543 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1544 largerPtr = nextPtr;
1545 matchIndex = nextPtr[0];
Yann Collet7beaa052016-01-21 11:57:45 +01001546 predictedLarge = predictPtr[0] + (predictPtr[0]>0);
Yann Colleta87278a2016-01-17 00:12:55 +01001547 continue;
1548 }
Yann Collet04b12d82016-02-11 06:23:24 +01001549#endif
Yann Colletfb810d62016-01-28 00:18:06 +01001550 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet1358f912016-01-01 07:29:39 +01001551 match = base + matchIndex;
1552 if (match[matchLength] == ip[matchLength])
1553 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001554 } else {
Yann Collet1358f912016-01-01 07:29:39 +01001555 match = dictBase + matchIndex;
1556 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
1557 if (matchIndex+matchLength >= dictLimit)
1558 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
1559 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001560
Yann Colletb8a6f682016-02-15 17:06:29 +01001561 if (matchLength > bestLength) {
1562 bestLength = matchLength;
1563 if (matchLength > matchEndIdx - matchIndex)
1564 matchEndIdx = matchIndex + (U32)matchLength;
1565 }
Yann Colletee3f4512015-12-29 22:26:09 +01001566
Yann Collet59d70632015-11-04 12:05:27 +01001567 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
Yann Collet1358f912016-01-01 07:29:39 +01001568 break; /* drop , to guarantee consistency ; miss a bit of compression, but other solutions can corrupt the tree */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001569
Yann Colletfb810d62016-01-28 00:18:06 +01001570 if (match[matchLength] < ip[matchLength]) { /* necessarily within correct buffer */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001571 /* match is smaller than current */
1572 *smallerPtr = matchIndex; /* update smaller idx */
1573 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
Yann Colletf48e35c2015-11-07 01:13:31 +01001574 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001575 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
Yann Colletf48e35c2015-11-07 01:13:31 +01001576 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001577 } else {
Yann Collet96b9f0b2015-11-04 03:52:54 +01001578 /* match is larger than current */
1579 *largerPtr = matchIndex;
1580 commonLengthLarger = matchLength;
Yann Colletf48e35c2015-11-07 01:13:31 +01001581 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
Yann Collet96b9f0b2015-11-04 03:52:54 +01001582 largerPtr = nextPtr;
Yann Colletf48e35c2015-11-07 01:13:31 +01001583 matchIndex = nextPtr[0];
Yann Colletfb810d62016-01-28 00:18:06 +01001584 } }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001585
Yann Collet59d70632015-11-04 12:05:27 +01001586 *smallerPtr = *largerPtr = 0;
Yann Colleta436a522016-06-20 23:34:04 +02001587 if (bestLength > 384) return MIN(192, (U32)(bestLength - 384)); /* speed optimization */
Yann Colletb8a6f682016-02-15 17:06:29 +01001588 if (matchEndIdx > current + 8) return matchEndIdx - current - 8;
1589 return 1;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001590}
1591
1592
Yann Collet82260dd2016-02-11 07:14:25 +01001593static size_t ZSTD_insertBtAndFindBestMatch (
Yann Collet03526e12015-11-23 15:29:15 +01001594 ZSTD_CCtx* zc,
1595 const BYTE* const ip, const BYTE* const iend,
1596 size_t* offsetPtr,
Yann Collet2cc12cb2016-01-01 07:47:58 +01001597 U32 nbCompares, const U32 mls,
1598 U32 extDict)
Yann Collet03526e12015-11-23 15:29:15 +01001599{
Yann Collet731ef162016-07-27 21:05:12 +02001600 U32* const hashTable = zc->hashTable;
1601 U32 const hashLog = zc->params.cParams.hashLog;
1602 size_t const h = ZSTD_hashPtr(ip, hashLog, mls);
1603 U32* const bt = zc->chainTable;
1604 U32 const btLog = zc->params.cParams.chainLog - 1;
1605 U32 const btMask = (1 << btLog) - 1;
Yann Collet03526e12015-11-23 15:29:15 +01001606 U32 matchIndex = hashTable[h];
1607 size_t commonLengthSmaller=0, commonLengthLarger=0;
1608 const BYTE* const base = zc->base;
1609 const BYTE* const dictBase = zc->dictBase;
1610 const U32 dictLimit = zc->dictLimit;
1611 const BYTE* const dictEnd = dictBase + dictLimit;
1612 const BYTE* const prefixStart = base + dictLimit;
1613 const U32 current = (U32)(ip-base);
1614 const U32 btLow = btMask >= current ? 0 : current - btMask;
1615 const U32 windowLow = zc->lowLimit;
1616 U32* smallerPtr = bt + 2*(current&btMask);
1617 U32* largerPtr = bt + 2*(current&btMask) + 1;
Yann Collet72e84cf2015-12-31 19:08:44 +01001618 U32 matchEndIdx = current+8;
Yann Collet03526e12015-11-23 15:29:15 +01001619 U32 dummy32; /* to be nullified at the end */
inikep64d7bcb2016-04-07 19:14:09 +02001620 size_t bestLength = 0;
Yann Collet03526e12015-11-23 15:29:15 +01001621
Yann Collet6c3e2e72015-12-11 10:44:07 +01001622 hashTable[h] = current; /* Update Hash Table */
Yann Collet03526e12015-11-23 15:29:15 +01001623
Yann Colletfb810d62016-01-28 00:18:06 +01001624 while (nbCompares-- && (matchIndex > windowLow)) {
Yann Collet25f46dc2016-11-29 16:59:27 -08001625 U32* const nextPtr = bt + 2*(matchIndex & btMask);
Yann Collet03526e12015-11-23 15:29:15 +01001626 size_t matchLength = MIN(commonLengthSmaller, commonLengthLarger); /* guaranteed minimum nb of common bytes */
1627 const BYTE* match;
1628
Yann Colletfb810d62016-01-28 00:18:06 +01001629 if ((!extDict) || (matchIndex+matchLength >= dictLimit)) {
Yann Collet03526e12015-11-23 15:29:15 +01001630 match = base + matchIndex;
1631 if (match[matchLength] == ip[matchLength])
1632 matchLength += ZSTD_count(ip+matchLength+1, match+matchLength+1, iend) +1;
Yann Colletfb810d62016-01-28 00:18:06 +01001633 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001634 match = dictBase + matchIndex;
1635 matchLength += ZSTD_count_2segments(ip+matchLength, match+matchLength, iend, dictEnd, prefixStart);
Yann Collet225179d2015-11-23 16:52:22 +01001636 if (matchIndex+matchLength >= dictLimit)
1637 match = base + matchIndex; /* to prepare for next usage of match[matchLength] */
Yann Collet03526e12015-11-23 15:29:15 +01001638 }
1639
Yann Colletfb810d62016-01-28 00:18:06 +01001640 if (matchLength > bestLength) {
Yann Colletee3f4512015-12-29 22:26:09 +01001641 if (matchLength > matchEndIdx - matchIndex)
Yann Collet48da1642015-12-29 23:40:02 +01001642 matchEndIdx = matchIndex + (U32)matchLength;
Yann Collet49bb0042016-06-04 20:17:38 +02001643 if ( (4*(int)(matchLength-bestLength)) > (int)(ZSTD_highbit32(current-matchIndex+1) - ZSTD_highbit32((U32)offsetPtr[0]+1)) )
inikep75716852016-04-06 12:34:42 +02001644 bestLength = matchLength, *offsetPtr = ZSTD_REP_MOVE + current - matchIndex;
Yann Collet03526e12015-11-23 15:29:15 +01001645 if (ip+matchLength == iend) /* equal : no way to know if inf or sup */
1646 break; /* drop, to guarantee consistency (miss a little bit of compression) */
1647 }
1648
Yann Colletfb810d62016-01-28 00:18:06 +01001649 if (match[matchLength] < ip[matchLength]) {
Yann Collet03526e12015-11-23 15:29:15 +01001650 /* match is smaller than current */
1651 *smallerPtr = matchIndex; /* update smaller idx */
1652 commonLengthSmaller = matchLength; /* all smaller will now have at least this guaranteed common length */
1653 if (matchIndex <= btLow) { smallerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1654 smallerPtr = nextPtr+1; /* new "smaller" => larger of match */
1655 matchIndex = nextPtr[1]; /* new matchIndex larger than previous (closer to current) */
Yann Colletfb810d62016-01-28 00:18:06 +01001656 } else {
Yann Collet03526e12015-11-23 15:29:15 +01001657 /* match is larger than current */
1658 *largerPtr = matchIndex;
1659 commonLengthLarger = matchLength;
1660 if (matchIndex <= btLow) { largerPtr=&dummy32; break; } /* beyond tree size, stop the search */
1661 largerPtr = nextPtr;
1662 matchIndex = nextPtr[0];
Yann Collet768c6bc2016-02-10 14:01:49 +01001663 } }
Yann Collet03526e12015-11-23 15:29:15 +01001664
1665 *smallerPtr = *largerPtr = 0;
1666
Yann Collet72e84cf2015-12-31 19:08:44 +01001667 zc->nextToUpdate = (matchEndIdx > current + 8) ? matchEndIdx - 8 : current+1;
inikep64d7bcb2016-04-07 19:14:09 +02001668 return bestLength;
Yann Collet03526e12015-11-23 15:29:15 +01001669}
1670
Yann Collet2cc12cb2016-01-01 07:47:58 +01001671
Yann Colletb8a6f682016-02-15 17:06:29 +01001672static 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 +01001673{
1674 const BYTE* const base = zc->base;
1675 const U32 target = (U32)(ip - base);
1676 U32 idx = zc->nextToUpdate;
Yann Colletb8a6f682016-02-15 17:06:29 +01001677
1678 while(idx < target)
1679 idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 0);
Yann Collet82260dd2016-02-11 07:14:25 +01001680}
1681
Yann Collet52447382016-03-20 16:00:00 +01001682/** ZSTD_BtFindBestMatch() : Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001683static size_t ZSTD_BtFindBestMatch (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001684 ZSTD_CCtx* zc,
1685 const BYTE* const ip, const BYTE* const iLimit,
1686 size_t* offsetPtr,
1687 const U32 maxNbAttempts, const U32 mls)
1688{
1689 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001690 ZSTD_updateTree(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001691 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 0);
1692}
1693
1694
Yann Collet768c6bc2016-02-10 14:01:49 +01001695static size_t ZSTD_BtFindBestMatch_selectMLS (
Yann Collet2cc12cb2016-01-01 07:47:58 +01001696 ZSTD_CCtx* zc, /* Index table will be updated */
1697 const BYTE* ip, const BYTE* const iLimit,
1698 size_t* offsetPtr,
1699 const U32 maxNbAttempts, const U32 matchLengthSearch)
1700{
1701 switch(matchLengthSearch)
1702 {
1703 default :
1704 case 4 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1705 case 5 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1706 case 6 : return ZSTD_BtFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1707 }
1708}
1709
1710
Yann Colletb8a6f682016-02-15 17:06:29 +01001711static void ZSTD_updateTree_extDict(ZSTD_CCtx* zc, const BYTE* const ip, const BYTE* const iend, const U32 nbCompares, const U32 mls)
1712{
1713 const BYTE* const base = zc->base;
1714 const U32 target = (U32)(ip - base);
1715 U32 idx = zc->nextToUpdate;
1716
1717 while (idx < target) idx += ZSTD_insertBt1(zc, base+idx, mls, iend, nbCompares, 1);
1718}
1719
inikep64d7bcb2016-04-07 19:14:09 +02001720
Yann Collet03526e12015-11-23 15:29:15 +01001721/** Tree updater, providing best match */
Yann Collet82260dd2016-02-11 07:14:25 +01001722static size_t ZSTD_BtFindBestMatch_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001723 ZSTD_CCtx* zc,
1724 const BYTE* const ip, const BYTE* const iLimit,
1725 size_t* offsetPtr,
1726 const U32 maxNbAttempts, const U32 mls)
1727{
Yann Colletee3f4512015-12-29 22:26:09 +01001728 if (ip < zc->base + zc->nextToUpdate) return 0; /* skipped area */
Yann Colletb8a6f682016-02-15 17:06:29 +01001729 ZSTD_updateTree_extDict(zc, ip, iLimit, maxNbAttempts, mls);
Yann Collet2cc12cb2016-01-01 07:47:58 +01001730 return ZSTD_insertBtAndFindBestMatch(zc, ip, iLimit, offsetPtr, maxNbAttempts, mls, 1);
Yann Collet03526e12015-11-23 15:29:15 +01001731}
1732
1733
Yann Collet82260dd2016-02-11 07:14:25 +01001734static size_t ZSTD_BtFindBestMatch_selectMLS_extDict (
Yann Collet03526e12015-11-23 15:29:15 +01001735 ZSTD_CCtx* zc, /* Index table will be updated */
1736 const BYTE* ip, const BYTE* const iLimit,
1737 size_t* offsetPtr,
1738 const U32 maxNbAttempts, const U32 matchLengthSearch)
1739{
1740 switch(matchLengthSearch)
1741 {
1742 default :
1743 case 4 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4);
1744 case 5 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5);
1745 case 6 : return ZSTD_BtFindBestMatch_extDict(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6);
1746 }
1747}
1748
1749
Yann Collet5106a762015-11-05 15:00:24 +01001750
Yann Collet731ef162016-07-27 21:05:12 +02001751/* *********************************
inikep64d7bcb2016-04-07 19:14:09 +02001752* Hash Chain
Yann Collet731ef162016-07-27 21:05:12 +02001753***********************************/
inikep64d7bcb2016-04-07 19:14:09 +02001754#define NEXT_IN_CHAIN(d, mask) chainTable[(d) & mask]
1755
1756/* Update chains up to ip (excluded)
Anders Oleson517577b2017-02-20 12:08:59 -08001757 Assumption : always within prefix (i.e. not within extDict) */
inikep64d7bcb2016-04-07 19:14:09 +02001758FORCE_INLINE
1759U32 ZSTD_insertAndFindFirstIndex (ZSTD_CCtx* zc, const BYTE* ip, U32 mls)
1760{
1761 U32* const hashTable = zc->hashTable;
1762 const U32 hashLog = zc->params.cParams.hashLog;
1763 U32* const chainTable = zc->chainTable;
1764 const U32 chainMask = (1 << zc->params.cParams.chainLog) - 1;
1765 const BYTE* const base = zc->base;
1766 const U32 target = (U32)(ip - base);
1767 U32 idx = zc->nextToUpdate;
1768
Yann Collet22d76322016-06-21 08:01:51 +02001769 while(idx < target) { /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02001770 size_t const h = ZSTD_hashPtr(base+idx, hashLog, mls);
1771 NEXT_IN_CHAIN(idx, chainMask) = hashTable[h];
1772 hashTable[h] = idx;
1773 idx++;
1774 }
1775
1776 zc->nextToUpdate = target;
1777 return hashTable[ZSTD_hashPtr(ip, hashLog, mls)];
1778}
1779
1780
1781
1782FORCE_INLINE /* inlining is important to hardwire a hot branch (template emulation) */
1783size_t ZSTD_HcFindBestMatch_generic (
1784 ZSTD_CCtx* zc, /* Index table will be updated */
1785 const BYTE* const ip, const BYTE* const iLimit,
1786 size_t* offsetPtr,
1787 const U32 maxNbAttempts, const U32 mls, const U32 extDict)
1788{
1789 U32* const chainTable = zc->chainTable;
1790 const U32 chainSize = (1 << zc->params.cParams.chainLog);
1791 const U32 chainMask = chainSize-1;
1792 const BYTE* const base = zc->base;
1793 const BYTE* const dictBase = zc->dictBase;
1794 const U32 dictLimit = zc->dictLimit;
1795 const BYTE* const prefixStart = base + dictLimit;
1796 const BYTE* const dictEnd = dictBase + dictLimit;
1797 const U32 lowLimit = zc->lowLimit;
1798 const U32 current = (U32)(ip-base);
1799 const U32 minChain = current > chainSize ? current - chainSize : 0;
1800 int nbAttempts=maxNbAttempts;
1801 size_t ml=EQUAL_READ32-1;
1802
1803 /* HC4 match finder */
1804 U32 matchIndex = ZSTD_insertAndFindFirstIndex (zc, ip, mls);
1805
Yann Collet22d76322016-06-21 08:01:51 +02001806 for ( ; (matchIndex>lowLimit) & (nbAttempts>0) ; nbAttempts--) {
inikep64d7bcb2016-04-07 19:14:09 +02001807 const BYTE* match;
1808 size_t currentMl=0;
1809 if ((!extDict) || matchIndex >= dictLimit) {
1810 match = base + matchIndex;
1811 if (match[ml] == ip[ml]) /* potentially better */
1812 currentMl = ZSTD_count(ip, match, iLimit);
1813 } else {
1814 match = dictBase + matchIndex;
1815 if (MEM_read32(match) == MEM_read32(ip)) /* assumption : matchIndex <= dictLimit-4 (by table construction) */
1816 currentMl = ZSTD_count_2segments(ip+EQUAL_READ32, match+EQUAL_READ32, iLimit, dictEnd, prefixStart) + EQUAL_READ32;
1817 }
1818
1819 /* save best solution */
Yann Collet22d76322016-06-21 08:01:51 +02001820 if (currentMl > ml) { ml = currentMl; *offsetPtr = current - matchIndex + ZSTD_REP_MOVE; if (ip+currentMl == iLimit) break; /* best possible, and avoid read overflow*/ }
inikep64d7bcb2016-04-07 19:14:09 +02001821
1822 if (matchIndex <= minChain) break;
1823 matchIndex = NEXT_IN_CHAIN(matchIndex, chainMask);
1824 }
1825
1826 return ml;
1827}
1828
1829
1830FORCE_INLINE size_t ZSTD_HcFindBestMatch_selectMLS (
1831 ZSTD_CCtx* zc,
1832 const BYTE* ip, const BYTE* const iLimit,
1833 size_t* offsetPtr,
1834 const U32 maxNbAttempts, const U32 matchLengthSearch)
1835{
1836 switch(matchLengthSearch)
1837 {
1838 default :
1839 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 0);
1840 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 0);
1841 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 0);
1842 }
1843}
1844
1845
1846FORCE_INLINE size_t ZSTD_HcFindBestMatch_extDict_selectMLS (
1847 ZSTD_CCtx* zc,
1848 const BYTE* ip, const BYTE* const iLimit,
1849 size_t* offsetPtr,
1850 const U32 maxNbAttempts, const U32 matchLengthSearch)
1851{
1852 switch(matchLengthSearch)
1853 {
1854 default :
1855 case 4 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 4, 1);
1856 case 5 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 5, 1);
1857 case 6 : return ZSTD_HcFindBestMatch_generic(zc, ip, iLimit, offsetPtr, maxNbAttempts, 6, 1);
1858 }
1859}
1860
inikep64d7bcb2016-04-07 19:14:09 +02001861
Yann Collet287b7d92015-11-22 13:24:05 +01001862/* *******************************
inikep64d7bcb2016-04-07 19:14:09 +02001863* Common parser - lazy strategy
inikepfaa8d8a2016-04-05 19:01:10 +02001864*********************************/
Yann Collet96b9f0b2015-11-04 03:52:54 +01001865FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02001866void ZSTD_compressBlock_lazy_generic(ZSTD_CCtx* ctx,
1867 const void* src, size_t srcSize,
1868 const U32 searchMethod, const U32 depth)
Yann Collet96b9f0b2015-11-04 03:52:54 +01001869{
inikepfaa8d8a2016-04-05 19:01:10 +02001870 seqStore_t* seqStorePtr = &(ctx->seqStore);
1871 const BYTE* const istart = (const BYTE*)src;
1872 const BYTE* ip = istart;
1873 const BYTE* anchor = istart;
1874 const BYTE* const iend = istart + srcSize;
1875 const BYTE* const ilimit = iend - 8;
1876 const BYTE* const base = ctx->base + ctx->dictLimit;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001877
Yann Collet793c6492016-04-09 20:32:00 +02001878 U32 const maxSearches = 1 << ctx->params.cParams.searchLog;
1879 U32 const mls = ctx->params.cParams.searchLength;
Yann Collet96b9f0b2015-11-04 03:52:54 +01001880
inikep64d7bcb2016-04-07 19:14:09 +02001881 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
1882 size_t* offsetPtr,
1883 U32 maxNbAttempts, U32 matchLengthSearch);
Yann Collet43dfe012016-06-13 21:43:06 +02001884 searchMax_f const searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS : ZSTD_HcFindBestMatch_selectMLS;
Yann Collet9634f672016-07-03 01:23:58 +02001885 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1], savedOffset=0;
inikep64d7bcb2016-04-07 19:14:09 +02001886
inikepfaa8d8a2016-04-05 19:01:10 +02001887 /* init */
Yann Collet4266c0a2016-06-14 01:49:25 +02001888 ip += (ip==base);
inikep64d7bcb2016-04-07 19:14:09 +02001889 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet9634f672016-07-03 01:23:58 +02001890 { U32 const maxRep = (U32)(ip-base);
1891 if (offset_2 > maxRep) savedOffset = offset_2, offset_2 = 0;
1892 if (offset_1 > maxRep) savedOffset = offset_1, offset_1 = 0;
1893 }
Yann Collet96b9f0b2015-11-04 03:52:54 +01001894
inikepfaa8d8a2016-04-05 19:01:10 +02001895 /* Match Loop */
1896 while (ip < ilimit) {
1897 size_t matchLength=0;
1898 size_t offset=0;
1899 const BYTE* start=ip+1;
Yann Collet5106a762015-11-05 15:00:24 +01001900
inikepfaa8d8a2016-04-05 19:01:10 +02001901 /* check repCode */
Yann Collet9634f672016-07-03 01:23:58 +02001902 if ((offset_1>0) & (MEM_read32(ip+1) == MEM_read32(ip+1 - offset_1))) {
inikepfaa8d8a2016-04-05 19:01:10 +02001903 /* repcode : we take it */
Yann Collet9634f672016-07-03 01:23:58 +02001904 matchLength = ZSTD_count(ip+1+EQUAL_READ32, ip+1+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001905 if (depth==0) goto _storeSequence;
Yann Collet5106a762015-11-05 15:00:24 +01001906 }
Yann Collet5be2dd22015-11-11 13:43:58 +01001907
inikepfaa8d8a2016-04-05 19:01:10 +02001908 /* first search (depth 0) */
1909 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02001910 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02001911 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02001912 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02001913 }
Yann Collet5106a762015-11-05 15:00:24 +01001914
inikep7bc19b62016-04-06 09:46:01 +02001915 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02001916 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
1917 continue;
1918 }
1919
inikep64d7bcb2016-04-07 19:14:09 +02001920 /* let's try to find a better solution */
1921 if (depth>=1)
1922 while (ip<ilimit) {
1923 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001924 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1925 size_t const mlRep = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001926 int const gain2 = (int)(mlRep * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02001927 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001928 if ((mlRep >= EQUAL_READ32) && (gain2 > gain1))
1929 matchLength = mlRep, offset = 0, start = ip;
1930 }
1931 { size_t offset2=99999999;
1932 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001933 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1934 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02001935 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1936 matchLength = ml2, offset = offset2, start = ip;
1937 continue; /* search a better one */
1938 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001939
inikep64d7bcb2016-04-07 19:14:09 +02001940 /* let's find an even better one */
1941 if ((depth==2) && (ip<ilimit)) {
1942 ip ++;
Yann Collet9634f672016-07-03 01:23:58 +02001943 if ((offset) && ((offset_1>0) & (MEM_read32(ip) == MEM_read32(ip - offset_1)))) {
1944 size_t const ml2 = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_1, iend) + EQUAL_READ32;
inikep64d7bcb2016-04-07 19:14:09 +02001945 int const gain2 = (int)(ml2 * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02001946 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02001947 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1))
1948 matchLength = ml2, offset = 0, start = ip;
1949 }
1950 { size_t offset2=99999999;
1951 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02001952 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
1953 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02001954 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
1955 matchLength = ml2, offset = offset2, start = ip;
1956 continue;
1957 } } }
1958 break; /* nothing found : store previous solution */
1959 }
1960
1961 /* catch up */
1962 if (offset) {
1963 while ((start>anchor) && (start>base+offset-ZSTD_REP_MOVE) && (start[-1] == start[-1-offset+ZSTD_REP_MOVE])) /* only search for offset within prefix */
1964 { start--; matchLength++; }
Yann Collet9634f672016-07-03 01:23:58 +02001965 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
inikep64d7bcb2016-04-07 19:14:09 +02001966 }
1967
inikepfaa8d8a2016-04-05 19:01:10 +02001968 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02001969_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02001970 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02001971 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02001972 anchor = ip = start + matchLength;
1973 }
Yann Collet48537162016-04-07 15:24:29 +02001974
inikepfaa8d8a2016-04-05 19:01:10 +02001975 /* check immediate repcode */
1976 while ( (ip <= ilimit)
Yann Collet9634f672016-07-03 01:23:58 +02001977 && ((offset_2>0)
1978 & (MEM_read32(ip) == MEM_read32(ip - offset_2)) )) {
inikepfaa8d8a2016-04-05 19:01:10 +02001979 /* store sequence */
Yann Collet9634f672016-07-03 01:23:58 +02001980 matchLength = ZSTD_count(ip+EQUAL_READ32, ip+EQUAL_READ32-offset_2, iend) + EQUAL_READ32;
1981 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap repcodes */
inikep7bc19b62016-04-06 09:46:01 +02001982 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
1983 ip += matchLength;
inikepfaa8d8a2016-04-05 19:01:10 +02001984 anchor = ip;
1985 continue; /* faster when present ... (?) */
inikep64d7bcb2016-04-07 19:14:09 +02001986 } }
inikepfaa8d8a2016-04-05 19:01:10 +02001987
Yann Collet4266c0a2016-06-14 01:49:25 +02001988 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08001989 ctx->repToConfirm[0] = offset_1 ? offset_1 : savedOffset;
1990 ctx->repToConfirm[1] = offset_2 ? offset_2 : savedOffset;
Yann Collet4266c0a2016-06-14 01:49:25 +02001991
inikepfaa8d8a2016-04-05 19:01:10 +02001992 /* Last Literals */
1993 { size_t const lastLLSize = iend - anchor;
1994 memcpy(seqStorePtr->lit, anchor, lastLLSize);
1995 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01001996 }
Yann Collet5106a762015-11-05 15:00:24 +01001997}
1998
Yann Collet5be2dd22015-11-11 13:43:58 +01001999
inikep64d7bcb2016-04-07 19:14:09 +02002000static void ZSTD_compressBlock_btlazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2001{
2002 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 1, 2);
2003}
2004
2005static void ZSTD_compressBlock_lazy2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2006{
2007 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 2);
2008}
2009
2010static void ZSTD_compressBlock_lazy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2011{
2012 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 1);
2013}
2014
2015static void ZSTD_compressBlock_greedy(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2016{
2017 ZSTD_compressBlock_lazy_generic(ctx, src, srcSize, 0, 0);
2018}
2019
2020
inikepfaa8d8a2016-04-05 19:01:10 +02002021FORCE_INLINE
inikep64d7bcb2016-04-07 19:14:09 +02002022void ZSTD_compressBlock_lazy_extDict_generic(ZSTD_CCtx* ctx,
2023 const void* src, size_t srcSize,
2024 const U32 searchMethod, const U32 depth)
Yann Collet5be2dd22015-11-11 13:43:58 +01002025{
inikepfaa8d8a2016-04-05 19:01:10 +02002026 seqStore_t* seqStorePtr = &(ctx->seqStore);
2027 const BYTE* const istart = (const BYTE*)src;
2028 const BYTE* ip = istart;
2029 const BYTE* anchor = istart;
2030 const BYTE* const iend = istart + srcSize;
2031 const BYTE* const ilimit = iend - 8;
2032 const BYTE* const base = ctx->base;
2033 const U32 dictLimit = ctx->dictLimit;
Yann Collet43dfe012016-06-13 21:43:06 +02002034 const U32 lowestIndex = ctx->lowLimit;
inikepfaa8d8a2016-04-05 19:01:10 +02002035 const BYTE* const prefixStart = base + dictLimit;
2036 const BYTE* const dictBase = ctx->dictBase;
2037 const BYTE* const dictEnd = dictBase + dictLimit;
2038 const BYTE* const dictStart = dictBase + ctx->lowLimit;
2039
2040 const U32 maxSearches = 1 << ctx->params.cParams.searchLog;
2041 const U32 mls = ctx->params.cParams.searchLength;
2042
inikep64d7bcb2016-04-07 19:14:09 +02002043 typedef size_t (*searchMax_f)(ZSTD_CCtx* zc, const BYTE* ip, const BYTE* iLimit,
2044 size_t* offsetPtr,
2045 U32 maxNbAttempts, U32 matchLengthSearch);
2046 searchMax_f searchMax = searchMethod ? ZSTD_BtFindBestMatch_selectMLS_extDict : ZSTD_HcFindBestMatch_extDict_selectMLS;
2047
Yann Collet302ff032016-07-03 01:28:16 +02002048 U32 offset_1 = ctx->rep[0], offset_2 = ctx->rep[1];
inikepfaa8d8a2016-04-05 19:01:10 +02002049
Yann Collet302ff032016-07-03 01:28:16 +02002050 /* init */
inikep64d7bcb2016-04-07 19:14:09 +02002051 ctx->nextToUpdate3 = ctx->nextToUpdate;
Yann Collet4266c0a2016-06-14 01:49:25 +02002052 ip += (ip == prefixStart);
inikepfaa8d8a2016-04-05 19:01:10 +02002053
2054 /* Match Loop */
2055 while (ip < ilimit) {
2056 size_t matchLength=0;
2057 size_t offset=0;
2058 const BYTE* start=ip+1;
inikep64d7bcb2016-04-07 19:14:09 +02002059 U32 current = (U32)(ip-base);
inikepfaa8d8a2016-04-05 19:01:10 +02002060
2061 /* check repCode */
Yann Collet302ff032016-07-03 01:28:16 +02002062 { const U32 repIndex = (U32)(current+1 - offset_1);
inikepfaa8d8a2016-04-05 19:01:10 +02002063 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2064 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002065 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002066 if (MEM_read32(ip+1) == MEM_read32(repMatch)) {
inikepfaa8d8a2016-04-05 19:01:10 +02002067 /* repcode detected we should take it */
2068 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep64d7bcb2016-04-07 19:14:09 +02002069 matchLength = ZSTD_count_2segments(ip+1+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2070 if (depth==0) goto _storeSequence;
inikepfaa8d8a2016-04-05 19:01:10 +02002071 } }
2072
2073 /* first search (depth 0) */
2074 { size_t offsetFound = 99999999;
inikep64d7bcb2016-04-07 19:14:09 +02002075 size_t const ml2 = searchMax(ctx, ip, iend, &offsetFound, maxSearches, mls);
inikepfaa8d8a2016-04-05 19:01:10 +02002076 if (ml2 > matchLength)
inikep75716852016-04-06 12:34:42 +02002077 matchLength = ml2, start = ip, offset=offsetFound;
inikepfaa8d8a2016-04-05 19:01:10 +02002078 }
2079
inikep7bc19b62016-04-06 09:46:01 +02002080 if (matchLength < EQUAL_READ32) {
inikepfaa8d8a2016-04-05 19:01:10 +02002081 ip += ((ip-anchor) >> g_searchStrength) + 1; /* jump faster over incompressible sections */
2082 continue;
2083 }
2084
inikep64d7bcb2016-04-07 19:14:09 +02002085 /* let's try to find a better solution */
2086 if (depth>=1)
2087 while (ip<ilimit) {
2088 ip ++;
2089 current++;
2090 /* check repCode */
2091 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002092 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002093 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2094 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002095 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002096 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2097 /* repcode detected */
2098 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2099 size_t const repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2100 int const gain2 = (int)(repLength * 3);
Yann Collet49bb0042016-06-04 20:17:38 +02002101 int const gain1 = (int)(matchLength*3 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002102 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2103 matchLength = repLength, offset = 0, start = ip;
2104 } }
2105
2106 /* search match, depth 1 */
2107 { size_t offset2=99999999;
2108 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002109 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2110 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 4);
inikep64d7bcb2016-04-07 19:14:09 +02002111 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2112 matchLength = ml2, offset = offset2, start = ip;
2113 continue; /* search a better one */
2114 } }
2115
2116 /* let's find an even better one */
2117 if ((depth==2) && (ip<ilimit)) {
2118 ip ++;
2119 current++;
2120 /* check repCode */
2121 if (offset) {
Yann Collet302ff032016-07-03 01:28:16 +02002122 const U32 repIndex = (U32)(current - offset_1);
inikep64d7bcb2016-04-07 19:14:09 +02002123 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2124 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002125 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikep64d7bcb2016-04-07 19:14:09 +02002126 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2127 /* repcode detected */
2128 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
2129 size_t repLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
2130 int gain2 = (int)(repLength * 4);
Yann Collet49bb0042016-06-04 20:17:38 +02002131 int gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 1);
inikep64d7bcb2016-04-07 19:14:09 +02002132 if ((repLength >= EQUAL_READ32) && (gain2 > gain1))
2133 matchLength = repLength, offset = 0, start = ip;
2134 } }
2135
2136 /* search match, depth 2 */
2137 { size_t offset2=99999999;
2138 size_t const ml2 = searchMax(ctx, ip, iend, &offset2, maxSearches, mls);
Yann Collet49bb0042016-06-04 20:17:38 +02002139 int const gain2 = (int)(ml2*4 - ZSTD_highbit32((U32)offset2+1)); /* raw approx */
2140 int const gain1 = (int)(matchLength*4 - ZSTD_highbit32((U32)offset+1) + 7);
inikep64d7bcb2016-04-07 19:14:09 +02002141 if ((ml2 >= EQUAL_READ32) && (gain2 > gain1)) {
2142 matchLength = ml2, offset = offset2, start = ip;
2143 continue;
2144 } } }
2145 break; /* nothing found : store previous solution */
2146 }
2147
inikepfaa8d8a2016-04-05 19:01:10 +02002148 /* catch up */
inikep64d7bcb2016-04-07 19:14:09 +02002149 if (offset) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002150 U32 const matchIndex = (U32)((start-base) - (offset - ZSTD_REP_MOVE));
inikepfaa8d8a2016-04-05 19:01:10 +02002151 const BYTE* match = (matchIndex < dictLimit) ? dictBase + matchIndex : base + matchIndex;
2152 const BYTE* const mStart = (matchIndex < dictLimit) ? dictStart : prefixStart;
inikep64d7bcb2016-04-07 19:14:09 +02002153 while ((start>anchor) && (match>mStart) && (start[-1] == match[-1])) { start--; match--; matchLength++; } /* catch up */
Yann Collet302ff032016-07-03 01:28:16 +02002154 offset_2 = offset_1; offset_1 = (U32)(offset - ZSTD_REP_MOVE);
Yann Collet48537162016-04-07 15:24:29 +02002155 }
inikepfaa8d8a2016-04-05 19:01:10 +02002156
inikepfaa8d8a2016-04-05 19:01:10 +02002157 /* store sequence */
inikep64d7bcb2016-04-07 19:14:09 +02002158_storeSequence:
inikepfaa8d8a2016-04-05 19:01:10 +02002159 { size_t const litLength = start - anchor;
Yann Colletd57dffb2016-07-03 01:48:26 +02002160 ZSTD_storeSeq(seqStorePtr, litLength, anchor, (U32)offset, matchLength-MINMATCH);
inikepfaa8d8a2016-04-05 19:01:10 +02002161 anchor = ip = start + matchLength;
2162 }
2163
2164 /* check immediate repcode */
2165 while (ip <= ilimit) {
Yann Collet302ff032016-07-03 01:28:16 +02002166 const U32 repIndex = (U32)((ip-base) - offset_2);
inikepfaa8d8a2016-04-05 19:01:10 +02002167 const BYTE* const repBase = repIndex < dictLimit ? dictBase : base;
2168 const BYTE* const repMatch = repBase + repIndex;
Yann Collet43dfe012016-06-13 21:43:06 +02002169 if (((U32)((dictLimit-1) - repIndex) >= 3) & (repIndex > lowestIndex)) /* intentional overflow */
inikepfaa8d8a2016-04-05 19:01:10 +02002170 if (MEM_read32(ip) == MEM_read32(repMatch)) {
2171 /* repcode detected we should take it */
2172 const BYTE* const repEnd = repIndex < dictLimit ? dictEnd : iend;
inikep7bc19b62016-04-06 09:46:01 +02002173 matchLength = ZSTD_count_2segments(ip+EQUAL_READ32, repMatch+EQUAL_READ32, iend, repEnd, prefixStart) + EQUAL_READ32;
Yann Collet302ff032016-07-03 01:28:16 +02002174 offset = offset_2; offset_2 = offset_1; offset_1 = (U32)offset; /* swap offset history */
inikepfaa8d8a2016-04-05 19:01:10 +02002175 ZSTD_storeSeq(seqStorePtr, 0, anchor, 0, matchLength-MINMATCH);
2176 ip += matchLength;
2177 anchor = ip;
2178 continue; /* faster when present ... (?) */
2179 }
2180 break;
2181 } }
2182
Yann Collet4266c0a2016-06-14 01:49:25 +02002183 /* Save reps for next block */
Yann Colletb459aad2017-01-19 17:33:37 -08002184 ctx->repToConfirm[0] = offset_1; ctx->repToConfirm[1] = offset_2;
Yann Collet4266c0a2016-06-14 01:49:25 +02002185
inikepfaa8d8a2016-04-05 19:01:10 +02002186 /* Last Literals */
2187 { size_t const lastLLSize = iend - anchor;
2188 memcpy(seqStorePtr->lit, anchor, lastLLSize);
2189 seqStorePtr->lit += lastLLSize;
Yann Collet5106a762015-11-05 15:00:24 +01002190 }
2191}
2192
2193
Yann Collet59d1f792016-01-23 19:28:41 +01002194void ZSTD_compressBlock_greedy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet9a24e592015-11-22 02:53:43 +01002195{
inikep64d7bcb2016-04-07 19:14:09 +02002196 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 0);
Yann Collet9a24e592015-11-22 02:53:43 +01002197}
2198
Yann Collet59d1f792016-01-23 19:28:41 +01002199static void ZSTD_compressBlock_lazy_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colletb7fc88e2015-11-22 03:12:28 +01002200{
Yann Colleta1249dc2016-01-25 04:22:03 +01002201 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 1);
Yann Colletb7fc88e2015-11-22 03:12:28 +01002202}
Yann Collet9a24e592015-11-22 02:53:43 +01002203
Yann Collet59d1f792016-01-23 19:28:41 +01002204static void ZSTD_compressBlock_lazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Colleta85c77b2015-11-22 12:22:04 +01002205{
Yann Colleta1249dc2016-01-25 04:22:03 +01002206 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 0, 2);
Yann Colleta85c77b2015-11-22 12:22:04 +01002207}
2208
Yann Collet59d1f792016-01-23 19:28:41 +01002209static void ZSTD_compressBlock_btlazy2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
Yann Collet5054ee02015-11-23 13:34:21 +01002210{
Yann Colleta1249dc2016-01-25 04:22:03 +01002211 ZSTD_compressBlock_lazy_extDict_generic(ctx, src, srcSize, 1, 2);
Yann Collet5054ee02015-11-23 13:34:21 +01002212}
2213
inikepef519412016-04-21 11:08:43 +02002214
inikepef519412016-04-21 11:08:43 +02002215/* The optimal parser */
2216#include "zstd_opt.h"
2217
2218static void ZSTD_compressBlock_btopt(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2219{
Yann Colletd4f4e582016-06-27 01:31:35 +02002220#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002221 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 0);
2222#else
2223 (void)ctx; (void)src; (void)srcSize;
2224 return;
2225#endif
2226}
2227
2228static void ZSTD_compressBlock_btopt2(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2229{
2230#ifdef ZSTD_OPT_H_91842398743
2231 ZSTD_compressBlock_opt_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002232#else
2233 (void)ctx; (void)src; (void)srcSize;
2234 return;
2235#endif
inikepef519412016-04-21 11:08:43 +02002236}
2237
inikepd3b8d7a2016-02-22 10:06:17 +01002238static void ZSTD_compressBlock_btopt_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
inikepe2bfe242016-01-31 11:25:48 +01002239{
Yann Colletd4f4e582016-06-27 01:31:35 +02002240#ifdef ZSTD_OPT_H_91842398743
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002241 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 0);
2242#else
2243 (void)ctx; (void)src; (void)srcSize;
2244 return;
2245#endif
2246}
2247
2248static void ZSTD_compressBlock_btopt2_extDict(ZSTD_CCtx* ctx, const void* src, size_t srcSize)
2249{
2250#ifdef ZSTD_OPT_H_91842398743
2251 ZSTD_compressBlock_opt_extDict_generic(ctx, src, srcSize, 1);
Yann Colletd4f4e582016-06-27 01:31:35 +02002252#else
2253 (void)ctx; (void)src; (void)srcSize;
2254 return;
2255#endif
inikepe2bfe242016-01-31 11:25:48 +01002256}
2257
Yann Collet7a231792015-11-21 15:27:35 +01002258
Yann Collet59d1f792016-01-23 19:28:41 +01002259typedef void (*ZSTD_blockCompressor) (ZSTD_CCtx* ctx, const void* src, size_t srcSize);
Yann Collet59d70632015-11-04 12:05:27 +01002260
Yann Colletb923f652016-01-26 03:14:20 +01002261static ZSTD_blockCompressor ZSTD_selectBlockCompressor(ZSTD_strategy strat, int extDict)
Yann Collet59d70632015-11-04 12:05:27 +01002262{
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002263 static const ZSTD_blockCompressor blockCompressor[2][8] = {
2264 { ZSTD_compressBlock_fast, ZSTD_compressBlock_doubleFast, ZSTD_compressBlock_greedy, ZSTD_compressBlock_lazy, ZSTD_compressBlock_lazy2, ZSTD_compressBlock_btlazy2, ZSTD_compressBlock_btopt, ZSTD_compressBlock_btopt2 },
2265 { ZSTD_compressBlock_fast_extDict, ZSTD_compressBlock_doubleFast_extDict, ZSTD_compressBlock_greedy_extDict, ZSTD_compressBlock_lazy_extDict,ZSTD_compressBlock_lazy2_extDict, ZSTD_compressBlock_btlazy2_extDict, ZSTD_compressBlock_btopt_extDict, ZSTD_compressBlock_btopt2_extDict }
Yann Collet7fe531e2015-11-29 02:38:09 +01002266 };
2267
2268 return blockCompressor[extDict][(U32)strat];
Yann Collet59d70632015-11-04 12:05:27 +01002269}
2270
2271
Yann Colletd1b26842016-03-15 01:24:33 +01002272static 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 +01002273{
Yann Collet19cab462016-06-17 12:54:52 +02002274 ZSTD_blockCompressor const blockCompressor = ZSTD_selectBlockCompressor(zc->params.cParams.strategy, zc->lowLimit < zc->dictLimit);
inikep98e08cb2016-08-10 15:00:30 +02002275 const BYTE* const base = zc->base;
2276 const BYTE* const istart = (const BYTE*)src;
2277 const U32 current = (U32)(istart-base);
Yann Collet2ce49232016-02-02 14:36:49 +01002278 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 +02002279 ZSTD_resetSeqStore(&(zc->seqStore));
inikep98e08cb2016-08-10 15:00:30 +02002280 if (current > zc->nextToUpdate + 384)
2281 zc->nextToUpdate = current - MIN(192, (U32)(current - zc->nextToUpdate - 384)); /* update tree not updated after finding very long rep matches */
Yann Collet59d1f792016-01-23 19:28:41 +01002282 blockCompressor(zc, src, srcSize);
Yann Colletd1b26842016-03-15 01:24:33 +01002283 return ZSTD_compressSequences(zc, dst, dstCapacity, srcSize);
Yann Colletbe2010e2015-10-31 12:57:14 +01002284}
2285
2286
Yann Colletc991cc12016-07-28 00:55:43 +02002287/*! ZSTD_compress_generic() :
2288* Compress a chunk of data into one or multiple blocks.
2289* All blocks will be terminated, all input will be consumed.
2290* Function will issue an error if there is not enough `dstCapacity` to hold the compressed content.
2291* Frame is supposed already started (header already produced)
2292* @return : compressed size, or an error code
2293*/
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002294static size_t ZSTD_compress_generic (ZSTD_CCtx* cctx,
2295 void* dst, size_t dstCapacity,
Yann Colletc991cc12016-07-28 00:55:43 +02002296 const void* src, size_t srcSize,
2297 U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002298{
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002299 size_t blockSize = cctx->blockSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002300 size_t remaining = srcSize;
2301 const BYTE* ip = (const BYTE*)src;
2302 BYTE* const ostart = (BYTE*)dst;
2303 BYTE* op = ostart;
Yann Colletd4180ca2016-07-27 21:21:36 +02002304 U32 const maxDist = 1 << cctx->params.cParams.windowLog;
Yann Collet9b11b462015-11-01 12:40:22 +01002305
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002306 if (cctx->params.fParams.checksumFlag && srcSize)
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002307 XXH64_update(&cctx->xxhState, src, srcSize);
2308
Yann Collet2ce49232016-02-02 14:36:49 +01002309 while (remaining) {
Yann Colletc991cc12016-07-28 00:55:43 +02002310 U32 const lastBlock = lastFrameChunk & (blockSize >= remaining);
Yann Collet3e358272015-11-04 18:19:39 +01002311 size_t cSize;
2312
inikepfb5df612016-05-24 15:36:37 +02002313 if (dstCapacity < ZSTD_blockHeaderSize + MIN_CBLOCK_SIZE) return ERROR(dstSize_tooSmall); /* not enough space to store compressed block */
Yann Collet3e358272015-11-04 18:19:39 +01002314 if (remaining < blockSize) blockSize = remaining;
Yann Collet89db5e02015-11-13 11:27:46 +01002315
Yann Collet346efcc2016-08-02 14:26:00 +02002316 /* preemptive overflow correction */
Yann Colletc261f712016-12-12 00:25:07 +01002317 if (cctx->lowLimit > (2U<<30)) {
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002318 U32 const cycleMask = (1 << ZSTD_cycleLog(cctx->params.cParams.hashLog, cctx->params.cParams.strategy)) - 1;
Yann Colletc261f712016-12-12 00:25:07 +01002319 U32 const current = (U32)(ip - cctx->base);
Yann Colletc3a5c4b2016-12-12 00:47:30 +01002320 U32 const newCurrent = (current & cycleMask) + (1 << cctx->params.cParams.windowLog);
Yann Colletc261f712016-12-12 00:25:07 +01002321 U32 const correction = current - newCurrent;
2322 ZSTD_STATIC_ASSERT(ZSTD_WINDOWLOG_MAX_64 <= 30);
Yann Collet346efcc2016-08-02 14:26:00 +02002323 ZSTD_reduceIndex(cctx, correction);
2324 cctx->base += correction;
2325 cctx->dictBase += correction;
Yann Colletc261f712016-12-12 00:25:07 +01002326 cctx->lowLimit -= correction;
Yann Collet346efcc2016-08-02 14:26:00 +02002327 cctx->dictLimit -= correction;
2328 if (cctx->nextToUpdate < correction) cctx->nextToUpdate = 0;
2329 else cctx->nextToUpdate -= correction;
2330 }
2331
Yann Collet06e76972017-01-25 16:39:03 -08002332 if ((U32)(ip+blockSize - cctx->base) > cctx->loadedDictEnd + maxDist) {
Yann Collet70e45772016-03-19 18:08:32 +01002333 /* enforce maxDist */
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002334 U32 const newLowLimit = (U32)(ip+blockSize - cctx->base) - maxDist;
2335 if (cctx->lowLimit < newLowLimit) cctx->lowLimit = newLowLimit;
2336 if (cctx->dictLimit < cctx->lowLimit) cctx->dictLimit = cctx->lowLimit;
Yann Colletc3652152015-11-24 14:06:07 +01002337 }
Yann Collet89db5e02015-11-13 11:27:46 +01002338
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002339 cSize = ZSTD_compressBlock_internal(cctx, op+ZSTD_blockHeaderSize, dstCapacity-ZSTD_blockHeaderSize, ip, blockSize);
inikepfb5df612016-05-24 15:36:37 +02002340 if (ZSTD_isError(cSize)) return cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002341
Yann Collet2ce49232016-02-02 14:36:49 +01002342 if (cSize == 0) { /* block is not compressible */
Yann Colletc991cc12016-07-28 00:55:43 +02002343 U32 const cBlockHeader24 = lastBlock + (((U32)bt_raw)<<1) + (U32)(blockSize << 3);
2344 if (blockSize + ZSTD_blockHeaderSize > dstCapacity) return ERROR(dstSize_tooSmall);
2345 MEM_writeLE32(op, cBlockHeader24); /* no pb, 4th byte will be overwritten */
2346 memcpy(op + ZSTD_blockHeaderSize, ip, blockSize);
2347 cSize = ZSTD_blockHeaderSize+blockSize;
Yann Collet2ce49232016-02-02 14:36:49 +01002348 } else {
Yann Colletc991cc12016-07-28 00:55:43 +02002349 U32 const cBlockHeader24 = lastBlock + (((U32)bt_compressed)<<1) + (U32)(cSize << 3);
Yann Collet6fa05a22016-07-20 14:58:49 +02002350 MEM_writeLE24(op, cBlockHeader24);
Yann Colletc991cc12016-07-28 00:55:43 +02002351 cSize += ZSTD_blockHeaderSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002352 }
2353
2354 remaining -= blockSize;
Yann Colletd1b26842016-03-15 01:24:33 +01002355 dstCapacity -= cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002356 ip += blockSize;
2357 op += cSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002358 }
2359
Yann Collet62470b42016-07-28 15:29:08 +02002360 if (lastFrameChunk && (op>ostart)) cctx->stage = ZSTDcs_ending;
Yann Colletf3eca252015-10-22 15:31:46 +01002361 return op-ostart;
2362}
2363
2364
Yann Collet6236eba2016-04-12 15:52:33 +02002365static size_t ZSTD_writeFrameHeader(void* dst, size_t dstCapacity,
Yann Colletc46fb922016-05-29 05:01:04 +02002366 ZSTD_parameters params, U64 pledgedSrcSize, U32 dictID)
Yann Collet6236eba2016-04-12 15:52:33 +02002367{ BYTE* const op = (BYTE*)dst;
Yann Collet731ef162016-07-27 21:05:12 +02002368 U32 const dictIDSizeCode = (dictID>0) + (dictID>=256) + (dictID>=65536); /* 0-3 */
2369 U32 const checksumFlag = params.fParams.checksumFlag>0;
2370 U32 const windowSize = 1U << params.cParams.windowLog;
Sean Purcell2db72492017-02-09 10:50:43 -08002371 U32 const singleSegment = params.fParams.contentSizeFlag && (windowSize >= pledgedSrcSize);
Yann Collet731ef162016-07-27 21:05:12 +02002372 BYTE const windowLogByte = (BYTE)((params.cParams.windowLog - ZSTD_WINDOWLOG_ABSOLUTEMIN) << 3);
2373 U32 const fcsCode = params.fParams.contentSizeFlag ?
Yann Collet673f0d72016-06-06 00:26:38 +02002374 (pledgedSrcSize>=256) + (pledgedSrcSize>=65536+256) + (pledgedSrcSize>=0xFFFFFFFFU) : /* 0-3 */
2375 0;
Yann Collet731ef162016-07-27 21:05:12 +02002376 BYTE const frameHeaderDecriptionByte = (BYTE)(dictIDSizeCode + (checksumFlag<<2) + (singleSegment<<5) + (fcsCode<<6) );
Yann Colletc46fb922016-05-29 05:01:04 +02002377 size_t pos;
2378
2379 if (dstCapacity < ZSTD_frameHeaderSize_max) return ERROR(dstSize_tooSmall);
Yann Collet6236eba2016-04-12 15:52:33 +02002380
2381 MEM_writeLE32(dst, ZSTD_MAGICNUMBER);
Yann Collet673f0d72016-06-06 00:26:38 +02002382 op[4] = frameHeaderDecriptionByte; pos=5;
Eric Biggerse4d02652016-07-26 10:42:19 -07002383 if (!singleSegment) op[pos++] = windowLogByte;
Yann Colletc46fb922016-05-29 05:01:04 +02002384 switch(dictIDSizeCode)
2385 {
2386 default: /* impossible */
2387 case 0 : break;
2388 case 1 : op[pos] = (BYTE)(dictID); pos++; break;
Yann Colletd4180ca2016-07-27 21:21:36 +02002389 case 2 : MEM_writeLE16(op+pos, (U16)dictID); pos+=2; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002390 case 3 : MEM_writeLE32(op+pos, dictID); pos+=4; break;
2391 }
Yann Collet673f0d72016-06-06 00:26:38 +02002392 switch(fcsCode)
Yann Collet6236eba2016-04-12 15:52:33 +02002393 {
2394 default: /* impossible */
Eric Biggerse4d02652016-07-26 10:42:19 -07002395 case 0 : if (singleSegment) op[pos++] = (BYTE)(pledgedSrcSize); break;
Yann Collet673f0d72016-06-06 00:26:38 +02002396 case 1 : MEM_writeLE16(op+pos, (U16)(pledgedSrcSize-256)); pos+=2; break;
2397 case 2 : MEM_writeLE32(op+pos, (U32)(pledgedSrcSize)); pos+=4; break;
Yann Colletc46fb922016-05-29 05:01:04 +02002398 case 3 : MEM_writeLE64(op+pos, (U64)(pledgedSrcSize)); pos+=8; break;
Yann Collet6236eba2016-04-12 15:52:33 +02002399 }
Yann Colletc46fb922016-05-29 05:01:04 +02002400 return pos;
Yann Collet6236eba2016-04-12 15:52:33 +02002401}
2402
2403
Yann Collet346efcc2016-08-02 14:26:00 +02002404static size_t ZSTD_compressContinue_internal (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002405 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002406 const void* src, size_t srcSize,
Yann Colletc991cc12016-07-28 00:55:43 +02002407 U32 frame, U32 lastFrameChunk)
Yann Colletf3eca252015-10-22 15:31:46 +01002408{
Yann Collet2acb5d32015-10-29 16:49:43 +01002409 const BYTE* const ip = (const BYTE*) src;
Yann Collet6236eba2016-04-12 15:52:33 +02002410 size_t fhSize = 0;
Yann Colletecd651b2016-01-07 15:35:18 +01002411
Yann Collet346efcc2016-08-02 14:26:00 +02002412 if (cctx->stage==ZSTDcs_created) return ERROR(stage_wrong); /* missing init (ZSTD_compressBegin) */
Yann Colletd4180ca2016-07-27 21:21:36 +02002413
Yann Collet346efcc2016-08-02 14:26:00 +02002414 if (frame && (cctx->stage==ZSTDcs_init)) {
2415 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, cctx->frameContentSize, cctx->dictID);
Yann Collet6236eba2016-04-12 15:52:33 +02002416 if (ZSTD_isError(fhSize)) return fhSize;
2417 dstCapacity -= fhSize;
2418 dst = (char*)dst + fhSize;
Yann Collet346efcc2016-08-02 14:26:00 +02002419 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002420 }
Yann Colletf3eca252015-10-22 15:31:46 +01002421
Yann Collet417890c2015-12-04 17:16:37 +01002422 /* Check if blocks follow each other */
Yann Collet346efcc2016-08-02 14:26:00 +02002423 if (src != cctx->nextSrc) {
Yann Collet417890c2015-12-04 17:16:37 +01002424 /* not contiguous */
Yann Collet346efcc2016-08-02 14:26:00 +02002425 ptrdiff_t const delta = cctx->nextSrc - ip;
2426 cctx->lowLimit = cctx->dictLimit;
2427 cctx->dictLimit = (U32)(cctx->nextSrc - cctx->base);
2428 cctx->dictBase = cctx->base;
2429 cctx->base -= delta;
2430 cctx->nextToUpdate = cctx->dictLimit;
2431 if (cctx->dictLimit - cctx->lowLimit < HASH_READ_SIZE) cctx->lowLimit = cctx->dictLimit; /* too small extDict */
Yann Collet417890c2015-12-04 17:16:37 +01002432 }
2433
Yann Collet346efcc2016-08-02 14:26:00 +02002434 /* if input and dictionary overlap : reduce dictionary (area presumed modified by input) */
2435 if ((ip+srcSize > cctx->dictBase + cctx->lowLimit) & (ip < cctx->dictBase + cctx->dictLimit)) {
2436 ptrdiff_t const highInputIdx = (ip + srcSize) - cctx->dictBase;
2437 U32 const lowLimitMax = (highInputIdx > (ptrdiff_t)cctx->dictLimit) ? cctx->dictLimit : (U32)highInputIdx;
2438 cctx->lowLimit = lowLimitMax;
Yann Colletf3eca252015-10-22 15:31:46 +01002439 }
2440
Yann Collet346efcc2016-08-02 14:26:00 +02002441 cctx->nextSrc = ip + srcSize;
Yann Collet89db5e02015-11-13 11:27:46 +01002442
Yann Collet5eb749e2017-01-11 18:21:25 +01002443 if (srcSize) {
2444 size_t const cSize = frame ?
Yann Collet346efcc2016-08-02 14:26:00 +02002445 ZSTD_compress_generic (cctx, dst, dstCapacity, src, srcSize, lastFrameChunk) :
2446 ZSTD_compressBlock_internal (cctx, dst, dstCapacity, src, srcSize);
Yann Colletecd651b2016-01-07 15:35:18 +01002447 if (ZSTD_isError(cSize)) return cSize;
Yann Collet6236eba2016-04-12 15:52:33 +02002448 return cSize + fhSize;
Yann Collet5eb749e2017-01-11 18:21:25 +01002449 } else
2450 return fhSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002451}
2452
Yann Colletbf42c8e2016-01-09 01:08:23 +01002453
Yann Collet5b567392016-07-28 01:17:22 +02002454size_t ZSTD_compressContinue (ZSTD_CCtx* cctx,
Yann Collet7cbe79a2016-03-23 22:31:57 +01002455 void* dst, size_t dstCapacity,
Yann Colletbf42c8e2016-01-09 01:08:23 +01002456 const void* src, size_t srcSize)
2457{
Yann Collet5b567392016-07-28 01:17:22 +02002458 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 0);
2459}
2460
2461
Yann Colletcf05b9d2016-07-18 16:52:10 +02002462size_t ZSTD_getBlockSizeMax(ZSTD_CCtx* cctx)
Yann Colletbf42c8e2016-01-09 01:08:23 +01002463{
Yann Colletcf05b9d2016-07-18 16:52:10 +02002464 return MIN (ZSTD_BLOCKSIZE_ABSOLUTEMAX, 1 << cctx->params.cParams.windowLog);
2465}
2466
2467size_t ZSTD_compressBlock(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize)
2468{
2469 size_t const blockSizeMax = ZSTD_getBlockSizeMax(cctx);
Yann Collet961b6a02016-07-15 11:56:53 +02002470 if (srcSize > blockSizeMax) return ERROR(srcSize_wrong);
Yann Colletc991cc12016-07-28 00:55:43 +02002471 return ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 0, 0);
Yann Colletbf42c8e2016-01-09 01:08:23 +01002472}
2473
2474
Yann Colletb923f652016-01-26 03:14:20 +01002475static size_t ZSTD_loadDictionaryContent(ZSTD_CCtx* zc, const void* src, size_t srcSize)
Yann Collet417890c2015-12-04 17:16:37 +01002476{
2477 const BYTE* const ip = (const BYTE*) src;
2478 const BYTE* const iend = ip + srcSize;
Yann Colletf3eca252015-10-22 15:31:46 +01002479
Yann Collet417890c2015-12-04 17:16:37 +01002480 /* input becomes current prefix */
2481 zc->lowLimit = zc->dictLimit;
2482 zc->dictLimit = (U32)(zc->nextSrc - zc->base);
2483 zc->dictBase = zc->base;
2484 zc->base += ip - zc->nextSrc;
2485 zc->nextToUpdate = zc->dictLimit;
Yann Collet06e76972017-01-25 16:39:03 -08002486 zc->loadedDictEnd = zc->forceWindow ? 0 : (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002487
2488 zc->nextSrc = iend;
Yann Collet731ef162016-07-27 21:05:12 +02002489 if (srcSize <= HASH_READ_SIZE) return 0;
Yann Collet417890c2015-12-04 17:16:37 +01002490
Yann Collet3b719252016-03-30 19:48:05 +02002491 switch(zc->params.cParams.strategy)
Yann Collet417890c2015-12-04 17:16:37 +01002492 {
2493 case ZSTD_fast:
Yann Collet3b719252016-03-30 19:48:05 +02002494 ZSTD_fillHashTable (zc, iend, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002495 break;
2496
Yann Collet45dc3562016-07-12 09:47:31 +02002497 case ZSTD_dfast:
2498 ZSTD_fillDoubleHashTable (zc, iend, zc->params.cParams.searchLength);
2499 break;
2500
Yann Collet417890c2015-12-04 17:16:37 +01002501 case ZSTD_greedy:
2502 case ZSTD_lazy:
2503 case ZSTD_lazy2:
Yann Collet731ef162016-07-27 21:05:12 +02002504 ZSTD_insertAndFindFirstIndex (zc, iend-HASH_READ_SIZE, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002505 break;
2506
2507 case ZSTD_btlazy2:
Yann Colletcefef8c2016-02-15 07:21:54 +01002508 case ZSTD_btopt:
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02002509 case ZSTD_btopt2:
Yann Collet731ef162016-07-27 21:05:12 +02002510 ZSTD_updateTree(zc, iend-HASH_READ_SIZE, iend, 1 << zc->params.cParams.searchLog, zc->params.cParams.searchLength);
Yann Collet417890c2015-12-04 17:16:37 +01002511 break;
2512
2513 default:
2514 return ERROR(GENERIC); /* strategy doesn't exist; impossible */
2515 }
2516
Nick Terrellecf90ca2017-02-13 18:27:34 -08002517 zc->nextToUpdate = (U32)(iend - zc->base);
Yann Collet417890c2015-12-04 17:16:37 +01002518 return 0;
2519}
2520
2521
Nick Terrellf9c9af32016-10-19 17:22:08 -07002522/* Dictionaries that assign zero probability to symbols that show up causes problems
2523 when FSE encoding. Refuse dictionaries that assign zero probability to symbols
2524 that we may encounter during compression.
2525 NOTE: This behavior is not standard and could be improved in the future. */
2526static size_t ZSTD_checkDictNCount(short* normalizedCounter, unsigned dictMaxSymbolValue, unsigned maxSymbolValue) {
2527 U32 s;
2528 if (dictMaxSymbolValue < maxSymbolValue) return ERROR(dictionary_corrupted);
2529 for (s = 0; s <= maxSymbolValue; ++s) {
2530 if (normalizedCounter[s] == 0) return ERROR(dictionary_corrupted);
2531 }
2532 return 0;
2533}
2534
2535
Yann Colletb923f652016-01-26 03:14:20 +01002536/* Dictionary format :
Yann Colletee5b7252016-10-27 14:20:55 -07002537 Magic == ZSTD_DICT_MAGIC (4 bytes)
2538 HUF_writeCTable(256)
2539 FSE_writeNCount(off)
2540 FSE_writeNCount(ml)
2541 FSE_writeNCount(ll)
2542 RepOffsets
2543 Dictionary content
Yann Colletb923f652016-01-26 03:14:20 +01002544*/
Yann Colletfb797352016-03-13 11:08:40 +01002545/*! ZSTD_loadDictEntropyStats() :
Yann Collet736d4192016-06-15 18:48:51 +02002546 @return : size read from dictionary
2547 note : magic number supposed already checked */
2548static size_t ZSTD_loadDictEntropyStats(ZSTD_CCtx* cctx, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002549{
Yann Collet52a06222016-06-15 13:53:34 +02002550 const BYTE* dictPtr = (const BYTE*)dict;
2551 const BYTE* const dictEnd = dictPtr + dictSize;
Nick Terrellf9c9af32016-10-19 17:22:08 -07002552 short offcodeNCount[MaxOff+1];
2553 unsigned offcodeMaxValue = MaxOff;
Yann Collet643d9a22016-12-01 16:24:04 -08002554 BYTE scratchBuffer[1<<MAX(MLFSELog,LLFSELog)];
Yann Colletfb810d62016-01-28 00:18:06 +01002555
Yann Collet736d4192016-06-15 18:48:51 +02002556 { size_t const hufHeaderSize = HUF_readCTable(cctx->hufTable, 255, dict, dictSize);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002557 if (HUF_isError(hufHeaderSize)) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002558 dictPtr += hufHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002559 }
Yann Colletfb810d62016-01-28 00:18:06 +01002560
Nick Terrellf9c9af32016-10-19 17:22:08 -07002561 { unsigned offcodeLog;
Yann Collet52a06222016-06-15 13:53:34 +02002562 size_t const offcodeHeaderSize = FSE_readNCount(offcodeNCount, &offcodeMaxValue, &offcodeLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002563 if (FSE_isError(offcodeHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002564 if (offcodeLog > OffFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002565 /* Defer checking offcodeMaxValue because we need to know the size of the dictionary content */
Yann Collet643d9a22016-12-01 16:24:04 -08002566 CHECK_E (FSE_buildCTable_wksp(cctx->offcodeCTable, offcodeNCount, offcodeMaxValue, offcodeLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002567 dictPtr += offcodeHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002568 }
Yann Colletfb810d62016-01-28 00:18:06 +01002569
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002570 { short matchlengthNCount[MaxML+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002571 unsigned matchlengthMaxValue = MaxML, matchlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002572 size_t const matchlengthHeaderSize = FSE_readNCount(matchlengthNCount, &matchlengthMaxValue, &matchlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002573 if (FSE_isError(matchlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002574 if (matchlengthLog > MLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002575 /* Every match length code must have non-zero probability */
2576 CHECK_F (ZSTD_checkDictNCount(matchlengthNCount, matchlengthMaxValue, MaxML));
Yann Collet643d9a22016-12-01 16:24:04 -08002577 CHECK_E (FSE_buildCTable_wksp(cctx->matchlengthCTable, matchlengthNCount, matchlengthMaxValue, matchlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002578 dictPtr += matchlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002579 }
Yann Colletfb810d62016-01-28 00:18:06 +01002580
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002581 { short litlengthNCount[MaxLL+1];
Nick Terrellbfd943a2016-10-17 16:55:52 -07002582 unsigned litlengthMaxValue = MaxLL, litlengthLog;
Yann Collet52a06222016-06-15 13:53:34 +02002583 size_t const litlengthHeaderSize = FSE_readNCount(litlengthNCount, &litlengthMaxValue, &litlengthLog, dictPtr, dictEnd-dictPtr);
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002584 if (FSE_isError(litlengthHeaderSize)) return ERROR(dictionary_corrupted);
Nick Terrellbfd943a2016-10-17 16:55:52 -07002585 if (litlengthLog > LLFSELog) return ERROR(dictionary_corrupted);
Nick Terrellf9c9af32016-10-19 17:22:08 -07002586 /* Every literal length code must have non-zero probability */
2587 CHECK_F (ZSTD_checkDictNCount(litlengthNCount, litlengthMaxValue, MaxLL));
Yann Collet643d9a22016-12-01 16:24:04 -08002588 CHECK_E(FSE_buildCTable_wksp(cctx->litlengthCTable, litlengthNCount, litlengthMaxValue, litlengthLog, scratchBuffer, sizeof(scratchBuffer)), dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002589 dictPtr += litlengthHeaderSize;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002590 }
Yann Colletfb810d62016-01-28 00:18:06 +01002591
Yann Collet52a06222016-06-15 13:53:34 +02002592 if (dictPtr+12 > dictEnd) return ERROR(dictionary_corrupted);
Nick Terrell8157a4c2016-12-20 10:47:52 -08002593 cctx->rep[0] = MEM_readLE32(dictPtr+0); if (cctx->rep[0] == 0 || cctx->rep[0] >= dictSize) return ERROR(dictionary_corrupted);
2594 cctx->rep[1] = MEM_readLE32(dictPtr+4); if (cctx->rep[1] == 0 || cctx->rep[1] >= dictSize) return ERROR(dictionary_corrupted);
2595 cctx->rep[2] = MEM_readLE32(dictPtr+8); if (cctx->rep[2] == 0 || cctx->rep[2] >= dictSize) return ERROR(dictionary_corrupted);
Yann Collet52a06222016-06-15 13:53:34 +02002596 dictPtr += 12;
2597
Nick Terrellb2c39a22016-10-24 14:11:27 -07002598 { U32 offcodeMax = MaxOff;
2599 if ((size_t)(dictEnd - dictPtr) <= ((U32)-1) - 128 KB) {
2600 U32 const maxOffset = (U32)(dictEnd - dictPtr) + 128 KB; /* The maximum offset that must be supported */
2601 /* Calculate minimum offset code required to represent maxOffset */
2602 offcodeMax = ZSTD_highbit32(maxOffset);
2603 }
Nick Terrellf9c9af32016-10-19 17:22:08 -07002604 /* Every possible supported offset <= dictContentSize + 128 KB must be representable */
2605 CHECK_F (ZSTD_checkDictNCount(offcodeNCount, offcodeMaxValue, MIN(offcodeMax, MaxOff)));
2606 }
2607
Yann Collet736d4192016-06-15 18:48:51 +02002608 cctx->flagStaticTables = 1;
Yann Collet52a06222016-06-15 13:53:34 +02002609 return dictPtr - (const BYTE*)dict;
Yann Colletb923f652016-01-26 03:14:20 +01002610}
2611
Yann Colletd1b26842016-03-15 01:24:33 +01002612/** ZSTD_compress_insertDictionary() :
2613* @return : 0, or an error code */
Yann Collet1c8e1942016-01-26 16:31:22 +01002614static size_t ZSTD_compress_insertDictionary(ZSTD_CCtx* zc, const void* dict, size_t dictSize)
Yann Colletb923f652016-01-26 03:14:20 +01002615{
Yann Colletc46fb922016-05-29 05:01:04 +02002616 if ((dict==NULL) || (dictSize<=8)) return 0;
Yann Colletb923f652016-01-26 03:14:20 +01002617
Yann Collet14312d82017-02-23 23:42:12 -08002618 /* dict as pure content */
2619 if ((MEM_readLE32(dict) != ZSTD_DICT_MAGIC) || (zc->forceRawDict))
2620 return ZSTD_loadDictionaryContent(zc, dict, dictSize);
Yann Colletc46fb922016-05-29 05:01:04 +02002621 zc->dictID = zc->params.fParams.noDictIDFlag ? 0 : MEM_readLE32((const char*)dict+4);
Yann Colletd1b26842016-03-15 01:24:33 +01002622
2623 /* known magic number : dict is parsed for entropy stats and content */
Yann Collet3e21ec52016-09-06 15:36:19 +02002624 { size_t const loadError = ZSTD_loadDictEntropyStats(zc, (const char*)dict+8 /* skip dictHeader */, dictSize-8);
2625 size_t const eSize = loadError + 8;
2626 if (ZSTD_isError(loadError)) return loadError;
Yann Collet21588e32016-03-30 16:50:44 +02002627 return ZSTD_loadDictionaryContent(zc, (const char*)dict+eSize, dictSize-eSize);
Yann Collet7b51a292016-01-26 15:58:49 +01002628 }
Yann Colletecd651b2016-01-07 15:35:18 +01002629}
2630
Yann Collet27caf2a2016-04-01 15:48:48 +02002631/*! ZSTD_compressBegin_internal() :
Yann Colletecd651b2016-01-07 15:35:18 +01002632* @return : 0, or an error code */
Yann Colleta7737f62016-09-06 09:44:59 +02002633static size_t ZSTD_compressBegin_internal(ZSTD_CCtx* cctx,
Yann Collet1c8e1942016-01-26 16:31:22 +01002634 const void* dict, size_t dictSize,
Yann Collet3b719252016-03-30 19:48:05 +02002635 ZSTD_parameters params, U64 pledgedSrcSize)
Yann Colletf3eca252015-10-22 15:31:46 +01002636{
Yann Colleta7737f62016-09-06 09:44:59 +02002637 ZSTD_compResetPolicy_e const crp = dictSize ? ZSTDcrp_fullReset : ZSTDcrp_continue;
Yann Collet3e21ec52016-09-06 15:36:19 +02002638 CHECK_F(ZSTD_resetCCtx_advanced(cctx, params, pledgedSrcSize, crp));
Yann Colleta7737f62016-09-06 09:44:59 +02002639 return ZSTD_compress_insertDictionary(cctx, dict, dictSize);
Yann Collet88fcd292015-11-25 14:42:45 +01002640}
2641
2642
Yann Collet27caf2a2016-04-01 15:48:48 +02002643/*! ZSTD_compressBegin_advanced() :
2644* @return : 0, or an error code */
Yann Collet81e13ef2016-06-07 00:51:51 +02002645size_t ZSTD_compressBegin_advanced(ZSTD_CCtx* cctx,
Yann Collet27caf2a2016-04-01 15:48:48 +02002646 const void* dict, size_t dictSize,
Yann Collet52c04fe2016-07-07 11:53:18 +02002647 ZSTD_parameters params, unsigned long long pledgedSrcSize)
Yann Collet27caf2a2016-04-01 15:48:48 +02002648{
2649 /* compression parameters verification and optimization */
Yann Colletcf409a72016-09-26 16:41:05 +02002650 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet81e13ef2016-06-07 00:51:51 +02002651 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, pledgedSrcSize);
Yann Collet27caf2a2016-04-01 15:48:48 +02002652}
2653
2654
Yann Collet81e13ef2016-06-07 00:51:51 +02002655size_t ZSTD_compressBegin_usingDict(ZSTD_CCtx* cctx, const void* dict, size_t dictSize, int compressionLevel)
Yann Colletb923f652016-01-26 03:14:20 +01002656{
Yann Collet6c6e1752016-06-27 15:28:45 +02002657 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002658 return ZSTD_compressBegin_internal(cctx, dict, dictSize, params, 0);
Yann Collet1c8e1942016-01-26 16:31:22 +01002659}
Yann Collet083fcc82015-10-25 14:06:35 +01002660
inikep19bd48f2016-04-04 12:10:00 +02002661
Yann Colletb05c4822017-01-12 02:01:28 +01002662size_t ZSTD_compressBegin(ZSTD_CCtx* cctx, int compressionLevel)
Yann Collet083fcc82015-10-25 14:06:35 +01002663{
Yann Colletb05c4822017-01-12 02:01:28 +01002664 return ZSTD_compressBegin_usingDict(cctx, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002665}
2666
2667
Yann Collet62470b42016-07-28 15:29:08 +02002668/*! ZSTD_writeEpilogue() :
2669* Ends a frame.
Yann Collet88fcd292015-11-25 14:42:45 +01002670* @return : nb of bytes written into dst (or an error code) */
Yann Collet62470b42016-07-28 15:29:08 +02002671static size_t ZSTD_writeEpilogue(ZSTD_CCtx* cctx, void* dst, size_t dstCapacity)
Yann Collet2acb5d32015-10-29 16:49:43 +01002672{
Yann Colletc991cc12016-07-28 00:55:43 +02002673 BYTE* const ostart = (BYTE*)dst;
2674 BYTE* op = ostart;
Yann Collet6236eba2016-04-12 15:52:33 +02002675 size_t fhSize = 0;
Yann Collet2acb5d32015-10-29 16:49:43 +01002676
Yann Collet87c18b22016-08-26 01:43:47 +02002677 if (cctx->stage == ZSTDcs_created) return ERROR(stage_wrong); /* init missing */
Yann Collet887e7da2016-04-11 20:12:27 +02002678
2679 /* special case : empty frame */
Yann Colletc991cc12016-07-28 00:55:43 +02002680 if (cctx->stage == ZSTDcs_init) {
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002681 fhSize = ZSTD_writeFrameHeader(dst, dstCapacity, cctx->params, 0, 0);
Yann Collet6236eba2016-04-12 15:52:33 +02002682 if (ZSTD_isError(fhSize)) return fhSize;
2683 dstCapacity -= fhSize;
2684 op += fhSize;
Yann Collet731ef162016-07-27 21:05:12 +02002685 cctx->stage = ZSTDcs_ongoing;
Yann Colletecd651b2016-01-07 15:35:18 +01002686 }
2687
Yann Colletc991cc12016-07-28 00:55:43 +02002688 if (cctx->stage != ZSTDcs_ending) {
2689 /* write one last empty block, make it the "last" block */
2690 U32 const cBlockHeader24 = 1 /* last block */ + (((U32)bt_raw)<<1) + 0;
2691 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2692 MEM_writeLE32(op, cBlockHeader24);
2693 op += ZSTD_blockHeaderSize;
2694 dstCapacity -= ZSTD_blockHeaderSize;
2695 }
2696
2697 if (cctx->params.fParams.checksumFlag) {
2698 U32 const checksum = (U32) XXH64_digest(&cctx->xxhState);
2699 if (dstCapacity<4) return ERROR(dstSize_tooSmall);
2700 MEM_writeLE32(op, checksum);
2701 op += 4;
Yann Colletf2a3b6e2016-05-31 18:13:56 +02002702 }
Yann Collet2acb5d32015-10-29 16:49:43 +01002703
Yann Collet731ef162016-07-27 21:05:12 +02002704 cctx->stage = ZSTDcs_created; /* return to "created but no init" status */
Yann Colletc991cc12016-07-28 00:55:43 +02002705 return op-ostart;
Yann Collet2acb5d32015-10-29 16:49:43 +01002706}
2707
Yann Colletfd416f12016-01-30 03:14:15 +01002708
Yann Collet62470b42016-07-28 15:29:08 +02002709size_t ZSTD_compressEnd (ZSTD_CCtx* cctx,
2710 void* dst, size_t dstCapacity,
2711 const void* src, size_t srcSize)
2712{
2713 size_t endResult;
2714 size_t const cSize = ZSTD_compressContinue_internal(cctx, dst, dstCapacity, src, srcSize, 1, 1);
2715 if (ZSTD_isError(cSize)) return cSize;
2716 endResult = ZSTD_writeEpilogue(cctx, (char*)dst + cSize, dstCapacity-cSize);
2717 if (ZSTD_isError(endResult)) return endResult;
2718 return cSize + endResult;
2719}
2720
2721
Yann Collet19c10022016-07-28 01:25:46 +02002722static size_t ZSTD_compress_internal (ZSTD_CCtx* cctx,
Yann Colletd1b26842016-03-15 01:24:33 +01002723 void* dst, size_t dstCapacity,
Yann Collet88fcd292015-11-25 14:42:45 +01002724 const void* src, size_t srcSize,
Yann Collet31683c02015-12-18 01:26:48 +01002725 const void* dict,size_t dictSize,
Yann Collet88fcd292015-11-25 14:42:45 +01002726 ZSTD_parameters params)
Yann Colletf3eca252015-10-22 15:31:46 +01002727{
Yann Collet3e21ec52016-09-06 15:36:19 +02002728 CHECK_F(ZSTD_compressBegin_internal(cctx, dict, dictSize, params, srcSize));
Yann Collet62470b42016-07-28 15:29:08 +02002729 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Colletf3eca252015-10-22 15:31:46 +01002730}
2731
Yann Collet21588e32016-03-30 16:50:44 +02002732size_t ZSTD_compress_advanced (ZSTD_CCtx* ctx,
2733 void* dst, size_t dstCapacity,
2734 const void* src, size_t srcSize,
2735 const void* dict,size_t dictSize,
2736 ZSTD_parameters params)
2737{
Yann Colletcf409a72016-09-26 16:41:05 +02002738 CHECK_F(ZSTD_checkCParams(params.cParams));
Yann Collet21588e32016-03-30 16:50:44 +02002739 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
2740}
2741
Yann Colletd1b26842016-03-15 01:24:33 +01002742size_t ZSTD_compress_usingDict(ZSTD_CCtx* ctx, void* dst, size_t dstCapacity, const void* src, size_t srcSize, const void* dict, size_t dictSize, int compressionLevel)
Yann Collet31683c02015-12-18 01:26:48 +01002743{
Yann Collet407a11f2016-11-03 15:52:01 -07002744 ZSTD_parameters params = ZSTD_getParams(compressionLevel, srcSize, dict ? dictSize : 0);
Yann Collet3b719252016-03-30 19:48:05 +02002745 params.fParams.contentSizeFlag = 1;
Yann Collet21588e32016-03-30 16:50:44 +02002746 return ZSTD_compress_internal(ctx, dst, dstCapacity, src, srcSize, dict, dictSize, params);
Yann Collet31683c02015-12-18 01:26:48 +01002747}
2748
Yann Colletd1b26842016-03-15 01:24:33 +01002749size_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 +01002750{
Yann Collet21588e32016-03-30 16:50:44 +02002751 return ZSTD_compress_usingDict(ctx, dst, dstCapacity, src, srcSize, NULL, 0, compressionLevel);
Yann Collet083fcc82015-10-25 14:06:35 +01002752}
2753
Yann Colletd1b26842016-03-15 01:24:33 +01002754size_t ZSTD_compress(void* dst, size_t dstCapacity, const void* src, size_t srcSize, int compressionLevel)
Yann Colletf3eca252015-10-22 15:31:46 +01002755{
Yann Collet44fe9912015-10-29 22:02:40 +01002756 size_t result;
Yann Collet5be2dd22015-11-11 13:43:58 +01002757 ZSTD_CCtx ctxBody;
Yann Collet712def92015-10-29 18:41:45 +01002758 memset(&ctxBody, 0, sizeof(ctxBody));
inikep28669512016-06-02 13:04:18 +02002759 memcpy(&ctxBody.customMem, &defaultCustomMem, sizeof(ZSTD_customMem));
Yann Colletd1b26842016-03-15 01:24:33 +01002760 result = ZSTD_compressCCtx(&ctxBody, dst, dstCapacity, src, srcSize, compressionLevel);
Yann Collet23b6e052016-08-28 21:05:43 -07002761 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 +01002762 return result;
Yann Colletf3eca252015-10-22 15:31:46 +01002763}
Yann Colletfdcad6d2015-12-17 23:50:15 +01002764
Yann Colletfd416f12016-01-30 03:14:15 +01002765
Yann Collet81e13ef2016-06-07 00:51:51 +02002766/* ===== Dictionary API ===== */
2767
2768struct ZSTD_CDict_s {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002769 void* dictBuffer;
2770 const void* dictContent;
Yann Collet81e13ef2016-06-07 00:51:51 +02002771 size_t dictContentSize;
2772 ZSTD_CCtx* refContext;
David Lamda9d3b72016-08-29 09:03:12 -07002773}; /* typedef'd tp ZSTD_CDict within "zstd.h" */
Yann Collet81e13ef2016-06-07 00:51:51 +02002774
Yann Colletd7c65892016-09-15 02:50:27 +02002775size_t ZSTD_sizeof_CDict(const ZSTD_CDict* cdict)
2776{
2777 if (cdict==NULL) return 0; /* support sizeof on NULL */
Yann Colletaca113f2016-12-23 22:25:03 +01002778 return ZSTD_sizeof_CCtx(cdict->refContext) + (cdict->dictBuffer ? cdict->dictContentSize : 0) + sizeof(*cdict);
Yann Colletd7c65892016-09-15 02:50:27 +02002779}
2780
Yann Collet1f57c2e2016-12-21 16:20:11 +01002781ZSTD_CDict* ZSTD_createCDict_advanced(const void* dictBuffer, size_t dictSize, unsigned byReference,
2782 ZSTD_parameters params, ZSTD_customMem customMem)
Yann Collet81e13ef2016-06-07 00:51:51 +02002783{
Yann Collet23b6e052016-08-28 21:05:43 -07002784 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2785 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet81e13ef2016-06-07 00:51:51 +02002786
Yann Collet23b6e052016-08-28 21:05:43 -07002787 { ZSTD_CDict* const cdict = (ZSTD_CDict*) ZSTD_malloc(sizeof(ZSTD_CDict), customMem);
Yann Collet81e13ef2016-06-07 00:51:51 +02002788 ZSTD_CCtx* const cctx = ZSTD_createCCtx_advanced(customMem);
2789
Yann Collet1f57c2e2016-12-21 16:20:11 +01002790 if (!cdict || !cctx) {
Yann Collet23b6e052016-08-28 21:05:43 -07002791 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01002792 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02002793 return NULL;
2794 }
2795
Yann Collet1f57c2e2016-12-21 16:20:11 +01002796 if ((byReference) || (!dictBuffer) || (!dictSize)) {
2797 cdict->dictBuffer = NULL;
2798 cdict->dictContent = dictBuffer;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002799 } else {
2800 void* const internalBuffer = ZSTD_malloc(dictSize, customMem);
Yann Collet4e5eea62016-12-21 16:44:35 +01002801 if (!internalBuffer) { ZSTD_free(cctx, customMem); ZSTD_free(cdict, customMem); return NULL; }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002802 memcpy(internalBuffer, dictBuffer, dictSize);
2803 cdict->dictBuffer = internalBuffer;
2804 cdict->dictContent = internalBuffer;
Nick Terrell3b9cdf92016-10-12 20:54:42 -07002805 }
Yann Collet1f57c2e2016-12-21 16:20:11 +01002806
2807 { size_t const errorCode = ZSTD_compressBegin_advanced(cctx, cdict->dictContent, dictSize, params, 0);
Yann Collet81e13ef2016-06-07 00:51:51 +02002808 if (ZSTD_isError(errorCode)) {
Yann Collet1f57c2e2016-12-21 16:20:11 +01002809 ZSTD_free(cdict->dictBuffer, customMem);
Yann Collet1f57c2e2016-12-21 16:20:11 +01002810 ZSTD_free(cdict, customMem);
Przemyslaw Skibinskid8114e52017-02-21 18:59:56 +01002811 ZSTD_freeCCtx(cctx);
Yann Collet81e13ef2016-06-07 00:51:51 +02002812 return NULL;
2813 } }
2814
Yann Collet81e13ef2016-06-07 00:51:51 +02002815 cdict->refContext = cctx;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002816 cdict->dictContentSize = dictSize;
Yann Collet81e13ef2016-06-07 00:51:51 +02002817 return cdict;
2818 }
2819}
2820
2821ZSTD_CDict* ZSTD_createCDict(const void* dict, size_t dictSize, int compressionLevel)
2822{
2823 ZSTD_customMem const allocator = { NULL, NULL, NULL };
Yann Collet07639052016-08-03 01:57:57 +02002824 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002825 params.fParams.contentSizeFlag = 1;
Yann Collet1f57c2e2016-12-21 16:20:11 +01002826 return ZSTD_createCDict_advanced(dict, dictSize, 0, params, allocator);
2827}
2828
2829ZSTD_CDict* ZSTD_createCDict_byReference(const void* dict, size_t dictSize, int compressionLevel)
2830{
2831 ZSTD_customMem const allocator = { NULL, NULL, NULL };
2832 ZSTD_parameters params = ZSTD_getParams(compressionLevel, 0, dictSize);
2833 params.fParams.contentSizeFlag = 1;
2834 return ZSTD_createCDict_advanced(dict, dictSize, 1, params, allocator);
Yann Collet81e13ef2016-06-07 00:51:51 +02002835}
2836
2837size_t ZSTD_freeCDict(ZSTD_CDict* cdict)
2838{
Yann Collet23b6e052016-08-28 21:05:43 -07002839 if (cdict==NULL) return 0; /* support free on NULL */
Yann Collet993060e2016-09-21 16:46:08 +02002840 { ZSTD_customMem const cMem = cdict->refContext->customMem;
Yann Collet23b6e052016-08-28 21:05:43 -07002841 ZSTD_freeCCtx(cdict->refContext);
Yann Collet4e5eea62016-12-21 16:44:35 +01002842 ZSTD_free(cdict->dictBuffer, cMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002843 ZSTD_free(cdict, cMem);
2844 return 0;
2845 }
Yann Collet81e13ef2016-06-07 00:51:51 +02002846}
2847
Yann Collet95162342016-10-25 16:19:52 -07002848static ZSTD_parameters ZSTD_getParamsFromCDict(const ZSTD_CDict* cdict) {
2849 return ZSTD_getParamsFromCCtx(cdict->refContext);
2850}
2851
Yann Colletc5933482017-01-22 16:40:06 -08002852size_t ZSTD_compressBegin_usingCDict(ZSTD_CCtx* cctx, const ZSTD_CDict* cdict, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02002853{
Yann Collet97b378a2016-09-21 17:20:19 +02002854 if (cdict->dictContentSize) CHECK_F(ZSTD_copyCCtx(cctx, cdict->refContext, pledgedSrcSize))
Sean Purcell2db72492017-02-09 10:50:43 -08002855 else {
2856 ZSTD_parameters params = cdict->refContext->params;
2857 params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
2858 CHECK_F(ZSTD_compressBegin_advanced(cctx, NULL, 0, params, pledgedSrcSize));
2859 }
Yann Collet4cb21292016-09-15 14:54:07 +02002860 return 0;
2861}
2862
Yann Collet07639052016-08-03 01:57:57 +02002863/*! ZSTD_compress_usingCDict() :
2864* Compression using a digested Dictionary.
2865* Faster startup than ZSTD_compress_usingDict(), recommended when same dictionary is used multiple times.
2866* Note that compression level is decided during dictionary creation */
Yann Collet4cb21292016-09-15 14:54:07 +02002867size_t ZSTD_compress_usingCDict(ZSTD_CCtx* cctx,
2868 void* dst, size_t dstCapacity,
2869 const void* src, size_t srcSize,
2870 const ZSTD_CDict* cdict)
Yann Collet81e13ef2016-06-07 00:51:51 +02002871{
Yann Collet4cb21292016-09-15 14:54:07 +02002872 CHECK_F(ZSTD_compressBegin_usingCDict(cctx, cdict, srcSize));
Yann Collet07639052016-08-03 01:57:57 +02002873
2874 if (cdict->refContext->params.fParams.contentSizeFlag==1) {
2875 cctx->params.fParams.contentSizeFlag = 1;
2876 cctx->frameContentSize = srcSize;
2877 }
2878
2879 return ZSTD_compressEnd(cctx, dst, dstCapacity, src, srcSize);
Yann Collet81e13ef2016-06-07 00:51:51 +02002880}
2881
2882
2883
Yann Collet104e5b02016-08-12 13:04:27 +02002884/* ******************************************************************
2885* Streaming
2886********************************************************************/
Yann Collet5a0c8e22016-08-12 01:20:36 +02002887
2888typedef enum { zcss_init, zcss_load, zcss_flush, zcss_final } ZSTD_cStreamStage;
2889
2890struct ZSTD_CStream_s {
Yann Colletfa0c0972016-09-15 14:11:01 +02002891 ZSTD_CCtx* cctx;
Yann Collet95162342016-10-25 16:19:52 -07002892 ZSTD_CDict* cdictLocal;
2893 const ZSTD_CDict* cdict;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002894 char* inBuff;
2895 size_t inBuffSize;
2896 size_t inToCompress;
2897 size_t inBuffPos;
2898 size_t inBuffTarget;
2899 size_t blockSize;
2900 char* outBuff;
2901 size_t outBuffSize;
2902 size_t outBuffContentSize;
2903 size_t outBuffFlushedSize;
2904 ZSTD_cStreamStage stage;
2905 U32 checksum;
2906 U32 frameEnded;
Yann Collete795c8a2016-12-13 16:39:36 +01002907 U64 pledgedSrcSize;
2908 U64 inputProcessed;
Yann Colletee5b7252016-10-27 14:20:55 -07002909 ZSTD_parameters params;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002910 ZSTD_customMem customMem;
2911}; /* typedef'd to ZSTD_CStream within "zstd.h" */
2912
2913ZSTD_CStream* ZSTD_createCStream(void)
2914{
2915 return ZSTD_createCStream_advanced(defaultCustomMem);
2916}
2917
2918ZSTD_CStream* ZSTD_createCStream_advanced(ZSTD_customMem customMem)
2919{
2920 ZSTD_CStream* zcs;
2921
Yann Collet23b6e052016-08-28 21:05:43 -07002922 if (!customMem.customAlloc && !customMem.customFree) customMem = defaultCustomMem;
2923 if (!customMem.customAlloc || !customMem.customFree) return NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02002924
Yann Collet23b6e052016-08-28 21:05:43 -07002925 zcs = (ZSTD_CStream*)ZSTD_malloc(sizeof(ZSTD_CStream), customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002926 if (zcs==NULL) return NULL;
2927 memset(zcs, 0, sizeof(ZSTD_CStream));
2928 memcpy(&zcs->customMem, &customMem, sizeof(ZSTD_customMem));
Yann Colletfa0c0972016-09-15 14:11:01 +02002929 zcs->cctx = ZSTD_createCCtx_advanced(customMem);
2930 if (zcs->cctx == NULL) { ZSTD_freeCStream(zcs); return NULL; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002931 return zcs;
2932}
2933
2934size_t ZSTD_freeCStream(ZSTD_CStream* zcs)
2935{
2936 if (zcs==NULL) return 0; /* support free on NULL */
Yann Collet23b6e052016-08-28 21:05:43 -07002937 { ZSTD_customMem const cMem = zcs->customMem;
Yann Colletfa0c0972016-09-15 14:11:01 +02002938 ZSTD_freeCCtx(zcs->cctx);
Yann Collet95162342016-10-25 16:19:52 -07002939 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet23b6e052016-08-28 21:05:43 -07002940 ZSTD_free(zcs->inBuff, cMem);
2941 ZSTD_free(zcs->outBuff, cMem);
2942 ZSTD_free(zcs, cMem);
2943 return 0;
2944 }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002945}
2946
2947
Yann Collet104e5b02016-08-12 13:04:27 +02002948/*====== Initialization ======*/
2949
2950size_t ZSTD_CStreamInSize(void) { return ZSTD_BLOCKSIZE_ABSOLUTEMAX; }
2951size_t ZSTD_CStreamOutSize(void) { return ZSTD_compressBound(ZSTD_BLOCKSIZE_ABSOLUTEMAX) + ZSTD_blockHeaderSize + 4 /* 32-bits hash */ ; }
Yann Collet5a0c8e22016-08-12 01:20:36 +02002952
Sean Purcell2db72492017-02-09 10:50:43 -08002953static size_t ZSTD_resetCStream_internal(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
Yann Collet4cb21292016-09-15 14:54:07 +02002954{
Yann Colletd564faa2016-12-18 21:39:15 +01002955 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 -07002956
2957 if (zcs->cdict) CHECK_F(ZSTD_compressBegin_usingCDict(zcs->cctx, zcs->cdict, pledgedSrcSize))
2958 else CHECK_F(ZSTD_compressBegin_advanced(zcs->cctx, NULL, 0, zcs->params, pledgedSrcSize));
Yann Collet4cb21292016-09-15 14:54:07 +02002959
2960 zcs->inToCompress = 0;
2961 zcs->inBuffPos = 0;
2962 zcs->inBuffTarget = zcs->blockSize;
2963 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
2964 zcs->stage = zcss_load;
2965 zcs->frameEnded = 0;
Yann Collete795c8a2016-12-13 16:39:36 +01002966 zcs->pledgedSrcSize = pledgedSrcSize;
2967 zcs->inputProcessed = 0;
Yann Collet4cb21292016-09-15 14:54:07 +02002968 return 0; /* ready to go */
2969}
2970
Sean Purcell2db72492017-02-09 10:50:43 -08002971size_t ZSTD_resetCStream(ZSTD_CStream* zcs, unsigned long long pledgedSrcSize)
2972{
2973
2974 zcs->params.fParams.contentSizeFlag = (pledgedSrcSize > 0);
2975
2976 return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
2977}
2978
Yann Collet5a0c8e22016-08-12 01:20:36 +02002979size_t ZSTD_initCStream_advanced(ZSTD_CStream* zcs,
2980 const void* dict, size_t dictSize,
2981 ZSTD_parameters params, unsigned long long pledgedSrcSize)
2982{
2983 /* allocate buffers */
2984 { size_t const neededInBuffSize = (size_t)1 << params.cParams.windowLog;
2985 if (zcs->inBuffSize < neededInBuffSize) {
2986 zcs->inBuffSize = neededInBuffSize;
Yann Colletcf409a72016-09-26 16:41:05 +02002987 ZSTD_free(zcs->inBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002988 zcs->inBuff = (char*) ZSTD_malloc(neededInBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002989 if (zcs->inBuff == NULL) return ERROR(memory_allocation);
2990 }
2991 zcs->blockSize = MIN(ZSTD_BLOCKSIZE_ABSOLUTEMAX, neededInBuffSize);
2992 }
2993 if (zcs->outBuffSize < ZSTD_compressBound(zcs->blockSize)+1) {
2994 zcs->outBuffSize = ZSTD_compressBound(zcs->blockSize)+1;
Yann Colletcf409a72016-09-26 16:41:05 +02002995 ZSTD_free(zcs->outBuff, zcs->customMem);
Yann Collet23b6e052016-08-28 21:05:43 -07002996 zcs->outBuff = (char*) ZSTD_malloc(zcs->outBuffSize, zcs->customMem);
Yann Collet5a0c8e22016-08-12 01:20:36 +02002997 if (zcs->outBuff == NULL) return ERROR(memory_allocation);
2998 }
2999
Sean Purcell57d423c2017-01-17 11:04:08 -08003000 if (dict && dictSize >= 8) {
Yann Colletee5b7252016-10-27 14:20:55 -07003001 ZSTD_freeCDict(zcs->cdictLocal);
Yann Collet1f57c2e2016-12-21 16:20:11 +01003002 zcs->cdictLocal = ZSTD_createCDict_advanced(dict, dictSize, 0, params, zcs->customMem);
Yann Colletee5b7252016-10-27 14:20:55 -07003003 if (zcs->cdictLocal == NULL) return ERROR(memory_allocation);
3004 zcs->cdict = zcs->cdictLocal;
3005 } else zcs->cdict = NULL;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003006
Yann Collet5a0c8e22016-08-12 01:20:36 +02003007 zcs->checksum = params.fParams.checksumFlag > 0;
Yann Colletee5b7252016-10-27 14:20:55 -07003008 zcs->params = params;
Yann Collet4cb21292016-09-15 14:54:07 +02003009
Sean Purcell2db72492017-02-09 10:50:43 -08003010 return ZSTD_resetCStream_internal(zcs, pledgedSrcSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003011}
3012
Yann Collet95162342016-10-25 16:19:52 -07003013/* note : cdict must outlive compression session */
3014size_t ZSTD_initCStream_usingCDict(ZSTD_CStream* zcs, const ZSTD_CDict* cdict)
3015{
3016 ZSTD_parameters const params = ZSTD_getParamsFromCDict(cdict);
3017 size_t const initError = ZSTD_initCStream_advanced(zcs, NULL, 0, params, 0);
3018 zcs->cdict = cdict;
Gregory Szorc7d6f4782017-01-14 17:44:54 -08003019 zcs->cctx->dictID = params.fParams.noDictIDFlag ? 0 : cdict->refContext->dictID;
Yann Collet95162342016-10-25 16:19:52 -07003020 return initError;
3021}
3022
Yann Collet5a0c8e22016-08-12 01:20:36 +02003023size_t ZSTD_initCStream_usingDict(ZSTD_CStream* zcs, const void* dict, size_t dictSize, int compressionLevel)
3024{
3025 ZSTD_parameters const params = ZSTD_getParams(compressionLevel, 0, dictSize);
3026 return ZSTD_initCStream_advanced(zcs, dict, dictSize, params, 0);
3027}
3028
Yann Collete795c8a2016-12-13 16:39:36 +01003029size_t ZSTD_initCStream_srcSize(ZSTD_CStream* zcs, int compressionLevel, unsigned long long pledgedSrcSize)
3030{
Yann Colletd564faa2016-12-18 21:39:15 +01003031 ZSTD_parameters params = ZSTD_getParams(compressionLevel, pledgedSrcSize, 0);
3032 if (pledgedSrcSize) params.fParams.contentSizeFlag = 1;
Yann Collete795c8a2016-12-13 16:39:36 +01003033 return ZSTD_initCStream_advanced(zcs, NULL, 0, params, pledgedSrcSize);
3034}
3035
Yann Collet5a0c8e22016-08-12 01:20:36 +02003036size_t ZSTD_initCStream(ZSTD_CStream* zcs, int compressionLevel)
3037{
3038 return ZSTD_initCStream_usingDict(zcs, NULL, 0, compressionLevel);
3039}
3040
Yann Collet70e3b312016-08-23 01:18:06 +02003041size_t ZSTD_sizeof_CStream(const ZSTD_CStream* zcs)
Yann Colletcb327632016-08-23 00:30:31 +02003042{
Yann Colletd7c65892016-09-15 02:50:27 +02003043 if (zcs==NULL) return 0; /* support sizeof on NULL */
Yann Collet335ad5d2016-10-25 17:47:02 -07003044 return sizeof(zcs) + ZSTD_sizeof_CCtx(zcs->cctx) + ZSTD_sizeof_CDict(zcs->cdictLocal) + zcs->outBuffSize + zcs->inBuffSize;
Yann Colletcb327632016-08-23 00:30:31 +02003045}
Yann Collet5a0c8e22016-08-12 01:20:36 +02003046
Yann Collet104e5b02016-08-12 13:04:27 +02003047/*====== Compression ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003048
3049typedef enum { zsf_gather, zsf_flush, zsf_end } ZSTD_flush_e;
3050
3051MEM_STATIC size_t ZSTD_limitCopy(void* dst, size_t dstCapacity, const void* src, size_t srcSize)
3052{
3053 size_t const length = MIN(dstCapacity, srcSize);
3054 memcpy(dst, src, length);
3055 return length;
3056}
3057
3058static size_t ZSTD_compressStream_generic(ZSTD_CStream* zcs,
3059 void* dst, size_t* dstCapacityPtr,
3060 const void* src, size_t* srcSizePtr,
3061 ZSTD_flush_e const flush)
3062{
3063 U32 someMoreWork = 1;
3064 const char* const istart = (const char*)src;
3065 const char* const iend = istart + *srcSizePtr;
3066 const char* ip = istart;
3067 char* const ostart = (char*)dst;
3068 char* const oend = ostart + *dstCapacityPtr;
3069 char* op = ostart;
3070
3071 while (someMoreWork) {
3072 switch(zcs->stage)
3073 {
3074 case zcss_init: return ERROR(init_missing); /* call ZBUFF_compressInit() first ! */
3075
3076 case zcss_load:
3077 /* complete inBuffer */
3078 { size_t const toLoad = zcs->inBuffTarget - zcs->inBuffPos;
3079 size_t const loaded = ZSTD_limitCopy(zcs->inBuff + zcs->inBuffPos, toLoad, ip, iend-ip);
3080 zcs->inBuffPos += loaded;
3081 ip += loaded;
3082 if ( (zcs->inBuffPos==zcs->inToCompress) || (!flush && (toLoad != loaded)) ) {
3083 someMoreWork = 0; break; /* not enough input to get a full block : stop there, wait for more */
3084 } }
3085 /* compress current block (note : this stage cannot be stopped in the middle) */
3086 { void* cDst;
3087 size_t cSize;
3088 size_t const iSize = zcs->inBuffPos - zcs->inToCompress;
3089 size_t oSize = oend-op;
3090 if (oSize >= ZSTD_compressBound(iSize))
3091 cDst = op; /* compress directly into output buffer (avoid flush stage) */
3092 else
3093 cDst = zcs->outBuff, oSize = zcs->outBuffSize;
3094 cSize = (flush == zsf_end) ?
Yann Colletfa0c0972016-09-15 14:11:01 +02003095 ZSTD_compressEnd(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize) :
3096 ZSTD_compressContinue(zcs->cctx, cDst, oSize, zcs->inBuff + zcs->inToCompress, iSize);
Yann Collet5a0c8e22016-08-12 01:20:36 +02003097 if (ZSTD_isError(cSize)) return cSize;
3098 if (flush == zsf_end) zcs->frameEnded = 1;
3099 /* prepare next block */
3100 zcs->inBuffTarget = zcs->inBuffPos + zcs->blockSize;
3101 if (zcs->inBuffTarget > zcs->inBuffSize)
3102 zcs->inBuffPos = 0, zcs->inBuffTarget = zcs->blockSize; /* note : inBuffSize >= blockSize */
3103 zcs->inToCompress = zcs->inBuffPos;
3104 if (cDst == op) { op += cSize; break; } /* no need to flush */
3105 zcs->outBuffContentSize = cSize;
3106 zcs->outBuffFlushedSize = 0;
3107 zcs->stage = zcss_flush; /* pass-through to flush stage */
3108 }
3109
3110 case zcss_flush:
3111 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3112 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3113 op += flushed;
3114 zcs->outBuffFlushedSize += flushed;
3115 if (toFlush!=flushed) { someMoreWork = 0; break; } /* dst too small to store flushed data : stop there */
3116 zcs->outBuffContentSize = zcs->outBuffFlushedSize = 0;
3117 zcs->stage = zcss_load;
3118 break;
3119 }
3120
3121 case zcss_final:
3122 someMoreWork = 0; /* do nothing */
3123 break;
3124
3125 default:
3126 return ERROR(GENERIC); /* impossible */
3127 }
3128 }
3129
3130 *srcSizePtr = ip - istart;
3131 *dstCapacityPtr = op - ostart;
Yann Collete795c8a2016-12-13 16:39:36 +01003132 zcs->inputProcessed += *srcSizePtr;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003133 if (zcs->frameEnded) return 0;
3134 { size_t hintInSize = zcs->inBuffTarget - zcs->inBuffPos;
3135 if (hintInSize==0) hintInSize = zcs->blockSize;
3136 return hintInSize;
3137 }
3138}
3139
Yann Collet53e17fb2016-08-17 01:39:22 +02003140size_t ZSTD_compressStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output, ZSTD_inBuffer* input)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003141{
Yann Collet53e17fb2016-08-17 01:39:22 +02003142 size_t sizeRead = input->size - input->pos;
3143 size_t sizeWritten = output->size - output->pos;
3144 size_t const result = ZSTD_compressStream_generic(zcs,
3145 (char*)(output->dst) + output->pos, &sizeWritten,
3146 (const char*)(input->src) + input->pos, &sizeRead, zsf_gather);
3147 input->pos += sizeRead;
3148 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003149 return result;
3150}
3151
3152
Yann Collet104e5b02016-08-12 13:04:27 +02003153/*====== Finalize ======*/
Yann Collet5a0c8e22016-08-12 01:20:36 +02003154
3155/*! ZSTD_flushStream() :
3156* @return : amount of data remaining to flush */
Yann Collet53e17fb2016-08-17 01:39:22 +02003157size_t ZSTD_flushStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003158{
3159 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003160 size_t sizeWritten = output->size - output->pos;
Yann Colletc4119022016-08-17 01:50:54 +02003161 size_t const result = ZSTD_compressStream_generic(zcs,
Yann Collet95d07d72016-09-06 16:38:51 +02003162 (char*)(output->dst) + output->pos, &sizeWritten,
3163 &srcSize, &srcSize, /* use a valid src address instead of NULL */
Yann Colletc4119022016-08-17 01:50:54 +02003164 zsf_flush);
Yann Collet53e17fb2016-08-17 01:39:22 +02003165 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003166 if (ZSTD_isError(result)) return result;
3167 return zcs->outBuffContentSize - zcs->outBuffFlushedSize; /* remaining to flush */
3168}
3169
3170
Yann Collet53e17fb2016-08-17 01:39:22 +02003171size_t ZSTD_endStream(ZSTD_CStream* zcs, ZSTD_outBuffer* output)
Yann Collet5a0c8e22016-08-12 01:20:36 +02003172{
Yann Collet53e17fb2016-08-17 01:39:22 +02003173 BYTE* const ostart = (BYTE*)(output->dst) + output->pos;
3174 BYTE* const oend = (BYTE*)(output->dst) + output->size;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003175 BYTE* op = ostart;
3176
Yann Collete795c8a2016-12-13 16:39:36 +01003177 if ((zcs->pledgedSrcSize) && (zcs->inputProcessed != zcs->pledgedSrcSize))
3178 return ERROR(srcSize_wrong); /* pledgedSrcSize not respected */
3179
Yann Collet5a0c8e22016-08-12 01:20:36 +02003180 if (zcs->stage != zcss_final) {
3181 /* flush whatever remains */
3182 size_t srcSize = 0;
Yann Collet53e17fb2016-08-17 01:39:22 +02003183 size_t sizeWritten = output->size - output->pos;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003184 size_t const notEnded = ZSTD_compressStream_generic(zcs, ostart, &sizeWritten, &srcSize, &srcSize, zsf_end); /* use a valid src address instead of NULL */
3185 size_t const remainingToFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3186 op += sizeWritten;
3187 if (remainingToFlush) {
Yann Collet53e17fb2016-08-17 01:39:22 +02003188 output->pos += sizeWritten;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003189 return remainingToFlush + ZSTD_BLOCKHEADERSIZE /* final empty block */ + (zcs->checksum * 4);
3190 }
3191 /* create epilogue */
3192 zcs->stage = zcss_final;
3193 zcs->outBuffContentSize = !notEnded ? 0 :
Yann Colletfa0c0972016-09-15 14:11:01 +02003194 ZSTD_compressEnd(zcs->cctx, zcs->outBuff, zcs->outBuffSize, NULL, 0); /* write epilogue, including final empty block, into outBuff */
Yann Collet5a0c8e22016-08-12 01:20:36 +02003195 }
3196
3197 /* flush epilogue */
3198 { size_t const toFlush = zcs->outBuffContentSize - zcs->outBuffFlushedSize;
3199 size_t const flushed = ZSTD_limitCopy(op, oend-op, zcs->outBuff + zcs->outBuffFlushedSize, toFlush);
3200 op += flushed;
3201 zcs->outBuffFlushedSize += flushed;
Yann Collet53e17fb2016-08-17 01:39:22 +02003202 output->pos += op-ostart;
Yann Collet5a0c8e22016-08-12 01:20:36 +02003203 if (toFlush==flushed) zcs->stage = zcss_init; /* end reached */
3204 return toFlush - flushed;
3205 }
3206}
3207
3208
3209
Yann Collet70e8c382016-02-10 13:37:52 +01003210/*-===== Pre-defined compression levels =====-*/
Yann Colletfd416f12016-01-30 03:14:15 +01003211
Yann Collet236d94f2016-05-18 12:06:33 +02003212#define ZSTD_DEFAULT_CLEVEL 1
inikep2c5eeea2016-04-15 13:44:46 +02003213#define ZSTD_MAX_CLEVEL 22
Yann Collet41105342016-07-27 15:09:11 +02003214int ZSTD_maxCLevel(void) { return ZSTD_MAX_CLEVEL; }
Yann Collet7d968c72016-02-03 02:11:32 +01003215
Yann Collet3b719252016-03-30 19:48:05 +02003216static const ZSTD_compressionParameters ZSTD_defaultCParameters[4][ZSTD_MAX_CLEVEL+1] = {
Yann Colletfd416f12016-01-30 03:14:15 +01003217{ /* "default" */
Yann Collet793c6492016-04-09 20:32:00 +02003218 /* W, C, H, S, L, TL, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003219 { 18, 12, 12, 1, 7, 16, ZSTD_fast }, /* level 0 - never used */
Yann Collet3c242e72016-07-13 14:56:24 +02003220 { 19, 13, 14, 1, 7, 16, ZSTD_fast }, /* level 1 */
3221 { 19, 15, 16, 1, 6, 16, ZSTD_fast }, /* level 2 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003222 { 20, 16, 17, 1, 5, 16, ZSTD_dfast }, /* level 3.*/
3223 { 20, 18, 18, 1, 5, 16, ZSTD_dfast }, /* level 4.*/
Yann Collet3c242e72016-07-13 14:56:24 +02003224 { 20, 15, 18, 3, 5, 16, ZSTD_greedy }, /* level 5 */
3225 { 21, 16, 19, 2, 5, 16, ZSTD_lazy }, /* level 6 */
3226 { 21, 17, 20, 3, 5, 16, ZSTD_lazy }, /* level 7 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003227 { 21, 18, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 8 */
Yann Collet3c242e72016-07-13 14:56:24 +02003228 { 21, 20, 20, 3, 5, 16, ZSTD_lazy2 }, /* level 9 */
3229 { 21, 19, 21, 4, 5, 16, ZSTD_lazy2 }, /* level 10 */
3230 { 22, 20, 22, 4, 5, 16, ZSTD_lazy2 }, /* level 11 */
3231 { 22, 20, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 12 */
3232 { 22, 21, 22, 5, 5, 16, ZSTD_lazy2 }, /* level 13 */
3233 { 22, 21, 22, 6, 5, 16, ZSTD_lazy2 }, /* level 14 */
3234 { 22, 21, 21, 5, 5, 16, ZSTD_btlazy2 }, /* level 15 */
3235 { 23, 22, 22, 5, 5, 16, ZSTD_btlazy2 }, /* level 16 */
Yann Collete19a9ef2016-08-26 20:02:49 +02003236 { 23, 21, 22, 4, 5, 24, ZSTD_btopt }, /* level 17 */
3237 { 23, 23, 22, 6, 5, 32, ZSTD_btopt }, /* level 18 */
3238 { 23, 23, 22, 6, 3, 48, ZSTD_btopt }, /* level 19 */
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003239 { 25, 25, 23, 7, 3, 64, ZSTD_btopt2 }, /* level 20 */
3240 { 26, 26, 23, 7, 3,256, ZSTD_btopt2 }, /* level 21 */
3241 { 27, 27, 25, 9, 3,512, ZSTD_btopt2 }, /* level 22 */
Yann Colletfd416f12016-01-30 03:14:15 +01003242},
3243{ /* for srcSize <= 256 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003244 /* W, C, H, S, L, T, strat */
Yann Collete19a9ef2016-08-26 20:02:49 +02003245 { 0, 0, 0, 0, 0, 0, ZSTD_fast }, /* level 0 - not used */
Yann Colleta2cdffe2016-08-24 19:42:15 +02003246 { 18, 13, 14, 1, 6, 8, ZSTD_fast }, /* level 1 */
Yann Collet24b68a52016-08-24 14:22:26 +02003247 { 18, 14, 13, 1, 5, 8, ZSTD_dfast }, /* level 2 */
3248 { 18, 16, 15, 1, 5, 8, ZSTD_dfast }, /* level 3 */
3249 { 18, 15, 17, 1, 5, 8, ZSTD_greedy }, /* level 4.*/
3250 { 18, 16, 17, 4, 5, 8, ZSTD_greedy }, /* level 5.*/
3251 { 18, 16, 17, 3, 5, 8, ZSTD_lazy }, /* level 6.*/
3252 { 18, 17, 17, 4, 4, 8, ZSTD_lazy }, /* level 7 */
3253 { 18, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3254 { 18, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3255 { 18, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3256 { 18, 18, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 11.*/
3257 { 18, 18, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 12.*/
3258 { 18, 19, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13 */
Yann Collet78267d12016-04-08 12:36:19 +02003259 { 18, 18, 18, 4, 4, 16, ZSTD_btopt }, /* level 14.*/
Yann Collet24b68a52016-08-24 14:22:26 +02003260 { 18, 18, 18, 4, 3, 16, ZSTD_btopt }, /* level 15.*/
3261 { 18, 19, 18, 6, 3, 32, ZSTD_btopt }, /* level 16.*/
3262 { 18, 19, 18, 8, 3, 64, ZSTD_btopt }, /* level 17.*/
Yann Collet78267d12016-04-08 12:36:19 +02003263 { 18, 19, 18, 9, 3,128, ZSTD_btopt }, /* level 18.*/
3264 { 18, 19, 18, 10, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003265 { 18, 19, 18, 11, 3,512, ZSTD_btopt2 }, /* level 20.*/
3266 { 18, 19, 18, 12, 3,512, ZSTD_btopt2 }, /* level 21.*/
3267 { 18, 19, 18, 13, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003268},
3269{ /* for srcSize <= 128 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003270 /* W, C, H, S, L, T, strat */
Yann Collet5894ea82016-07-22 14:36:46 +02003271 { 17, 12, 12, 1, 7, 8, ZSTD_fast }, /* level 0 - not used */
3272 { 17, 12, 13, 1, 6, 8, ZSTD_fast }, /* level 1 */
3273 { 17, 13, 16, 1, 5, 8, ZSTD_fast }, /* level 2 */
3274 { 17, 16, 16, 2, 5, 8, ZSTD_dfast }, /* level 3 */
3275 { 17, 13, 15, 3, 4, 8, ZSTD_greedy }, /* level 4 */
3276 { 17, 15, 17, 4, 4, 8, ZSTD_greedy }, /* level 5 */
3277 { 17, 16, 17, 3, 4, 8, ZSTD_lazy }, /* level 6 */
3278 { 17, 15, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 7 */
3279 { 17, 17, 17, 4, 4, 8, ZSTD_lazy2 }, /* level 8 */
3280 { 17, 17, 17, 5, 4, 8, ZSTD_lazy2 }, /* level 9 */
3281 { 17, 17, 17, 6, 4, 8, ZSTD_lazy2 }, /* level 10 */
3282 { 17, 17, 17, 7, 4, 8, ZSTD_lazy2 }, /* level 11 */
3283 { 17, 17, 17, 8, 4, 8, ZSTD_lazy2 }, /* level 12 */
3284 { 17, 18, 17, 6, 4, 8, ZSTD_btlazy2 }, /* level 13.*/
Yann Collet3b719252016-03-30 19:48:05 +02003285 { 17, 17, 17, 7, 3, 8, ZSTD_btopt }, /* level 14.*/
3286 { 17, 17, 17, 7, 3, 16, ZSTD_btopt }, /* level 15.*/
3287 { 17, 18, 17, 7, 3, 32, ZSTD_btopt }, /* level 16.*/
3288 { 17, 18, 17, 7, 3, 64, ZSTD_btopt }, /* level 17.*/
3289 { 17, 18, 17, 7, 3,256, ZSTD_btopt }, /* level 18.*/
3290 { 17, 18, 17, 8, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003291 { 17, 18, 17, 9, 3,256, ZSTD_btopt2 }, /* level 20.*/
3292 { 17, 18, 17, 10, 3,256, ZSTD_btopt2 }, /* level 21.*/
3293 { 17, 18, 17, 11, 3,512, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003294},
3295{ /* for srcSize <= 16 KB */
Yann Collet3b719252016-03-30 19:48:05 +02003296 /* W, C, H, S, L, T, strat */
Yann Collet2b1a3632016-07-13 15:16:00 +02003297 { 14, 12, 12, 1, 7, 6, ZSTD_fast }, /* level 0 - not used */
Yann Collete557fd52016-07-17 16:21:37 +02003298 { 14, 14, 14, 1, 6, 6, ZSTD_fast }, /* level 1 */
Yann Collet2b1a3632016-07-13 15:16:00 +02003299 { 14, 14, 14, 1, 4, 6, ZSTD_fast }, /* level 2 */
3300 { 14, 14, 14, 1, 4, 6, ZSTD_dfast }, /* level 3.*/
3301 { 14, 14, 14, 4, 4, 6, ZSTD_greedy }, /* level 4.*/
3302 { 14, 14, 14, 3, 4, 6, ZSTD_lazy }, /* level 5.*/
3303 { 14, 14, 14, 4, 4, 6, ZSTD_lazy2 }, /* level 6 */
3304 { 14, 14, 14, 5, 4, 6, ZSTD_lazy2 }, /* level 7 */
3305 { 14, 14, 14, 6, 4, 6, ZSTD_lazy2 }, /* level 8.*/
3306 { 14, 15, 14, 6, 4, 6, ZSTD_btlazy2 }, /* level 9.*/
Yann Collet3b719252016-03-30 19:48:05 +02003307 { 14, 15, 14, 3, 3, 6, ZSTD_btopt }, /* level 10.*/
3308 { 14, 15, 14, 6, 3, 8, ZSTD_btopt }, /* level 11.*/
3309 { 14, 15, 14, 6, 3, 16, ZSTD_btopt }, /* level 12.*/
3310 { 14, 15, 14, 6, 3, 24, ZSTD_btopt }, /* level 13.*/
3311 { 14, 15, 15, 6, 3, 48, ZSTD_btopt }, /* level 14.*/
3312 { 14, 15, 15, 6, 3, 64, ZSTD_btopt }, /* level 15.*/
3313 { 14, 15, 15, 6, 3, 96, ZSTD_btopt }, /* level 16.*/
3314 { 14, 15, 15, 6, 3,128, ZSTD_btopt }, /* level 17.*/
3315 { 14, 15, 15, 6, 3,256, ZSTD_btopt }, /* level 18.*/
3316 { 14, 15, 15, 7, 3,256, ZSTD_btopt }, /* level 19.*/
Przemyslaw Skibinski5c5f01f2016-10-25 12:25:07 +02003317 { 14, 15, 15, 8, 3,256, ZSTD_btopt2 }, /* level 20.*/
3318 { 14, 15, 15, 9, 3,256, ZSTD_btopt2 }, /* level 21.*/
3319 { 14, 15, 15, 10, 3,256, ZSTD_btopt2 }, /* level 22.*/
Yann Colletfd416f12016-01-30 03:14:15 +01003320},
3321};
3322
Yann Collet236d94f2016-05-18 12:06:33 +02003323/*! ZSTD_getCParams() :
3324* @return ZSTD_compressionParameters structure for a selected compression level, `srcSize` and `dictSize`.
3325* Size values are optional, provide 0 if not known or unused */
Yann Collet52c04fe2016-07-07 11:53:18 +02003326ZSTD_compressionParameters ZSTD_getCParams(int compressionLevel, unsigned long long srcSize, size_t dictSize)
Yann Colletfd416f12016-01-30 03:14:15 +01003327{
Yann Collet15354142016-04-04 04:22:53 +02003328 ZSTD_compressionParameters cp;
Yann Collet1005fc12016-04-04 13:28:28 +02003329 size_t const addedSize = srcSize ? 0 : 500;
Yann Collet15354142016-04-04 04:22:53 +02003330 U64 const rSize = srcSize+dictSize ? srcSize+dictSize+addedSize : (U64)-1;
Yann Collet3b719252016-03-30 19:48:05 +02003331 U32 const tableID = (rSize <= 256 KB) + (rSize <= 128 KB) + (rSize <= 16 KB); /* intentional underflow for srcSizeHint == 0 */
Yann Collet236d94f2016-05-18 12:06:33 +02003332 if (compressionLevel <= 0) compressionLevel = ZSTD_DEFAULT_CLEVEL; /* 0 == default; no negative compressionLevel yet */
Yann Colletfd416f12016-01-30 03:14:15 +01003333 if (compressionLevel > ZSTD_MAX_CLEVEL) compressionLevel = ZSTD_MAX_CLEVEL;
Yann Collet15354142016-04-04 04:22:53 +02003334 cp = ZSTD_defaultCParameters[tableID][compressionLevel];
Yann Collet1005fc12016-04-04 13:28:28 +02003335 if (MEM_32bits()) { /* auto-correction, for 32-bits mode */
3336 if (cp.windowLog > ZSTD_WINDOWLOG_MAX) cp.windowLog = ZSTD_WINDOWLOG_MAX;
Yann Collet8a57b922016-04-04 13:49:18 +02003337 if (cp.chainLog > ZSTD_CHAINLOG_MAX) cp.chainLog = ZSTD_CHAINLOG_MAX;
Yann Collet1005fc12016-04-04 13:28:28 +02003338 if (cp.hashLog > ZSTD_HASHLOG_MAX) cp.hashLog = ZSTD_HASHLOG_MAX;
3339 }
Yann Collet70d13012016-06-01 18:45:34 +02003340 cp = ZSTD_adjustCParams(cp, srcSize, dictSize);
Yann Collet15354142016-04-04 04:22:53 +02003341 return cp;
Yann Colletfd416f12016-01-30 03:14:15 +01003342}
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003343
3344/*! ZSTD_getParams() :
Yann Colleta43a8542016-07-12 13:42:10 +02003345* same as ZSTD_getCParams(), but @return a `ZSTD_parameters` object (instead of `ZSTD_compressionParameters`).
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003346* All fields of `ZSTD_frameParameters` are set to default (0) */
Yann Collet52c04fe2016-07-07 11:53:18 +02003347ZSTD_parameters ZSTD_getParams(int compressionLevel, unsigned long long srcSize, size_t dictSize) {
Yann Collet3d2cd7f2016-06-27 15:12:26 +02003348 ZSTD_parameters params;
3349 ZSTD_compressionParameters const cParams = ZSTD_getCParams(compressionLevel, srcSize, dictSize);
3350 memset(&params, 0, sizeof(params));
3351 params.cParams = cParams;
3352 return params;
3353}